【问题标题】:Retrieving data from PostgreSQL in C program在 C 程序中从 PostgreSQL 中检索数据
【发布时间】:2017-08-07 22:46:36
【问题描述】:

在我的 C 程序中使用 libpq db 引擎在 postgresql db 中检索数据时遇到问题。存储数据后,我可以使用终端验证其完整性,因此它会保留在数据库中,但是当我尝试访问它时,我得到一个 segv(由于 null ref / ptr)。以下是使用的相关例程/函数。

创建表:

int createTable() {
    const char *conninfo = "user=tmp password=pass dbname=testdb hostaddr=127.0.0.1 port=5432 sslmode=require";
    PGconn *conn = PQconnectdb(conninfo);   /* connect to db */
    PGresult *res;
    FILE data;
    int nFields;
    int i, j;

    // Make a connection to the database
    conn = PQconnectdb(conninfo);

    /* Check to see that the backend connection was successfully made */
    if (PQstatus(conn) != CONNECTION_OK) {
        fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
        PQfinish(conn);
        return -1;
    }

    printDBInfo(conn); // DEBUG

    /* drop table if exists */
    res = PQexec(conn, "DROP TABLE IF EXISTS Users");
    if (PQresultStatus(res) != PGRES_COMMAND_OK) {
        failInt(conn, res);
    }
    PQclear(res);

    /* create table */
    res = PQexec(conn, "CREATE TABLE Users(username VARCHAR(20) PRIMARY KEY," \
        "password VARCHAR(45))");
    if (PQresultStatus(res) != PGRES_COMMAND_OK) {
        failInt(conn, res);
    }
    PQclear(res);

    /* add some users */
    res = PQexec(conn, "INSERT INTO Users (username,password) VALUES ('foo','bar')");
    if (PQresultStatus(res) != PGRES_COMMAND_OK) {
        fprintf(stderr, "INSERT failed: %s", PQerrorMessage(conn));
        failInt(conn, res);
    }
    PQclear(res);

    res = PQexec(conn, "INSERT INTO Users (username,password) VALUES ('foofoo','extrabar')");
    if (PQresultStatus(res) != PGRES_COMMAND_OK) {
        fprintf(stderr, "INSERT failed: %s", PQerrorMessage(conn));
        failInt(conn, res);
    }
    PQclear(res);

    res = PQexec(conn, "INSERT INTO Users (username,password) VALUES ('TheFooestF00','H1gh3stBar')");
    if (PQresultStatus(res) != PGRES_COMMAND_OK) {
        fprintf(stderr, "INSERT failed: %s", PQerrorMessage(conn));
        failInt(conn, res);
    }
    PQclear(res);

//    res = PQexec(conn, "COMMIT");
//    if (PQresultStatus(res) != PGRES_COMMAND_OK) {
//        printf("COMMIT command failed\n");
//        failInt(res, conn);
//    }
//    PQclear(res);

    PQfinish(conn); /* close the connection */
    return 0;
}

身份验证(这是我得到某种类型的空引用的地方)

/* TODO: whitelisting / parsing / verifying user and pass */
int authenticateUser(const char *user, const char *pass) {
    const char *statement = "SELECT user FROM Users WHERE user=";
    size_t query_size = strlen(statement) + strlen(user) + 1;
    char *query = malloc(query_size);
    memset(query, '\0', query_size);

    PGconn *conn = PQconnectdb("user=tmp password=pass dbname=testdb hostaddr=127.0.0.1 port=5432 sslmode=require");

    if (PQstatus(conn) == CONNECTION_BAD) {
        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
        PQfinish(conn);
        exit(1);
    }

    strcat(query, statement);
    strcat(query, user);
    strcat(query, "\0");
    printf("query: %s\n",query);

    PGresult *res = PQexec(conn, query);
    printf("num of tuples: %i\n", PQntuples(res));
    printf("num of columns: %i\n", PQnfields(res));
//    PQprintTuples(res, STDOUT_FILENO, )

    if (PQresultStatus(res) != PGRES_TUPLES_OK) {
        printf("No data retrieved\n");
        failInt(conn, res);
    }

    const char *pass_check = PQgetvalue(res, 0, 1);
    if (strcmp(user, pass_check) == 0) {
        success(conn, res);
    }

    PQclear(res);
    PQfinish(conn);
    return -1;
}

