Как обрабатывать слова с апострофом?

Я заполняю массив несколькими городами, но один из них («Reggio nell'Emilia») имеет апостроф в названии, и когда я выбираю его в приложении, он вылетает. Вот код:

SQLiteDatabase db_read = db.getReadableDatabase();
city = new ArrayList<Object>();
Cursor result;
for (int i =0 ; i<region.size(); i++) {
    result = db_read.rawQuery("select distinct city from merchants where region='"+region.get(i)+"' order by city ASC",null);
    ArrayList<String> cities = new ArrayList<String>();
    while (result.moveToNext()) {
        String city = result.getString(0);
        cities.add(city);
    }
    city.add(cities);
}

Вот ошибка в LogCat:

07-26 14:25:4    0.11    0: I/Timeline(155    06): Timeline: Activity_launch_request id:com.example.myapp time:1    0873122
07-26 14:25:4    0.225: E/SQLiteLog(155    06): (1) near "Emilia": syntax error
07-26 14:25:4    0.225: D/AndroidRuntime(155    06): Shutting down VM
07-26 14:25:4    0.225: W/dalvikvm(155    06): threadid=1: thread exiting with uncaught exception (group=    0x41f17ce    0)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06): FATAL EXCEPTION: main
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06): Process: com.example.myapp, PID: 155    06
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myapp/com.example.myapp.ListMerchant}: android.database.sqlite.SQLiteException: near "Emilia": syntax error (code 1): , while compiling: Select _id,title,phone,comune from merchants where city='Reggio nell'Emilia'
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2217)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2266)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.app.ActivityThread.access$8    0    0(ActivityThread.java:145)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:12    06)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.os.Handler.dispatchMessage(Handler.java:1    02)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.os.Looper.loop(Looper.java:136)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.app.ActivityThread.main(ActivityThread.java:5141)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at java.lang.reflect.Method.invokeNative(Native Method)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at java.lang.reflect.Method.invoke(Method.java:515)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:611)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at dalvik.system.NativeStart.main(Native Method)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06): Caused by: android.database.sqlite.SQLiteException: near "Emilia": syntax error (code 1): , while compiling: Select _id,title,phone,comune from merchants where city='Reggio nell'Emilia'
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:5    0    0)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1253)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at com.example.myapp.ListMerchant.createListFromCity(ListMerchant.java:63)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at com.example.myapp.ListMerchant.onCreate(ListMerchant.java:43)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.app.Activity.performCreate(Activity.java:5231)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1    087)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2171)
07-26 14:25:4    0.24    0: E/AndroidRuntime(155    06):    ... 11 more

Я попытался использовать эту подсказку:

String city = result.getString(0);
city = city.replace("'", "''");

и это исправляет ошибку, но я получаю имя с двойным апострофом:

введите здесь описание изображения

Вы знаете лучшее решение? Заранее спасибо.


person smartmouse    schedule 18.08.2014    source источник
comment
Это связано с тем, что вы уязвимы для атак с внедрением кода SQL.   -  person Marc B    schedule 18.08.2014
comment
Можете ли вы записать данные с помощью другого символа, например | или что-то? затем заменить его во время выполнения?   -  person durbnpoisn    schedule 18.08.2014
comment
Как это исправить в моем приложении?   -  person smartmouse    schedule 18.08.2014
comment
Не меняйте вопрос; это сделает любые ответы недействительными.   -  person CL.    schedule 18.08.2014
comment
Я сделал это, чтобы ответить на ваш ответ, извините, если я был неправ   -  person smartmouse    schedule 18.08.2014


Ответы (3)


Использование параметров устраняет такие проблемы с форматированием:

result = db_read.rawQuery("select ... where region = ? ...",
                          new String[] { region.get(i) });
person CL.    schedule 18.08.2014
comment
Я отредактировал код, пожалуйста, посмотрите на него и скажите, правильно ли он. В любом случае я получаю ту же ошибку... - person smartmouse; 18.08.2014
comment
Если ошибка по-прежнему показывает старый запрос, это не из нового кода. - person CL.; 18.08.2014

Вы должны использовать SqliteQueryBuilder, чтобы сделать безопасный запрос:

SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// Set the table
queryBuilder.setTables('Table_Name');

SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection,
    selectionArgs, null, null, sortOrder);

Удачи.

Отредактировано:

Также есть метод util в классе 'DatabaseUtils` в andorid справке вам, чтобы избежать нежелательных символов:

value = DatabaseUtils.sqlEscapeString(value);
person Sadegh    schedule 18.08.2014
comment
Почему вы используете getWritableDatabase() вместо getReadableDatabase()? В любом случае это не работает, я получаю ту же ошибку :( - person smartmouse; 18.08.2014

Наконец-то я решил проблему, используя подсказку (описанную в моем вопросе) в другой части кода (она использовалась как дополнительная в другом действии).

person smartmouse    schedule 18.08.2014