在C程序中从PostgreSQL中检索数据

时间:2017-03-16 16:20:19

标签: c database postgresql null data-retrieval

在我的C程序中使用libpq db engine在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;
}

身份验证(这是我获得某种类型的null ref的地方)

/* 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调用相同的func并且它有效。

1 个答案:

答案 0 :(得分:0)

为了回答原始问题,我问问题是查询的语法是不正确的,我不得不在0,0上使用PQget值,因为它返回了我在查询中要求的(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;
}