Как искать в SQLite строку с одинарными и двойными кавычками в Android?

Я запрашиваю SQLite с Android с помощью курсора следующим образом.

Cursor searchCusor = getCursorForSearchQuery(str);

где str — строка. Эта строка может содержать одинарные и двойные кавычки. Поэтому, когда курсор пытается выполнить поиск, он выдает исключение

04-12 17:32:11.961: E/AndroidRuntime(2337): FATAL EXCEPTION: main
04-12 17:32:11.961: E/AndroidRuntime(2337): android.database.sqlite.SQLiteException: unrecognized token: "' AND latitude != 0 AND longitude != 0 ORDER BY title ASC": , while compiling: SELECT _id, title FROM node WHERE title LIKE '%'%' AND latitude != 0 AND longitude != 0 ORDER BY title ASC
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteCompiledSql.native_compile(Native Method)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:91)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:64)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:80)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:46)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1412)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1296)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1251)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1331)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at com.mid.kew.apies.KewDatabaseHelper.getCursorForSearchMapPage(KewDatabaseHelper.java:285)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at com.mid.kew.activities.MapFragment.getCursorForSearchQuery(MapFragment.java:538)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at com.mid.kew.activities.MapFragment.access$12(MapFragment.java:537)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at com.mid.kew.activities.MapFragment$6.afterTextChanged(MapFragment.java:348)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.widget.TextView.sendAfterTextChanged(TextView.java:6271)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.widget.TextView$ChangeWatcher.afterTextChanged(TextView.java:6454)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.text.SpannableStringBuilder.sendTextHasChanged(SpannableStringBuilder.java:903)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.text.SpannableStringBuilder.change(SpannableStringBuilder.java:359)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.text.SpannableStringBuilder.change(SpannableStringBuilder.java:275)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:438)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:415)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:28)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.view.inputmethod.BaseInputConnection.replaceText(BaseInputConnection.java:583)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.view.inputmethod.BaseInputConnection.commitText(BaseInputConnection.java:174)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at com.android.internal.widget.EditableInputConnection.commitText(EditableInputConnection.java:120)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:247)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:73)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.os.Handler.dispatchMessage(Handler.java:99)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.os.Looper.loop(Looper.java:144)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at android.app.ActivityThread.main(ActivityThread.java:4937)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at java.lang.reflect.Method.invokeNative(Native Method)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at java.lang.reflect.Method.invoke(Method.java:521)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
04-12 17:32:11.961: E/AndroidRuntime(2337):     at dalvik.system.NativeStart.main(Native Method)

Я попытался заменить одинарные кавычки следующим образом

str.replace("'", "\' ");

Но это не сработало и выдало ту же ошибку


person Nik    schedule 11.04.2012    source источник


Ответы (2)


Вы не показали, что делает ваш метод getCursorForSearchQuery, но я предполагаю, что он просто включает значение непосредственно в SQL. Не делай этого. Используйте параметризованный SQL-запрос с PreparedStatement, и все должно быть хорошо. Мало того, что ваша текущая ошибка исчезнет, ​​вы также закроете уязвимость SQL Injection Attack, и вы будете в лучшем положении для обработки других типов данных без проблем с преобразованием.

person Jon Skeet    schedule 11.04.2012
comment
Привет, спасибо за помощь... Это то, что делает метод myDatabase.query(node, new String[]{_id,title}, title LIKE \'% + stringToSearch +%\' И широта! = 0 И долгота! = 0, null, null, null, заголовок ASC); Не могли бы вы привести пример того, что вы мне предложили, пожалуйста. - person Nik; 12.04.2012
comment
@Raj: см. developer.android.com/reference/java/sql/PreparedStatement. html и связанные темы. - person Jon Skeet; 12.04.2012
comment
Еще раз спасибо ... Я попробовал следующую строку, и это сработало ... myDatabase.rawQuery (ВЫБЕРИТЕ _id, заголовок ОТ узла, ГДЕ заголовок НРАВИТСЯ? И широта! = 0 И долгота! = 0 ORDER BY title ASC, новая строка [] {%+stringToSearch+%}); это то, что вы упоминаете в своем ответе - person Nik; 12.04.2012
comment
@Raj: Ну, я бы, наверное, использовал SQLiteStatement, но это, по крайней мере, вид того, что я имел в виду. Вам все еще нужно подумать о том, что произойдет, если входные данные содержат знаки %, но, по крайней мере, вы не получите атаки с помощью SQL-инъекций... - person Jon Skeet; 12.04.2012

Ранее я использовал следующее утверждение

myDatabase.query("node", new String[]{"_id","title"}, "title LIKE \'%" + stringToSearch +"%\' AND latitude != 0 AND longitude != 0" ,null, null,null, "title ASC");

что создало проблему, которую я упомянул

Поэтому я изменил запрос на

myDb.query("node", new String[]{"_id","title"}, "title LIKE ? AND latitude != 0 AND longitude != 0" ,new String[]{"%"+stringToSearch+"%"}, null,null, "title ASC");

и сейчас работает нормально.

person Nik    schedule 12.04.2012