О результатах запроса в одной строке с параметризованным запросом - PullRequest
2 голосов
/ 09 июля 2010

Так, у меня есть несколько мест в моей программе, где я просто выбираю одну строку (иногда даже один столбец в одной строке), например

SELECT id,title,posted FROM posts WHERE id=4;

Так как это вернет только одну строку (если только я не сосуся с базой данных и каким-то образом не получу дублированные идентификаторы), я чувствую, что излишне проходить весь путь sqlite3_prepare_v2(...), sqlite3_bind_int(...), sqlite3_step(...), sqlite3_finalize(...) просто чтобы получить один ряд.

Я знаю, что это можно сделать с помощью sqlite3_exec(...) и использованием функции обратного вызова для обработки результатов, которые также return 1;, для прерывания дальнейших выполнений, но в моем случае это не работает, потому что мой запрос выглядит так:

SELECT id,title,posted FROM posts WHERE id=?;

И у вас не может быть параметризованных запросов с sqlite3_exec(...). Вставка идентификатора через printf(...) здесь также небезопасна.

Итак, это то, чем я сейчас занимаюсь

char *sql;
sqlite3_stmt *stmt;

sql = sqlite3_mprintf(
       "SELECT \
          title, \
          ((julianday(posted) - 2440587.5) * 86400), \
          text \
        FROM \
           %s \
        WHERE id=?;",
     POSTS_TABLE); /* printf safe here, POSTS_TABLE is a #define */

if (sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL) != SQLITE_OK)
   show_sqlite_error(db);
else
{
   sqlite3_bind_text(stmt, 1, id, strlen(id), SQLITE_TRANSIENT);
   sqlite_code = sqlite3_step(stmt); /* This right here seems just ugly */

   if (sqlite_code != SQLITE_ROW) /* especially this */
      printf("<div id=\"error\">ERROR: No such ID in database</div>\n");
   else
   {
      int i;
      char time_string[25];

      const unsigned char *title = sqlite3_column_text(stmt, 0);
      time_t time = sqlite3_column_int(stmt, 1);
      const unsigned char *text  = sqlite3_column_text(stmt, 2);

      strftime(time_string, 25, DATE_FORMAT, gmtime(&time));

      printf("<h2 id=\"post_headline\">%s</h2>\n\n", title);
      printf("<h3 id=\"post_time\">%s</h3>\n", time_string);
      printf("<p id=\"post_body\">\n");

      for (i = 0; i < strlen((char *)text); i++)
         if (text[i] == '\n')
            printf("<br />");
         else
            printf("%c", text[i]);
   }
}

Моя проблема с этим кодом заключается в том, что я вызываю sqlite3_step() один раз, выдает ошибку, если все, кроме SQLITE_ROW, возвращается, отображает все, что нужно, если возвращается SQLITE_ROW, и вызывает finalize, фактически не переходя к SQLITE_DONE. Хотя это (как мне сказали) не принесет никакого вреда с помощью SELECT заявления, оно кажется уродливым и излишним.

Другая вещь - это запросы, которые просто возвращают одно значение.

SELECT MAX(id) FROM posts;

В моем случае это просто возвращает "5". Не больше, не меньше. Тем более, что здесь очень сложно пройти весь процесс подготовки, привязки, шага, завершения, но я ДОЛЖЕН сделать это именно так, потому что мой запрос снова выглядит как

SELECT MIN(id) FROM posts WHERE id > ?;

чтобы получить следующий идентификатор после текущего, например. Он просто возвращает «5», когда текущий идентификатор равен «4».

Подводя итог: есть ли быстрый способ получить результаты из одной строки из оператора SELECT без явного зацикливания, пока не будет получено SQLITE_DONE от sqlite3_step() И как получить значение из одной строки в одном столбце (скаляр в основном), не пройдя весь путь снова, включая вызов sqlite_column_...?

1 Ответ

1 голос
/ 09 июля 2010

Я сторонник предотвращения SQL-инъекций , но я думаю, что это можно сделать безопасно:

sql = sqlite3_mprintf("SELECT ... WHERE id=%d;", atoi(id));

Это интерпретирует строку id как целое число через atoi(), поэтому нет шансов на внедрение SQL.

Что касается выборки одной строки или одного скаляра, я бы написал функцию-оболочку, которая выполняет SQL и просто возвращает содержимое. Возможно, вам придется использовать global для передачи содержимого из функции обратного вызова в функцию-оболочку.

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