而且我知道它需要一些输入验证,这是列表中的下一个 :)

编辑:

GDB 输出

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff787c9de in ?? () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) backtrace
#0  0x00007ffff787c9de in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x0000000000402520 in authenticateUser (user=0x402b05 "foo", pass=0x402b1d "bar") at /pwdmanlib/src/db/database.h:272
#2  0x000000000040266b in main () at /pwdmanlib/src/test/db_test.c:51
(gdb) frame 1
#1  0x0000000000402520 in authenticateUser (user=0x402b05 "foo", pass=0x402b1d "bar") at /pwdmanlib/src/db/database.h:272
272     if (strcmp(user, pass_check) == 0) {
(gdb) next
Cannot find bounds of current function

这一行:const char *pass_check = PQgetvalue(res, 0, 1); 返回一个空 ptr,我不知道为什么,因为在此之前我用相同的 args 调用了相同的函数并且它可以工作。

【问题讨论】:

  • 请在gdb 中运行您的代码以准确了解分段错误发生的位置(并使用-g 编译它)。 valgrind 也有很大帮助。
  • strcat(query, statement); strcat(query, user); strcat(query, "\0");请不要这样做。相反,请使用准备好的查询,这也将解决您的引用问题。
  • 好主意@wildplasser 我也会实现它,但我仍然不确定为什么会出现空引用(如上面的 gdb 调试输出所示)。我知道其中有数据db 中的行,我可以从 cmd 行查询和接收,但是当我尝试通过 c 函数获取它时,它返回 null ptr

标签: c database postgresql null data-retrieval


【解决方案1】:

为了回答我提出的原始问题,问题是查询的语法不正确,我不得不在 0,0 上使用 PQgetvalue,因为它返回的是我在查询中请求的 (1) 值而不是元组(比如我原本以为)。下面为任何偶然发现此问题的人提供了完整的实现。快乐的黑客:)

int authenticateUser(const char *user, const char *pass) {
    const char *statement = "SELECT password FROM Users WHERE username='";
    size_t query_size = strlen(statement) + strlen(user) + 3;
    char *query = malloc(query_size);
    memset(query, '\0', query_size);

    PGconn *conn = PQconnectdb("user=tmp password=pass dbname=testdb hostaddr=127.0.0.1 port=5432 sslmode=require");

    if (PQstatus(conn) == CONNECTION_BAD) {
        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
        PQfinish(conn);
        return -1;
    }

    strcat(query, statement);
    strcat(query, user);
    strcat(query, "';\0");
    printf("query: %s\n",query);

    PGresult *res = PQexec(conn, query);
    printf("num of tuples: %i\n", PQntuples(res));
    printf("num of columns: %i\n", PQnfields(res));
//    PQprintTuples(res, STDOUT_FILENO, )

    if (PQresultStatus(res) != PGRES_TUPLES_OK) {
        printf("No data retrieved\n");
        return failInt(conn, res);
    }

    char *pass_check = PQgetvalue(res, 0, 0);
    if (strcmp(pass, pass_check) == 0) {
        return success(conn, res);
    }

    PQclear(res);
    PQfinish(conn);
    return -1;
}

【讨论】:

    猜你喜欢
    • 2010-09-25
    • 2018-09-04
    • 2012-03-23
    • 1970-01-01
    • 2015-06-27
    • 2023-03-07
    • 1970-01-01
    • 2012-09-19
    • 1970-01-01
    相关资源
    最近更新 更多