Использование sqlite3_exec - PullRequest
       16

Использование sqlite3_exec

9 голосов
/ 27 ноября 2009

У меня есть следующие команды SQLITE3, которые генерируют файл с более чем 60 миллионами записей:

.mode csv
.output matppp.csv
select mat, ppp from matppp order by mat;
.output stdout

Как я могу включить эти команды в программу на C, используя:

 sqlite3_exec(db, "..........", NULL, 0, &db_err); 

Когда я пытаюсь сделать это сам, программа c выдает ошибку выражения при выполнении.

Спасибо !!

Ответы [ 4 ]

8 голосов
/ 27 ноября 2009

Если вы хотите сделать это в C (в отличие от передачи чего-либо в программу командной строки sqlite3, которая имеет эти изящные команды точек), вам придется использовать обратный вызов.

Для удобства вырезания и вставки приведен код, взломанный из библиотеки Apophenia для статистических вычислений.

Часть I:

sqlite3 *db=NULL; //The global database handle.

static int apop_db_open(char *filename){
    if (!filename)  
        sqlite3_open(":memory:",&db);
    else            
        sqlite3_open(filename,&db);
    if (!db)
        printf("Not sure why, but the database didn't open.\n");
    return 0;
}

//From the SQLite manual:
#define ERRCHECK {if (err!=NULL) {printf("%s\n",err); sqlite3_free(err);  return 0;}}

apop_data * apop_sqlite_query_to_screen(char *query){
  char *err = NULL;
    if (db==NULL) 
        apop_db_open(NULL);
    sqlite3_exec(db, query, The_Callback, a_param, &err); 
    ERRCHECK
}

Часть II:

Обратный вызов будет иметь следующую форму и будет запускаться один раз для каждой возвращаемой строки. Обратите внимание, как передается параметр a_param; если вам это не нужно (как в этом примере), просто установите его в NULL выше.

int The_Callback(void *a_param, int argc, char **argv, char **column){
    for (int i=0; i< argc; i++)
        printf("%s,\t", argv[i]);
    printf("\n");
    return 0;
}
3 голосов
/ 15 марта 2011

Сопутствующий веб-сайт книги Использование SQLite имеет несколько примеров. В частности, в главе 7 приведены некоторые примеры API C / C ++.

Пример кода: http://examples.oreilly.com/9780596521196/

3 голосов
/ 27 ноября 2009

Я думаю, что вы действительно хотите использовать функцию обратного вызова и, возможно, fprintf () для записи вашего отформатированного вывода в файл. К счастью, прототип для указателя обратного вызова содержит дополнительный (необязательный) void *, который может служить потоком FILE *, что делает повторный вызов более удобным для использования в будущем.

AFAIK, sqlite3_exec () не предлагает тот же интерфейс, что и CLI sqlite3. Это только для запросов, а не выходных модификаторов.

Посмотрите пример кода внизу ссылки, которую я дал, очень легко использовать функцию обратного вызова.

2 голосов
/ 06 июня 2013

Я провожу некоторые эксперименты с SQLite с использованием простого тестового набора, используя одну таблицу, которая содержит ключ строки символов и одно целочисленное значение. Ниже приведены фрагменты источника из экспериментального жгута, который я использую. Я вытащил эти фрагменты, чтобы показать создание таблицы вместе с функцией, которую я использую для создания набора записей из оператора SQL выбора, используя функциональность обратного вызова SQLite. В разных местах есть операторы printf() и операторы fprintf(), поэтому я могу видеть результаты действий, поскольку это простое приложение консольного типа для тестового жгута.

Обратите внимание, что бывают случаи, когда вам не нужен аргумент обратного вызова, поэтому SQLite позволяет вам указывать NULL-указатель, указывающий не беспокоить обратный вызов.

И когда вы читаете источник, просто помните, что это экспериментальный взлом!

Функция для создания таблицы выглядит так:

