将C变量传递给SQL命令

时间:2014-04-14 22:49:37

标签: c postgresql libpq

我是使用libpq并在postgresql数据库上工作的新手。

所以,我可以使用C程序插入/更新/等一个postgresql数据库,只要我在引号内给出实际值。

我想知道如何在命令??

中传递字符串/整数变量

E.g。以下代码将一个名为“comment”的列添加到现有表“people”中,其中包含“TRUE”默认值。我需要将“comment”的值更新为“FALSE”,其中id = 2。

    #include <stdio.h>
    #include <stdlib.h>
    #include <libpq-fe.h>
    #include <string.h>

 void exit_nicely(PGconn *conn)
 {
  PQfinish(conn);
  exit(1);
 }

 int main()
 {
     PGconn *conn;
     PGresult *res;
 int nFields;
 int row_count=0,col_count=0;
 int row=0;
 int col=0;

 conn = PQconnectdb("dbname=test host=localhost user=postgres password=xxx");

     if(PQstatus(conn) == CONNECTION_BAD) 
     {
    fprintf(stderr, "Connection to database \"%s\" failed.\n", PQerrorMessage(conn));
            fprintf(stderr, "%s", PQerrorMessage(conn));
            exit_nicely(conn);
     }

res = PQexec(conn, "ALTER TABLE people ADD comment VARCHAR(50) DEFAULT 'TRUE'");
if((!res) || PQresultStatus(res) != PGRES_COMMAND_OK) 
{
    fprintf(stderr, "Adding col to table (ALTER) Failed: %s", PQerrorMessage(conn));
    PQclear(res);
    exit_nicely(conn);
    }

res = PQexec(conn, "SELECT * FROM people");
if((!res) || (PQresultStatus(res) != PGRES_TUPLES_OK))
    {
        fprintf(stderr, "SELECT command did not return tuples properly\n");
        PQclear(res);
    }

int query1 = 2;
res = PQexec(conn,"UPDATE people SET comment='FALSE' WHERE id =\'query1\'");
if((!res) || PQresultStatus(res) != PGRES_COMMAND_OK) 
{
    fprintf(stderr, "Insertion Failed: %s", PQerrorMessage(conn));
    PQclear(res);
    exit_nicely(conn);
}
else
    printf("Successfully inserted value in Table..... \n");

res = PQexec(conn, "SELECT * FROM people");
if((!res) || (PQresultStatus(res) != PGRES_TUPLES_OK))
    {
         fprintf(stderr, "SELECT command did not return tuples properly\n");
         PQclear(res);
    }

    puts("==========================");

for(row=0;row<PQntuples(res);row++) 
{
        for(col=0;col<PQnfields(res);col++) 
        {
            printf("%s\t", PQgetvalue(res, row, col));
        }
        puts("");
    }

PQclear(res);

    PQfinish(conn);

    return 0;
  }

我想要以下输出:

id | firstname | lastname | comment
1 | Fred | Flintstone | 5055551234 | TRUE
2 | Wilma | Flintstone | 5055551234 | FALSE
5 | XXX | YYY | 7633839276 | TRUE
3 | Barny | Rubble | 5055550000 | TRUE

但是,我收到以下错误:

Insertion Failed: ERROR:  invalid input syntax for integer: "query1"
LINE 1: UPDATE people SET comment='FALSE' WHERE id ='query1'

请帮我提一些建议。

1 个答案:

答案 0 :(得分:6)

有两种方法可以解决这个问题。第一种是准备字符串,并在其中插入值。第二种是使用可以单独替换值的查询参数。

对于第一种方法,您可以使用snprintf之类的函数来准备要发送到服务器的命令。例如:

char buffer[512];

int num=snprintf(buffer, sizeof(buffer), 
    "SELECT name FROM MYTABLE WHERE id=%d", id);

if (num>sizeof(buffer)) {
    /* error: buffer was too small */
}

此缓冲区将包含SQL查询,包括变量id的实际值。

注意需要检查snprintf的返回值以查看缓冲区是否溢出。

另请注意,当在命令中放置字符串时,您需要确保该字符串不包含任何引号或其他特殊字符。如果字符串来自您的程序之外,例如。从用户输入,然后没有正确引用它留下了一个很大的漏洞,有人可以注入一些恶意SQL。 libpq为此提供PQescapeLiteral函数。

在大多数情况下,另一种方法是将SQL命令和参数分别传递给服务器。例如,您可以使用PQexecParams libpq functoin执行此操作。您的SQL字符串如下所示:

PGresult r = PQexecParams(conn, /* Connection to database */
    "SELECT name FROM mytable WHERE id=$1",
    1,             /* Number of parameters */
    NULL,          /* NULL means server should figure out the parameter types */
    params,        /* Pointer to array of strings containing parameters */
    NULL,          /* Not needed unless binary format used */
    NULL,          /* Not needed unless binary format used */
    0              /* Result to come back in text format */
);

此功能允许您以文本或二进制格式提供参数和/或获得结果。为简单起见,我上面的示例假定两者都有文本格式。

对此的变体是使用预准备语句。在这种情况下,您对libpq进行两次单独调用:

  1. 根据上面的示例,调用PQprepare,您将SQL语句传递给参数值$ 1,$ 2等。这将返回一个语句句柄。

  2. 调用PQexecPrepared,您传递语句句柄以及参数本身,以与PQexecParams类似的方式指定。

  3. 使用这样的两个步骤的好处是,您可以准备一次,并执行多次,这样可以减少与解析和规划查询相关的服务器开销。