2

I am a newbie in using libpq and work on a postgresql database.

So, far I can insert/update/etc a postgresql database using C program, provided I give the actual values inside the quotes.

I want to know how to pass a string/integer variable in the command??

E.g. The following code adds a column called "comment" containing "TRUE" default value into an existing table "people". I need to update the value of the "comment" by "FALSE" where the 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;
  }

I want the following output:

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

However, I am getting the following error:

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

Please help me with some suggestions.

4

1 回答 1

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,按照我上面的示例,将带有参数值 $1、$2 等的 SQL 语句传递给它。这将返回一个语句句柄。

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

使用像这样的两个步骤的优点是您可以准备语句一次,并多次执行它,这减少了与解析它和规划查询相关的服务器开销。

于 2014-04-14T23:54:05.153 回答