una declaración preparada le permite hacer dos cosas
- acelerar el rendimiento, ya que la base de datos no tiene que analizar la instrucción cada vez
- unen & argumentos de escape en la cuenta de lo que son salvación contra ataques de inyección
que no saben exactamente dónde/cuándo aplicación androides SQLite utiliza realmente sqlite3_prepare
(afiak no sqlite3_prepare_v2
- ver here) pero t lo usa de lo contrario no podría obtener Reached MAX size for compiled-sql statement cache errors.
Así que si quiere consultar la base de datos debe confiar en la implementación, no hay manera de que yo sepa hacerlo con SQLiteStatement
.
Con respecto a la seguridad de inyección, cada método de consulta, inserción, etc. de la base de datos tiene versiones (a veces alternativas) que le permiten vincular argumentos.
E.g.si usted desea conseguir un Cursor
de
SELECT * FROM table WHERE column1='value1' OR column2='value2'
Cursor SQLiteDatabase#rawQuery(
String sql
,: completa SELECT
DECLARACIÓN que puede incluir ?
todas partes
String[] selectionArgs
: lista de valores que reemplazan ?
, en Para que aparezcan
)
Cursor c1 = db.rawQuery(
"SELECT * FROM table WHERE column1=? OR column2=?",
new String[] {"value1", "value2"}
);
Cursor SQLiteDatabase#query (
String table
,: nombre de la tabla, puede incluir JOIN
etc
String[] columns
,: lista de las columnas se requiere, null
= *
String selection
,: WHERE
cláusula withouth WHERE
puede/debe incluir ?
String[] selectionArgs
,: lista de valores que reemplazan ?
, en el orden en que aparecen
String groupBy
,: GROUP BY
cláusula w/o GROUP BY
String having
,: HAVING
cláusula w/o HAVING
String orderBy
: ORDER BY
cláusula w/o ORDER BY
)
Cursor c2 = db.query("table", null,
"column1=? OR column2=?",
new String[] {"value1", "value2"},
null, null, null);
Via ContentProviders - ese caso es un poco diferente, ya que interactúa con un proveedor abstracta, no es una base de datos. No hay garantía de que exista una base de datos sqlite que respalde el ContentProvider
. Entonces, a menos que sepa qué columnas hay/cómo el proveedor funciona internamente, debe apegarse a lo que dice la documentación.
Cursor ContentResolver#query(
Uri uri
,: un URI que representa la fuente de datos (traducido internamente a una mesa)
String[] projection
,: lista de las columnas se requiere, null
= *
String selection
,: WHERE
cláusula withouth WHERE
puede/debe incluir ?
String[] selectionArgs
,: lista de valores que reemplazan ?
, en el orden en que aparecen
String sortOrder
: ORDER BY
cláusula w/o ORDER BY
)
Cursor c3 = getContentResolver().query(
Uri.parse("content://provider/table"), null,
"column=? OR column2=?",
new String[] {"value1", "value2"},
null);
Consejo: si quieres LIMIT
Aquí puede añadir a la ORDER BY
cláusula:
String sortOrder = "somecolumn LIMIT 5";
o dependiendo de la aplicación de la ContentProvider
añadirlo como un parámetro a la 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");
En todos los casos ?
será reemplazado por la versión escapado de lo que se pone en el argumento se unen.
?
+ "hack'me"
= 'hack''me'
posterior excepcional, gracias, me ha ayudado mucho. Tiempos como estos me hacen pensar que necesitamos poder modificar más de una vez. – Louis
Incluso si esta respuesta es muy antigua, ¿hay alguna solución para enlazar algo más que una Cadena? Mis consultas solicitan un valor numérico para ser vinculante, pero todos los métodos de SqliteDatabase usan una matriz String. Y si yo mismo creo el PreparedStatement, puedo ejecutar la consulta para recuperar el Cursor ... No puedo creer que no haya solución, pero no lo he encontrado todavía. – AxelH
@AxelH La solución es que todo se puede expresar como una cadena. Por ejemplo, use 'String.valueOf (yourNumericThingHere)'. – zapl