Skip to content

Commit

Permalink
support fetchtype
Browse files Browse the repository at this point in the history
  • Loading branch information
SunBeau committed May 18, 2024
1 parent 48534f3 commit 8ab8d84
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 48 deletions.
145 changes: 99 additions & 46 deletions src/extensions/qdatabase.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ Provide interfaces with naming convention similar to mysql_xyz().

typedef enum {
PQ_UNKNOWN,
PQ_WRITE,
PQ_READ,
PQ_PING,
PQ_QUERY,
PQ_UPDATE,
PQ_TRANSACTION,
} pgquery_t;

typedef struct {
Expand Down Expand Up @@ -173,7 +174,8 @@ static inline void pgsql_query_result(pgsql_t* pgsql)
}
}

static inline int pgsql_query(pgsql_t* pgsql, const char *query, pgquery_t type)
static inline int pgsql_query(pgsql_t* pgsql, bool fetchtype,
const char *query, pgquery_t type)
{
if (pgsql == NULL || pgsql->pgconn == NULL) {
return -1; /* error */
Expand All @@ -186,8 +188,28 @@ static inline int pgsql_query(pgsql_t* pgsql, const char *query, pgquery_t type)
query = "";
}

PGresult *result = PQexec(pgsql->pgconn, query);
ExecStatusType status = PQresultStatus(result);
PGresult *result = NULL;
ExecStatusType status = -1;

if (fetchtype && type == PQ_QUERY) {
if (PQsendQuery(pgsql->pgconn, query)) {
if (PQsetSingleRowMode(pgsql->pgconn)) {
result = PQgetResult(pgsql->pgconn);
} else {
return -1; /* error */
}
} else {
return -1; /* error */
}
} else {
result = PQexec(pgsql->pgconn, query);
}

if (result == NULL) {
return -1; /* error */
}

status = PQresultStatus(result);

switch (type) {
case PQ_PING: {
Expand All @@ -197,8 +219,9 @@ static inline int pgsql_query(pgsql_t* pgsql, const char *query, pgquery_t type)
break;
}

case PQ_READ: {
if (status != PGRES_TUPLES_OK) {
case PQ_QUERY: {
if (status != PGRES_TUPLES_OK &&
status != PGRES_SINGLE_TUPLE) {
return -1; /* error */
}
break;
Expand Down Expand Up @@ -246,6 +269,27 @@ static inline int pgsql_num_fields(pgsql_t* pgsql)
/* error */
return -1;
}

static inline int pgsql_fetch_row(pgsql_t* pgsql)
{
if (pgsql && pgsql->pgconn) {
PGresult *result = PQgetResult(pgsql->pgconn);
if (result) {
pgsql_query_result(pgsql);
pgsql->pgresult = result;
pgsql->rows = pgsql_num_rows(pgsql);
pgsql->cols = pgsql_num_fields(pgsql);
return 0;
} else {
/* error */
return -1;
}
}

/* error */
return -1;
}

#endif /* ENABLE_PGSQL */

#include "qinternal.h"
Expand Down Expand Up @@ -614,7 +658,7 @@ static int execute_update(qdb_t *db, const char *query)
#endif /* Q_ENABLE_MYSQL */

#if defined(Q_ENABLE_PGSQL)
if (pgsql_query(db->pgsql, query, PQ_WRITE) == 0) {
if (pgsql_query(db->pgsql, db->info.fetchtype, query, PQ_UPDATE) == 0) {
/* get affected rows */
if ((affected = pgsql_affected_rows(db->pgsql)) < 0) affected = -1;
}
Expand Down Expand Up @@ -691,7 +735,7 @@ static qdbresult_t *execute_query(qdb_t *db, const char *query)

#if defined(Q_ENABLE_PGSQL)
// query
if (pgsql_query(db->pgsql, query, PQ_READ)) return NULL;
if (pgsql_query(db->pgsql, db->info.fetchtype, query, PQ_QUERY)) return NULL;

// store
qdbresult_t *result = (qdbresult_t *)malloc(sizeof(qdbresult_t));
Expand Down Expand Up @@ -779,7 +823,7 @@ static bool begin_tran(qdb_t *db)
#endif /* Q_ENABLE_MYSQL */

#if defined(Q_ENABLE_PGSQL)
if (pgsql_query(db->pgsql, "START TRANSACTION", PQ_WRITE) < 0) {
if (pgsql_query(db->pgsql, db->info.fetchtype, "START TRANSACTION", PQ_TRANSACTION) < 0) {
Q_MUTEX_LEAVE(db->qmutex);
return false;
}
Expand Down Expand Up @@ -812,7 +856,7 @@ static bool commit(qdb_t *db)
#endif /* Q_ENABLE_MYSQL */

#if defined(Q_ENABLE_PGSQL)
if (pgsql_query(db->pgsql, "COMMIT", PQ_WRITE) == 0) {
if (pgsql_query(db->pgsql, db->info.fetchtype, "COMMIT", PQ_TRANSACTION) == 0) {
ret = true;
}
#endif /* Q_ENABLE_PGSQL */
Expand Down Expand Up @@ -847,7 +891,7 @@ static bool rollback(qdb_t *db)
#endif /* Q_ENABLE_MYSQL */

#if defined(Q_ENABLE_PGSQL)
if (pgsql_query(db->pgsql, "ROLLBACK", PQ_WRITE) == 0) {
if (pgsql_query(db->pgsql, db->info.fetchtype, "ROLLBACK", PQ_TRANSACTION) == 0) {
ret = true;
}
#endif /* Q_ENABLE_PGSQL */
Expand Down Expand Up @@ -890,9 +934,8 @@ static bool set_fetchtype(qdb_t *db, bool fromdb)
#endif /* Q_ENABLE_MYSQL */

#if defined(Q_ENABLE_PGSQL)
if (db->pgsql == NULL) return false;
pgsql_set_emsg(db->pgsql, "unsupported operation");
return false;
db->info.fetchtype = fromdb;
return true;
#endif /* Q_ENABLE_PGSQL */

#else /* Q_ENABLE_MYSQL || Q_ENABLE_PGSQL */
Expand Down Expand Up @@ -943,7 +986,7 @@ static bool ping(qdb_t *db)
#endif /* Q_ENABLE_MYSQL */

#if defined(Q_ENABLE_PGSQL)
if (db->connected == true && pgsql_query(db->pgsql, NULL, PQ_PING) == 0) {
if (db->connected == true && pgsql_query(db->pgsql, db->info.fetchtype, NULL, PQ_PING) == 0) {
return true;
}
ping_failed = true;
Expand Down Expand Up @@ -1062,31 +1105,29 @@ static const char *result_get_str(qdbresult_t *result, const char *field)
#endif /* Q_ENABLE_MYSQL */

#if defined(Q_ENABLE_PGSQL)
if (result->pgsql == NULL || qtype_cast(pgsql_t*, result->pgsql)->cols <= 0) {
pgsql_t* pgsql = result->pgsql;
if (pgsql == NULL || pgsql->cols <= 0) {
return NULL;
}

const char *val = NULL;
int rows = qtype_cast(pgsql_t*, result->pgsql)->rows;
int cols = qtype_cast(pgsql_t*, result->pgsql)->cols;
int cur = qtype_cast(pgsql_t*, result->pgsql)->cursor;

/* get row num */
int row = -1;
for (int i = 0; i < rows; i++) {
val = PQfname(qtype_cast(pgsql_t*, result->pgsql)->pgresult, i);
if (!strcasecmp(val, field)) {
row = i;
break;
}
/* get field num */
const char *value = NULL;
int field_num = PQfnumber(pgsql->pgresult, field);
if (field_num == -1) {
return NULL;
}

if (row == -1) {
return NULL;
/* get row num */
int row_num = -1;
if (pgsql->rows == 1) {
row_num = 0;
} else {
row_num = pgsql->cursor;
}

val = PQgetvalue(qtype_cast(pgsql_t*, result->pgsql)->pgresult, cur, row);
return val;
/* get value */
value = PQgetvalue(pgsql->pgresult, row_num, field_num);
return value;
#endif /* Q_ENABLE_PGSQL */
#else /* Q_ENABLE_MYSQL || Q_ENABLE_PGSQL */
return NULL;
Expand Down Expand Up @@ -1117,17 +1158,26 @@ static const char *result_get_str_at(qdbresult_t *result, int idx)
#endif /* Q_ENABLE_MYSQL */

#if defined(Q_ENABLE_PGSQL)
pgsql_t* pgsql = result->pgsql;
if (result->pgsql == NULL
|| qtype_cast(pgsql_t*, result->pgsql)->rows == 0
|| qtype_cast(pgsql_t*, result->pgsql)->cols == 0
|| pgsql->rows == 0
|| pgsql->cols == 0
|| idx <= 0
|| idx > qtype_cast(pgsql_t*, result->pgsql)->cols) {
|| idx > pgsql->cols) {
return NULL;
}

int cur = qtype_cast(pgsql_t*, result->pgsql)->cursor;
const char *val = PQgetvalue(qtype_cast(pgsql_t*, result->pgsql)->pgresult, cur, idx - 1);
return val;
/* get row num */
int row_num = -1;
if (pgsql->rows == 1) {
row_num = 0;
} else {
row_num = pgsql->cursor;
}

/* get value */
const char *value = PQgetvalue(pgsql->pgresult, row_num, idx - 1);
return value;
#endif /* Q_ENABLE_PGSQL */
#else /* Q_ENABLE_MYSQL || Q_ENABLE_PGSQL */
return NULL;
Expand Down Expand Up @@ -1186,17 +1236,20 @@ static bool result_get_next(qdbresult_t *result)
#endif /* Q_ENABLE_MYSQL */

#if defined(Q_ENABLE_PGSQL)
if (result->pgsql == NULL
|| qtype_cast(pgsql_t*, result->pgsql)->pgresult == NULL) {
pgsql_t* pgsql = result->pgsql;

if (pgsql == NULL || pgsql->pgresult == NULL) {
return false;
}

int cursor = qtype_cast(pgsql_t*, result->pgsql)->cursor;
if (++cursor == qtype_cast(pgsql_t*, result->pgsql)->rows) {
return false;
int cursor = pgsql->cursor;
if (++cursor >= pgsql->rows) {
if (pgsql_fetch_row(pgsql) != 0) {
return false;
}
}

qtype_cast(pgsql_t*, result->pgsql)->cursor = cursor;
pgsql->cursor = cursor;
return true;
#endif /* Q_ENABLE_PGSQL */
#else /* Q_ENABLE_MYSQL || Q_ENABLE_PGSQL */
Expand Down
39 changes: 37 additions & 2 deletions tests/test_qdatabase_pgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,43 @@ TEST("Test5: autocommit") {
ASSERT_NULL(db);
}

TEST("Test6: fetchtype") {
qdb_t *default_db = test_connect_database(default_database);
ASSERT_TRUE(default_db->connected);
qdb_t *test_db = test_connect_testdb(default_db);
test_create_table_animals(test_db);

/* test: set_fetchtype true */
ASSERT_TRUE(test_db->set_fetchtype(test_db, true));

/* test: execute_queryf in fetchtype mode */
qdbresult_t *qrst = test_db->execute_queryf(test_db, "SELECT * FROM %s;", "animals");
ASSERT_EQUAL_INT(qrst->get_rows(qrst), 1);
ASSERT_EQUAL_INT(qrst->get_cols(qrst), 7);
ASSERT_EQUAL_INT(qrst->get_row(qrst), 0);
ASSERT_EQUAL_STR(qrst->get_str(qrst, "animal_name"), "Dog");
ASSERT_EQUAL_STR(qrst->get_str_at(qrst, 3), "Canis lupus familiaris");
ASSERT_TRUE(qrst->get_next(qrst));
ASSERT_EQUAL_INT(qrst->get_row(qrst), 1);
ASSERT_TRUE(qrst->get_next(qrst));
ASSERT_EQUAL_INT(qrst->get_row(qrst), 2);

ASSERT_EQUAL_INT(qrst->get_int(qrst, "animal_id"), 3);
ASSERT_EQUAL_INT(qrst->get_int_at(qrst, 5), 1);
qrst->free(qrst);

/* test: set_fetchtype false */
ASSERT_TRUE(test_db->set_fetchtype(test_db, false));

/* disconnect */
ASSERT_TRUE(test_db->close(test_db));
ASSERT_TRUE(default_db->close(default_db));

/* free */
test_db->free(test_db);
default_db->free(default_db);
}

TEST("Test6: other") {
qdb_t *default_db = test_connect_database(default_database);
ASSERT_TRUE(default_db->connected);
Expand All @@ -281,8 +318,6 @@ TEST("Test6: other") {

/* test:get_error */
ASSERT_EQUAL_STR(test_db->get_error(test_db, NULL), "(no error)");
ASSERT_FALSE(test_db->set_fetchtype(test_db, true));
ASSERT_EQUAL_STR(test_db->get_error(test_db, NULL), "unsupported operation");

/* test: ping */
ASSERT_TRUE(test_db->ping(test_db));
Expand Down

0 comments on commit 8ab8d84

Please sign in to comment.