Регистрация SQL-запросов в Android - PullRequest
52 голосов
/ 11 мая 2011

Я использую функции query для построения запросов SQL для моих таблиц. Есть ли способ увидеть фактический запрос, который выполняется? Например, войти где-нибудь?

Пока что лучшее, что я мог сделать, - это посмотреть на член курсора mQuery, используя точку останова. Я хотел бы выводить запросы автоматически, хотя. Этот участник, конечно, не является публичным и не имеет получателя.


Просто для протокола, вот реализация принятого ответа.

/**
 * Implement the cursor factory in order to log the queries before returning 
 * the cursor
 * 
 * @author Vincent @ MarvinLabs
 */
public class SQLiteCursorFactory implements CursorFactory {

    private boolean debugQueries = false;

    public SQLiteCursorFactory() {
        this.debugQueries = false;
    }

    public SQLiteCursorFactory(boolean debugQueries) {
        this.debugQueries = debugQueries;
    }

    @Override
    public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, 
                            String editTable, SQLiteQuery query) {
        if (debugQueries) {
            Log.d("SQL", query.toString());
        }
        return new SQLiteCursor(db, masterQuery, editTable, query);
    }
}

Ответы [ 9 ]

35 голосов
/ 19 мая 2011

Вы можете применить свой собственный SQLiteDatabase.CursorFactory к базе данных. (См. Параметры openDatabase .) Это позволит вам создать свой собственный подкласс Cursor, который хранит запрос в легко доступном поле.

edit : На самом деле, вам даже не нужно создавать подкласс Cursor. Просто попросите метод фабрики newCursor() вернуть стандартный SQLiteCursor, но перед этим запишите запрос.

31 голосов
/ 03 октября 2013
adb shell setprop log.tag.SQLiteStatements VERBOSE

Не забудьте перезапустить приложение после установки этого свойства.

Также возможно включить ведение журнала времени выполнения.Более подробная информация доступна здесь: http://androidxref.com/4.2.2_r1/xref/frameworks/base/core/java/android/database/sqlite/SQLiteDebug.java

16 голосов
/ 06 февраля 2016
adb shell setprop log.tag.SQLiteLog V
adb shell setprop log.tag.SQLiteStatements V
adb shell stop
adb shell start
5 голосов
/ 13 января 2013

Используя SQLiteQueryBuilder это больно просто. buildQuery() возвращает необработанную строку sql, которую затем можно зарегистрировать:

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(ExampleTable.TABLE_NAME);
String sql = qb.buildQuery(projection, selection, null, null, sortOrder, null);
Log.d("Example", sql);
3 голосов
/ 18 мая 2011

До сих пор лучшее, что я мог сделать, - это посмотреть на член курсора mQuery, используя точку останова.Этот член, конечно, не является общедоступным и не имеет получателя, следовательно, нет способа его вывода.Любое лучшее предложение?

1 голос
/ 25 декабря 2013

Если вы используете SQLiteDatabase со стандартными методами, такими как вставка, обновление и удаление пользовательских CursorFactory не будут работать.

Я реализовал свое не очень хорошее, но работающее решение на основе класса SQLiteDatabase.Он просто повторяет логику методов вставки, обновления и удаления, но без операторов и фактически делает запись операторов SQL.

public class SQLiteStatementsLogger {

    private static final String TAG = SQLiteStatementsLogger.class.getSimpleName();

    private static final String[] CONFLICT_VALUES = new String[]
            {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};

    public void logInsert(String table, String nullColumnHack, ContentValues values) {
        logInsertWithOnConflict(table, nullColumnHack, values, 0);
    }

    public static void logInsertWithOnConflict(String table, String nullColumnHack,
                                     ContentValues initialValues, int conflictAlgorithm) {
        StringBuilder sql = new StringBuilder();
        sql.append("INSERT");
        sql.append(CONFLICT_VALUES[conflictAlgorithm]);
        sql.append(" INTO ");
        sql.append(table);
        sql.append('(');

        Object[] bindArgs = null;
        int size = (initialValues != null && initialValues.size() > 0)
                ? initialValues.size() : 0;
        if (size > 0) {
            bindArgs = new Object[size];
            int i = 0;
            for (String colName : initialValues.keySet()) {
                sql.append((i > 0) ? "," : "");
                sql.append(colName);
                bindArgs[i++] = initialValues.get(colName);
            }
            sql.append(')');
            sql.append(" VALUES (");
            for (i = 0; i < size; i++) {
                sql.append((i > 0) ? ",?" : "?");
            }
        } else {
            sql.append(nullColumnHack + ") VALUES (NULL");
        }
        sql.append(')');
        sql.append(". (");
        for (Object arg : bindArgs) {
            sql.append(String.valueOf(arg)).append(",");
        }
        sql.deleteCharAt(sql.length()-1).append(')');
        Log.d(TAG, sql.toString());
    }

