diff options
-rw-r--r-- | src/datacache/plugin_datacache_postgres.c | 25 | ||||
-rw-r--r-- | src/datastore/plugin_datastore_postgres.c | 20 | ||||
-rw-r--r-- | src/include/gnunet_pq_lib.h | 133 | ||||
-rw-r--r-- | src/namecache/plugin_namecache_postgres.c | 38 | ||||
-rw-r--r-- | src/namestore/plugin_namestore_postgres.c | 64 | ||||
-rw-r--r-- | src/pq/Makefile.am | 2 | ||||
-rw-r--r-- | src/pq/pq.c | 43 | ||||
-rw-r--r-- | src/pq/pq.h | 57 | ||||
-rw-r--r-- | src/pq/pq_connect.c | 169 | ||||
-rw-r--r-- | src/pq/pq_eval.c | 59 | ||||
-rw-r--r-- | src/pq/pq_exec.c | 15 | ||||
-rw-r--r-- | src/pq/pq_prepare.c | 39 | ||||
-rw-r--r-- | src/pq/pq_result_helper.c | 2 | ||||
-rw-r--r-- | src/pq/test_pq.c | 186 |
14 files changed, 517 insertions, 335 deletions
diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c index 59dff9067..c532550ae 100644 --- a/src/datacache/plugin_datacache_postgres.c +++ b/src/datacache/plugin_datacache_postgres.c | |||
@@ -48,7 +48,7 @@ struct Plugin | |||
48 | /** | 48 | /** |
49 | * Native Postgres database handle. | 49 | * Native Postgres database handle. |
50 | */ | 50 | */ |
51 | PGconn *dbh; | 51 | struct GNUNET_PQ_Context *dbh; |
52 | 52 | ||
53 | /** | 53 | /** |
54 | * Number of key-value pairs in the database. | 54 | * Number of key-value pairs in the database. |
@@ -122,26 +122,11 @@ init_connection (struct Plugin *plugin) | |||
122 | }; | 122 | }; |
123 | 123 | ||
124 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg, | 124 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg, |
125 | "datacache-postgres"); | 125 | "datacache-postgres", |
126 | es, | ||
127 | ps); | ||
126 | if (NULL == plugin->dbh) | 128 | if (NULL == plugin->dbh) |
127 | return GNUNET_SYSERR; | 129 | return GNUNET_SYSERR; |
128 | if (GNUNET_OK != | ||
129 | GNUNET_PQ_exec_statements (plugin->dbh, | ||
130 | es)) | ||
131 | { | ||
132 | PQfinish (plugin->dbh); | ||
133 | plugin->dbh = NULL; | ||
134 | return GNUNET_SYSERR; | ||
135 | } | ||
136 | |||
137 | if (GNUNET_OK != | ||
138 | GNUNET_PQ_prepare_statements (plugin->dbh, | ||
139 | ps)) | ||
140 | { | ||
141 | PQfinish (plugin->dbh); | ||
142 | plugin->dbh = NULL; | ||
143 | return GNUNET_SYSERR; | ||
144 | } | ||
145 | return GNUNET_OK; | 130 | return GNUNET_OK; |
146 | } | 131 | } |
147 | 132 | ||
@@ -710,7 +695,7 @@ libgnunet_plugin_datacache_postgres_done (void *cls) | |||
710 | struct GNUNET_DATACACHE_PluginFunctions *api = cls; | 695 | struct GNUNET_DATACACHE_PluginFunctions *api = cls; |
711 | struct Plugin *plugin = api->cls; | 696 | struct Plugin *plugin = api->cls; |
712 | 697 | ||
713 | PQfinish (plugin->dbh); | 698 | GNUNET_PQ_disconnect (plugin->dbh); |
714 | GNUNET_free (plugin); | 699 | GNUNET_free (plugin); |
715 | GNUNET_free (api); | 700 | GNUNET_free (api); |
716 | return NULL; | 701 | return NULL; |
diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c index 181cf8cf8..0811edfd7 100644 --- a/src/datastore/plugin_datastore_postgres.c +++ b/src/datastore/plugin_datastore_postgres.c | |||
@@ -54,7 +54,7 @@ struct Plugin | |||
54 | /** | 54 | /** |
55 | * Native Postgres database handle. | 55 | * Native Postgres database handle. |
56 | */ | 56 | */ |
57 | PGconn *dbh; | 57 | struct GNUNET_PQ_Context *dbh; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | 60 | ||
@@ -172,21 +172,11 @@ init_connection (struct Plugin *plugin) | |||
172 | #undef RESULT_COLUMNS | 172 | #undef RESULT_COLUMNS |
173 | 173 | ||
174 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg, | 174 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg, |
175 | "datastore-postgres"); | 175 | "datastore-postgres", |
176 | es, | ||
177 | ps); | ||
176 | if (NULL == plugin->dbh) | 178 | if (NULL == plugin->dbh) |
177 | return GNUNET_SYSERR; | 179 | return GNUNET_SYSERR; |
178 | |||
179 | if ((GNUNET_OK != | ||
180 | GNUNET_PQ_exec_statements (plugin->dbh, | ||
181 | es)) || | ||
182 | (GNUNET_OK != | ||
183 | GNUNET_PQ_prepare_statements (plugin->dbh, | ||
184 | ps))) | ||
185 | { | ||
186 | PQfinish (plugin->dbh); | ||
187 | plugin->dbh = NULL; | ||
188 | return GNUNET_SYSERR; | ||
189 | } | ||
190 | return GNUNET_OK; | 180 | return GNUNET_OK; |
191 | } | 181 | } |
192 | 182 | ||
@@ -974,7 +964,7 @@ libgnunet_plugin_datastore_postgres_done (void *cls) | |||
974 | struct GNUNET_DATASTORE_PluginFunctions *api = cls; | 964 | struct GNUNET_DATASTORE_PluginFunctions *api = cls; |
975 | struct Plugin *plugin = api->cls; | 965 | struct Plugin *plugin = api->cls; |
976 | 966 | ||
977 | PQfinish (plugin->dbh); | 967 | GNUNET_PQ_disconnect (plugin->dbh); |
978 | GNUNET_free (plugin); | 968 | GNUNET_free (plugin); |
979 | GNUNET_free (api); | 969 | GNUNET_free (api); |
980 | return NULL; | 970 | return NULL; |
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h index 6c576c8ab..a56df21fd 100644 --- a/src/include/gnunet_pq_lib.h +++ b/src/include/gnunet_pq_lib.h | |||
@@ -46,15 +46,16 @@ | |||
46 | * @param scratch_length number of entries left in @a scratch | 46 | * @param scratch_length number of entries left in @a scratch |
47 | * @return -1 on error, number of offsets used in @a scratch otherwise | 47 | * @return -1 on error, number of offsets used in @a scratch otherwise |
48 | */ | 48 | */ |
49 | typedef int (*GNUNET_PQ_QueryConverter) (void *cls, | 49 | typedef int |
50 | const void *data, | 50 | (*GNUNET_PQ_QueryConverter) (void *cls, |
51 | size_t data_len, | 51 | const void *data, |
52 | void *param_values[], | 52 | size_t data_len, |
53 | int param_lengths[], | 53 | void *param_values[], |
54 | int param_formats[], | 54 | int param_lengths[], |
55 | unsigned int param_length, | 55 | int param_formats[], |
56 | void *scratch[], | 56 | unsigned int param_length, |
57 | unsigned int scratch_length); | 57 | void *scratch[], |
58 | unsigned int scratch_length); | ||
58 | 59 | ||
59 | 60 | ||
60 | /** | 61 | /** |
@@ -214,12 +215,13 @@ GNUNET_PQ_query_param_uint64 (const uint64_t *x); | |||
214 | * #GNUNET_YES if all results could be extracted | 215 | * #GNUNET_YES if all results could be extracted |
215 | * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) | 216 | * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) |
216 | */ | 217 | */ |
217 | typedef int (*GNUNET_PQ_ResultConverter) (void *cls, | 218 | typedef int |
218 | PGresult *result, | 219 | (*GNUNET_PQ_ResultConverter) (void *cls, |
219 | int row, | 220 | PGresult *result, |
220 | const char *fname, | 221 | int row, |
221 | size_t *dst_size, | 222 | const char *fname, |
222 | void *dst); | 223 | size_t *dst_size, |
224 | void *dst); | ||
223 | 225 | ||
224 | 226 | ||
225 | /** | 227 | /** |
@@ -229,7 +231,9 @@ typedef int (*GNUNET_PQ_ResultConverter) (void *cls, | |||
229 | * @param cls closure | 231 | * @param cls closure |
230 | * @param rd result data to clean up | 232 | * @param rd result data to clean up |
231 | */ | 233 | */ |
232 | typedef void (*GNUNET_PQ_ResultCleanup) (void *cls, void *rd); | 234 | typedef void |
235 | (*GNUNET_PQ_ResultCleanup) (void *cls, | ||
236 | void *rd); | ||
233 | 237 | ||
234 | 238 | ||
235 | /** | 239 | /** |
@@ -420,16 +424,22 @@ GNUNET_PQ_result_spec_uint64 (const char *name, uint64_t *u64); | |||
420 | /* ************************* pq.c functions ************************ */ | 424 | /* ************************* pq.c functions ************************ */ |
421 | 425 | ||
422 | /** | 426 | /** |
427 | * Postgres context. | ||
428 | */ | ||
429 | struct GNUNET_PQ_Context; | ||
430 | |||
431 | |||
432 | /** | ||
423 | * Execute a prepared statement. | 433 | * Execute a prepared statement. |
424 | * | 434 | * |
425 | * @param db_conn database connection | 435 | * @param db database context |
426 | * @param name name of the prepared statement | 436 | * @param name name of the prepared statement |
427 | * @param params parameters to the statement | 437 | * @param params parameters to the statement |
428 | * @return postgres result | 438 | * @return postgres result |
429 | * @deprecated (should become an internal API) | 439 | * @deprecated (should become an internal API) |
430 | */ | 440 | */ |
431 | PGresult * | 441 | PGresult * |
432 | GNUNET_PQ_exec_prepared (PGconn *db_conn, | 442 | GNUNET_PQ_exec_prepared (struct GNUNET_PQ_Context *db, |
433 | const char *name, | 443 | const char *name, |
434 | const struct GNUNET_PQ_QueryParam *params); | 444 | const struct GNUNET_PQ_QueryParam *params); |
435 | 445 | ||
@@ -468,7 +478,7 @@ GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs); | |||
468 | * Check the @a result's error code to see what happened. | 478 | * Check the @a result's error code to see what happened. |
469 | * Also logs errors. | 479 | * Also logs errors. |
470 | * | 480 | * |
471 | * @param connection connection to execute the statement in | 481 | * @param db database to execute the statement in |
472 | * @param statement_name name of the statement that created @a result | 482 | * @param statement_name name of the statement that created @a result |
473 | * @param result result to check | 483 | * @param result result to check |
474 | * @return status code from the result, mapping PQ status | 484 | * @return status code from the result, mapping PQ status |
@@ -478,7 +488,7 @@ GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs); | |||
478 | * @deprecated (low level, let's see if we can do with just the high-level functions) | 488 | * @deprecated (low level, let's see if we can do with just the high-level functions) |
479 | */ | 489 | */ |
480 | enum GNUNET_DB_QueryStatus | 490 | enum GNUNET_DB_QueryStatus |
481 | GNUNET_PQ_eval_result (PGconn *connection, | 491 | GNUNET_PQ_eval_result (struct GNUNET_PQ_Context *db, |
482 | const char *statement_name, | 492 | const char *statement_name, |
483 | PGresult *result); | 493 | PGresult *result); |
484 | 494 | ||
@@ -488,7 +498,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
488 | * statement in @a connnection using the given @a params. Returns the | 498 | * statement in @a connnection using the given @a params. Returns the |
489 | * resulting session state. | 499 | * resulting session state. |
490 | * | 500 | * |
491 | * @param connection connection to execute the statement in | 501 | * @param db database to execute the statement with |
492 | * @param statement_name name of the statement | 502 | * @param statement_name name of the statement |
493 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | 503 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) |
494 | * @return status code from the result, mapping PQ status | 504 | * @return status code from the result, mapping PQ status |
@@ -500,7 +510,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
500 | * zero; if INSERT was successful, we return one. | 510 | * zero; if INSERT was successful, we return one. |
501 | */ | 511 | */ |
502 | enum GNUNET_DB_QueryStatus | 512 | enum GNUNET_DB_QueryStatus |
503 | GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | 513 | GNUNET_PQ_eval_prepared_non_select (struct GNUNET_PQ_Context *db, |
504 | const char *statement_name, | 514 | const char *statement_name, |
505 | const struct GNUNET_PQ_QueryParam *params); | 515 | const struct GNUNET_PQ_QueryParam *params); |
506 | 516 | ||
@@ -513,9 +523,10 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | |||
513 | * @param result the postgres result | 523 | * @param result the postgres result |
514 | * @param num_result the number of results in @a result | 524 | * @param num_result the number of results in @a result |
515 | */ | 525 | */ |
516 | typedef void (*GNUNET_PQ_PostgresResultHandler) (void *cls, | 526 | typedef void |
517 | PGresult *result, | 527 | (*GNUNET_PQ_PostgresResultHandler) (void *cls, |
518 | unsigned int num_results); | 528 | PGresult *result, |
529 | unsigned int num_results); | ||
519 | 530 | ||
520 | 531 | ||
521 | /** | 532 | /** |
@@ -525,7 +536,7 @@ typedef void (*GNUNET_PQ_PostgresResultHandler) (void *cls, | |||
525 | * status including the number of results given to @a rh (possibly zero). | 536 | * status including the number of results given to @a rh (possibly zero). |
526 | * @a rh will not have been called if the return value is negative. | 537 | * @a rh will not have been called if the return value is negative. |
527 | * | 538 | * |
528 | * @param connection connection to execute the statement in | 539 | * @param db database to execute the statement with |
529 | * @param statement_name name of the statement | 540 | * @param statement_name name of the statement |
530 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | 541 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) |
531 | * @param rh function to call with the result set, NULL to ignore | 542 | * @param rh function to call with the result set, NULL to ignore |
@@ -534,7 +545,7 @@ typedef void (*GNUNET_PQ_PostgresResultHandler) (void *cls, | |||
534 | * codes to `enum GNUNET_DB_QueryStatus`. | 545 | * codes to `enum GNUNET_DB_QueryStatus`. |
535 | */ | 546 | */ |
536 | enum GNUNET_DB_QueryStatus | 547 | enum GNUNET_DB_QueryStatus |
537 | GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | 548 | GNUNET_PQ_eval_prepared_multi_select (struct GNUNET_PQ_Context *db, |
538 | const char *statement_name, | 549 | const char *statement_name, |
539 | const struct GNUNET_PQ_QueryParam *params, | 550 | const struct GNUNET_PQ_QueryParam *params, |
540 | GNUNET_PQ_PostgresResultHandler rh, | 551 | GNUNET_PQ_PostgresResultHandler rh, |
@@ -549,7 +560,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | |||
549 | * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the | 560 | * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the |
550 | * resulting session status. | 561 | * resulting session status. |
551 | * | 562 | * |
552 | * @param connection connection to execute the statement in | 563 | * @param db database to execute the statement with |
553 | * @param statement_name name of the statement | 564 | * @param statement_name name of the statement |
554 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | 565 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) |
555 | * @param[in,out] rs result specification to use for storing the result of the query | 566 | * @param[in,out] rs result specification to use for storing the result of the query |
@@ -557,11 +568,11 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | |||
557 | * codes to `enum GNUNET_DB_QueryStatus`. | 568 | * codes to `enum GNUNET_DB_QueryStatus`. |
558 | */ | 569 | */ |
559 | enum GNUNET_DB_QueryStatus | 570 | enum GNUNET_DB_QueryStatus |
560 | GNUNET_PQ_eval_prepared_singleton_select ( | 571 | GNUNET_PQ_eval_prepared_singleton_select (struct GNUNET_PQ_Context *db, |
561 | PGconn *connection, | 572 | const char *statement_name, |
562 | const char *statement_name, | 573 | const struct |
563 | const struct GNUNET_PQ_QueryParam *params, | 574 | GNUNET_PQ_QueryParam *params, |
564 | struct GNUNET_PQ_ResultSpec *rs); | 575 | struct GNUNET_PQ_ResultSpec *rs); |
565 | 576 | ||
566 | 577 | ||
567 | /* ******************** pq_prepare.c functions ************** */ | 578 | /* ******************** pq_prepare.c functions ************** */ |
@@ -587,6 +598,7 @@ struct GNUNET_PQ_PreparedStatement | |||
587 | * Number of arguments included in @e sql. | 598 | * Number of arguments included in @e sql. |
588 | */ | 599 | */ |
589 | unsigned int num_arguments; | 600 | unsigned int num_arguments; |
601 | |||
590 | }; | 602 | }; |
591 | 603 | ||
592 | 604 | ||
@@ -616,14 +628,14 @@ GNUNET_PQ_make_prepare (const char *name, | |||
616 | /** | 628 | /** |
617 | * Request creation of prepared statements @a ps from Postgres. | 629 | * Request creation of prepared statements @a ps from Postgres. |
618 | * | 630 | * |
619 | * @param connection connection to prepare the statements for | 631 | * @param db database to prepare the statements for |
620 | * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | 632 | * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared |
621 | * statements. | 633 | * statements. |
622 | * @return #GNUNET_OK on success, | 634 | * @return #GNUNET_OK on success, |
623 | * #GNUNET_SYSERR on error | 635 | * #GNUNET_SYSERR on error |
624 | */ | 636 | */ |
625 | int | 637 | int |
626 | GNUNET_PQ_prepare_statements (PGconn *connection, | 638 | GNUNET_PQ_prepare_statements (struct GNUNET_PQ_Context *db, |
627 | const struct GNUNET_PQ_PreparedStatement *ps); | 639 | const struct GNUNET_PQ_PreparedStatement *ps); |
628 | 640 | ||
629 | 641 | ||
@@ -681,14 +693,14 @@ GNUNET_PQ_make_try_execute (const char *sql); | |||
681 | /** | 693 | /** |
682 | * Request execution of an array of statements @a es from Postgres. | 694 | * Request execution of an array of statements @a es from Postgres. |
683 | * | 695 | * |
684 | * @param connection connection to execute the statements over | 696 | * @param pq database to execute the statements in |
685 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | 697 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared |
686 | * statements. | 698 | * statements. |
687 | * @return #GNUNET_OK on success (modulo statements where errors can be ignored) | 699 | * @return #GNUNET_OK on success (modulo statements where errors can be ignored) |
688 | * #GNUNET_SYSERR on error | 700 | * #GNUNET_SYSERR on error |
689 | */ | 701 | */ |
690 | int | 702 | int |
691 | GNUNET_PQ_exec_statements (PGconn *connection, | 703 | GNUNET_PQ_exec_statements (struct GNUNET_PQ_Context *db, |
692 | const struct GNUNET_PQ_ExecuteStatement *es); | 704 | const struct GNUNET_PQ_ExecuteStatement *es); |
693 | 705 | ||
694 | 706 | ||
@@ -698,26 +710,61 @@ GNUNET_PQ_exec_statements (PGconn *connection, | |||
698 | /** | 710 | /** |
699 | * Create a connection to the Postgres database using @a config_str | 711 | * Create a connection to the Postgres database using @a config_str |
700 | * for the configuration. Initialize logging via GNUnet's log | 712 | * for the configuration. Initialize logging via GNUnet's log |
701 | * routines and disable Postgres's logger. | 713 | * routines and disable Postgres's logger. Also ensures that the |
714 | * statements in @a es are executed whenever we (re)connect to the | ||
715 | * database, and that the prepared statements in @a ps are "ready". | ||
716 | * If statements in @es fail that were created with | ||
717 | * #GNUNET_PQ_make_execute(), then the entire operation fails. | ||
702 | * | 718 | * |
703 | * @param config_str configuration to use | 719 | * @param config_str configuration to use |
720 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated | ||
721 | * array of statements to execute upon EACH connection, can be NULL | ||
722 | * @param ps array of prepared statements to prepare, can be NULL | ||
704 | * @return NULL on error | 723 | * @return NULL on error |
705 | */ | 724 | */ |
706 | PGconn * | 725 | struct GNUNET_PQ_Context * |
707 | GNUNET_PQ_connect (const char *config_str); | 726 | GNUNET_PQ_connect (const char *config_str, |
727 | const struct GNUNET_PQ_ExecuteStatement *es, | ||
728 | const struct GNUNET_PQ_PreparedStatement *ps); | ||
708 | 729 | ||
709 | 730 | ||
710 | /** | 731 | /** |
711 | * Connect to a postgres database using the configuration | 732 | * Connect to a postgres database using the configuration |
712 | * option "CONFIG" in @a section. | 733 | * option "CONFIG" in @a section. Also ensures that the |
734 | * statements in @a es are executed whenever we (re)connect to the | ||
735 | * database, and that the prepared statements in @a ps are "ready". | ||
713 | * | 736 | * |
714 | * @param cfg configuration | 737 | * @param cfg configuration |
715 | * @param section configuration section to use to get Postgres configuration options | 738 | * @param section configuration section to use to get Postgres configuration options |
739 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated | ||
740 | * array of statements to execute upon EACH connection, can be NULL | ||
741 | * @param ps array of prepared statements to prepare, can be NULL | ||
716 | * @return the postgres handle, NULL on error | 742 | * @return the postgres handle, NULL on error |
717 | */ | 743 | */ |
718 | PGconn * | 744 | struct GNUNET_PQ_Context * |
719 | GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, | 745 | GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, |
720 | const char *section); | 746 | const char *section, |
747 | const struct GNUNET_PQ_ExecuteStatement *es, | ||
748 | const struct GNUNET_PQ_PreparedStatement *ps); | ||
749 | |||
750 | |||
751 | /** | ||
752 | * Reinitialize the database @a db. | ||
753 | * | ||
754 | * @param db database connection to reinitialize | ||
755 | */ | ||
756 | void | ||
757 | GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db); | ||
758 | |||
759 | |||
760 | /** | ||
761 | * Disconnect from the database, destroying the prepared statements | ||
762 | * and releasing other associated resources. | ||
763 | * | ||
764 | * @param db database handle to disconnect (will be free'd) | ||
765 | */ | ||
766 | void | ||
767 | GNUNET_PQ_disconnect (struct GNUNET_PQ_Context *db); | ||
721 | 768 | ||
722 | 769 | ||
723 | #endif /* GNUNET_PQ_LIB_H_ */ | 770 | #endif /* GNUNET_PQ_LIB_H_ */ |
diff --git a/src/namecache/plugin_namecache_postgres.c b/src/namecache/plugin_namecache_postgres.c index e4b360ef2..35bf5c2ff 100644 --- a/src/namecache/plugin_namecache_postgres.c +++ b/src/namecache/plugin_namecache_postgres.c | |||
@@ -42,9 +42,9 @@ struct Plugin | |||
42 | const struct GNUNET_CONFIGURATION_Handle *cfg; | 42 | const struct GNUNET_CONFIGURATION_Handle *cfg; |
43 | 43 | ||
44 | /** | 44 | /** |
45 | * Native Postgres database handle. | 45 | * Postgres database handle. |
46 | */ | 46 | */ |
47 | PGconn *dbh; | 47 | struct GNUNET_PQ_Context *dbh; |
48 | }; | 48 | }; |
49 | 49 | ||
50 | 50 | ||
@@ -75,10 +75,6 @@ database_setup (struct Plugin *plugin) | |||
75 | "WITH OIDS"); | 75 | "WITH OIDS"); |
76 | const struct GNUNET_PQ_ExecuteStatement *cr; | 76 | const struct GNUNET_PQ_ExecuteStatement *cr; |
77 | 77 | ||
78 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, | ||
79 | "namecache-postgres"); | ||
80 | if (NULL == plugin->dbh) | ||
81 | return GNUNET_SYSERR; | ||
82 | if (GNUNET_YES == | 78 | if (GNUNET_YES == |
83 | GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, | 79 | GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, |
84 | "namecache-postgres", | 80 | "namecache-postgres", |
@@ -90,7 +86,6 @@ database_setup (struct Plugin *plugin) | |||
90 | { | 86 | { |
91 | cr = &es_default; | 87 | cr = &es_default; |
92 | } | 88 | } |
93 | |||
94 | { | 89 | { |
95 | struct GNUNET_PQ_ExecuteStatement es[] = { | 90 | struct GNUNET_PQ_ExecuteStatement es[] = { |
96 | *cr, | 91 | *cr, |
@@ -100,18 +95,6 @@ database_setup (struct Plugin *plugin) | |||
100 | "CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)"), | 95 | "CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)"), |
101 | GNUNET_PQ_EXECUTE_STATEMENT_END | 96 | GNUNET_PQ_EXECUTE_STATEMENT_END |
102 | }; | 97 | }; |
103 | |||
104 | if (GNUNET_OK != | ||
105 | GNUNET_PQ_exec_statements (plugin->dbh, | ||
106 | es)) | ||
107 | { | ||
108 | PQfinish (plugin->dbh); | ||
109 | plugin->dbh = NULL; | ||
110 | return GNUNET_SYSERR; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | { | ||
115 | struct GNUNET_PQ_PreparedStatement ps[] = { | 98 | struct GNUNET_PQ_PreparedStatement ps[] = { |
116 | GNUNET_PQ_make_prepare ("cache_block", | 99 | GNUNET_PQ_make_prepare ("cache_block", |
117 | "INSERT INTO ns096blocks (query, block, expiration_time) VALUES " | 100 | "INSERT INTO ns096blocks (query, block, expiration_time) VALUES " |
@@ -128,16 +111,13 @@ database_setup (struct Plugin *plugin) | |||
128 | GNUNET_PQ_PREPARED_STATEMENT_END | 111 | GNUNET_PQ_PREPARED_STATEMENT_END |
129 | }; | 112 | }; |
130 | 113 | ||
131 | if (GNUNET_OK != | 114 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, |
132 | GNUNET_PQ_prepare_statements (plugin->dbh, | 115 | "namecache-postgres", |
133 | ps)) | 116 | es, |
134 | { | 117 | ps); |
135 | PQfinish (plugin->dbh); | ||
136 | plugin->dbh = NULL; | ||
137 | return GNUNET_SYSERR; | ||
138 | } | ||
139 | } | 118 | } |
140 | 119 | if (NULL == plugin->dbh) | |
120 | return GNUNET_SYSERR; | ||
141 | return GNUNET_OK; | 121 | return GNUNET_OK; |
142 | } | 122 | } |
143 | 123 | ||
@@ -311,7 +291,7 @@ namecache_postgres_lookup_block (void *cls, | |||
311 | static void | 291 | static void |
312 | database_shutdown (struct Plugin *plugin) | 292 | database_shutdown (struct Plugin *plugin) |
313 | { | 293 | { |
314 | PQfinish (plugin->dbh); | 294 | GNUNET_PQ_disconnect (plugin->dbh); |
315 | plugin->dbh = NULL; | 295 | plugin->dbh = NULL; |
316 | } | 296 | } |
317 | 297 | ||
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c index 5148ca0f5..23893538b 100644 --- a/src/namestore/plugin_namestore_postgres.c +++ b/src/namestore/plugin_namestore_postgres.c | |||
@@ -45,9 +45,9 @@ struct Plugin | |||
45 | const struct GNUNET_CONFIGURATION_Handle *cfg; | 45 | const struct GNUNET_CONFIGURATION_Handle *cfg; |
46 | 46 | ||
47 | /** | 47 | /** |
48 | * Native Postgres database handle. | 48 | * Postgres database handle. |
49 | */ | 49 | */ |
50 | PGconn *dbh; | 50 | struct GNUNET_PQ_Context *dbh; |
51 | }; | 51 | }; |
52 | 52 | ||
53 | 53 | ||
@@ -88,30 +88,8 @@ database_setup (struct Plugin *plugin) | |||
88 | ")" | 88 | ")" |
89 | "WITH OIDS"); | 89 | "WITH OIDS"); |
90 | const struct GNUNET_PQ_ExecuteStatement *cr; | 90 | const struct GNUNET_PQ_ExecuteStatement *cr; |
91 | struct GNUNET_PQ_ExecuteStatement sc = GNUNET_PQ_EXECUTE_STATEMENT_END; | ||
91 | 92 | ||
92 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, | ||
93 | "namestore-postgres"); | ||
94 | if (NULL == plugin->dbh) | ||
95 | return GNUNET_SYSERR; | ||
96 | if (GNUNET_YES == | ||
97 | GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, | ||
98 | "namestore-postgres", | ||
99 | "ASYNC_COMMIT")) | ||
100 | { | ||
101 | struct GNUNET_PQ_ExecuteStatement es[] = { | ||
102 | GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off"), | ||
103 | GNUNET_PQ_EXECUTE_STATEMENT_END | ||
104 | }; | ||
105 | |||
106 | if (GNUNET_OK != | ||
107 | GNUNET_PQ_exec_statements (plugin->dbh, | ||
108 | es)) | ||
109 | { | ||
110 | PQfinish (plugin->dbh); | ||
111 | plugin->dbh = NULL; | ||
112 | return GNUNET_SYSERR; | ||
113 | } | ||
114 | } | ||
115 | if (GNUNET_YES == | 93 | if (GNUNET_YES == |
116 | GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, | 94 | GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, |
117 | "namestore-postgres", | 95 | "namestore-postgres", |
@@ -124,6 +102,12 @@ database_setup (struct Plugin *plugin) | |||
124 | cr = &es_default; | 102 | cr = &es_default; |
125 | } | 103 | } |
126 | 104 | ||
105 | if (GNUNET_YES == | ||
106 | GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, | ||
107 | "namestore-postgres", | ||
108 | "ASYNC_COMMIT")) | ||
109 | sc = GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off"); | ||
110 | |||
127 | { | 111 | { |
128 | struct GNUNET_PQ_ExecuteStatement es[] = { | 112 | struct GNUNET_PQ_ExecuteStatement es[] = { |
129 | *cr, | 113 | *cr, |
@@ -135,20 +119,9 @@ database_setup (struct Plugin *plugin) | |||
135 | "ON ns098records (label)"), | 119 | "ON ns098records (label)"), |
136 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS zone_label " | 120 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS zone_label " |
137 | "ON ns098records (zone_private_key,label)"), | 121 | "ON ns098records (zone_private_key,label)"), |
122 | sc, | ||
138 | GNUNET_PQ_EXECUTE_STATEMENT_END | 123 | GNUNET_PQ_EXECUTE_STATEMENT_END |
139 | }; | 124 | }; |
140 | |||
141 | if (GNUNET_OK != | ||
142 | GNUNET_PQ_exec_statements (plugin->dbh, | ||
143 | es)) | ||
144 | { | ||
145 | PQfinish (plugin->dbh); | ||
146 | plugin->dbh = NULL; | ||
147 | return GNUNET_SYSERR; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | { | ||
152 | struct GNUNET_PQ_PreparedStatement ps[] = { | 125 | struct GNUNET_PQ_PreparedStatement ps[] = { |
153 | GNUNET_PQ_make_prepare ("store_records", | 126 | GNUNET_PQ_make_prepare ("store_records", |
154 | "INSERT INTO ns098records" | 127 | "INSERT INTO ns098records" |
@@ -183,16 +156,13 @@ database_setup (struct Plugin *plugin) | |||
183 | GNUNET_PQ_PREPARED_STATEMENT_END | 156 | GNUNET_PQ_PREPARED_STATEMENT_END |
184 | }; | 157 | }; |
185 | 158 | ||
186 | if (GNUNET_OK != | 159 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, |
187 | GNUNET_PQ_prepare_statements (plugin->dbh, | 160 | "namestore-postgres", |
188 | ps)) | 161 | es, |
189 | { | 162 | ps); |
190 | PQfinish (plugin->dbh); | ||
191 | plugin->dbh = NULL; | ||
192 | return GNUNET_SYSERR; | ||
193 | } | ||
194 | } | 163 | } |
195 | 164 | if (NULL == plugin->dbh) | |
165 | return GNUNET_SYSERR; | ||
196 | return GNUNET_OK; | 166 | return GNUNET_OK; |
197 | } | 167 | } |
198 | 168 | ||
@@ -593,7 +563,7 @@ namestore_postgres_zone_to_name (void *cls, | |||
593 | static void | 563 | static void |
594 | database_shutdown (struct Plugin *plugin) | 564 | database_shutdown (struct Plugin *plugin) |
595 | { | 565 | { |
596 | PQfinish (plugin->dbh); | 566 | GNUNET_PQ_disconnect (plugin->dbh); |
597 | plugin->dbh = NULL; | 567 | plugin->dbh = NULL; |
598 | } | 568 | } |
599 | 569 | ||
diff --git a/src/pq/Makefile.am b/src/pq/Makefile.am index 9270e6fe0..750a1d48d 100644 --- a/src/pq/Makefile.am +++ b/src/pq/Makefile.am | |||
@@ -22,7 +22,7 @@ libgnunetpq_la_LIBADD = -lpq \ | |||
22 | libgnunetpq_la_LDFLAGS = \ | 22 | libgnunetpq_la_LDFLAGS = \ |
23 | $(POSTGRESQL_LDFLAGS) \ | 23 | $(POSTGRESQL_LDFLAGS) \ |
24 | $(GN_LIB_LDFLAGS) \ | 24 | $(GN_LIB_LDFLAGS) \ |
25 | -version-info 0:0:0 | 25 | -version-info 1:0:0 |
26 | 26 | ||
27 | if ENABLE_TEST_RUN | 27 | if ENABLE_TEST_RUN |
28 | TESTS = \ | 28 | TESTS = \ |
diff --git a/src/pq/pq.c b/src/pq/pq.c index 7e97c8f72..d2b9a6174 100644 --- a/src/pq/pq.c +++ b/src/pq/pq.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | Copyright (C) 2014, 2015, 2016 GNUnet e.V. | 3 | Copyright (C) 2014, 2015, 2016, 2017, 2019 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software: you can redistribute it and/or modify it |
6 | under the terms of the GNU Affero General Public License as published | 6 | under the terms of the GNU Affero General Public License as published |
@@ -25,33 +25,30 @@ | |||
25 | * @author Christian Grothoff | 25 | * @author Christian Grothoff |
26 | */ | 26 | */ |
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet_util_lib.h" | 28 | #include "pq.h" |
29 | #include "gnunet_pq_lib.h" | ||
30 | |||
31 | 29 | ||
32 | /** | 30 | /** |
33 | * Execute a prepared statement. | 31 | * Execute a prepared statement. |
34 | * | 32 | * |
35 | * @param db_conn database connection | 33 | * @param db database handle |
36 | * @param name name of the prepared statement | 34 | * @param name name of the prepared statement |
37 | * @param params parameters to the statement | 35 | * @param params parameters to the statement |
38 | * @return postgres result | 36 | * @return postgres result |
39 | */ | 37 | */ |
40 | PGresult * | 38 | PGresult * |
41 | GNUNET_PQ_exec_prepared (PGconn *db_conn, | 39 | GNUNET_PQ_exec_prepared (struct GNUNET_PQ_Context *db, |
42 | const char *name, | 40 | const char *name, |
43 | const struct GNUNET_PQ_QueryParam *params) | 41 | const struct GNUNET_PQ_QueryParam *params) |
44 | { | 42 | { |
45 | unsigned int len; | 43 | unsigned int len; |
46 | unsigned int i; | ||
47 | 44 | ||
48 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 45 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
49 | "Running prepared statement `%s' on %p\n", | 46 | "Running prepared statement `%s' on %p\n", |
50 | name, | 47 | name, |
51 | db_conn); | 48 | db); |
52 | /* count the number of parameters */ | 49 | /* count the number of parameters */ |
53 | len = 0; | 50 | len = 0; |
54 | for (i = 0; 0 != params[i].num_params; i++) | 51 | for (unsigned int i = 0; 0 != params[i].num_params; i++) |
55 | len += params[i].num_params; | 52 | len += params[i].num_params; |
56 | 53 | ||
57 | /* new scope to allow stack allocation without alloca */ | 54 | /* new scope to allow stack allocation without alloca */ |
@@ -67,10 +64,11 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, | |||
67 | unsigned int soff; | 64 | unsigned int soff; |
68 | PGresult *res; | 65 | PGresult *res; |
69 | int ret; | 66 | int ret; |
67 | ConnStatusType status; | ||
70 | 68 | ||
71 | off = 0; | 69 | off = 0; |
72 | soff = 0; | 70 | soff = 0; |
73 | for (i = 0; 0 != params[i].num_params; i++) | 71 | for (unsigned int i = 0; 0 != params[i].num_params; i++) |
74 | { | 72 | { |
75 | const struct GNUNET_PQ_QueryParam *x = ¶ms[i]; | 73 | const struct GNUNET_PQ_QueryParam *x = ¶ms[i]; |
76 | 74 | ||
@@ -97,13 +95,24 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, | |||
97 | "pq", | 95 | "pq", |
98 | "Executing prepared SQL statement `%s'\n", | 96 | "Executing prepared SQL statement `%s'\n", |
99 | name); | 97 | name); |
100 | res = PQexecPrepared (db_conn, | 98 | res = PQexecPrepared (db->conn, |
101 | name, | 99 | name, |
102 | len, | 100 | len, |
103 | (const char **) param_values, | 101 | (const char **) param_values, |
104 | param_lengths, | 102 | param_lengths, |
105 | param_formats, | 103 | param_formats, |
106 | 1); | 104 | 1); |
105 | if ( (PGRES_COMMAND_OK != PQresultStatus (res)) && | ||
106 | (CONNECTION_OK != (status = PQstatus (db->conn))) ) | ||
107 | { | ||
108 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
109 | "pq", | ||
110 | "Database disconnected on SQL statement `%s' (reconnecting)\n", | ||
111 | name); | ||
112 | GNUNET_PQ_reconnect (db); | ||
113 | res = NULL; | ||
114 | } | ||
115 | |||
107 | for (off = 0; off < soff; off++) | 116 | for (off = 0; off < soff; off++) |
108 | GNUNET_free (scratch[off]); | 117 | GNUNET_free (scratch[off]); |
109 | return res; | 118 | return res; |
@@ -120,9 +129,7 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, | |||
120 | void | 129 | void |
121 | GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs) | 130 | GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs) |
122 | { | 131 | { |
123 | unsigned int i; | 132 | for (unsigned int i = 0; NULL != rs[i].conv; i++) |
124 | |||
125 | for (i = 0; NULL != rs[i].conv; i++) | ||
126 | if (NULL != rs[i].cleaner) | 133 | if (NULL != rs[i].cleaner) |
127 | rs[i].cleaner (rs[i].cls, | 134 | rs[i].cleaner (rs[i].cls, |
128 | rs[i].dst); | 135 | rs[i].dst); |
@@ -145,12 +152,12 @@ GNUNET_PQ_extract_result (PGresult *result, | |||
145 | struct GNUNET_PQ_ResultSpec *rs, | 152 | struct GNUNET_PQ_ResultSpec *rs, |
146 | int row) | 153 | int row) |
147 | { | 154 | { |
148 | unsigned int i; | 155 | if (NULL == result) |
149 | int ret; | 156 | return GNUNET_SYSERR; |
150 | 157 | for (unsigned int i = 0; NULL != rs[i].conv; i++) | |
151 | for (i = 0; NULL != rs[i].conv; i++) | ||
152 | { | 158 | { |
153 | struct GNUNET_PQ_ResultSpec *spec; | 159 | struct GNUNET_PQ_ResultSpec *spec; |
160 | int ret; | ||
154 | 161 | ||
155 | spec = &rs[i]; | 162 | spec = &rs[i]; |
156 | ret = spec->conv (spec->cls, | 163 | ret = spec->conv (spec->cls, |
diff --git a/src/pq/pq.h b/src/pq/pq.h new file mode 100644 index 000000000..b30f4f0d4 --- /dev/null +++ b/src/pq/pq.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2017, 2019 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file pq/pq.h | ||
22 | * @brief shared internal data structures of libgnunetpq | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #ifndef PQ_H | ||
26 | #define PQ_H | ||
27 | |||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_pq_lib.h" | ||
30 | |||
31 | /** | ||
32 | * Handle to Postgres database. | ||
33 | */ | ||
34 | struct GNUNET_PQ_Context | ||
35 | { | ||
36 | /** | ||
37 | * Actual connection. | ||
38 | */ | ||
39 | PGconn *conn; | ||
40 | |||
41 | /** | ||
42 | * Statements to execute upon connection. | ||
43 | */ | ||
44 | struct GNUNET_PQ_ExecuteStatement *es; | ||
45 | |||
46 | /** | ||
47 | * Prepared statements. | ||
48 | */ | ||
49 | struct GNUNET_PQ_PreparedStatement *ps; | ||
50 | |||
51 | /** | ||
52 | * Configuration to use to connect to the DB. | ||
53 | */ | ||
54 | char *config_str; | ||
55 | }; | ||
56 | |||
57 | #endif | ||
diff --git a/src/pq/pq_connect.c b/src/pq/pq_connect.c index 79b9d6107..7599f4b15 100644 --- a/src/pq/pq_connect.c +++ b/src/pq/pq_connect.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | Copyright (C) 2017 GNUnet e.V. | 3 | Copyright (C) 2017, 2019 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software: you can redistribute it and/or modify it |
6 | under the terms of the GNU Affero General Public License as published | 6 | under the terms of the GNU Affero General Public License as published |
@@ -23,8 +23,7 @@ | |||
23 | * @author Christian Grothoff | 23 | * @author Christian Grothoff |
24 | */ | 24 | */ |
25 | #include "platform.h" | 25 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 26 | #include "pq.h" |
27 | #include "gnunet_pq_lib.h" | ||
28 | 27 | ||
29 | 28 | ||
30 | /** | 29 | /** |
@@ -40,12 +39,14 @@ pq_notice_receiver_cb (void *arg, | |||
40 | const PGresult *res) | 39 | const PGresult *res) |
41 | { | 40 | { |
42 | /* do nothing, intentionally */ | 41 | /* do nothing, intentionally */ |
42 | (void) arg; | ||
43 | (void) res; | ||
43 | } | 44 | } |
44 | 45 | ||
45 | 46 | ||
46 | /** | 47 | /** |
47 | * Function called by libpq whenever it wants to log something. | 48 | * Function called by libpq whenever it wants to log something. |
48 | * We log those using the Taler logger. | 49 | * We log those using the GNUnet logger. |
49 | * | 50 | * |
50 | * @param arg the SQL connection that was used | 51 | * @param arg the SQL connection that was used |
51 | * @param message information about some libpq event | 52 | * @param message information about some libpq event |
@@ -54,6 +55,7 @@ static void | |||
54 | pq_notice_processor_cb (void *arg, | 55 | pq_notice_processor_cb (void *arg, |
55 | const char *message) | 56 | const char *message) |
56 | { | 57 | { |
58 | (void) arg; | ||
57 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | 59 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, |
58 | "pq", | 60 | "pq", |
59 | "%s", | 61 | "%s", |
@@ -64,68 +66,175 @@ pq_notice_processor_cb (void *arg, | |||
64 | /** | 66 | /** |
65 | * Create a connection to the Postgres database using @a config_str | 67 | * Create a connection to the Postgres database using @a config_str |
66 | * for the configuration. Initialize logging via GNUnet's log | 68 | * for the configuration. Initialize logging via GNUnet's log |
67 | * routines and disable Postgres's logger. | 69 | * routines and disable Postgres's logger. Also ensures that the |
70 | * statements in @a es are executed whenever we (re)connect to the | ||
71 | * database, and that the prepared statements in @a ps are "ready". | ||
72 | * If statements in @es fail that were created with | ||
73 | * #GNUNET_PQ_make_execute(), then the entire operation fails. | ||
74 | * | ||
75 | * The caller MUST ensure that @a es and @a ps remain allocated and | ||
76 | * initialized in memory until #GNUNET_PQ_disconnect() is called, | ||
77 | * as they may be needed repeatedly and no copy will be made. | ||
68 | * | 78 | * |
69 | * @param config_str configuration to use | 79 | * @param config_str configuration to use |
80 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated | ||
81 | * array of statements to execute upon EACH connection, can be NULL | ||
82 | * @param ps array of prepared statements to prepare, can be NULL | ||
70 | * @return NULL on error | 83 | * @return NULL on error |
71 | */ | 84 | */ |
72 | PGconn * | 85 | struct GNUNET_PQ_Context * |
73 | GNUNET_PQ_connect (const char *config_str) | 86 | GNUNET_PQ_connect (const char *config_str, |
87 | const struct GNUNET_PQ_ExecuteStatement *es, | ||
88 | const struct GNUNET_PQ_PreparedStatement *ps) | ||
74 | { | 89 | { |
75 | PGconn *conn; | 90 | struct GNUNET_PQ_Context *db; |
91 | unsigned int elen = 0; | ||
92 | unsigned int plen = 0; | ||
93 | |||
94 | if (NULL != es) | ||
95 | while (NULL != es[elen].sql) | ||
96 | elen++; | ||
97 | if (NULL != ps) | ||
98 | while (NULL != ps[plen].name) | ||
99 | plen++; | ||
100 | |||
101 | db = GNUNET_new (struct GNUNET_PQ_Context); | ||
102 | db->config_str = GNUNET_strdup (config_str); | ||
103 | if (0 != elen) | ||
104 | { | ||
105 | db->es = GNUNET_new_array (elen + 1, | ||
106 | struct GNUNET_PQ_ExecuteStatement); | ||
107 | memcpy (db->es, | ||
108 | es, | ||
109 | elen * sizeof (struct GNUNET_PQ_ExecuteStatement)); | ||
110 | } | ||
111 | if (0 != plen) | ||
112 | { | ||
113 | db->ps = GNUNET_new_array (plen + 1, | ||
114 | struct GNUNET_PQ_PreparedStatement); | ||
115 | memcpy (db->ps, | ||
116 | ps, | ||
117 | plen * sizeof (struct GNUNET_PQ_PreparedStatement)); | ||
118 | } | ||
119 | GNUNET_PQ_reconnect (db); | ||
120 | if (NULL == db->conn) | ||
121 | { | ||
122 | GNUNET_free (db->config_str); | ||
123 | GNUNET_free (db); | ||
124 | return NULL; | ||
125 | } | ||
126 | return db; | ||
127 | } | ||
128 | |||
76 | 129 | ||
77 | conn = PQconnectdb (config_str); | 130 | /** |
78 | if ((NULL == conn) || | 131 | * Reinitialize the database @a db. |
79 | (CONNECTION_OK != | 132 | * |
80 | PQstatus (conn))) | 133 | * @param db database connection to reinitialize |
134 | */ | ||
135 | void | ||
136 | GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db) | ||
137 | { | ||
138 | if (NULL != db->conn) | ||
139 | PQfinish (db->conn); | ||
140 | db->conn = PQconnectdb (db->config_str); | ||
141 | if ((NULL == db->conn) || | ||
142 | (CONNECTION_OK != PQstatus (db->conn))) | ||
81 | { | 143 | { |
82 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | 144 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, |
83 | "pq", | 145 | "pq", |
84 | "Database connection to '%s' failed: %s\n", | 146 | "Database connection to '%s' failed: %s\n", |
85 | config_str, | 147 | db->config_str, |
86 | (NULL != conn) ? | 148 | (NULL != db->conn) ? |
87 | PQerrorMessage (conn) | 149 | PQerrorMessage (db->conn) |
88 | : "PQconnectdb returned NULL"); | 150 | : "PQconnectdb returned NULL"); |
89 | if (NULL != conn) | 151 | if (NULL != db->conn) |
90 | PQfinish (conn); | 152 | { |
91 | return NULL; | 153 | PQfinish (db->conn); |
154 | db->conn = NULL; | ||
155 | } | ||
156 | return; | ||
92 | } | 157 | } |
93 | PQsetNoticeReceiver (conn, | 158 | PQsetNoticeReceiver (db->conn, |
94 | &pq_notice_receiver_cb, | 159 | &pq_notice_receiver_cb, |
95 | conn); | 160 | db); |
96 | PQsetNoticeProcessor (conn, | 161 | PQsetNoticeProcessor (db->conn, |
97 | &pq_notice_processor_cb, | 162 | &pq_notice_processor_cb, |
98 | conn); | 163 | db); |
99 | return conn; | 164 | if ( (NULL != db->es) && |
165 | (GNUNET_OK != | ||
166 | GNUNET_PQ_exec_statements (db, | ||
167 | db->es)) ) | ||
168 | { | ||
169 | PQfinish (db->conn); | ||
170 | db->conn = NULL; | ||
171 | return; | ||
172 | } | ||
173 | if ( (NULL != db->ps) && | ||
174 | (GNUNET_OK != | ||
175 | GNUNET_PQ_prepare_statements (db, | ||
176 | db->ps)) ) | ||
177 | { | ||
178 | PQfinish (db->conn); | ||
179 | db->conn = NULL; | ||
180 | return; | ||
181 | } | ||
100 | } | 182 | } |
101 | 183 | ||
102 | 184 | ||
103 | /** | 185 | /** |
104 | * Connect to a postgres database using the configuration | 186 | * Connect to a postgres database using the configuration |
105 | * option "CONFIG" in @a section. | 187 | * option "CONFIG" in @a section. Also ensures that the |
188 | * statements in @a es are executed whenever we (re)connect to the | ||
189 | * database, and that the prepared statements in @a ps are "ready". | ||
190 | * | ||
191 | * The caller MUST ensure that @a es and @a ps remain allocated and | ||
192 | * initialized in memory until #GNUNET_PQ_disconnect() is called, | ||
193 | * as they may be needed repeatedly and no copy will be made. | ||
106 | * | 194 | * |
107 | * @param cfg configuration | 195 | * @param cfg configuration |
108 | * @param section configuration section to use to get Postgres configuration options | 196 | * @param section configuration section to use to get Postgres configuration options |
197 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated | ||
198 | * array of statements to execute upon EACH connection, can be NULL | ||
199 | * @param ps array of prepared statements to prepare, can be NULL | ||
109 | * @return the postgres handle, NULL on error | 200 | * @return the postgres handle, NULL on error |
110 | */ | 201 | */ |
111 | PGconn * | 202 | struct GNUNET_PQ_Context * |
112 | GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, | 203 | GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, |
113 | const char *section) | 204 | const char *section, |
205 | const struct GNUNET_PQ_ExecuteStatement *es, | ||
206 | const struct GNUNET_PQ_PreparedStatement *ps) | ||
114 | { | 207 | { |
115 | PGconn *dbh; | 208 | struct GNUNET_PQ_Context *db; |
116 | char *conninfo; | 209 | char *conninfo; |
117 | 210 | ||
118 | /* Open database and precompile statements */ | ||
119 | if (GNUNET_OK != | 211 | if (GNUNET_OK != |
120 | GNUNET_CONFIGURATION_get_value_string (cfg, | 212 | GNUNET_CONFIGURATION_get_value_string (cfg, |
121 | section, | 213 | section, |
122 | "CONFIG", | 214 | "CONFIG", |
123 | &conninfo)) | 215 | &conninfo)) |
124 | conninfo = NULL; | 216 | conninfo = NULL; |
125 | dbh = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo); | 217 | db = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo, |
218 | es, | ||
219 | ps); | ||
126 | GNUNET_free_non_null (conninfo); | 220 | GNUNET_free_non_null (conninfo); |
127 | return dbh; | 221 | return db; |
128 | } | 222 | } |
129 | 223 | ||
130 | 224 | ||
225 | /** | ||
226 | * Disconnect from the database, destroying the prepared statements | ||
227 | * and releasing other associated resources. | ||
228 | * | ||
229 | * @param db database handle to disconnect (will be free'd) | ||
230 | */ | ||
231 | void | ||
232 | GNUNET_PQ_disconnect (struct GNUNET_PQ_Context *db) | ||
233 | { | ||
234 | GNUNET_free_non_null (db->es); | ||
235 | GNUNET_free_non_null (db->ps); | ||
236 | PQfinish (db->conn); | ||
237 | GNUNET_free (db); | ||
238 | } | ||
239 | |||
131 | /* end of pq/pq_connect.c */ | 240 | /* end of pq/pq_connect.c */ |
diff --git a/src/pq/pq_eval.c b/src/pq/pq_eval.c index 1d041f226..5bcf8ca0e 100644 --- a/src/pq/pq_eval.c +++ b/src/pq/pq_eval.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | Copyright (C) 2017 GNUnet e.V. | 3 | Copyright (C) 2017, 2019 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software: you can redistribute it and/or modify it |
6 | under the terms of the GNU Affero General Public License as published | 6 | under the terms of the GNU Affero General Public License as published |
@@ -23,8 +23,7 @@ | |||
23 | * @author Christian Grothoff | 23 | * @author Christian Grothoff |
24 | */ | 24 | */ |
25 | #include "platform.h" | 25 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 26 | #include "pq.h" |
27 | #include "gnunet_pq_lib.h" | ||
28 | 27 | ||
29 | 28 | ||
30 | /** | 29 | /** |
@@ -47,7 +46,7 @@ | |||
47 | * Check the @a result's error code to see what happened. | 46 | * Check the @a result's error code to see what happened. |
48 | * Also logs errors. | 47 | * Also logs errors. |
49 | * | 48 | * |
50 | * @param connection connection to execute the statement in | 49 | * @param db database to execute the statement with |
51 | * @param statement_name name of the statement that created @a result | 50 | * @param statement_name name of the statement that created @a result |
52 | * @param result result to check | 51 | * @param result result to check |
53 | * @return status code from the result, mapping PQ status | 52 | * @return status code from the result, mapping PQ status |
@@ -57,17 +56,31 @@ | |||
57 | * @deprecated (low level, let's see if we can do with just the high-level functions) | 56 | * @deprecated (low level, let's see if we can do with just the high-level functions) |
58 | */ | 57 | */ |
59 | enum GNUNET_DB_QueryStatus | 58 | enum GNUNET_DB_QueryStatus |
60 | GNUNET_PQ_eval_result (PGconn *connection, | 59 | GNUNET_PQ_eval_result (struct GNUNET_PQ_Context *db, |
61 | const char *statement_name, | 60 | const char *statement_name, |
62 | PGresult *result) | 61 | PGresult *result) |
63 | { | 62 | { |
64 | ExecStatusType est; | 63 | ExecStatusType est; |
65 | 64 | ||
65 | if (NULL == result) | ||
66 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
66 | est = PQresultStatus (result); | 67 | est = PQresultStatus (result); |
67 | if ((PGRES_COMMAND_OK != est) && | 68 | if ((PGRES_COMMAND_OK != est) && |
68 | (PGRES_TUPLES_OK != est)) | 69 | (PGRES_TUPLES_OK != est)) |
69 | { | 70 | { |
70 | const char *sqlstate; | 71 | const char *sqlstate; |
72 | ConnStatusType status; | ||
73 | |||
74 | if (CONNECTION_OK != (status = PQstatus (db->conn))) | ||
75 | { | ||
76 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | ||
77 | "pq", | ||
78 | "Database connection failed during query `%s': %d (reconnecting)\n", | ||
79 | statement_name, | ||
80 | status); | ||
81 | GNUNET_PQ_reconnect (db); | ||
82 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
83 | } | ||
71 | 84 | ||
72 | sqlstate = PQresultErrorField (result, | 85 | sqlstate = PQresultErrorField (result, |
73 | PG_DIAG_SQLSTATE); | 86 | PG_DIAG_SQLSTATE); |
@@ -94,7 +107,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
94 | PG_DIAG_MESSAGE_DETAIL), | 107 | PG_DIAG_MESSAGE_DETAIL), |
95 | PQresultErrorMessage (result), | 108 | PQresultErrorMessage (result), |
96 | PQresStatus (PQresultStatus (result)), | 109 | PQresStatus (PQresultStatus (result)), |
97 | PQerrorMessage (connection)); | 110 | PQerrorMessage (db->conn)); |
98 | return GNUNET_DB_STATUS_SOFT_ERROR; | 111 | return GNUNET_DB_STATUS_SOFT_ERROR; |
99 | } | 112 | } |
100 | if (0 == strcmp (sqlstate, | 113 | if (0 == strcmp (sqlstate, |
@@ -111,7 +124,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
111 | PG_DIAG_MESSAGE_DETAIL), | 124 | PG_DIAG_MESSAGE_DETAIL), |
112 | PQresultErrorMessage (result), | 125 | PQresultErrorMessage (result), |
113 | PQresStatus (PQresultStatus (result)), | 126 | PQresStatus (PQresultStatus (result)), |
114 | PQerrorMessage (connection)); | 127 | PQerrorMessage (db->conn)); |
115 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; | 128 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; |
116 | } | 129 | } |
117 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | 130 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, |
@@ -124,7 +137,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
124 | PG_DIAG_MESSAGE_DETAIL), | 137 | PG_DIAG_MESSAGE_DETAIL), |
125 | PQresultErrorMessage (result), | 138 | PQresultErrorMessage (result), |
126 | PQresStatus (PQresultStatus (result)), | 139 | PQresStatus (PQresultStatus (result)), |
127 | PQerrorMessage (connection)); | 140 | PQerrorMessage (db->conn)); |
128 | return GNUNET_DB_STATUS_HARD_ERROR; | 141 | return GNUNET_DB_STATUS_HARD_ERROR; |
129 | } | 142 | } |
130 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; | 143 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; |
@@ -136,7 +149,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
136 | * statement in @a connnection using the given @a params. Returns the | 149 | * statement in @a connnection using the given @a params. Returns the |
137 | * resulting session state. | 150 | * resulting session state. |
138 | * | 151 | * |
139 | * @param connection connection to execute the statement in | 152 | * @param db database to execute the statement with |
140 | * @param statement_name name of the statement | 153 | * @param statement_name name of the statement |
141 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | 154 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) |
142 | * @return status code from the result, mapping PQ status | 155 | * @return status code from the result, mapping PQ status |
@@ -148,17 +161,19 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
148 | * zero; if INSERT was successful, we return one. | 161 | * zero; if INSERT was successful, we return one. |
149 | */ | 162 | */ |
150 | enum GNUNET_DB_QueryStatus | 163 | enum GNUNET_DB_QueryStatus |
151 | GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | 164 | GNUNET_PQ_eval_prepared_non_select (struct GNUNET_PQ_Context *db, |
152 | const char *statement_name, | 165 | const char *statement_name, |
153 | const struct GNUNET_PQ_QueryParam *params) | 166 | const struct GNUNET_PQ_QueryParam *params) |
154 | { | 167 | { |
155 | PGresult *result; | 168 | PGresult *result; |
156 | enum GNUNET_DB_QueryStatus qs; | 169 | enum GNUNET_DB_QueryStatus qs; |
157 | 170 | ||
158 | result = GNUNET_PQ_exec_prepared (connection, | 171 | result = GNUNET_PQ_exec_prepared (db, |
159 | statement_name, | 172 | statement_name, |
160 | params); | 173 | params); |
161 | qs = GNUNET_PQ_eval_result (connection, | 174 | if (NULL == result) |
175 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
176 | qs = GNUNET_PQ_eval_result (db, | ||
162 | statement_name, | 177 | statement_name, |
163 | result); | 178 | result); |
164 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) | 179 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) |
@@ -182,7 +197,7 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | |||
182 | * status including the number of results given to @a rh (possibly zero). | 197 | * status including the number of results given to @a rh (possibly zero). |
183 | * @a rh will not have been called if the return value is negative. | 198 | * @a rh will not have been called if the return value is negative. |
184 | * | 199 | * |
185 | * @param connection connection to execute the statement in | 200 | * @param db database to execute the statement with |
186 | * @param statement_name name of the statement | 201 | * @param statement_name name of the statement |
187 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | 202 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) |
188 | * @param rh function to call with the result set, NULL to ignore | 203 | * @param rh function to call with the result set, NULL to ignore |
@@ -191,7 +206,7 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | |||
191 | * codes to `enum GNUNET_DB_QueryStatus`. | 206 | * codes to `enum GNUNET_DB_QueryStatus`. |
192 | */ | 207 | */ |
193 | enum GNUNET_DB_QueryStatus | 208 | enum GNUNET_DB_QueryStatus |
194 | GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | 209 | GNUNET_PQ_eval_prepared_multi_select (struct GNUNET_PQ_Context *db, |
195 | const char *statement_name, | 210 | const char *statement_name, |
196 | const struct GNUNET_PQ_QueryParam *params, | 211 | const struct GNUNET_PQ_QueryParam *params, |
197 | GNUNET_PQ_PostgresResultHandler rh, | 212 | GNUNET_PQ_PostgresResultHandler rh, |
@@ -201,10 +216,12 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | |||
201 | enum GNUNET_DB_QueryStatus qs; | 216 | enum GNUNET_DB_QueryStatus qs; |
202 | unsigned int ret; | 217 | unsigned int ret; |
203 | 218 | ||
204 | result = GNUNET_PQ_exec_prepared (connection, | 219 | result = GNUNET_PQ_exec_prepared (db, |
205 | statement_name, | 220 | statement_name, |
206 | params); | 221 | params); |
207 | qs = GNUNET_PQ_eval_result (connection, | 222 | if (NULL == result) |
223 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
224 | qs = GNUNET_PQ_eval_result (db, | ||
208 | statement_name, | 225 | statement_name, |
209 | result); | 226 | result); |
210 | if (qs < 0) | 227 | if (qs < 0) |
@@ -230,7 +247,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | |||
230 | * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the | 247 | * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the |
231 | * resulting session status. | 248 | * resulting session status. |
232 | * | 249 | * |
233 | * @param connection connection to execute the statement in | 250 | * @param db database to execute the statement with |
234 | * @param statement_name name of the statement | 251 | * @param statement_name name of the statement |
235 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | 252 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) |
236 | * @param[in,out] rs result specification to use for storing the result of the query | 253 | * @param[in,out] rs result specification to use for storing the result of the query |
@@ -238,7 +255,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | |||
238 | * codes to `enum GNUNET_DB_QueryStatus`. | 255 | * codes to `enum GNUNET_DB_QueryStatus`. |
239 | */ | 256 | */ |
240 | enum GNUNET_DB_QueryStatus | 257 | enum GNUNET_DB_QueryStatus |
241 | GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection, | 258 | GNUNET_PQ_eval_prepared_singleton_select (struct GNUNET_PQ_Context *db, |
242 | const char *statement_name, | 259 | const char *statement_name, |
243 | const struct | 260 | const struct |
244 | GNUNET_PQ_QueryParam *params, | 261 | GNUNET_PQ_QueryParam *params, |
@@ -247,10 +264,12 @@ GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection, | |||
247 | PGresult *result; | 264 | PGresult *result; |
248 | enum GNUNET_DB_QueryStatus qs; | 265 | enum GNUNET_DB_QueryStatus qs; |
249 | 266 | ||
250 | result = GNUNET_PQ_exec_prepared (connection, | 267 | result = GNUNET_PQ_exec_prepared (db, |
251 | statement_name, | 268 | statement_name, |
252 | params); | 269 | params); |
253 | qs = GNUNET_PQ_eval_result (connection, | 270 | if (NULL == result) |
271 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
272 | qs = GNUNET_PQ_eval_result (db, | ||
254 | statement_name, | 273 | statement_name, |
255 | result); | 274 | result); |
256 | if (qs < 0) | 275 | if (qs < 0) |
diff --git a/src/pq/pq_exec.c b/src/pq/pq_exec.c index 00527151a..fd4feae53 100644 --- a/src/pq/pq_exec.c +++ b/src/pq/pq_exec.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | Copyright (C) 2017 GNUnet e.V. | 3 | Copyright (C) 2017, 2019 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software: you can redistribute it and/or modify it |
6 | under the terms of the GNU Affero General Public License as published | 6 | under the terms of the GNU Affero General Public License as published |
@@ -23,8 +23,7 @@ | |||
23 | * @author Christian Grothoff | 23 | * @author Christian Grothoff |
24 | */ | 24 | */ |
25 | #include "platform.h" | 25 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 26 | #include "pq.h" |
27 | #include "gnunet_pq_lib.h" | ||
28 | 27 | ||
29 | 28 | ||
30 | /** | 29 | /** |
@@ -67,14 +66,14 @@ GNUNET_PQ_make_try_execute (const char *sql) | |||
67 | /** | 66 | /** |
68 | * Request execution of an array of statements @a es from Postgres. | 67 | * Request execution of an array of statements @a es from Postgres. |
69 | * | 68 | * |
70 | * @param connection connection to execute the statements over | 69 | * @param db database to execute the statements with |
71 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | 70 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared |
72 | * statements. | 71 | * statements. |
73 | * @return #GNUNET_OK on success (modulo statements where errors can be ignored) | 72 | * @return #GNUNET_OK on success (modulo statements where errors can be ignored) |
74 | * #GNUNET_SYSERR on error | 73 | * #GNUNET_SYSERR on error |
75 | */ | 74 | */ |
76 | int | 75 | int |
77 | GNUNET_PQ_exec_statements (PGconn *connection, | 76 | GNUNET_PQ_exec_statements (struct GNUNET_PQ_Context *db, |
78 | const struct GNUNET_PQ_ExecuteStatement *es) | 77 | const struct GNUNET_PQ_ExecuteStatement *es) |
79 | { | 78 | { |
80 | for (unsigned int i = 0; NULL != es[i].sql; i++) | 79 | for (unsigned int i = 0; NULL != es[i].sql; i++) |
@@ -84,8 +83,8 @@ GNUNET_PQ_exec_statements (PGconn *connection, | |||
84 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 83 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
85 | "Running statement `%s' on %p\n", | 84 | "Running statement `%s' on %p\n", |
86 | es[i].sql, | 85 | es[i].sql, |
87 | connection); | 86 | db); |
88 | result = PQexec (connection, | 87 | result = PQexec (db->conn, |
89 | es[i].sql); | 88 | es[i].sql); |
90 | if ((GNUNET_NO == es[i].ignore_errors) && | 89 | if ((GNUNET_NO == es[i].ignore_errors) && |
91 | (PGRES_COMMAND_OK != PQresultStatus (result))) | 90 | (PGRES_COMMAND_OK != PQresultStatus (result))) |
@@ -100,7 +99,7 @@ GNUNET_PQ_exec_statements (PGconn *connection, | |||
100 | PG_DIAG_MESSAGE_DETAIL), | 99 | PG_DIAG_MESSAGE_DETAIL), |
101 | PQresultErrorMessage (result), | 100 | PQresultErrorMessage (result), |
102 | PQresStatus (PQresultStatus (result)), | 101 | PQresStatus (PQresultStatus (result)), |
103 | PQerrorMessage (connection)); | 102 | PQerrorMessage (db->conn)); |
104 | PQclear (result); | 103 | PQclear (result); |
105 | return GNUNET_SYSERR; | 104 | return GNUNET_SYSERR; |
106 | } | 105 | } |
diff --git a/src/pq/pq_prepare.c b/src/pq/pq_prepare.c index 0facf100f..b7003fb69 100644 --- a/src/pq/pq_prepare.c +++ b/src/pq/pq_prepare.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | Copyright (C) 2017 GNUnet e.V. | 3 | Copyright (C) 2017, 2019 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software: you can redistribute it and/or modify it |
6 | under the terms of the GNU Affero General Public License as published | 6 | under the terms of the GNU Affero General Public License as published |
@@ -23,8 +23,7 @@ | |||
23 | * @author Christian Grothoff | 23 | * @author Christian Grothoff |
24 | */ | 24 | */ |
25 | #include "platform.h" | 25 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 26 | #include "pq.h" |
27 | #include "gnunet_pq_lib.h" | ||
28 | 27 | ||
29 | 28 | ||
30 | /** | 29 | /** |
@@ -53,16 +52,42 @@ GNUNET_PQ_make_prepare (const char *name, | |||
53 | /** | 52 | /** |
54 | * Request creation of prepared statements @a ps from Postgres. | 53 | * Request creation of prepared statements @a ps from Postgres. |
55 | * | 54 | * |
56 | * @param connection connection to prepare the statements for | 55 | * @param db database to prepare the statements for |
57 | * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | 56 | * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared |
58 | * statements. | 57 | * statements. |
59 | * @return #GNUNET_OK on success, | 58 | * @return #GNUNET_OK on success, |
60 | * #GNUNET_SYSERR on error | 59 | * #GNUNET_SYSERR on error |
61 | */ | 60 | */ |
62 | int | 61 | int |
63 | GNUNET_PQ_prepare_statements (PGconn *connection, | 62 | GNUNET_PQ_prepare_statements (struct GNUNET_PQ_Context *db, |
64 | const struct GNUNET_PQ_PreparedStatement *ps) | 63 | const struct GNUNET_PQ_PreparedStatement *ps) |
65 | { | 64 | { |
65 | if (db->ps != ps) | ||
66 | { | ||
67 | /* add 'ps' to list db->ps of prepared statements to run on reconnect! */ | ||
68 | unsigned int olen = 0; /* length of existing 'db->ps' array */ | ||
69 | unsigned int nlen = 0; /* length of 'ps' array */ | ||
70 | struct GNUNET_PQ_PreparedStatement *rps; /* combined array */ | ||
71 | |||
72 | if (NULL != db->ps) | ||
73 | while (NULL != db->ps[olen].name) | ||
74 | olen++; | ||
75 | while (NULL != ps[nlen].name) | ||
76 | nlen++; | ||
77 | rps = GNUNET_new_array (olen + nlen + 1, | ||
78 | struct GNUNET_PQ_PreparedStatement); | ||
79 | if (NULL != db->ps) | ||
80 | memcpy (rps, | ||
81 | db->ps, | ||
82 | olen * sizeof (struct GNUNET_PQ_PreparedStatement)); | ||
83 | memcpy (&rps[olen], | ||
84 | ps, | ||
85 | nlen * sizeof (struct GNUNET_PQ_PreparedStatement)); | ||
86 | GNUNET_free_non_null (db->ps); | ||
87 | db->ps = rps; | ||
88 | } | ||
89 | |||
90 | /* actually prepare statements */ | ||
66 | for (unsigned int i = 0; NULL != ps[i].name; i++) | 91 | for (unsigned int i = 0; NULL != ps[i].name; i++) |
67 | { | 92 | { |
68 | PGresult *ret; | 93 | PGresult *ret; |
@@ -72,7 +97,7 @@ GNUNET_PQ_prepare_statements (PGconn *connection, | |||
72 | "Preparing SQL statement `%s' as `%s'\n", | 97 | "Preparing SQL statement `%s' as `%s'\n", |
73 | ps[i].sql, | 98 | ps[i].sql, |
74 | ps[i].name); | 99 | ps[i].name); |
75 | ret = PQprepare (connection, | 100 | ret = PQprepare (db->conn, |
76 | ps[i].name, | 101 | ps[i].name, |
77 | ps[i].sql, | 102 | ps[i].sql, |
78 | ps[i].num_arguments, | 103 | ps[i].num_arguments, |
@@ -84,7 +109,7 @@ GNUNET_PQ_prepare_statements (PGconn *connection, | |||
84 | _ ("PQprepare (`%s' as `%s') failed with error: %s\n"), | 109 | _ ("PQprepare (`%s' as `%s') failed with error: %s\n"), |
85 | ps[i].sql, | 110 | ps[i].sql, |
86 | ps[i].name, | 111 | ps[i].name, |
87 | PQerrorMessage (connection)); | 112 | PQerrorMessage (db->conn)); |
88 | PQclear (ret); | 113 | PQclear (ret); |
89 | return GNUNET_SYSERR; | 114 | return GNUNET_SYSERR; |
90 | } | 115 | } |
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c index cfb16ac12..1fb1e71c0 100644 --- a/src/pq/pq_result_helper.c +++ b/src/pq/pq_result_helper.c | |||
@@ -587,7 +587,7 @@ extract_abs_time (void *cls, | |||
587 | res = (int64_t *) PQgetvalue (result, | 587 | res = (int64_t *) PQgetvalue (result, |
588 | row, | 588 | row, |
589 | fnum); | 589 | fnum); |
590 | if (INT64_MAX == *res) | 590 | if (INT64_MAX == GNUNET_ntohll ((uint64_t) *res)) |
591 | *udst = GNUNET_TIME_UNIT_FOREVER_ABS; | 591 | *udst = GNUNET_TIME_UNIT_FOREVER_ABS; |
592 | else | 592 | else |
593 | udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res); | 593 | udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res); |
diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c index 697d8e580..a103aca5d 100644 --- a/src/pq/test_pq.c +++ b/src/pq/test_pq.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | (C) 2015, 2016 GNUnet e.V. | 3 | (C) 2015, 2016, 2019 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software: you can redistribute it and/or modify it |
6 | under the terms of the GNU Affero General Public License as published | 6 | under the terms of the GNU Affero General Public License as published |
@@ -23,75 +23,65 @@ | |||
23 | * @author Christian Grothoff <christian@grothoff.org> | 23 | * @author Christian Grothoff <christian@grothoff.org> |
24 | */ | 24 | */ |
25 | #include "platform.h" | 25 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 26 | #include "pq.h" |
27 | #include "gnunet_pq_lib.h" | ||
28 | 27 | ||
29 | 28 | ||
30 | /** | 29 | /** |
31 | * Setup prepared statements. | 30 | * Setup prepared statements. |
32 | * | 31 | * |
33 | * @param db_conn connection handle to initialize | 32 | * @param db database handle to initialize |
34 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | 33 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure |
35 | */ | 34 | */ |
36 | static int | 35 | static int |
37 | postgres_prepare (PGconn *db_conn) | 36 | postgres_prepare (struct GNUNET_PQ_Context *db) |
38 | { | 37 | { |
39 | PGresult *result; | 38 | struct GNUNET_PQ_PreparedStatement ps[] = { |
40 | 39 | GNUNET_PQ_make_prepare ("test_insert", | |
41 | #define PREPARE(name, sql, ...) \ | 40 | "INSERT INTO test_pq (" |
42 | do { \ | 41 | " pub" |
43 | result = PQprepare (db_conn, name, sql, __VA_ARGS__); \ | 42 | ",sig" |
44 | if (PGRES_COMMAND_OK != PQresultStatus (result)) \ | 43 | ",abs_time" |
45 | { \ | 44 | ",forever" |
46 | GNUNET_break (0); \ | 45 | ",hash" |
47 | PQclear (result); result = NULL; \ | 46 | ",vsize" |
48 | return GNUNET_SYSERR; \ | 47 | ",u16" |
49 | } \ | 48 | ",u32" |
50 | PQclear (result); result = NULL; \ | 49 | ",u64" |
51 | } while (0); | 50 | ") VALUES " |
51 | "($1, $2, $3, $4, $5, $6," | ||
52 | "$7, $8, $9);", | ||
53 | 9), | ||
54 | GNUNET_PQ_make_prepare ("test_select", | ||
55 | "SELECT" | ||
56 | " pub" | ||
57 | ",sig" | ||
58 | ",abs_time" | ||
59 | ",forever" | ||
60 | ",hash" | ||
61 | ",vsize" | ||
62 | ",u16" | ||
63 | ",u32" | ||
64 | ",u64" | ||
65 | " FROM test_pq" | ||
66 | " ORDER BY abs_time DESC " | ||
67 | " LIMIT 1;", | ||
68 | 0), | ||
69 | GNUNET_PQ_PREPARED_STATEMENT_END | ||
70 | }; | ||
52 | 71 | ||
53 | PREPARE ("test_insert", | 72 | return GNUNET_PQ_prepare_statements (db, |
54 | "INSERT INTO test_pq (" | 73 | ps); |
55 | " pub" | ||
56 | ",sig" | ||
57 | ",abs_time" | ||
58 | ",forever" | ||
59 | ",hash" | ||
60 | ",vsize" | ||
61 | ",u16" | ||
62 | ",u32" | ||
63 | ",u64" | ||
64 | ") VALUES " | ||
65 | "($1, $2, $3, $4, $5, $6," | ||
66 | "$7, $8, $9);", | ||
67 | 9, NULL); | ||
68 | PREPARE ("test_select", | ||
69 | "SELECT" | ||
70 | " pub" | ||
71 | ",sig" | ||
72 | ",abs_time" | ||
73 | ",forever" | ||
74 | ",hash" | ||
75 | ",vsize" | ||
76 | ",u16" | ||
77 | ",u32" | ||
78 | ",u64" | ||
79 | " FROM test_pq" | ||
80 | " ORDER BY abs_time DESC " | ||
81 | " LIMIT 1;", | ||
82 | 0, NULL); | ||
83 | return GNUNET_OK; | ||
84 | #undef PREPARE | ||
85 | } | 74 | } |
86 | 75 | ||
87 | 76 | ||
88 | /** | 77 | /** |
89 | * Run actual test queries. | 78 | * Run actual test queries. |
90 | * | 79 | * |
80 | * @param db database handle | ||
91 | * @return 0 on success | 81 | * @return 0 on success |
92 | */ | 82 | */ |
93 | static int | 83 | static int |
94 | run_queries (PGconn *conn) | 84 | run_queries (struct GNUNET_PQ_Context *db) |
95 | { | 85 | { |
96 | struct GNUNET_CRYPTO_RsaPublicKey *pub; | 86 | struct GNUNET_CRYPTO_RsaPublicKey *pub; |
97 | struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL; | 87 | struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL; |
@@ -155,7 +145,7 @@ run_queries (PGconn *conn) | |||
155 | GNUNET_PQ_result_spec_end | 145 | GNUNET_PQ_result_spec_end |
156 | }; | 146 | }; |
157 | 147 | ||
158 | result = GNUNET_PQ_exec_prepared (conn, | 148 | result = GNUNET_PQ_exec_prepared (db, |
159 | "test_insert", | 149 | "test_insert", |
160 | params_insert); | 150 | params_insert); |
161 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | 151 | if (PGRES_COMMAND_OK != PQresultStatus (result)) |
@@ -171,7 +161,7 @@ run_queries (PGconn *conn) | |||
171 | } | 161 | } |
172 | 162 | ||
173 | PQclear (result); | 163 | PQclear (result); |
174 | result = GNUNET_PQ_exec_prepared (conn, | 164 | result = GNUNET_PQ_exec_prepared (db, |
175 | "test_select", | 165 | "test_select", |
176 | params_select); | 166 | params_select); |
177 | if (1 != | 167 | if (1 != |
@@ -224,67 +214,71 @@ int | |||
224 | main (int argc, | 214 | main (int argc, |
225 | const char *const argv[]) | 215 | const char *const argv[]) |
226 | { | 216 | { |
227 | PGconn *conn; | 217 | struct GNUNET_PQ_ExecuteStatement es[] = { |
228 | PGresult *result; | 218 | GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq (" |
219 | " pub BYTEA NOT NULL" | ||
220 | ",sig BYTEA NOT NULL" | ||
221 | ",abs_time INT8 NOT NULL" | ||
222 | ",forever INT8 NOT NULL" | ||
223 | ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)" | ||
224 | ",vsize VARCHAR NOT NULL" | ||
225 | ",u16 INT2 NOT NULL" | ||
226 | ",u32 INT4 NOT NULL" | ||
227 | ",u64 INT8 NOT NULL" | ||
228 | ")"), | ||
229 | GNUNET_PQ_EXECUTE_STATEMENT_END | ||
230 | }; | ||
231 | struct GNUNET_PQ_Context *db; | ||
229 | int ret; | 232 | int ret; |
230 | 233 | ||
231 | GNUNET_log_setup ("test-pq", | 234 | GNUNET_log_setup ("test-pq", |
232 | "WARNING", | 235 | "WARNING", |
233 | NULL); | 236 | NULL); |
234 | conn = PQconnectdb ("postgres:///gnunetcheck"); | 237 | db = GNUNET_PQ_connect ("postgres:///gnunetcheck", |
235 | if (CONNECTION_OK != PQstatus (conn)) | 238 | es, |
239 | NULL); | ||
240 | if (CONNECTION_OK != PQstatus (db->conn)) | ||
236 | { | 241 | { |
237 | fprintf (stderr, | 242 | fprintf (stderr, |
238 | "Cannot run test, database connection failed: %s\n", | 243 | "Cannot run test, database connection failed: %s\n", |
239 | PQerrorMessage (conn)); | 244 | PQerrorMessage (db->conn)); |
240 | GNUNET_break (0); | 245 | GNUNET_break (0); |
241 | PQfinish (conn); | 246 | GNUNET_PQ_disconnect (db); |
242 | return 77; /* signal test was skipped */ | 247 | return 77; /* signal test was skipped */ |
243 | } | 248 | } |
244 | |||
245 | result = PQexec (conn, | ||
246 | "CREATE TEMPORARY TABLE IF NOT EXISTS test_pq (" | ||
247 | " pub BYTEA NOT NULL" | ||
248 | ",sig BYTEA NOT NULL" | ||
249 | ",abs_time INT8 NOT NULL" | ||
250 | ",forever INT8 NOT NULL" | ||
251 | ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)" | ||
252 | ",vsize VARCHAR NOT NULL" | ||
253 | ",u16 INT2 NOT NULL" | ||
254 | ",u32 INT4 NOT NULL" | ||
255 | ",u64 INT8 NOT NULL" | ||
256 | ")"); | ||
257 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
258 | { | ||
259 | fprintf (stderr, | ||
260 | "Failed to create table: %s\n", | ||
261 | PQerrorMessage (conn)); | ||
262 | PQclear (result); | ||
263 | PQfinish (conn); | ||
264 | return 1; | ||
265 | } | ||
266 | PQclear (result); | ||
267 | if (GNUNET_OK != | 249 | if (GNUNET_OK != |
268 | postgres_prepare (conn)) | 250 | postgres_prepare (db)) |
269 | { | 251 | { |
270 | GNUNET_break (0); | 252 | GNUNET_break (0); |
271 | PQfinish (conn); | 253 | GNUNET_PQ_disconnect (db); |
272 | return 1; | 254 | return 1; |
273 | } | 255 | } |
274 | ret = run_queries (conn); | 256 | ret = run_queries (db); |
275 | result = PQexec (conn, | 257 | #if TEST_RESTART |
276 | "DROP TABLE test_pq"); | 258 | fprintf (stderr, "Please restart Postgres database now!\n"); |
277 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | 259 | sleep (60); |
260 | ret = run_queries (db); | ||
261 | fprintf (stderr, "Result: %d (expect: 1 -- if you restarted the DB)\n", ret); | ||
262 | ret = run_queries (db); | ||
263 | fprintf (stderr, "Result: %d (expect: 0)\n", ret); | ||
264 | #endif | ||
278 | { | 265 | { |
279 | fprintf (stderr, | 266 | struct GNUNET_PQ_ExecuteStatement es[] = { |
280 | "Failed to create table: %s\n", | 267 | GNUNET_PQ_make_execute ("DROP TABLE test_pq"), |
281 | PQerrorMessage (conn)); | 268 | GNUNET_PQ_EXECUTE_STATEMENT_END |
282 | PQclear (result); | 269 | }; |
283 | PQfinish (conn); | 270 | |
284 | return 1; | 271 | if (GNUNET_OK != |
272 | GNUNET_PQ_exec_statements (db, | ||
273 | es)) | ||
274 | { | ||
275 | fprintf (stderr, | ||
276 | "Failed to drop table\n"); | ||
277 | GNUNET_PQ_disconnect (db); | ||
278 | return 1; | ||
279 | } | ||
285 | } | 280 | } |
286 | PQclear (result); | 281 | GNUNET_PQ_disconnect (db); |
287 | PQfinish (conn); | ||
288 | return ret; | 282 | return ret; |
289 | } | 283 | } |
290 | 284 | ||