2010-09-17 2 views
7

У меня есть файл, содержащий несколько операторов sql, которые я хотел бы использовать для инициализации нового файла базы данных sqlite3. По-видимому, sqlite3 обрабатывает только несколько операторов в одном запросе через функцию sqlite3_exec, а не через функции подготовки/шага/завершения. Все в порядке, но я бы хотел использовать apt QtSQL, а не c api. Загрузка в тот же файл инициализатора через QSqlQuery выполняет только первый оператор, точно так же, как непосредственно с помощью функций prepare/step/finalize из sqlite3 api. Есть ли способ заставить QSqlQuery запускать несколько запросов без необходимости иметь отдельные вызовы query.exec() для каждого оператора?несколько операторов sql в QSqlQuery с использованием драйвера sqlite3

ответ

9

Как четко указано в Qt документации для QSqlQuery::prepare() и QSqlQuery::exec(),

Для SQLite, строка запроса может содержать только один оператор в то время. Если задано несколько операторов, функция возвращает false.

Как вы уже догадались, единственным известным обходным путем для этого ограничения является наличие всех операторов sql, разделенных некоторой строкой, разделение операторов и выполнение каждого из них в цикле.

См. Следующий примерный код (который использует «;» как разделитель и предполагает, что в запросах используется тот же символ, который не используется внутри этих запросов.Это не хватает общности, поскольку у вас может быть данный символ в строковых литералах, где/insert /):

QSqlDatabase database; 
QSqlQuery query(database); 
QFile scriptFile("/path/to/your/script.sql"); 
if (scriptFile.open(QIODevice::ReadOnly)) 
{ 
    // The SQLite driver executes only a single (the first) query in the QSqlQuery 
    // if the script contains more queries, it needs to be splitted. 
    QStringList scriptQueries = QTextStream(&scriptFile).readAll().split(';'); 

    foreach (QString queryTxt, scriptQueries) 
    { 
     if (queryTxt.trimmed().isEmpty()) { 
      continue; 
     } 
     if (!query.exec(queryTxt)) 
     { 
      qFatal(QString("One of the query failed to execute." 
         " Error detail: " + query.lastError().text()).toLocal8Bit()); 
     } 
     query.finish(); 
    } 
} 
+1

как о 'SELECT "привет; мир из таблицы" или' SELECT * FROM таблицы --hello; world'? – yrHeTaTeJlb

1

Я написал простую функцию для чтения SQL из файла и выполнения ее по одной инструкции за раз.

/** 
* @brief executeQueriesFromFile Read each line from a .sql QFile 
* (assumed to not have been opened before this function), and when ; is reached, execute 
* the SQL gathered until then on the query object. Then do this until a COMMIT SQL 
* statement is found. In other words, this function assumes each file is a single 
* SQL transaction, ending with a COMMIT line. 
*/ 

void executeQueriesFromFile(QFile *file, QSqlQuery *query) 
{ 
    while (!file->atEnd()){ 
     QByteArray readLine=""; 
     QString cleanedLine; 
     QString line=""; 
     bool finished=false; 
     while(!finished){ 
      readLine = file->readLine(); 
      cleanedLine=readLine.trimmed(); 
      // remove comments at end of line 
      QStringList strings=cleanedLine.split("--"); 
      cleanedLine=strings.at(0); 

      // remove lines with only comment, and DROP lines 
      if(!cleanedLine.startsWith("--") 
        && !cleanedLine.startsWith("DROP") 
        && !cleanedLine.isEmpty()){ 
       line+=cleanedLine; 
      } 
      if(cleanedLine.endsWith(";")){ 
       break; 
      } 
      if(cleanedLine.startsWith("COMMIT")){ 
       finished=true; 
      } 
     } 

     if(!line.isEmpty()){ 
      query->exec(line); 
     } 
     if(!query->isActive()){ 
      qDebug() << QSqlDatabase::drivers(); 
      qDebug() << query->lastError(); 
      qDebug() << "test executed query:"<< query->executedQuery(); 
      qDebug() << "test last query:"<< query->lastQuery(); 
     } 
    } 
}