00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "../config.h"
00024
00025 #ifdef USE_POSTGRESQL
00026
00027 #include <libpq-fe.h>
00028 #include <postgres.h>
00029
00030 #include "buf.h"
00031 #include "db_conn.h"
00032
00033
00035 #define BASENAME "Database"
00036
00038 #define BASEHOST "Host"
00039
00041 #define BASEPORT "Port"
00042
00044 #define BASELOGIN "Username"
00045
00047 #define BASEPASS "Password"
00048
00050 typedef struct {
00052 PGconn *pgconn;
00053
00055 DBTableDef *table_def;
00056
00058 int table_num;
00059 } DBConnection_PG;
00060
00063 static char *psqlSqlKeywords[] = {
00064 "ABORT", "AGGREGATE", "ALL", "AND", "ALTER", "ASC",
00065 "BEGIN",
00066 "CLUSTER", "CLOSE", "COMMIT", "COPY", "COUNT", "CREATE",
00067 "DATABASE", "DECLARE", "DELETE", "DESC", "DISTINCT", "DROP",
00068 "END", "EXPLAIN",
00069 "FETCH", "FROM", "FUNCTION",
00070 "GRANT", "GROUP BY",
00071 "INDEX", "INSERT", "INTO",
00072 "LIKE", "LISTEN", "LOAD", "LOCK",
00073 "MAX", "MIN", "MEAN", "MOVE",
00074 "NOTIFY",
00075 "OPERATOR", "OR", "ORDER BY",
00076 "RESET", "REVOKE", "ROLLBACK", "RULE",
00077 "SELECT", "SEQUENCE", "SET", "SHOW", "SUM",
00078 "TABLE", "TRANSACTION", "TRIGGER", "TYPE",
00079 "UNION", "UPDATE", "USER", "USING",
00080 "VACUUM", "VIEW",
00081 "WHERE", "WORK",
00082 NULL
00083 };
00084
00088 DBConnection *pg_dbconnection_free(DBConnection *dbc) {
00089 if (dbc) {
00090 if (dbc->pvt)
00091 free(dbc->pvt);
00092 free(dbc);
00093 }
00094 return NULL;
00095 }
00096
00100 static int pg_DBdisconnect(DBConnection * dbconn)
00101 {
00102 DBConnection_PG *dbpg = (DBConnection_PG *) (dbconn->pvt);
00103 PGconn *co = dbpg->pgconn;
00104
00105
00106 PQfinish(co);
00107
00108
00109 keywords_remove_all(dbconn);
00110
00111
00112 pg_dbconnection_free(dbconn);
00113
00114 return 0;
00115 }
00116
00118 static char *pg_DBget_error_message(DBConnection * dbconn)
00119 {
00120 DBConnection_PG *dbpg = (DBConnection_PG *) (dbconn->pvt);
00121 PGconn *co = dbpg->pgconn;
00122
00123 return PQerrorMessage(co);
00124 }
00125
00127 static char *pg_DBget_db_name(DBConnection * dbconn)
00128 {
00129 DBConnection_PG *dbpg = (DBConnection_PG *) (dbconn->pvt);
00130 PGconn *co = dbpg->pgconn;
00131
00132 return PQdb(co);
00133 }
00134
00136 static void *pg_DBexecute_query(DBConnection * dbconn, char *query)
00137 {
00138 DBConnection_PG *dbconn_pg = (DBConnection_PG *) (dbconn->pvt);
00139 PGconn *co = dbconn_pg->pgconn;
00140
00141 return (void *) PQexec(co, query);
00142 }
00143
00145 static int pg_DBget_query_status(DBConnection * dbconn, void *result)
00146 {
00147 if (result == NULL)
00148 return DB_QUERY_ERROR;
00149
00150 switch (PQresultStatus((PGresult *) result)) {
00151 case PGRES_TUPLES_OK:
00152 return DB_QUERY_RECORDS_OK;
00153 case PGRES_COMMAND_OK:
00154 return DB_QUERY_COMMAND_OK;
00155 case PGRES_EMPTY_QUERY:
00156 return DB_QUERY_EMPTY;
00157 case PGRES_BAD_RESPONSE:
00158 case PGRES_NONFATAL_ERROR:
00159 case PGRES_FATAL_ERROR:
00160 return DB_QUERY_ERROR;
00161 default:
00162 return DB_QUERY_OTHER;
00163 }
00164 }
00165
00167 static int pg_DBget_record_number(DBConnection * dbconn, void *result)
00168 {
00169 return PQntuples((PGresult *) result);
00170 }
00171
00173 static int pg_DBget_field_number(DBConnection * dbconn, void *result)
00174 {
00175 return PQnfields((PGresult *) result);
00176 }
00177
00179 static char *pg_DBget_field_name(DBConnection * dbconn, void *result, int field)
00180 {
00181 return PQfname((PGresult *) result, field);
00182 }
00183
00185 static char *pg_DBget_field_value(DBConnection * dbconn, void *result,
00186 int record, int field)
00187 {
00188 return PQgetvalue((PGresult *) result, record, field);
00189 }
00190
00192 static void pg_DBclear_result(DBConnection * dbconn, void *result)
00193 {
00194 PQclear((PGresult *) result);
00195 }
00196
00198 static int pg_add_field_def(DBConnection *dbconn, DBTableDef * tbf)
00199 {
00201 #define DEFQUERY_S "SELECT a.attnum, a.attname, t.typname, a.attlen," \
00202 "a.atttypmod, a.attnotnull, a.atthasdef\n" \
00203 "FROM pg_class c, pg_attribute a, pg_type t\n" \
00204 "WHERE c.relname = '%s' AND\n" \
00205 "a.attnum > 0 AND\n" \
00206 "a.attrelid = c.oid AND\n" \
00207 "a.atttypid = t.oid\n" \
00208 "ORDER BY attnum"
00209
00211 #define PGDEF_S "SELECT d.adsrc\n" \
00212 "FROM pg_attrdef d, pg_class c\n" \
00213 "WHERE c.relname = '%s' AND\n" \
00214 "c.oid = d.adrelid AND\n" \
00215 "d.adnum = %s"
00216
00217 PGresult *table_info;
00218 DBConnection_PG *dbconn_pg = (DBConnection_PG *) (dbconn->pvt);
00219 PGconn *pgconn = dbconn_pg->pgconn;
00220 ABuf *query = NULL;
00221 ABuf *type_str = NULL;
00222
00223 query = buf_new(strlen(DEFQUERY_S) + strlen(tbf->name) + 10);
00224 snprintf(query->b_dat, query->b_len, DEFQUERY_S, tbf->name);
00225
00226 table_info = PQexec(pgconn, query->b_dat);
00227 query = buf_free(query);
00228 if ((table_info == NULL) ||
00229 (PQresultStatus(table_info) != PGRES_TUPLES_OK)) {
00230
00231 if (table_info != NULL)
00232 PQclear(table_info);
00233
00234 return -1;
00235 }
00236 else {
00237 int i;
00238
00239 tbf->field_num = PQntuples(table_info);
00240 tbf->field_def = (DBFieldDef *)
00241 malloc(tbf->field_num * sizeof(DBFieldDef));
00242
00243 for (i = 0; i < tbf->field_num; i++) {
00244 char *line[3];
00245 char *rtype, *rnotnull, *rhasdef;
00246 int attlen, atttypmod;
00247 char buf[512];
00248 PGresult *table_info2;
00249
00250 line[0] = PQgetvalue(table_info, i, 1);
00251 add_keyword(dbconn, line[0], KEYWORD_FIELD);
00252
00253 rtype = PQgetvalue(table_info, i, 2);
00254 attlen = atoi(PQgetvalue(table_info, i, 3));
00255 atttypmod = atoi(PQgetvalue(table_info, i, 4));
00256 rnotnull = PQgetvalue(table_info, i, 5);
00257 rhasdef = PQgetvalue(table_info, i, 6);
00258
00259 type_str = buf_strcpy(type_str, rtype);
00260 if (strncmp(rtype, "bpchar", 6) == 0)
00261 type_str = buf_strcpy(type_str, "char()");
00262 else if (strncmp(rtype, "varchar", 8) == 0)
00263 type_str = buf_strcpy(type_str, "varchar()");
00264 else if (rtype[0] == '_') {
00265 type_str = buf_strcpy(type_str, rtype + 1);
00266 type_str = buf_strcat(type_str, "[]");
00267 }
00268
00269 if (rnotnull[0] == 't')
00270 type_str = buf_strcat(type_str, " not null");
00271 if (rhasdef[0] == 't') {
00272 sprintf(buf, PGDEF_S, tbf->name, PQgetvalue(table_info, i, 0));
00273 table_info2 = PQexec(pgconn, buf);
00274 if ((table_info2 == NULL) ||
00275 (PQresultStatus(table_info2) != PGRES_TUPLES_OK)) {
00276 if (table_info != NULL)
00277 PQclear(table_info);
00278 if (table_info2 != NULL)
00279 PQclear(table_info2);
00280
00281 type_str = buf_free(type_str);
00282 return -1;
00283 }
00284 type_str = buf_strcat(type_str, " default ");
00285 type_str = buf_strcat(type_str, PQgetvalue(table_info2, 0, 0));
00286 PQclear(table_info2);
00287 }
00288 line[1] = type_str->b_dat;
00289
00290 if (strcmp(rtype, "text") == 0)
00291 sprintf(buf, "var");
00292 else if (strcmp(rtype, "bpchar") == 0 ||
00293 strcmp(rtype, "varchar") == 0) {
00294 sprintf(buf, "%i",
00295 atttypmod != -1 ? atttypmod - VARHDRSZ : 0);
00296 }
00297 else {
00298 if (attlen > 0)
00299 sprintf(buf, "%i", attlen);
00300 else
00301 sprintf(buf, "var");
00302 }
00303 line[2] = buf;
00304
00305 tbf->field_def[i].name = strdup(line[0]);
00306 tbf->field_def[i].type = strdup(line[1]);
00307 tbf->field_def[i].length = strdup(line[2]);
00308 }
00309
00310 if (table_info != NULL)
00311 PQclear(table_info);
00312 }
00313 type_str = buf_free(type_str);
00314 return 0;
00315 }
00316
00318 static int pg_DBget_table_def(DBConnection * dbconn)
00319 {
00321 #define TBLDEF_S "SELECT usename, relname, relkind, relhasrules\n" \
00322 "FROM pg_class, pg_user\n" \
00323 "WHERE relkind = 'r' AND\n" \
00324 "relname !~ '^pg_' AND\n" \
00325 "relname !~ '^xin[vx][0-9]+' AND\n" \
00326 "usesysid = relowner\n" \
00327 "ORDER BY relname"
00328
00329 DBConnection_PG *dbconn_pg = (DBConnection_PG *) (dbconn->pvt);
00330 if (dbconn_pg == NULL) {
00331 printf("Internal error. DBConnection_PG not initialised.\n");
00332 return -1;
00333 }
00334
00335 if (dbconn_pg->table_def != NULL) {
00336 fprintf(stderr, "Internal error (memory leak)...\n");
00337 return -1;
00338 }
00339 else {
00340 int i;
00341 PGresult *tables;
00342 char query[512];
00343
00344 sprintf(query, TBLDEF_S);
00345 tables = PQexec(dbconn_pg->pgconn, query);
00346 if ((tables == NULL) || (PQresultStatus(tables) != PGRES_TUPLES_OK)) {
00347 printf("Error. tables = %p. PQresultStatus = %d\n", tables, PQresultStatus(tables));
00348 if (tables != NULL)
00349 PQclear(tables); return -1;
00350 }
00351 else {
00352 int tablesInList = PQntuples(tables);
00353
00354
00355 dbconn_pg->table_num = tablesInList;
00356 dbconn_pg->table_def = (DBTableDef *)
00357 malloc(tablesInList * sizeof(DBTableDef));
00358
00359
00360 for (i = 0; i < tablesInList; i++) {
00361 char *table_name = PQgetvalue(tables, i, 1);
00362
00363
00364 dbconn_pg->table_def[i].name = strdup(table_name);
00365
00366
00367 if (pg_add_field_def(dbconn, dbconn_pg->table_def + i) < 0) {
00368
00369
00370 dbconn_pg->table_def = NULL;
00371
00372 return -1;
00373 }
00374
00375
00376 add_keyword(dbconn, table_name, KEYWORD_TABLE);
00377 }
00378 if (tables != NULL)
00379 PQclear(tables);
00380 }
00381 }
00382
00383 return 0;
00384 }
00385
00386 static ABuf *f2ubuf = NULL;
00387
00390 char *pg_DBform_to_url(Form *frm) {
00391 char *s;
00392
00393 if (frm == NULL)
00394 return NULL;
00395
00396 f2ubuf = buf_check(f2ubuf, 100);
00397 f2ubuf = buf_strcpy(f2ubuf, frm_get_title(frm));
00398 f2ubuf = buf_strcat(f2ubuf, "://");
00399 s = frm_get_value_by_name(frm, BASELOGIN);
00400 if (s != NULL) {
00401 f2ubuf = buf_strcat(f2ubuf, s);
00402 s = frm_get_value_by_name(frm, BASEPASS);
00403 if (s != NULL) {
00404 f2ubuf = buf_strcat(f2ubuf, ":");
00405 f2ubuf = buf_strcat(f2ubuf, s);
00406 }
00407 f2ubuf = buf_strcat(f2ubuf, "@");
00408 }
00409 s = frm_get_value_by_name(frm, BASEHOST);
00410 if (s == NULL)
00411 s = "localhost";
00412
00413 f2ubuf = buf_strcat(f2ubuf, s);
00414 f2ubuf = buf_strcat(f2ubuf, "/");
00415 s = frm_get_value_by_name(frm, BASENAME);
00416 if (s != NULL)
00417 f2ubuf = buf_strcat(f2ubuf, s);
00418
00419 return f2ubuf->b_dat;
00420 }
00421
00423 static void pg_DBfree_table_def(DBConnection * dbconn)
00424 {
00425 DBConnection_PG *conn = (DBConnection_PG *) (dbconn->pvt);
00426
00427 if (conn->table_def == NULL) {
00428
00429
00430 return;
00431 }
00432 else {
00433 DBFieldDef *dbf;
00434 int i, j;
00435
00436 for (j = 0; j < conn->table_num; j++) {
00437 int fnum = (conn->table_def)[j].field_num;
00438
00439 free(conn->table_def[j].name);
00440
00441 dbf = (conn->table_def)[j].field_def;
00442 for (i = 0; i < fnum; i++) {
00443 free(dbf[i].name);
00444 free(dbf[i].type);
00445 }
00446 free(dbf);
00447 }
00448 free(conn->table_def);
00449 conn->table_def = NULL;
00450
00451
00452 keywords_remove(dbconn, KEYWORD_TABLE);
00453 keywords_remove(dbconn, KEYWORD_FIELD);
00454 }
00455 }
00456
00458 static int pg_DBget_table_num(DBConnection * dbconn)
00459 {
00460 DBConnection_PG *dbconn_pg = (DBConnection_PG *) (dbconn->pvt);
00461
00462 return dbconn_pg->table_num;
00463 }
00464
00465
00470 void pg_DBurl_to_form(Form *frm, char *url) {
00471 char *u;
00472 char *p;
00473 char *start;
00474 char *end;
00475 char *username = NULL;
00476 char *password = NULL;
00477 char *host = NULL;
00478 char *port = NULL;
00479 char *database = NULL;
00480
00481
00482 frm_clear_fields(frm);
00483
00484 if (url == NULL)
00485 return;
00486
00487 u = strdup(url);
00488 start = u;
00489
00490
00491 p = strstr(start, "://");
00492 if (p != NULL) {
00493 p += 3;
00494
00495
00496 start = p;
00497 p = strchr(start, '@');
00498 if (p != NULL) {
00499 *p = '\0';
00500 end = p;
00501 username = strdup(start);
00502 p++;
00503 start = p;
00504 }
00505
00506
00507 p = strchr(start, '/');
00508 if (p == NULL) {
00509 host = strdup(start);
00510 }
00511 else {
00512 *p = '\0';
00513 host = strdup(start);
00514 p++;
00515 if (strlen(p) > 0)
00516 database = strdup(p);
00517 }
00518
00519
00520 if (username != NULL) {
00521 p = strchr(username, ':');
00522 if (p != NULL) {
00523 *p = '\0';
00524 p++;
00525 password = strdup(p);
00526 }
00527 }
00528
00529
00530 if (host != NULL) {
00531 p = strchr(host, ':');
00532 if (p != NULL) {
00533 *p = '\0';
00534 p++;
00535 port = strdup(p);
00536 }
00537 }
00538 }
00539
00540
00541 if (username != NULL) {
00542 frm_set_value_by_name(frm, BASELOGIN, username);
00543 free(username);
00544 }
00545
00546 if (password != NULL) {
00547 frm_set_value_by_name(frm, BASEPASS, password);
00548 free(password);
00549 }
00550
00551 if (host != NULL) {
00552 frm_set_value_by_name(frm, BASEHOST, host);
00553 free(host);
00554 }
00555
00556 if (port != NULL) {
00557 frm_set_value_by_name(frm, BASEPORT, port);
00558 free(port);
00559 }
00560
00561 if (database != NULL) {
00562 frm_set_value_by_name(frm, BASENAME, database);
00563 free(database);
00564 }
00565 free(u);
00566 }
00567
00569 static DBTableDef *pg_DBget_table(DBConnection * dbconn, int table)
00570 {
00571 DBConnection_PG *dbconn_pg = (DBConnection_PG *) (dbconn->pvt);
00572
00573 if (table > dbconn_pg->table_num) {
00574 fprintf(stderr, "Internal error (table number too big)...\n");
00575 return NULL;
00576 }
00577
00578 if (dbconn_pg->table_def == NULL) {
00579 fprintf(stderr, "Internal error (searching a NULL table)...\n");
00580 return NULL;
00581 }
00582 else {
00583 return dbconn_pg->table_def + table;
00584 }
00585 }
00589 DBConnection *pg_dbconnection_new()
00590 {
00591 DBConnection *dbconn = calloc(1, sizeof(DBConnection));
00592 if (dbconn) {
00593 dbconn->pvt = calloc(1, sizeof(DBConnection_PG));
00594 if (dbconn->pvt)
00595 dbconn->pvtlen = sizeof(DBConnection_PG);
00596 }
00597 return dbconn;
00598 }
00599
00601 static int pg_connect_callback(DBConnector * dbc, DBConnection ** ret) {
00603 #define DB_CONNECT_ERROR_S "Database connection error : \n %s"
00604 char *bname, *bhost, *bport, *blogin, *bpass;
00605 PGconn *pg_conn = NULL;
00606 ABuf *errbuf = NULL;
00607
00608
00609 bname = frm_get_value_by_name(dbc->db_frm, BASENAME);
00610 bhost = frm_get_value_by_name(dbc->db_frm, BASEHOST);
00611 if ((bhost != NULL) && (strlen(bhost) == 0))
00612 bhost = NULL;
00613
00614 bport = frm_get_value_by_name(dbc->db_frm, BASEPORT);
00615 if ((bport != NULL) && (strlen(bport) == 0))
00616 bport = NULL;
00617
00618 blogin = frm_get_value_by_name(dbc->db_frm, BASELOGIN);
00619
00620 if ((blogin != NULL) && (strlen(blogin) == 0))
00621 blogin = NULL;
00622
00623 bpass = frm_get_value_by_name(dbc->db_frm, BASEPASS);
00624 if ((bpass != NULL) && (strlen(bpass) == 0))
00625 bpass = NULL;
00626
00627
00628 if ((bname == NULL) || (strlen(bname) == 0)) {
00629 dbc->app_error_dialog("Connection Error", "You need to provide a database name");
00630 return CONNECT_ERROR;
00631 }
00632 else {
00633
00634 pg_conn =
00635 PQsetdbLogin(bhost, bport, NULL, NULL, bname, blogin, bpass);
00636 if (pg_conn == NULL) {
00637
00638 dbc->app_error_dialog("Connection Error", "PostgreSQL returned a NULL pg_conn\n ");
00639 return CONNECT_ERROR;
00640 }
00641 if (PQstatus(pg_conn) == CONNECTION_BAD) {
00642
00643 char *errmsg = PQerrorMessage(pg_conn);
00644
00645 errbuf = buf_strcpy(errbuf, "Database connection error : \n ");
00646 errbuf = buf_strcat(errbuf, errmsg);
00647 dbc->app_error_dialog("Connection Error", errbuf->b_dat);
00648 PQfinish(pg_conn);
00649 errbuf = buf_free(errbuf);
00650
00651 return CONNECT_ERROR;
00652 }
00653 else {
00654 DBConnection *dbconn;
00655 DBConnection_PG *dbconn_pg;
00656 int i;
00657
00658 dbconn = pg_dbconnection_new();
00659 dbconn->connector = dbc;
00660
00661 dbconn_pg = (DBConnection_PG *)(dbconn->pvt);
00662 dbconn_pg->pgconn = pg_conn;
00663
00664
00665 dbconn->DBdisconnect = pg_DBdisconnect;
00666 dbconn->DBget_error_message = pg_DBget_error_message;
00667 dbconn->DBget_db_name = pg_DBget_db_name;
00668 dbconn->DBexecute_query = pg_DBexecute_query;
00669 dbconn->DBget_query_status = pg_DBget_query_status;
00670 dbconn->DBget_record_number = pg_DBget_record_number;
00671 dbconn->DBget_field_number = pg_DBget_field_number;
00672 dbconn->DBget_field_name = pg_DBget_field_name;
00673 dbconn->DBget_field_value = pg_DBget_field_value;
00674 dbconn->DBclear_result = pg_DBclear_result;
00675
00676
00677
00678
00679 dbconn->keylist = NULL;
00680 i = 0;
00681 while (psqlSqlKeywords[i] != NULL)
00682 add_keyword(dbconn, psqlSqlKeywords[i++], KEYWORD_SQL);
00683
00684
00685 dbconn->DBget_table_def = pg_DBget_table_def;
00686 dbconn->DBfree_table_def = pg_DBfree_table_def;
00687 dbconn->DBget_table_num = pg_DBget_table_num;
00688 dbconn->DBget_table = pg_DBget_table;
00689
00690 *ret = dbconn;
00691 }
00692 errbuf = buf_free(errbuf);
00693 }
00694 return CONNECT_OK;
00695 }
00696
00698 #define PSQL_TYPESTR "PostgreSQL";
00699
00701 DBConnector *register_PostgreSQL(void (*error_dialog) (char *, char *))
00702 {
00703 DBConnector *ret;
00704 FormField *fld;
00705
00706 ret = dbconnector_new();
00707 if (ret == NULL)
00708 return NULL;
00709
00710 ret->dbtype = PSQL_TYPESTR;
00711
00712
00713 ret->app_error_dialog = error_dialog;
00714 ret->db_connect_callback = pg_connect_callback;
00715 ret->url_to_form = pg_DBurl_to_form;
00716 ret->form_to_url = pg_DBform_to_url;
00717
00718
00719 ret->db_frm = frm_new(NULL);
00720 frm_set_title(ret->db_frm, "PostgreSQL");
00721
00722 fld = frm_add_field(ret->db_frm, BASENAME, NULL);
00723 fld_set_tip(fld, "Database name");
00724
00725 fld = frm_add_field(ret->db_frm, BASEHOST, NULL);
00726 fld_set_tip(fld, "Host database is on (optional)");
00727
00728 fld = frm_add_field(ret->db_frm, BASEPORT, NULL);
00729 fld_set_tip(fld, "Port database is listening on (optional)");
00730
00731 fld = frm_add_field(ret->db_frm, BASELOGIN, NULL);
00732 fld_set_tip(fld, "Username for connection (optional)");
00733
00734 fld = frm_add_field(ret->db_frm, BASEPASS, NULL);
00735 fld_set_type(fld, FT_PWD);
00736 fld_set_tip(fld, "Password for connection (optional)");
00737
00738 return ret;
00739 }
00740
00741 #endif