Запросы с готовыми заявлениями в Android?

В Android android.database.sqlite.SQLiteStatement позволяет использовать подготовленные инструкции в SQLite, чтобы избежать инъекций. Его метод execute подходит для операций create/update/delete, но, похоже, не существует метода для запросов, который возвращает курсор или тому подобное.

Теперь в iOS я могу создать подготовленные операторы типа sqlite3_stmt* и использовать их для запросов, поэтому я знаю, что это не ограничение SQLite. Как я могу выполнять запросы с подготовленными операторами в Android?

Ответ 1

подготовленный оператор позволяет вам делать две вещи

  • ускорить работу, поскольку база данных не нуждается в синтаксическом анализе оператора
  • связывать и убирать аргументы в инструкции, чтобы вы спаслись от инъекционных атак.

Я точно не знаю, где/когда реализация SQLite на Androids фактически использует sqlite3_prepare (afiak not sqlite3_prepare_v2 - см. здесь) но он использует его, иначе вы не смогли бы получить Достигнутый размер MAX для ошибок кэша операторов compiled-sql.

Поэтому, если вы хотите запросить базу данных, вы должны полагаться на реализацию, я не знаю, как это сделать с помощью SQLiteStatement.

Что касается безопасности инъекций, каждый запрос на базу данных, insert и т.д. имеет (иногда альтернативные) версии, которые позволяют связывать аргументы.

например. если вы хотите получить Cursor из

SELECT * FROM table WHERE column1='value1' OR column2='value2'

Cursor SQLiteDatabase#rawQuery(

  • String sql,: full SELECT statment, который может включать ? всюду
  • String[] selectionArgs: список значений, которые заменяют ?, чтобы они отображались

)

Cursor c1 = db.rawQuery(
    "SELECT * FROM table WHERE column1=? OR column2=?",
    new String[] {"value1", "value2"}
);

Cursor SQLiteDatabase#query (

  • String table,: имя таблицы, может включать JOIN и т.д.
  • String[] columns,: список требуемых столбцов, null= *
  • String selection,: WHERE оговорка withouth WHERE может/должна включать ?
  • String[] selectionArgs,: список значений, которые заменяют ?, чтобы они отображались
  • String groupBy,: GROUP BY статья без GROUP BY
  • String having,: HAVING статья без HAVING
  • String orderBy: ORDER BY статья без ORDER BY

)

Cursor c2 = db.query("table", null, 
     "column1=? OR column2=?", 
      new String[] {"value1", "value2"},
      null, null, null);

Через ContentProviders - этот случай немного отличается, поскольку вы взаимодействуете с абстрактным провайдером, а не с базой данных. Невозможно гарантировать, что база данных sqlite поддерживает ContentProvider. Поэтому, если вы не знаете, какие столбцы существуют/как работает поставщик, вы должны придерживаться того, что говорит документация.

Cursor ContentResolver#query(

  • Uri uri,: URI, представляющий источник данных (внутренне переведенный в таблицу)
  • String[] projection,: список требуемых столбцов, null= *
  • String selection,: WHERE оговорка withouth WHERE может/должна включать ?
  • String[] selectionArgs,: список значений, которые заменяют ?, чтобы они отображались
  • String sortOrder: ORDER BY статья w/o ORDER BY

)

Cursor c3 = getContentResolver().query(
     Uri.parse("content://provider/table"), null,
     "column=? OR column2=?", 
      new String[] {"value1", "value2"},
      null);

Подсказка: если вы хотите LIMIT здесь, вы можете добавить его в предложение ORDER BY:

String sortOrder = "somecolumn LIMIT 5";

или в зависимости от реализации ContentProvider добавьте его как параметр в Uri:

Uri.parse("content://provider/table?limit=5");
// or better via buildUpon()
Uri audio = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
audio.buildUpon().appendQueryParameter("limit", "5");

Во всех случаях ? будет заменен экранированной версией того, что вы положили в аргументе bind.

? + "hack'me"= 'hack''me'