2010-07-09 77 views
2

洙,我有我的计划了几个地方,我只取单排(有时甚至在一个单行单列),例如关于单行查询结果与参数查询

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

因为这将只返回一行(除非我吸收数据库的东西,并以某种方式设法重复的ID)我觉得这是矫枉过正整个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(...)插入ID在这里也不安全。

所以,这是我在做什么,现在

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,并且调用完成而不实际步进到SQLITE_DONE。虽然(据我所知),这不会对SELECT声明造成任何损害,但它会让人觉得丑陋和过度。

另一件事是只返回单个值的查询。

SELECT MAX(id) FROM posts; 

在我的情况下,这只是返回“5”。没有更多,不少。尤其是这里真的矫枉过正去整备,绑定,步骤,最终确定的方式,但我必须这样做的,因为我再次查询看起来像

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

当前一个后获取下一个ID例。当前ID是“4”时它只返回“5”。

总结这件事:有没有快速的方法来抓住从一个SELECT声明单列结果没有明确的循环,直到SQLITE_DONEsqlite3_step()接收,我怎么抢单列,单独列的值(skalar基本上)没有去的整个方式再次,包括一个电话sqlite_column_...

+0

为什么不在这里插入id与sprintf安全? – nos 2010-07-09 17:59:51

+1

如果没有别的...我会重新考虑这一点,让所有的SQL管理都在一个函数中完成,这样当我真正使用它时,这是一个单行的调用。 – Fosco 2010-07-09 18:00:18

+0

@nos这是一个CGI脚本,该ID通过URL提供。虽然我可以通过简单地将ID转换为实际数字而不是将其保留为字符串来实现,但我迟早会再次面对这些问题:) – LukeN 2010-07-09 18:02:57

回答

1

我是advocate of preventing SQL injection,但我认为它应该是安全的做到这一点:

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

这通过atoi()解释id字符串作为一个整数,所以没有SQL注入的机会。

至于提取单行或单个标量,我会编写一个包装函数来执行SQL并简单地返回内容。您可能必须使用全局将内容从回调函数传递到包装函数。

+0

注意到我认为最好的方法。顺便说一下,请仔细阅读有关SQL注入的内容。现在我又偏执了。 :( – LukeN 2010-07-10 08:44:30

+0

你不需要是偏执狂,你只需要有条不紊,并确保你使用过滤,引用或参数化处理每个不安全的输入。 – 2010-07-10 17:18:15