    public static void logUpdate(String table, ContentValues values, String whereClause, String[] whereArgs) {
        logUpdateWithOnConflict(table, values, whereClause, whereArgs, 0);
    }

    public static void logUpdateWithOnConflict(String table, ContentValues values,
                                        String whereClause, String[] whereArgs, int conflictAlgorithm) {

        StringBuilder sql = new StringBuilder(120);
        sql.append("UPDATE ");
        sql.append(CONFLICT_VALUES[conflictAlgorithm]);
        sql.append(table);
        sql.append(" SET ");

        // move all bind args to one array
        int setValuesSize = values.size();
        int bindArgsSize = (whereArgs == null) ? setValuesSize : (setValuesSize + whereArgs.length);
        Object[] bindArgs = new Object[bindArgsSize];
        int i = 0;
        for (String colName : values.keySet()) {
            sql.append((i > 0) ? "," : "");
            sql.append(colName);
            bindArgs[i++] = values.get(colName);
            sql.append("=?");
        }
        if (whereArgs != null) {
            for (i = setValuesSize; i < bindArgsSize; i++) {
                bindArgs[i] = whereArgs[i - setValuesSize];
            }
        }
        if (!TextUtils.isEmpty(whereClause)) {
            sql.append(" WHERE ");
            sql.append(whereClause);
        }
        sql.append(". (");
        for (Object arg : bindArgs) {
            sql.append(String.valueOf(arg)).append(",");
        }
        sql.deleteCharAt(sql.length()-1).append(')');
        Log.d(TAG, sql.toString());
    }

    public static void logDelete(String table, String whereClause, String[] whereArgs) {
        StringBuilder sql = new StringBuilder("DELETE FROM " + table);
        if (!TextUtils.isEmpty(whereClause)) {
            sql.append(" WHERE " + whereClause);
            sql.append(". (");
            for (Object arg : whereArgs) {
                sql.append(String.valueOf(arg)).append(",");
            }
            sql.deleteCharAt(sql.length()-1).append(')');
        }
        Log.d(TAG, sql.toString());
    }
}

Помните, что не следует использовать регистратор в версиях выпуска.Это может увеличить время выполнения запросов.Вы можете проверить, находится ли сборка в режиме отладки, с помощью следующей строки кода:

0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)
1 голос
/ 14 июня 2012

Если это один раз для сценария, я бы предложил ввести ошибку (например, введите выражение, например, LIEK вместо LIKE!), И просмотрите Eclipse LogCat на наличие ошибок!НТН!

0 голосов
/ 07 июня 2012

Если вы используете ContentProvider для доступа к БД, я получил это, регистрируя запросы. Не идеальное решение, но оно работает на развитие

@Override
  public boolean onCreate() {
    dbHelper = new MySQLiteHelper(getContext());
    database=dbHelper.getWritableDatabase();

    if(!database.isReadOnly())
      database.execSQL("PRAGMA foreign_keys=ON;");
    return true;
  }            

  SQLiteDatabase.CursorFactory cursorFactory = new SQLiteDatabase.CursorFactory() {      
    @Override
    public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, SQLiteQuery query) {
      Log.d(TAG, "Query: "+query);

      return new SQLiteCursor(db, masterQuery, editTable, query);
    }
  };

  @Override
  public Cursor query(Uri uri, String[] projection, String selection,
      String[] selectionArgs, String sortOrder) {
    String table =getTableName(uri);

    if(Constants.LOG_QUERIES){
      database = SQLiteDatabase.openOrCreateDatabase(database.getPath(), cursorFactory);
    }

    Cursor cursor =database.query(table,  projection, selection, selectionArgs, null, null, sortOrder);
    cursor.moveToFirst();

    return cursor;
  }

Будет сгенерировано исключение DatabaseNotClosed, но вы сможете увидеть запрос

0 голосов
/ 11 мая 2011

Лично я регистрирую текст, используя java.util.Log и функцию Log.w("MYAPPNAME", "My text..."). Он отображается в представлении «Журнал» Eclipse и может быть отфильтрован для вывода только журналов «MYAPPNAME».

...