int CreateSetupTable (sqlite3 *db)
{
    char *zErrMsg = 0;
    int rc;
    char  *aszSqlCreate = "create table tbl1(one varchar(10), two smallint)";
    char  *aszSqlCreateIndex01 = "create unique index index1 on tbl1 (one)";

    do {
        rc = sqlite3_exec(db, aszSqlCreate, 0, 0, &zErrMsg);
        if( rc!=SQLITE_OK ){
          fprintf(stderr, "SQL error: %s\n", zErrMsg);
          sqlite3_free(zErrMsg);
          break;
        }

        rc = sqlite3_exec(db, aszSqlCreateIndex01, 0, 0, &zErrMsg);
        if( rc!=SQLITE_OK ){
          fprintf(stderr, "SQL error: %s\n", zErrMsg);
          sqlite3_free(zErrMsg);
          break;
        }
    } while (0);  // loop only once to allow breaks on errors

    return rc;
}

Я вставляю некоторые записи в эту таблицу, а затем вызываю функцию, которая вызывает одну или несколько записей из таблицы с помощью оператора select SQL. Функция select извлекает записи и использует обратный вызов для преобразования каждой записи, возвращенной в структуру C. Структура C выглядит следующим образом:

typedef struct {
    char cKey[20];
    int  iValue;
} Tbl1Record;

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

Структура управления обратным вызовом выглядит следующим образом:

typedef struct _RecordProcessor {
    void  *pRecordSet;
    int   nRecordSetMax;
    int   nRecordSetActual;
} RecordProcessor;

Функция выбора выглядит так:

int SelectRecord (sqlite3 *db, char *cSelect, char *cKey)
{
    char *zErrMsg = 0;
    int rc;
    char aszSqlSelect[128];
    Tbl1Record  myRec[20];
    RecordProcessor myProcessor;

    myProcessor.pRecordSet = myRec;
    myProcessor.nRecordSetActual = 0;
    myProcessor.nRecordSetMax = 20;

    if (cKey) {
        sprintf (aszSqlSelect, "select %s from tbl1 where one='%s'", cSelect, cKey);
    } else {
        sprintf (aszSqlSelect, "select %s from tbl1", cSelect);
    }
    rc = sqlite3_exec(db, aszSqlSelect, MyRecordProcessor, &myProcessor, &zErrMsg);
    if( rc!=SQLITE_OK ){
      fprintf(stderr, "SQL error SelectRecord: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
    } else {
        int i;
        for (i = 0; i < myProcessor.nRecordSetActual; i++) {
            printf ("Rec #%d cKey = %s iValue = %d\n", i+1, myRec[i].cKey, myRec[i].iValue);
        }
    }

    return rc;
}

Обратный вызов, который обрабатывает каждую запись, возвращаемую select, выглядит следующим образом:

static int MyRecordProcessor (void *callBackArg, int argc, char **argv, char **azColName)
{
    int iRetStatus = 0;
    char *colNameTable[] = {
        "one",
        "two"
    };
    Tbl1Record *pTbl1Record = (Tbl1Record *)((RecordProcessor *)callBackArg)->pRecordSet;

    if (((RecordProcessor *)callBackArg)->nRecordSetActual < ((RecordProcessor *)callBackArg)->nRecordSetMax) {
        int i, j;
        int iIndex = ((RecordProcessor *)callBackArg)->nRecordSetActual;

        memset (pTbl1Record + iIndex, 0, sizeof(Tbl1Record));
        ((RecordProcessor *)callBackArg)->nRecordSetActual++;
        for (i = 0; i < argc; i++){
            int j;
            for (j = 0; j < sizeof (colNameTable)/sizeof(colNameTable[0]); j++) {
                if (strcmp (azColName[i], colNameTable[j]) == 0) {
                    switch (j) {
                        case 0:
                            strncpy (pTbl1Record[iIndex].cKey, (argv[i] ? argv[i] : "NULL"), 19);
                            break;
                        case 1:
                            pTbl1Record[iIndex].iValue = atoi (argv[i] ? argv[i] : "0");
                            break;
                        default:
                            break;
                    }
                    break;
                }
            }
        }
    }

    return iRetStatus;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...