-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support PostgreSQL: interface/test-cases/ci-testing #113
Conversation
src/extensions/qdatabase.c
Outdated
// set auto-commit | ||
/* do nothing */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we remove these comments?
src/extensions/qdatabase.c
Outdated
/* get affected rows */ | ||
if ((affected = pgsql_affected_rows(db->pgsql)) < 0) affected = -1; | ||
} | ||
|
||
Q_MUTEX_LEAVE(db->qmutex); | ||
return affected; | ||
#else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can furder reduce the code duplication like the following example:
#if defined(Q_ENABLE_MYSQL) || defined(Q_ENABLE_PGSQL)
common codes...
#ifdef Q_ENABLE_MYSQL
if (mysql_query(db->mysql, query) == 0) {
if ((affected = mysql_affected_rows(db->mysql)) < 0) affected = -1;
}
#elif defined(Q_ENABLE_PGSQL)
if (pgsql_query(db->pgsql, query, PQ_WRITE) == 0) {
if ((affected = pgsql_affected_rows(db->pgsql)) < 0) affected = -1;
}
#endif
common codes...
#endif
src/extensions/qdatabase.c
Outdated
// store | ||
qdbresult_t *result = (qdbresult_t *)malloc(sizeof(qdbresult_t)); | ||
if (result == NULL) return NULL; | ||
result->pgsql = db->pgsql; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it enough to store only pgresult, not the pgsql?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fetchtype is supported in new commits
src/extensions/qdatabase.c
Outdated
/* assign methods */ | ||
result->get_str = result_get_str; | ||
result->get_str_at = result_get_str_at; | ||
result->get_int = result_get_int; | ||
result->get_int_at = result_get_int_at; | ||
result->get_next = result_get_next; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like these are common and can ignore code duplication.
I'm not trying to remove 100% of code duplication but some level that isn't very hard to do and still provides good code readability. Can you review the change from that perspective once again?
src/extensions/qdatabase.c
Outdated
Q_MUTEX_ENTER(db->qmutex); | ||
if (qtype_cast(qmutex_t*, db->qmutex)->count != 1) { | ||
Q_MUTEX_LEAVE(db->qmutex); | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, I would place this in the common code section
src/internal/qlibpq.h
Outdated
|
||
/* Wrap the low-level functions of the libpq library */ | ||
|
||
#ifndef QLIBPQ_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd merge this into qdatabase.c
tests/test_qdatabase_pgsql.c
Outdated
*****************************************************************************/ | ||
/* This code is written and updated by following people and released under | ||
* the same license as above qLibc license. | ||
* Copyright (c) 2015 Zhenjiang Xie - https://github.com/Charles0429 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment doesn't apply to your test. We can remove it.
const char *default_password = "123456"; | ||
const bool default_autocommit = true; | ||
|
||
QUNIT_START("Test qdatabase_pgsql.c"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the test. Thanks.
tests/test_qdatabase_pgsql.c
Outdated
default_db->free(default_db); | ||
} | ||
|
||
QUNIT_END(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing new line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for a great PR. I think this is a great addition to qLibc. Just left some of my thoughts. Please take a look.
Please review new commits |
@@ -176,6 +397,12 @@ qdb_t *qdb(const char *dbtype, const char *addr, int port, const char *username, | |||
return NULL; | |||
} | |||
|
|||
#ifdef Q_ENABLE_PGSQL | |||
if (autocommit == false) { | |||
return NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this function can return NULL for more than a single reason, should we set errno ? like EINVAL for users to be able to determine what failed?
src/extensions/qdatabase.c
Outdated
const char *password, const char *database, bool autocommit) | ||
qdb_t *qdb(const char *dbtype, | ||
const char *addr, int port, const char *database, | ||
const char *username, const char *password, bool autocommit) | ||
{ | ||
// check db type | ||
#ifdef Q_ENABLE_MYSQL | ||
if (strcmp(dbtype, "MYSQL")) return NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should set errno = ENOTSUP
src/extensions/qdatabase.c
Outdated
{ | ||
// check db type | ||
#ifdef Q_ENABLE_MYSQL | ||
if (strcmp(dbtype, "MYSQL")) return NULL; | ||
#elif defined(Q_ENABLE_PGSQL) | ||
if (strcmp(dbtype, "PGSQL")) return NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here too errno = ENOTSUP
* The pgsql server and libpq library does not provide a setting for autocommit.<br> | ||
* The following instructions are from the official manual(https://www.postgresql.org/docs/15/sql-begin.html):<br> | ||
* BEGIN initiates a transaction block, that is, all statements after a BEGIN command | ||
* will be executed in a single transaction until an explicit COMMIT or ROLLBACK is given. | ||
* By default (without BEGIN), PostgreSQL executes transactions in “autocommit” mode, | ||
* that is, each statement is executed in its own transaction | ||
* and a commit is implicitly performed at the end of the statement | ||
* (if execution was successful, otherwise a rollback is done). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks good to me. Just left some trivia comments about errno.
Thanks for your review, I've set errno. |
src/extensions/qdatabase.c
Outdated
return -1; | ||
} | ||
|
||
static inline int pgsql_num_rows(pgsql_t* pgsql) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this strange. Since this function is scoped to handle the result, not the connection.
Ideally, I think the prototype should be "pgsql_num_rows(PGresult * pgresult)"
src/extensions/qdatabase.c
Outdated
return -1; | ||
} | ||
|
||
static inline int pgsql_num_fields(pgsql_t* pgsql) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same thoughts on here as well, pgsql_num_fields(PGresult * pgresult)
src/extensions/qdatabase.c
Outdated
} | ||
|
||
int cursor = pgsql->cursor; | ||
if (++cursor >= pgsql->rows) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not, if (++cursor < pgsql->rows)
???
BTW, does it need to check the cursor number before it tries to fetch a row? Why not just attempt to fetch a row and return false when it's empty like below?
if (pgsql_fetch_row(pgsql) != 0) {
return false;
}
pgsql->cursor++
src/extensions/qdatabase.c
Outdated
/* 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this block be simplified as below?
const char *value = PQgetvalue(pgsql->pgresult, pgsql-rows - 1, idx - 1);
src/extensions/qdatabase.c
Outdated
|
||
#if defined(Q_ENABLE_PGSQL) | ||
pgsql_t* pgsql = result->pgsql; | ||
if (pgsql == NULL || pgsql->cols <= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like it is not really necessary to check pgsql->cols <= 0
as PGGetVallue() will handle out of range argument.
src/extensions/qdatabase.c
Outdated
if (pgsql->pgresult) { | ||
PQclear(pgsql->pgresult); | ||
pgsql->pgresult = NULL; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can just call pgsql_query_result()
instead?
src/extensions/qdatabase.c
Outdated
int rows; | ||
int cols; | ||
int cursor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why store these in pgsql struct? Should they be in the result struct?
src/extensions/qdatabase.c
Outdated
int rows; | ||
int cols; | ||
int cursor; | ||
} pgsql_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have qdb_s struct already for this. Having a separate struct doesn't seem to be necessary.
include/qlibc/extensions/qdatabase.h
Outdated
|
||
#ifdef Q_ENABLE_PGSQL | ||
/* private variables for pgsql database - do not access directly */ | ||
void *pgsql; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pgsql_t's members can be defined here rather than a separate inline struct.
PGresult *pgresult;
int rows;
int cols;
int cursor;
|
||
#ifdef Q_ENABLE_PGSQL | ||
/* private variables for pgsql database - do not access directly */ | ||
void *pgsql; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we remove pgsql struct.
char *emsg;
PGconn *pgconn;
I happened to leave a lot of comments. Please take a review. |
I've been busy at work recently, so I spent some time today to complete the code update. |
I read this.
PostgreSQL actually treats every SQL statement as being executed within a
transaction. If you do not issue a BEGIN command, then each individual
statement has an implicit BEGIN and (if successful) COMMIT wrapped around
it. A group of statements surrounded by BEGIN and COMMIT is sometimes
called a *transaction block*.
Note
…On Sun, Jun 2, 2024, 1:33 AM SunBeau ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In src/extensions/qdatabase.c
<#113 (comment)>:
> Q_MUTEX_LEAVE(db->qmutex);
return false;
}
+#if defined(Q_ENABLE_MYSQL)
qdbresult_t *result;
result = db->execute_query(db, "START TRANSACTION");
Regardless of whether autocommit is true or false, if you want to execute
multiple statements in one transaction, you should start transaction.
—
Reply to this email directly, view it on GitHub
<#113 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABUKQMO4XBJP62EXXT2ZGXTZFHZWRAVCNFSM6AAAAABHLEYLWSVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDAOJSGEZTQMRTGE>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Mysql create table test(id int);
SET autocommit = OFF;
insert into test values (1);
select * from test; -- can get 1
-- exit,"id = 1" will be discarded, because "autocommit = OFF"
-- login again
select * from test; -- can not get 1
SET autocommit = ON;
insert into test values (2);
select * from test; -- can get 2
-- exit,"id = 2" will be commit
-- login again
select * from test; -- can get 2
-- A group of statements in one transaction
begin;
update test set id = 3 where id = 2;
insert into test values (4);
insert into test values (5);
rollback; -- if want to do this, "begin" is necessary Pgsql create table test(id int);
-- SET autocommit = OFF; -- This is not supported
insert into test values (1); -- "id = 1" will be commit
select * from test; -- can get 1
-- exit
-- login again
select * from test; -- can get 1
-- SET autocommit = ON; -- This is not supported
insert into test values (2); -- "id = 2" will be commit
select * from test; -- can get 1&2
-- exit
-- login again
select * from test; -- can get 1&2
-- A group of statements in one transaction
begin; -- This is always necessary
delete from test where id = 1;
update test set id = 3 where id = 2;
insert into test values (4);
insert into test values (5);
rollback; |
Thanks for the update. Can you please indicate in each of the comments how it was handled? I see the updates but hard to track what was addressed. |
This PR still needs to address feedback and undergo more thorough testing. Since there hasn't been any recent activity, I'm closing this PR for now. Please feel free to reopen it when it's ready for another look. I appreciate your contribution and efforts. |
No description provided.