diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/datacache/plugin_datacache_postgres.c | 4 | ||||
-rw-r--r-- | src/datastore/plugin_datastore_postgres.c | 3 | ||||
-rw-r--r-- | src/include/gnunet_pq_lib.h | 293 | ||||
-rw-r--r-- | src/namecache/plugin_namecache_postgres.c | 152 | ||||
-rw-r--r-- | src/namestore/plugin_namestore_postgres.c | 200 | ||||
-rw-r--r-- | src/postgres/postgres.c | 42 | ||||
-rw-r--r-- | src/pq/Makefile.am | 4 | ||||
-rw-r--r-- | src/pq/pq_connect.c | 127 | ||||
-rw-r--r-- | src/pq/pq_eval.c | 249 | ||||
-rw-r--r-- | src/pq/pq_exec.c | 106 | ||||
-rw-r--r-- | src/pq/pq_prepare.c | 92 | ||||
-rw-r--r-- | src/psycstore/plugin_psycstore_postgres.c | 219 |
12 files changed, 1144 insertions, 347 deletions
diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c index 13c2c26a2..8f5cdbde1 100644 --- a/src/datacache/plugin_datacache_postgres.c +++ b/src/datacache/plugin_datacache_postgres.c | |||
@@ -68,8 +68,8 @@ init_connection (struct Plugin *plugin) | |||
68 | { | 68 | { |
69 | PGresult *ret; | 69 | PGresult *ret; |
70 | 70 | ||
71 | plugin->dbh = GNUNET_POSTGRES_connect (plugin->env->cfg, | 71 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg, |
72 | "datacache-postgres"); | 72 | "datacache-postgres"); |
73 | if (NULL == plugin->dbh) | 73 | if (NULL == plugin->dbh) |
74 | return GNUNET_SYSERR; | 74 | return GNUNET_SYSERR; |
75 | ret = | 75 | ret = |
diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c index b6aeb0be6..1c9ded4f4 100644 --- a/src/datastore/plugin_datastore_postgres.c +++ b/src/datastore/plugin_datastore_postgres.c | |||
@@ -72,7 +72,8 @@ init_connection (struct Plugin *plugin) | |||
72 | { | 72 | { |
73 | PGresult *ret; | 73 | PGresult *ret; |
74 | 74 | ||
75 | plugin->dbh = GNUNET_POSTGRES_connect (plugin->env->cfg, "datastore-postgres"); | 75 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg, |
76 | "datastore-postgres"); | ||
76 | if (NULL == plugin->dbh) | 77 | if (NULL == plugin->dbh) |
77 | return GNUNET_SYSERR; | 78 | return GNUNET_SYSERR; |
78 | 79 | ||
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h index 756370b74..5e54813e3 100644 --- a/src/include/gnunet_pq_lib.h +++ b/src/include/gnunet_pq_lib.h | |||
@@ -25,6 +25,9 @@ | |||
25 | #include "gnunet_util_lib.h" | 25 | #include "gnunet_util_lib.h" |
26 | 26 | ||
27 | 27 | ||
28 | /* ************************* pq_query_helper.c functions ************************ */ | ||
29 | |||
30 | |||
28 | /** | 31 | /** |
29 | * Function called to convert input argument into SQL parameters. | 32 | * Function called to convert input argument into SQL parameters. |
30 | * | 33 | * |
@@ -188,6 +191,9 @@ struct GNUNET_PQ_QueryParam | |||
188 | GNUNET_PQ_query_param_uint64 (const uint64_t *x); | 191 | GNUNET_PQ_query_param_uint64 (const uint64_t *x); |
189 | 192 | ||
190 | 193 | ||
194 | /* ************************* pq_result_helper.c functions ************************ */ | ||
195 | |||
196 | |||
191 | /** | 197 | /** |
192 | * Extract data from a Postgres database @a result at row @a row. | 198 | * Extract data from a Postgres database @a result at row @a row. |
193 | * | 199 | * |
@@ -412,6 +418,8 @@ GNUNET_PQ_result_spec_uint64 (const char *name, | |||
412 | uint64_t *u64); | 418 | uint64_t *u64); |
413 | 419 | ||
414 | 420 | ||
421 | /* ************************* pq.c functions ************************ */ | ||
422 | |||
415 | /** | 423 | /** |
416 | * Execute a prepared statement. | 424 | * Execute a prepared statement. |
417 | * | 425 | * |
@@ -419,6 +427,7 @@ GNUNET_PQ_result_spec_uint64 (const char *name, | |||
419 | * @param name name of the prepared statement | 427 | * @param name name of the prepared statement |
420 | * @param params parameters to the statement | 428 | * @param params parameters to the statement |
421 | * @return postgres result | 429 | * @return postgres result |
430 | * @deprecated (should become an internal API) | ||
422 | */ | 431 | */ |
423 | PGresult * | 432 | PGresult * |
424 | GNUNET_PQ_exec_prepared (PGconn *db_conn, | 433 | GNUNET_PQ_exec_prepared (PGconn *db_conn, |
@@ -435,6 +444,7 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, | |||
435 | * @return | 444 | * @return |
436 | * #GNUNET_YES if all results could be extracted | 445 | * #GNUNET_YES if all results could be extracted |
437 | * #GNUNET_SYSERR if a result was invalid (non-existing field) | 446 | * #GNUNET_SYSERR if a result was invalid (non-existing field) |
447 | * @deprecated (should become an internal API) | ||
438 | */ | 448 | */ |
439 | int | 449 | int |
440 | GNUNET_PQ_extract_result (PGresult *result, | 450 | GNUNET_PQ_extract_result (PGresult *result, |
@@ -452,6 +462,289 @@ void | |||
452 | GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs); | 462 | GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs); |
453 | 463 | ||
454 | 464 | ||
465 | /* ******************** pq_eval.c functions ************** */ | ||
466 | |||
467 | |||
468 | /** | ||
469 | * Status code returned from functions running PQ commands. | ||
470 | * Can be combined with a function that returns the number | ||
471 | * of results, so non-negative values indicate success. | ||
472 | */ | ||
473 | enum GNUNET_PQ_QueryStatus | ||
474 | { | ||
475 | /** | ||
476 | * A hard error occurred, retrying will not help. | ||
477 | */ | ||
478 | GNUNET_PQ_STATUS_HARD_ERROR = -2, | ||
479 | |||
480 | /** | ||
481 | * A soft error occurred, retrying the transaction may succeed. | ||
482 | */ | ||
483 | GNUNET_PQ_STATUS_SOFT_ERROR = -1, | ||
484 | |||
485 | /** | ||
486 | * The transaction succeeded, but yielded zero results. | ||
487 | */ | ||
488 | GNUNET_PQ_STATUS_SUCCESS_NO_RESULTS = 0, | ||
489 | |||
490 | /** | ||
491 | * The transaction succeeded, and yielded one result. | ||
492 | */ | ||
493 | GNUNET_PQ_STATUS_SUCCESS_ONE_RESULT = 1 | ||
494 | |||
495 | }; | ||
496 | |||
497 | |||
498 | /** | ||
499 | * Check the @a result's error code to see what happened. | ||
500 | * Also logs errors. | ||
501 | * | ||
502 | * @param connection connection to execute the statement in | ||
503 | * @param statement_name name of the statement that created @a result | ||
504 | * @param result result to check | ||
505 | * @return status code from the result, mapping PQ status | ||
506 | * codes to `enum GNUNET_PQ_QueryStatus`. Never | ||
507 | * returns positive values as this function does | ||
508 | * not look at the result set. | ||
509 | * @deprecated (low level, let's see if we can do with just the high-level functions) | ||
510 | */ | ||
511 | enum GNUNET_PQ_QueryStatus | ||
512 | GNUNET_PQ_eval_result (PGconn *connection, | ||
513 | const char *statement_name, | ||
514 | PGresult *result); | ||
515 | |||
516 | |||
517 | /** | ||
518 | * Execute a named prepared @a statement that is NOT a SELECT | ||
519 | * statement in @a connnection using the given @a params. Returns the | ||
520 | * resulting session state. | ||
521 | * | ||
522 | * @param connection connection to execute the statement in | ||
523 | * @param statement_name name of the statement | ||
524 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | ||
525 | * @return status code from the result, mapping PQ status | ||
526 | * codes to `enum GNUNET_PQ_QueryStatus`. Never | ||
527 | * returns positive values as this function does | ||
528 | * not look at the result set. | ||
529 | */ | ||
530 | enum GNUNET_PQ_QueryStatus | ||
531 | GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | ||
532 | const char *statement_name, | ||
533 | const struct GNUNET_PQ_QueryParam *params); | ||
534 | |||
535 | |||
536 | /** | ||
537 | * Function to be called with the results of a SELECT statement | ||
538 | * that has returned @a num_results results. | ||
539 | * | ||
540 | * @param cls closure | ||
541 | * @param result the postgres result | ||
542 | * @param num_result the number of results in @a result | ||
543 | */ | ||
544 | typedef void | ||
545 | (*GNUNET_PQ_PostgresResultHandler)(void *cls, | ||
546 | PGresult *result, | ||
547 | unsigned int num_results); | ||
548 | |||
549 | |||
550 | /** | ||
551 | * Execute a named prepared @a statement that is a SELECT statement | ||
552 | * which may return multiple results in @a connection using the given | ||
553 | * @a params. Call @a rh with the results. Returns the query | ||
554 | * status including the number of results given to @a rh (possibly zero). | ||
555 | * @a rh will not have been called if the return value is negative. | ||
556 | * | ||
557 | * @param connection connection to execute the statement in | ||
558 | * @param statement_name name of the statement | ||
559 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | ||
560 | * @param rh function to call with the result set, NULL to ignore | ||
561 | * @param rh_cls closure to pass to @a rh | ||
562 | * @return status code from the result, mapping PQ status | ||
563 | * codes to `enum GNUNET_PQ_QueryStatus`. | ||
564 | */ | ||
565 | enum GNUNET_PQ_QueryStatus | ||
566 | GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | ||
567 | const char *statement_name, | ||
568 | const struct GNUNET_PQ_QueryParam *params, | ||
569 | GNUNET_PQ_PostgresResultHandler rh, | ||
570 | void *rh_cls); | ||
571 | |||
572 | |||
573 | /** | ||
574 | * Execute a named prepared @a statement that is a SELECT statement | ||
575 | * which must return a single result in @a connection using the given | ||
576 | * @a params. Stores the result (if any) in @a rs, which the caller | ||
577 | * must then clean up using #GNUNET_PQ_cleanup_result() if the return | ||
578 | * value was #GNUNET_PQ_STATUS_SUCCESS_ONE_RESULT. Returns the | ||
579 | * resulting session status. | ||
580 | * | ||
581 | * @param connection connection to execute the statement in | ||
582 | * @param statement_name name of the statement | ||
583 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | ||
584 | * @param[in,out] rs result specification to use for storing the result of the query | ||
585 | * @return status code from the result, mapping PQ status | ||
586 | * codes to `enum GNUNET_PQ_QueryStatus`. | ||
587 | */ | ||
588 | enum GNUNET_PQ_QueryStatus | ||
589 | GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection, | ||
590 | const char *statement_name, | ||
591 | const struct GNUNET_PQ_QueryParam *params, | ||
592 | struct GNUNET_PQ_ResultSpec *rs); | ||
593 | |||
594 | |||
595 | /* ******************** pq_prepare.c functions ************** */ | ||
596 | |||
597 | |||
598 | /** | ||
599 | * Information needed to prepare a list of SQL statements using | ||
600 | * #GNUNET_PQ_prepare_statements(). | ||
601 | */ | ||
602 | struct GNUNET_PQ_PreparedStatement { | ||
603 | |||
604 | /** | ||
605 | * Name of the statement. | ||
606 | */ | ||
607 | const char *name; | ||
608 | |||
609 | /** | ||
610 | * Actual SQL statement. | ||
611 | */ | ||
612 | const char *sql; | ||
613 | |||
614 | /** | ||
615 | * Number of arguments included in @e sql. | ||
616 | */ | ||
617 | unsigned int num_arguments; | ||
618 | |||
619 | }; | ||
620 | |||
621 | |||
622 | /** | ||
623 | * Terminator for prepared statement list. | ||
624 | */ | ||
625 | #define GNUNET_PQ_PREPARED_STATEMENT_END { NULL, NULL, 0 } | ||
626 | |||
627 | |||
628 | /** | ||
629 | * Create a `struct GNUNET_PQ_PreparedStatement`. | ||
630 | * | ||
631 | * @param name name of the statement | ||
632 | * @param sql actual SQL statement | ||
633 | * @param num_args number of arguments in the statement | ||
634 | * @return initialized struct | ||
635 | */ | ||
636 | struct GNUNET_PQ_PreparedStatement | ||
637 | GNUNET_PQ_make_prepare (const char *name, | ||
638 | const char *sql, | ||
639 | unsigned int num_args); | ||
640 | |||
641 | |||
642 | /** | ||
643 | * Request creation of prepared statements @a ps from Postgres. | ||
644 | * | ||
645 | * @param connection connection to prepare the statements for | ||
646 | * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | ||
647 | * statements. | ||
648 | * @return #GNUNET_OK on success, | ||
649 | * #GNUNET_SYSERR on error | ||
650 | */ | ||
651 | int | ||
652 | GNUNET_PQ_prepare_statements (PGconn *connection, | ||
653 | const struct GNUNET_PQ_PreparedStatement *ps); | ||
654 | |||
655 | |||
656 | /* ******************** pq_exec.c functions ************** */ | ||
657 | |||
658 | |||
659 | /** | ||
660 | * Information needed to run a list of SQL statements using | ||
661 | * #GNUNET_PQ_exec_statements(). | ||
662 | */ | ||
663 | struct GNUNET_PQ_ExecuteStatement { | ||
664 | |||
665 | /** | ||
666 | * Actual SQL statement. | ||
667 | */ | ||
668 | const char *sql; | ||
669 | |||
670 | /** | ||
671 | * Should we ignore errors? | ||
672 | */ | ||
673 | int ignore_errors; | ||
674 | |||
675 | }; | ||
676 | |||
677 | |||
678 | /** | ||
679 | * Terminator for executable statement list. | ||
680 | */ | ||
681 | #define GNUNET_PQ_EXECUTE_STATEMENT_END { NULL, GNUNET_SYSERR } | ||
682 | |||
683 | |||
684 | /** | ||
685 | * Create a `struct GNUNET_PQ_ExecuteStatement` where errors are fatal. | ||
686 | * | ||
687 | * @param sql actual SQL statement | ||
688 | * @return initialized struct | ||
689 | */ | ||
690 | struct GNUNET_PQ_ExecuteStatement | ||
691 | GNUNET_PQ_make_execute (const char *sql); | ||
692 | |||
693 | |||
694 | /** | ||
695 | * Create a `struct GNUNET_PQ_ExecuteStatement` where errors should | ||
696 | * be tolerated. | ||
697 | * | ||
698 | * @param sql actual SQL statement | ||
699 | * @return initialized struct | ||
700 | */ | ||
701 | struct GNUNET_PQ_ExecuteStatement | ||
702 | GNUNET_PQ_make_try_execute (const char *sql); | ||
703 | |||
704 | |||
705 | /** | ||
706 | * Request execution of an array of statements @a es from Postgres. | ||
707 | * | ||
708 | * @param connection connection to execute the statements over | ||
709 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | ||
710 | * statements. | ||
711 | * @return #GNUNET_OK on success (modulo statements where errors can be ignored) | ||
712 | * #GNUNET_SYSERR on error | ||
713 | */ | ||
714 | int | ||
715 | GNUNET_PQ_exec_statements (PGconn *connection, | ||
716 | const struct GNUNET_PQ_ExecuteStatement *es); | ||
717 | |||
718 | |||
719 | /* ******************** pq_connect.c functions ************** */ | ||
720 | |||
721 | |||
722 | /** | ||
723 | * Create a connection to the Postgres database using @a config_str | ||
724 | * for the configuration. Initialize logging via GNUnet's log | ||
725 | * routines and disable Postgres's logger. | ||
726 | * | ||
727 | * @param config_str configuration to use | ||
728 | * @return NULL on error | ||
729 | */ | ||
730 | PGconn * | ||
731 | GNUNET_PQ_connect (const char *config_str); | ||
732 | |||
733 | |||
734 | /** | ||
735 | * Connect to a postgres database using the configuration | ||
736 | * option "CONFIG" in @a section. | ||
737 | * | ||
738 | * @param cfg configuration | ||
739 | * @param section configuration section to use to get Postgres configuration options | ||
740 | * @return the postgres handle, NULL on error | ||
741 | */ | ||
742 | PGconn * | ||
743 | GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
744 | const char *section); | ||
745 | |||
746 | |||
747 | |||
455 | #endif /* GNUNET_PQ_LIB_H_ */ | 748 | #endif /* GNUNET_PQ_LIB_H_ */ |
456 | 749 | ||
457 | /* end of include/gnunet_pq_lib.h */ | 750 | /* end of include/gnunet_pq_lib.h */ |
diff --git a/src/namecache/plugin_namecache_postgres.c b/src/namecache/plugin_namecache_postgres.c index bec8bffd2..9c85f4470 100644 --- a/src/namecache/plugin_namecache_postgres.c +++ b/src/namecache/plugin_namecache_postgres.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of GNUnet | 2 | * This file is part of GNUnet |
3 | * Copyright (C) 2009-2013, 2016 GNUnet e.V. | 3 | * Copyright (C) 2009-2013, 2016, 2017 GNUnet e.V. |
4 | * | 4 | * |
5 | * GNUnet is free software; you can redistribute it and/or modify | 5 | * GNUnet is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published | 6 | * it under the terms of the GNU General Public License as published |
@@ -72,40 +72,34 @@ struct Plugin | |||
72 | 72 | ||
73 | 73 | ||
74 | /** | 74 | /** |
75 | * Create our database indices. | ||
76 | * | ||
77 | * @param dbh handle to the database | ||
78 | */ | ||
79 | static void | ||
80 | create_indices (PGconn * dbh) | ||
81 | { | ||
82 | /* create indices */ | ||
83 | if ( (GNUNET_OK != | ||
84 | GNUNET_POSTGRES_exec (dbh, | ||
85 | "CREATE INDEX ir_query_hash ON ns096blocks (query,expiration_time)")) || | ||
86 | (GNUNET_OK != | ||
87 | GNUNET_POSTGRES_exec (dbh, | ||
88 | "CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)")) ) | ||
89 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
90 | _("Failed to create indices\n")); | ||
91 | } | ||
92 | |||
93 | |||
94 | /** | ||
95 | * Initialize the database connections and associated | 75 | * Initialize the database connections and associated |
96 | * data structures (create tables and indices | 76 | * data structures (create tables and indices |
97 | * as needed as well). | 77 | * as needed as well). |
98 | * | 78 | * |
99 | * @param plugin the plugin context (state for this module) | 79 | * @param plugin the plugin context (state for this module) |
100 | * @return GNUNET_OK on success | 80 | * @return #GNUNET_OK on success |
101 | */ | 81 | */ |
102 | static int | 82 | static int |
103 | database_setup (struct Plugin *plugin) | 83 | database_setup (struct Plugin *plugin) |
104 | { | 84 | { |
105 | PGresult *res; | 85 | struct GNUNET_PQ_ExecuteStatement es_temporary = |
106 | 86 | GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS ns096blocks (" | |
107 | plugin->dbh = GNUNET_POSTGRES_connect (plugin->cfg, | 87 | " query BYTEA NOT NULL DEFAULT ''," |
108 | "namecache-postgres"); | 88 | " block BYTEA NOT NULL DEFAULT ''," |
89 | " expiration_time BIGINT NOT NULL DEFAULT 0" | ||
90 | ")" | ||
91 | "WITH OIDS"); | ||
92 | struct GNUNET_PQ_ExecuteStatement es_default = | ||
93 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns096blocks (" | ||
94 | " query BYTEA NOT NULL DEFAULT ''," | ||
95 | " block BYTEA NOT NULL DEFAULT ''," | ||
96 | " expiration_time BIGINT NOT NULL DEFAULT 0" | ||
97 | ")" | ||
98 | "WITH OIDS"); | ||
99 | const struct GNUNET_PQ_ExecuteStatement *cr; | ||
100 | |||
101 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, | ||
102 | "namecache-postgres"); | ||
109 | if (NULL == plugin->dbh) | 103 | if (NULL == plugin->dbh) |
110 | return GNUNET_SYSERR; | 104 | return GNUNET_SYSERR; |
111 | if (GNUNET_YES == | 105 | if (GNUNET_YES == |
@@ -113,65 +107,56 @@ database_setup (struct Plugin *plugin) | |||
113 | "namecache-postgres", | 107 | "namecache-postgres", |
114 | "TEMPORARY_TABLE")) | 108 | "TEMPORARY_TABLE")) |
115 | { | 109 | { |
116 | res = | 110 | cr = &es_temporary; |
117 | PQexec (plugin->dbh, | ||
118 | "CREATE TEMPORARY TABLE ns096blocks (" | ||
119 | " query BYTEA NOT NULL DEFAULT ''," | ||
120 | " block BYTEA NOT NULL DEFAULT ''," | ||
121 | " expiration_time BIGINT NOT NULL DEFAULT 0" | ||
122 | ")" "WITH OIDS"); | ||
123 | } | 111 | } |
124 | else | 112 | else |
125 | { | 113 | { |
126 | res = | 114 | cr = &es_default; |
127 | PQexec (plugin->dbh, | ||
128 | "CREATE TABLE ns096blocks (" | ||
129 | " query BYTEA NOT NULL DEFAULT ''," | ||
130 | " block BYTEA NOT NULL DEFAULT ''," | ||
131 | " expiration_time BIGINT NOT NULL DEFAULT 0" | ||
132 | ")" "WITH OIDS"); | ||
133 | } | 115 | } |
134 | if ( (NULL == res) || | 116 | |
135 | ((PQresultStatus (res) != PGRES_COMMAND_OK) && | ||
136 | (0 != strcmp ("42P07", /* duplicate table */ | ||
137 | PQresultErrorField | ||
138 | (res, | ||
139 | PG_DIAG_SQLSTATE))))) | ||
140 | { | 117 | { |
141 | (void) GNUNET_POSTGRES_check_result (plugin->dbh, res, | 118 | struct GNUNET_PQ_ExecuteStatement es[] = { |
142 | PGRES_COMMAND_OK, "CREATE TABLE", | 119 | *cr, |
143 | "ns096blocks"); | 120 | GNUNET_PQ_make_try_execute ("CREATE INDEX ir_query_hash ON ns096blocks (query,expiration_time)"), |
144 | PQfinish (plugin->dbh); | 121 | GNUNET_PQ_make_try_execute ("CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)"), |
145 | plugin->dbh = NULL; | 122 | GNUNET_PQ_EXECUTE_STATEMENT_END |
146 | return GNUNET_SYSERR; | 123 | }; |
124 | |||
125 | if (GNUNET_OK != | ||
126 | GNUNET_PQ_exec_statements (plugin->dbh, | ||
127 | es)) | ||
128 | { | ||
129 | PQfinish (plugin->dbh); | ||
130 | plugin->dbh = NULL; | ||
131 | return GNUNET_SYSERR; | ||
132 | } | ||
147 | } | 133 | } |
148 | if (PQresultStatus (res) == PGRES_COMMAND_OK) | ||
149 | create_indices (plugin->dbh); | ||
150 | PQclear (res); | ||
151 | 134 | ||
152 | if ((GNUNET_OK != | ||
153 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
154 | "cache_block", | ||
155 | "INSERT INTO ns096blocks (query, block, expiration_time) VALUES " | ||
156 | "($1, $2, $3)", 3)) || | ||
157 | (GNUNET_OK != | ||
158 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
159 | "expire_blocks", | ||
160 | "DELETE FROM ns096blocks WHERE expiration_time<$1", 1)) || | ||
161 | (GNUNET_OK != | ||
162 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
163 | "delete_block", | ||
164 | "DELETE FROM ns096blocks WHERE query=$1 AND expiration_time<=$2", 2)) || | ||
165 | (GNUNET_OK != | ||
166 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
167 | "lookup_block", | ||
168 | "SELECT block FROM ns096blocks WHERE query=$1" | ||
169 | " ORDER BY expiration_time DESC LIMIT 1", 1))) | ||
170 | { | 135 | { |
171 | PQfinish (plugin->dbh); | 136 | struct GNUNET_PQ_PreparedStatement ps[] = { |
172 | plugin->dbh = NULL; | 137 | GNUNET_PQ_make_prepare ("cache_block", |
173 | return GNUNET_SYSERR; | 138 | "INSERT INTO ns096blocks (query, block, expiration_time) VALUES " |
139 | "($1, $2, $3)", 3), | ||
140 | GNUNET_PQ_make_prepare ("expire_blocks", | ||
141 | "DELETE FROM ns096blocks WHERE expiration_time<$1", 1), | ||
142 | GNUNET_PQ_make_prepare ("delete_block", | ||
143 | "DELETE FROM ns096blocks WHERE query=$1 AND expiration_time<=$2", 2), | ||
144 | GNUNET_PQ_make_prepare ("lookup_block", | ||
145 | "SELECT block FROM ns096blocks WHERE query=$1" | ||
146 | " ORDER BY expiration_time DESC LIMIT 1", 1), | ||
147 | GNUNET_PQ_PREPARED_STATEMENT_END | ||
148 | }; | ||
149 | |||
150 | if (GNUNET_OK != | ||
151 | GNUNET_PQ_prepare_statements (plugin->dbh, | ||
152 | ps)) | ||
153 | { | ||
154 | PQfinish (plugin->dbh); | ||
155 | plugin->dbh = NULL; | ||
156 | return GNUNET_SYSERR; | ||
157 | } | ||
174 | } | 158 | } |
159 | |||
175 | return GNUNET_OK; | 160 | return GNUNET_OK; |
176 | } | 161 | } |
177 | 162 | ||
@@ -185,7 +170,7 @@ static void | |||
185 | namecache_postgres_expire_blocks (struct Plugin *plugin) | 170 | namecache_postgres_expire_blocks (struct Plugin *plugin) |
186 | { | 171 | { |
187 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | 172 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); |
188 | struct GNUNET_PQ_QueryParam params[] = { | 173 | struct GNUNET_PQ_QueryParam params[] = { |
189 | GNUNET_PQ_query_param_absolute_time (&now), | 174 | GNUNET_PQ_query_param_absolute_time (&now), |
190 | GNUNET_PQ_query_param_end | 175 | GNUNET_PQ_query_param_end |
191 | }; | 176 | }; |
@@ -217,7 +202,7 @@ delete_old_block (struct Plugin *plugin, | |||
217 | const struct GNUNET_HashCode *query, | 202 | const struct GNUNET_HashCode *query, |
218 | struct GNUNET_TIME_AbsoluteNBO expiration_time) | 203 | struct GNUNET_TIME_AbsoluteNBO expiration_time) |
219 | { | 204 | { |
220 | struct GNUNET_PQ_QueryParam params[] = { | 205 | struct GNUNET_PQ_QueryParam params[] = { |
221 | GNUNET_PQ_query_param_auto_from_type (query), | 206 | GNUNET_PQ_query_param_auto_from_type (query), |
222 | GNUNET_PQ_query_param_absolute_time_nbo (&expiration_time), | 207 | GNUNET_PQ_query_param_absolute_time_nbo (&expiration_time), |
223 | GNUNET_PQ_query_param_end | 208 | GNUNET_PQ_query_param_end |
@@ -254,7 +239,7 @@ namecache_postgres_cache_block (void *cls, | |||
254 | size_t block_size = ntohl (block->purpose.size) + | 239 | size_t block_size = ntohl (block->purpose.size) + |
255 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) + | 240 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) + |
256 | sizeof (struct GNUNET_CRYPTO_EcdsaSignature); | 241 | sizeof (struct GNUNET_CRYPTO_EcdsaSignature); |
257 | struct GNUNET_PQ_QueryParam params[] = { | 242 | struct GNUNET_PQ_QueryParam params[] = { |
258 | GNUNET_PQ_query_param_auto_from_type (&query), | 243 | GNUNET_PQ_query_param_auto_from_type (&query), |
259 | GNUNET_PQ_query_param_fixed_size (block, block_size), | 244 | GNUNET_PQ_query_param_fixed_size (block, block_size), |
260 | GNUNET_PQ_query_param_absolute_time_nbo (&block->expiration_time), | 245 | GNUNET_PQ_query_param_absolute_time_nbo (&block->expiration_time), |
@@ -271,7 +256,9 @@ namecache_postgres_cache_block (void *cls, | |||
271 | GNUNET_break (0); | 256 | GNUNET_break (0); |
272 | return GNUNET_SYSERR; | 257 | return GNUNET_SYSERR; |
273 | } | 258 | } |
274 | delete_old_block (plugin, &query, block->expiration_time); | 259 | delete_old_block (plugin, |
260 | &query, | ||
261 | block->expiration_time); | ||
275 | 262 | ||
276 | res = GNUNET_PQ_exec_prepared (plugin->dbh, | 263 | res = GNUNET_PQ_exec_prepared (plugin->dbh, |
277 | "cache_block", | 264 | "cache_block", |
@@ -301,10 +288,11 @@ namecache_postgres_cache_block (void *cls, | |||
301 | static int | 288 | static int |
302 | namecache_postgres_lookup_block (void *cls, | 289 | namecache_postgres_lookup_block (void *cls, |
303 | const struct GNUNET_HashCode *query, | 290 | const struct GNUNET_HashCode *query, |
304 | GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls) | 291 | GNUNET_NAMECACHE_BlockCallback iter, |
292 | void *iter_cls) | ||
305 | { | 293 | { |
306 | struct Plugin *plugin = cls; | 294 | struct Plugin *plugin = cls; |
307 | struct GNUNET_PQ_QueryParam params[] = { | 295 | struct GNUNET_PQ_QueryParam params[] = { |
308 | GNUNET_PQ_query_param_auto_from_type (query), | 296 | GNUNET_PQ_query_param_auto_from_type (query), |
309 | GNUNET_PQ_query_param_end | 297 | GNUNET_PQ_query_param_end |
310 | }; | 298 | }; |
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c index 01dbf9e61..4bf931c93 100644 --- a/src/namestore/plugin_namestore_postgres.c +++ b/src/namestore/plugin_namestore_postgres.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of GNUnet | 2 | * This file is part of GNUnet |
3 | * Copyright (C) 2009-2013, 2016 GNUnet e.V. | 3 | * Copyright (C) 2009-2013, 2016, 2017 GNUnet e.V. |
4 | * | 4 | * |
5 | * GNUnet is free software; you can redistribute it and/or modify | 5 | * GNUnet is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published | 6 | * it under the terms of the GNU General Public License as published |
@@ -75,30 +75,6 @@ struct Plugin | |||
75 | 75 | ||
76 | 76 | ||
77 | /** | 77 | /** |
78 | * Create our database indices. | ||
79 | * | ||
80 | * @param dbh handle to the database | ||
81 | */ | ||
82 | static void | ||
83 | create_indices (PGconn * dbh) | ||
84 | { | ||
85 | /* create indices */ | ||
86 | if ( (GNUNET_OK != | ||
87 | GNUNET_POSTGRES_exec (dbh, | ||
88 | "CREATE INDEX IF NOT EXISTS ir_pkey_reverse ON ns097records (zone_private_key,pkey)")) || | ||
89 | (GNUNET_OK != | ||
90 | GNUNET_POSTGRES_exec (dbh, | ||
91 | "CREATE INDEX IF NOT EXISTS ir_pkey_iter ON ns097records (zone_private_key,rvalue)")) || | ||
92 | (GNUNET_OK != | ||
93 | GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS it_iter ON ns097records (rvalue)")) || | ||
94 | (GNUNET_OK != | ||
95 | GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_label ON ns097records (label)")) ) | ||
96 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
97 | _("Failed to create indices\n")); | ||
98 | } | ||
99 | |||
100 | |||
101 | /** | ||
102 | * Initialize the database connections and associated | 78 | * Initialize the database connections and associated |
103 | * data structures (create tables and indices | 79 | * data structures (create tables and indices |
104 | * as needed as well). | 80 | * as needed as well). |
@@ -109,10 +85,30 @@ create_indices (PGconn * dbh) | |||
109 | static int | 85 | static int |
110 | database_setup (struct Plugin *plugin) | 86 | database_setup (struct Plugin *plugin) |
111 | { | 87 | { |
112 | PGresult *res; | 88 | struct GNUNET_PQ_ExecuteStatement es_temporary = |
113 | 89 | GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS ns097records (" | |
114 | plugin->dbh = GNUNET_POSTGRES_connect (plugin->cfg, | 90 | " zone_private_key BYTEA NOT NULL DEFAULT ''," |
115 | "namestore-postgres"); | 91 | " pkey BYTEA DEFAULT ''," |
92 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
93 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
94 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
95 | " label TEXT NOT NULL DEFAULT ''" | ||
96 | ")" | ||
97 | "WITH OIDS"); | ||
98 | struct GNUNET_PQ_ExecuteStatement es_default = | ||
99 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns097records (" | ||
100 | " zone_private_key BYTEA NOT NULL DEFAULT ''," | ||
101 | " pkey BYTEA DEFAULT ''," | ||
102 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
103 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
104 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
105 | " label TEXT NOT NULL DEFAULT ''" | ||
106 | ")" | ||
107 | "WITH OIDS"); | ||
108 | const struct GNUNET_PQ_ExecuteStatement *cr; | ||
109 | |||
110 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, | ||
111 | "namestore-postgres"); | ||
116 | if (NULL == plugin->dbh) | 112 | if (NULL == plugin->dbh) |
117 | return GNUNET_SYSERR; | 113 | return GNUNET_SYSERR; |
118 | if (GNUNET_YES == | 114 | if (GNUNET_YES == |
@@ -120,80 +116,70 @@ database_setup (struct Plugin *plugin) | |||
120 | "namestore-postgres", | 116 | "namestore-postgres", |
121 | "TEMPORARY_TABLE")) | 117 | "TEMPORARY_TABLE")) |
122 | { | 118 | { |
123 | res = | 119 | cr = &es_temporary; |
124 | PQexec (plugin->dbh, | ||
125 | "CREATE TEMPORARY TABLE IF NOT EXISTS ns097records (" | ||
126 | " zone_private_key BYTEA NOT NULL DEFAULT ''," | ||
127 | " pkey BYTEA DEFAULT ''," | ||
128 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
129 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
130 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
131 | " label TEXT NOT NULL DEFAULT ''" | ||
132 | ")" "WITH OIDS"); | ||
133 | } | 120 | } |
134 | else | 121 | else |
135 | { | 122 | { |
136 | res = | 123 | cr = &es_default; |
137 | PQexec (plugin->dbh, | ||
138 | "CREATE TABLE IF NOT EXISTS ns097records (" | ||
139 | " zone_private_key BYTEA NOT NULL DEFAULT ''," | ||
140 | " pkey BYTEA DEFAULT ''," | ||
141 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
142 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
143 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
144 | " label TEXT NOT NULL DEFAULT ''" | ||
145 | ")" "WITH OIDS"); | ||
146 | } | 124 | } |
147 | if ( (NULL == res) || | 125 | |
148 | ((PQresultStatus (res) != PGRES_COMMAND_OK) && | ||
149 | (0 != strcmp ("42P07", /* duplicate table */ | ||
150 | PQresultErrorField | ||
151 | (res, | ||
152 | PG_DIAG_SQLSTATE))))) | ||
153 | { | 126 | { |
154 | (void) GNUNET_POSTGRES_check_result (plugin->dbh, res, | 127 | struct GNUNET_PQ_ExecuteStatement es[] = { |
155 | PGRES_COMMAND_OK, "CREATE TABLE", | 128 | *cr, |
156 | "ns097records"); | 129 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse " |
157 | PQfinish (plugin->dbh); | 130 | "ON ns097records (zone_private_key,pkey)"), |
158 | plugin->dbh = NULL; | 131 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter " |
159 | return GNUNET_SYSERR; | 132 | "ON ns097records (zone_private_key,rvalue)"), |
133 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS it_iter " | ||
134 | "ON ns097records (rvalue)"), | ||
135 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_label " | ||
136 | "ON ns097records (label)"), | ||
137 | GNUNET_PQ_EXECUTE_STATEMENT_END | ||
138 | }; | ||
139 | |||
140 | if (GNUNET_OK != | ||
141 | GNUNET_PQ_exec_statements (plugin->dbh, | ||
142 | es)) | ||
143 | { | ||
144 | PQfinish (plugin->dbh); | ||
145 | plugin->dbh = NULL; | ||
146 | return GNUNET_SYSERR; | ||
147 | } | ||
160 | } | 148 | } |
161 | create_indices (plugin->dbh); | 149 | |
162 | |||
163 | if ((GNUNET_OK != | ||
164 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
165 | "store_records", | ||
166 | "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label) VALUES " | ||
167 | "($1, $2, $3, $4, $5, $6)", 6)) || | ||
168 | (GNUNET_OK != | ||
169 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
170 | "delete_records", | ||
171 | "DELETE FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2)) || | ||
172 | (GNUNET_OK != | ||
173 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
174 | "zone_to_name", | ||
175 | "SELECT record_count,record_data,label FROM ns097records" | ||
176 | " WHERE zone_private_key=$1 AND pkey=$2", 2)) || | ||
177 | (GNUNET_OK != | ||
178 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
179 | "iterate_zone", | ||
180 | "SELECT record_count,record_data,label FROM ns097records" | ||
181 | " WHERE zone_private_key=$1 ORDER BY rvalue LIMIT 1 OFFSET $2", 2)) || | ||
182 | (GNUNET_OK != | ||
183 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
184 | "iterate_all_zones", | ||
185 | "SELECT record_count,record_data,label,zone_private_key" | ||
186 | " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET $1", 1)) || | ||
187 | (GNUNET_OK != | ||
188 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
189 | "lookup_label", | ||
190 | "SELECT record_count,record_data,label" | ||
191 | " FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2))) | ||
192 | { | 150 | { |
193 | PQfinish (plugin->dbh); | 151 | struct GNUNET_PQ_PreparedStatement ps[] = { |
194 | plugin->dbh = NULL; | 152 | GNUNET_PQ_make_prepare ("store_records", |
195 | return GNUNET_SYSERR; | 153 | "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label) VALUES " |
154 | "($1, $2, $3, $4, $5, $6)", 6), | ||
155 | GNUNET_PQ_make_prepare ("delete_records", | ||
156 | "DELETE FROM ns097records " | ||
157 | "WHERE zone_private_key=$1 AND label=$2", 2), | ||
158 | GNUNET_PQ_make_prepare ("zone_to_name", | ||
159 | "SELECT record_count,record_data,label FROM ns097records" | ||
160 | " WHERE zone_private_key=$1 AND pkey=$2", 2), | ||
161 | GNUNET_PQ_make_prepare ("iterate_zone", | ||
162 | "SELECT record_count,record_data,label FROM ns097records " | ||
163 | "WHERE zone_private_key=$1 ORDER BY rvalue LIMIT 1 OFFSET $2", 2), | ||
164 | GNUNET_PQ_make_prepare ("iterate_all_zones", | ||
165 | "SELECT record_count,record_data,label,zone_private_key" | ||
166 | " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET $1", 1), | ||
167 | GNUNET_PQ_make_prepare ("lookup_label", | ||
168 | "SELECT record_count,record_data,label " | ||
169 | "FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2), | ||
170 | GNUNET_PQ_PREPARED_STATEMENT_END | ||
171 | }; | ||
172 | |||
173 | if (GNUNET_OK != | ||
174 | GNUNET_PQ_prepare_statements (plugin->dbh, | ||
175 | ps)) | ||
176 | { | ||
177 | PQfinish (plugin->dbh); | ||
178 | plugin->dbh = NULL; | ||
179 | return GNUNET_SYSERR; | ||
180 | } | ||
196 | } | 181 | } |
182 | |||
197 | return GNUNET_OK; | 183 | return GNUNET_OK; |
198 | } | 184 | } |
199 | 185 | ||
@@ -221,19 +207,19 @@ namestore_postgres_store_records (void *cls, | |||
221 | uint64_t rvalue; | 207 | uint64_t rvalue; |
222 | uint32_t rd_count_nbo = htonl ((uint32_t) rd_count); | 208 | uint32_t rd_count_nbo = htonl ((uint32_t) rd_count); |
223 | size_t data_size; | 209 | size_t data_size; |
224 | unsigned int i; | ||
225 | 210 | ||
226 | memset (&pkey, 0, sizeof (pkey)); | 211 | memset (&pkey, 0, sizeof (pkey)); |
227 | for (i=0;i<rd_count;i++) | 212 | for (unsigned int i=0;i<rd_count;i++) |
228 | if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type) | 213 | if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type) |
229 | { | 214 | { |
230 | GNUNET_break (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) == rd[i].data_size); | 215 | GNUNET_break (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) == rd[i].data_size); |
231 | GNUNET_memcpy (&pkey, | 216 | GNUNET_memcpy (&pkey, |
232 | rd[i].data, | 217 | rd[i].data, |
233 | rd[i].data_size); | 218 | rd[i].data_size); |
234 | break; | 219 | break; |
235 | } | 220 | } |
236 | rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); | 221 | rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, |
222 | UINT64_MAX); | ||
237 | data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd); | 223 | data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd); |
238 | if (data_size > 64 * 65536) | 224 | if (data_size > 64 * 65536) |
239 | { | 225 | { |
@@ -262,9 +248,10 @@ namestore_postgres_store_records (void *cls, | |||
262 | const int paramFormats[] = { 1, 1, 1, 1, 1, 1 }; | 248 | const int paramFormats[] = { 1, 1, 1, 1, 1, 1 }; |
263 | PGresult *res; | 249 | PGresult *res; |
264 | 250 | ||
265 | if (data_size != GNUNET_GNSRECORD_records_serialize (rd_count, rd, | 251 | if (data_size != |
266 | data_size, data)) | 252 | GNUNET_GNSRECORD_records_serialize (rd_count, rd, |
267 | { | 253 | data_size, data)) |
254 | { | ||
268 | GNUNET_break (0); | 255 | GNUNET_break (0); |
269 | return GNUNET_SYSERR; | 256 | return GNUNET_SYSERR; |
270 | } | 257 | } |
@@ -301,7 +288,8 @@ static int | |||
301 | get_record_and_call_iterator (struct Plugin *plugin, | 288 | get_record_and_call_iterator (struct Plugin *plugin, |
302 | PGresult *res, | 289 | PGresult *res, |
303 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, | 290 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, |
304 | GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) | 291 | GNUNET_NAMESTORE_RecordIterator iter, |
292 | void *iter_cls) | ||
305 | { | 293 | { |
306 | const char *data; | 294 | const char *data; |
307 | size_t data_size; | 295 | size_t data_size; |
@@ -311,7 +299,9 @@ get_record_and_call_iterator (struct Plugin *plugin, | |||
311 | unsigned int cnt; | 299 | unsigned int cnt; |
312 | 300 | ||
313 | if (GNUNET_OK != | 301 | if (GNUNET_OK != |
314 | GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK, | 302 | GNUNET_POSTGRES_check_result (plugin->dbh, |
303 | res, | ||
304 | PGRES_TUPLES_OK, | ||
315 | "PQexecPrepared", | 305 | "PQexecPrepared", |
316 | "iteration")) | 306 | "iteration")) |
317 | { | 307 | { |
diff --git a/src/postgres/postgres.c b/src/postgres/postgres.c index 14095c5a4..828842d9d 100644 --- a/src/postgres/postgres.c +++ b/src/postgres/postgres.c | |||
@@ -161,48 +161,6 @@ GNUNET_POSTGRES_prepare_ (PGconn *dbh, | |||
161 | 161 | ||
162 | 162 | ||
163 | /** | 163 | /** |
164 | * Connect to a postgres database | ||
165 | * | ||
166 | * @param cfg configuration | ||
167 | * @param section configuration section to use to get Postgres configuration options | ||
168 | * @return the postgres handle | ||
169 | */ | ||
170 | PGconn * | ||
171 | GNUNET_POSTGRES_connect (const struct GNUNET_CONFIGURATION_Handle * cfg, | ||
172 | const char *section) | ||
173 | { | ||
174 | PGconn *dbh; | ||
175 | char *conninfo; | ||
176 | |||
177 | /* Open database and precompile statements */ | ||
178 | if (GNUNET_OK != | ||
179 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
180 | section, | ||
181 | "CONFIG", | ||
182 | &conninfo)) | ||
183 | conninfo = NULL; | ||
184 | dbh = PQconnectdb (conninfo == NULL ? "" : conninfo); | ||
185 | |||
186 | if (NULL != dbh) | ||
187 | { | ||
188 | if (PQstatus (dbh) != CONNECTION_OK) | ||
189 | { | ||
190 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
191 | "postgres", | ||
192 | _("Unable to connect to Postgres database '%s': %s\n"), | ||
193 | conninfo, | ||
194 | PQerrorMessage (dbh)); | ||
195 | PQfinish (dbh); | ||
196 | dbh = NULL; | ||
197 | } | ||
198 | } | ||
199 | // FIXME: warn about out-of-memory when dbh is NULL? | ||
200 | GNUNET_free_non_null (conninfo); | ||
201 | return dbh; | ||
202 | } | ||
203 | |||
204 | |||
205 | /** | ||
206 | * Delete the row identified by the given rowid (qid | 164 | * Delete the row identified by the given rowid (qid |
207 | * in postgres). | 165 | * in postgres). |
208 | * | 166 | * |
diff --git a/src/pq/Makefile.am b/src/pq/Makefile.am index 8bb0a0132..d0c71703b 100644 --- a/src/pq/Makefile.am +++ b/src/pq/Makefile.am | |||
@@ -15,6 +15,10 @@ endif | |||
15 | 15 | ||
16 | libgnunetpq_la_SOURCES = \ | 16 | libgnunetpq_la_SOURCES = \ |
17 | pq.c \ | 17 | pq.c \ |
18 | pq_connect.c \ | ||
19 | pq_eval.c \ | ||
20 | pq_exec.c \ | ||
21 | pq_prepare.c \ | ||
18 | pq_query_helper.c \ | 22 | pq_query_helper.c \ |
19 | pq_result_helper.c | 23 | pq_result_helper.c |
20 | libgnunetpq_la_LIBADD = -lpq \ | 24 | libgnunetpq_la_LIBADD = -lpq \ |
diff --git a/src/pq/pq_connect.c b/src/pq/pq_connect.c new file mode 100644 index 000000000..99ad06485 --- /dev/null +++ b/src/pq/pq_connect.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify it under the | ||
6 | terms of the GNU General Public License as published by the Free Software | ||
7 | Foundation; either version 3, or (at your option) any later version. | ||
8 | |||
9 | GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
11 | A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License along with | ||
14 | GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> | ||
15 | */ | ||
16 | /** | ||
17 | * @file pq/pq_connect.c | ||
18 | * @brief functions to connect to libpq (PostGres) | ||
19 | * @author Christian Grothoff | ||
20 | */ | ||
21 | #include "platform.h" | ||
22 | #include "gnunet_util_lib.h" | ||
23 | #include "gnunet_pq_lib.h" | ||
24 | |||
25 | |||
26 | /** | ||
27 | * Function called by libpq whenever it wants to log something. | ||
28 | * We already log whenever we care, so this function does nothing | ||
29 | * and merely exists to silence the libpq logging. | ||
30 | * | ||
31 | * @param arg the SQL connection that was used | ||
32 | * @param res information about some libpq event | ||
33 | */ | ||
34 | static void | ||
35 | pq_notice_receiver_cb (void *arg, | ||
36 | const PGresult *res) | ||
37 | { | ||
38 | /* do nothing, intentionally */ | ||
39 | } | ||
40 | |||
41 | |||
42 | /** | ||
43 | * Function called by libpq whenever it wants to log something. | ||
44 | * We log those using the Taler logger. | ||
45 | * | ||
46 | * @param arg the SQL connection that was used | ||
47 | * @param message information about some libpq event | ||
48 | */ | ||
49 | static void | ||
50 | pq_notice_processor_cb (void *arg, | ||
51 | const char *message) | ||
52 | { | ||
53 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | ||
54 | "pq", | ||
55 | "%s", | ||
56 | message); | ||
57 | } | ||
58 | |||
59 | |||
60 | /** | ||
61 | * Create a connection to the Postgres database using @a config_str | ||
62 | * for the configuration. Initialize logging via GNUnet's log | ||
63 | * routines and disable Postgres's logger. | ||
64 | * | ||
65 | * @param config_str configuration to use | ||
66 | * @return NULL on error | ||
67 | */ | ||
68 | PGconn * | ||
69 | GNUNET_PQ_connect (const char *config_str) | ||
70 | { | ||
71 | PGconn *conn; | ||
72 | |||
73 | conn = PQconnectdb (config_str); | ||
74 | if ( (NULL == conn) || | ||
75 | (CONNECTION_OK != | ||
76 | PQstatus (conn)) ) | ||
77 | { | ||
78 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
79 | "pq", | ||
80 | "Database connection to '%s' failed: %s\n", | ||
81 | config_str, | ||
82 | (NULL != conn) ? | ||
83 | PQerrorMessage (conn) | ||
84 | : "PQconnectdb returned NULL"); | ||
85 | if (NULL != conn) | ||
86 | PQfinish (conn); | ||
87 | return NULL; | ||
88 | } | ||
89 | PQsetNoticeReceiver (conn, | ||
90 | &pq_notice_receiver_cb, | ||
91 | conn); | ||
92 | PQsetNoticeProcessor (conn, | ||
93 | &pq_notice_processor_cb, | ||
94 | conn); | ||
95 | return conn; | ||
96 | } | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Connect to a postgres database using the configuration | ||
101 | * option "CONFIG" in @a section. | ||
102 | * | ||
103 | * @param cfg configuration | ||
104 | * @param section configuration section to use to get Postgres configuration options | ||
105 | * @return the postgres handle, NULL on error | ||
106 | */ | ||
107 | PGconn * | ||
108 | GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle * cfg, | ||
109 | const char *section) | ||
110 | { | ||
111 | PGconn *dbh; | ||
112 | char *conninfo; | ||
113 | |||
114 | /* Open database and precompile statements */ | ||
115 | if (GNUNET_OK != | ||
116 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
117 | section, | ||
118 | "CONFIG", | ||
119 | &conninfo)) | ||
120 | conninfo = NULL; | ||
121 | dbh = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo); | ||
122 | GNUNET_free_non_null (conninfo); | ||
123 | return dbh; | ||
124 | } | ||
125 | |||
126 | |||
127 | /* end of pq/pq_connect.c */ | ||
diff --git a/src/pq/pq_eval.c b/src/pq/pq_eval.c new file mode 100644 index 000000000..39a7a2c98 --- /dev/null +++ b/src/pq/pq_eval.c | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify it under the | ||
6 | terms of the GNU General Public License as published by the Free Software | ||
7 | Foundation; either version 3, or (at your option) any later version. | ||
8 | |||
9 | GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
11 | A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License along with | ||
14 | GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> | ||
15 | */ | ||
16 | /** | ||
17 | * @file pq/pq_eval.c | ||
18 | * @brief functions to execute SQL statements with arguments and/or results (PostGres) | ||
19 | * @author Christian Grothoff | ||
20 | */ | ||
21 | #include "platform.h" | ||
22 | #include "gnunet_util_lib.h" | ||
23 | #include "gnunet_pq_lib.h" | ||
24 | |||
25 | |||
26 | /** | ||
27 | * Error code returned by Postgres for deadlock. | ||
28 | */ | ||
29 | #define PQ_DIAG_SQLSTATE_DEADLOCK "40P01" | ||
30 | |||
31 | /** | ||
32 | * Error code returned by Postgres for uniqueness violation. | ||
33 | */ | ||
34 | #define PQ_DIAG_SQLSTATE_UNIQUE_VIOLATION "23505" | ||
35 | |||
36 | /** | ||
37 | * Error code returned by Postgres on serialization failure. | ||
38 | */ | ||
39 | #define PQ_DIAG_SQLSTATE_SERIALIZATION_FAILURE "40001" | ||
40 | |||
41 | |||
42 | /** | ||
43 | * Check the @a result's error code to see what happened. | ||
44 | * Also logs errors. | ||
45 | * | ||
46 | * @param connection connection to execute the statement in | ||
47 | * @param statement_name name of the statement that created @a result | ||
48 | * @param result result to check | ||
49 | * @return status code from the result, mapping PQ status | ||
50 | * codes to `enum GNUNET_PQ_QueryStatus`. Never | ||
51 | * returns positive values as this function does | ||
52 | * not look at the result set. | ||
53 | * @deprecated (low level, let's see if we can do with just the high-level functions) | ||
54 | */ | ||
55 | enum GNUNET_PQ_QueryStatus | ||
56 | GNUNET_PQ_eval_result (PGconn *connection, | ||
57 | const char *statement_name, | ||
58 | PGresult *result) | ||
59 | { | ||
60 | if (PGRES_COMMAND_OK != | ||
61 | PQresultStatus (result)) | ||
62 | { | ||
63 | const char *sqlstate; | ||
64 | |||
65 | sqlstate = PQresultErrorField (result, | ||
66 | PG_DIAG_SQLSTATE); | ||
67 | if (NULL == sqlstate) | ||
68 | { | ||
69 | /* very unexpected... */ | ||
70 | GNUNET_break (0); | ||
71 | return GNUNET_PQ_STATUS_HARD_ERROR; | ||
72 | } | ||
73 | if ( (0 == strcmp (sqlstate, | ||
74 | PQ_DIAG_SQLSTATE_DEADLOCK)) || | ||
75 | (0 == strcmp (sqlstate, | ||
76 | PQ_DIAG_SQLSTATE_SERIALIZATION_FAILURE)) ) | ||
77 | { | ||
78 | /* These two can be retried and have a fair chance of working | ||
79 | the next time */ | ||
80 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | ||
81 | "pq", | ||
82 | "Query `%s' failed with result: %s/%s/%s/%s/%s\n", | ||
83 | statement_name, | ||
84 | PQresultErrorField (result, | ||
85 | PG_DIAG_MESSAGE_PRIMARY), | ||
86 | PQresultErrorField (result, | ||
87 | PG_DIAG_MESSAGE_DETAIL), | ||
88 | PQresultErrorMessage (result), | ||
89 | PQresStatus (PQresultStatus (result)), | ||
90 | PQerrorMessage (connection)); | ||
91 | return GNUNET_PQ_STATUS_SOFT_ERROR; | ||
92 | } | ||
93 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
94 | "pq", | ||
95 | "Query `%s' failed with result: %s/%s/%s/%s/%s\n", | ||
96 | statement_name, | ||
97 | PQresultErrorField (result, | ||
98 | PG_DIAG_MESSAGE_PRIMARY), | ||
99 | PQresultErrorField (result, | ||
100 | PG_DIAG_MESSAGE_DETAIL), | ||
101 | PQresultErrorMessage (result), | ||
102 | PQresStatus (PQresultStatus (result)), | ||
103 | PQerrorMessage (connection)); | ||
104 | return GNUNET_PQ_STATUS_HARD_ERROR; | ||
105 | } | ||
106 | return GNUNET_PQ_STATUS_SUCCESS_NO_RESULTS; | ||
107 | } | ||
108 | |||
109 | |||
110 | /** | ||
111 | * Execute a named prepared @a statement that is NOT a SELECT | ||
112 | * statement in @a connnection using the given @a params. Returns the | ||
113 | * resulting session state. | ||
114 | * | ||
115 | * @param connection connection to execute the statement in | ||
116 | * @param statement_name name of the statement | ||
117 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | ||
118 | * @return status code from the result, mapping PQ status | ||
119 | * codes to `enum GNUNET_PQ_QueryStatus`. Never | ||
120 | * returns positive values as this function does | ||
121 | * not look at the result set. | ||
122 | */ | ||
123 | enum GNUNET_PQ_QueryStatus | ||
124 | GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | ||
125 | const char *statement_name, | ||
126 | const struct GNUNET_PQ_QueryParam *params) | ||
127 | { | ||
128 | PGresult *result; | ||
129 | enum GNUNET_PQ_QueryStatus qs; | ||
130 | |||
131 | result = GNUNET_PQ_exec_prepared (connection, | ||
132 | statement_name, | ||
133 | params); | ||
134 | qs = GNUNET_PQ_eval_result (connection, | ||
135 | statement_name, | ||
136 | result); | ||
137 | PQclear (result); | ||
138 | return qs; | ||
139 | } | ||
140 | |||
141 | |||
142 | /** | ||
143 | * Execute a named prepared @a statement that is a SELECT statement | ||
144 | * which may return multiple results in @a connection using the given | ||
145 | * @a params. Call @a rh with the results. Returns the query | ||
146 | * status including the number of results given to @a rh (possibly zero). | ||
147 | * @a rh will not have been called if the return value is negative. | ||
148 | * | ||
149 | * @param connection connection to execute the statement in | ||
150 | * @param statement_name name of the statement | ||
151 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | ||
152 | * @param rh function to call with the result set, NULL to ignore | ||
153 | * @param rh_cls closure to pass to @a rh | ||
154 | * @return status code from the result, mapping PQ status | ||
155 | * codes to `enum GNUNET_PQ_QueryStatus`. | ||
156 | */ | ||
157 | enum GNUNET_PQ_QueryStatus | ||
158 | GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | ||
159 | const char *statement_name, | ||
160 | const struct GNUNET_PQ_QueryParam *params, | ||
161 | GNUNET_PQ_PostgresResultHandler rh, | ||
162 | void *rh_cls) | ||
163 | { | ||
164 | PGresult *result; | ||
165 | enum GNUNET_PQ_QueryStatus qs; | ||
166 | unsigned int ret; | ||
167 | |||
168 | result = GNUNET_PQ_exec_prepared (connection, | ||
169 | statement_name, | ||
170 | params); | ||
171 | qs = GNUNET_PQ_eval_result (connection, | ||
172 | statement_name, | ||
173 | result); | ||
174 | if (qs < 0) | ||
175 | { | ||
176 | PQclear (result); | ||
177 | return qs; | ||
178 | } | ||
179 | ret = PQntuples (result); | ||
180 | if (NULL != rh) | ||
181 | rh (rh_cls, | ||
182 | result, | ||
183 | ret); | ||
184 | PQclear (result); | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | |||
189 | /** | ||
190 | * Execute a named prepared @a statement that is a SELECT statement | ||
191 | * which must return a single result in @a connection using the given | ||
192 | * @a params. Stores the result (if any) in @a rs, which the caller | ||
193 | * must then clean up using #GNUNET_PQ_cleanup_result() if the return | ||
194 | * value was #GNUNET_PQ_STATUS_SUCCESS_ONE_RESULT. Returns the | ||
195 | * resulting session status. | ||
196 | * | ||
197 | * @param connection connection to execute the statement in | ||
198 | * @param statement_name name of the statement | ||
199 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | ||
200 | * @param[in,out] rs result specification to use for storing the result of the query | ||
201 | * @return status code from the result, mapping PQ status | ||
202 | * codes to `enum GNUNET_PQ_QueryStatus`. | ||
203 | */ | ||
204 | enum GNUNET_PQ_QueryStatus | ||
205 | GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection, | ||
206 | const char *statement_name, | ||
207 | const struct GNUNET_PQ_QueryParam *params, | ||
208 | struct GNUNET_PQ_ResultSpec *rs) | ||
209 | { | ||
210 | PGresult *result; | ||
211 | enum GNUNET_PQ_QueryStatus qs; | ||
212 | |||
213 | result = GNUNET_PQ_exec_prepared (connection, | ||
214 | statement_name, | ||
215 | params); | ||
216 | qs = GNUNET_PQ_eval_result (connection, | ||
217 | statement_name, | ||
218 | result); | ||
219 | if (qs < 0) | ||
220 | { | ||
221 | PQclear (result); | ||
222 | return qs; | ||
223 | } | ||
224 | if (0 == PQntuples (result)) | ||
225 | { | ||
226 | PQclear (result); | ||
227 | return GNUNET_PQ_STATUS_SUCCESS_NO_RESULTS; | ||
228 | } | ||
229 | if (1 != PQntuples (result)) | ||
230 | { | ||
231 | /* more than one result, but there must be at most one */ | ||
232 | GNUNET_break (0); | ||
233 | PQclear (result); | ||
234 | return GNUNET_PQ_STATUS_HARD_ERROR; | ||
235 | } | ||
236 | if (GNUNET_OK != | ||
237 | GNUNET_PQ_extract_result (result, | ||
238 | rs, | ||
239 | 0)) | ||
240 | { | ||
241 | PQclear (result); | ||
242 | return GNUNET_PQ_STATUS_HARD_ERROR; | ||
243 | } | ||
244 | PQclear (result); | ||
245 | return GNUNET_PQ_STATUS_SUCCESS_ONE_RESULT; | ||
246 | } | ||
247 | |||
248 | |||
249 | /* end of pq/pq_eval.c */ | ||
diff --git a/src/pq/pq_exec.c b/src/pq/pq_exec.c new file mode 100644 index 000000000..1e5e4eb76 --- /dev/null +++ b/src/pq/pq_exec.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify it under the | ||
6 | terms of the GNU General Public License as published by the Free Software | ||
7 | Foundation; either version 3, or (at your option) any later version. | ||
8 | |||
9 | GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
11 | A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License along with | ||
14 | GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> | ||
15 | */ | ||
16 | /** | ||
17 | * @file pq/pq_exec.c | ||
18 | * @brief functions to execute plain SQL statements (PostGres) | ||
19 | * @author Christian Grothoff | ||
20 | */ | ||
21 | #include "platform.h" | ||
22 | #include "gnunet_util_lib.h" | ||
23 | #include "gnunet_pq_lib.h" | ||
24 | |||
25 | |||
26 | /** | ||
27 | * Create a `struct GNUNET_PQ_ExecuteStatement` where errors are fatal. | ||
28 | * | ||
29 | * @param sql actual SQL statement | ||
30 | * @return initialized struct | ||
31 | */ | ||
32 | struct GNUNET_PQ_ExecuteStatement | ||
33 | GNUNET_PQ_make_execute (const char *sql) | ||
34 | { | ||
35 | struct GNUNET_PQ_ExecuteStatement es = { | ||
36 | .sql = sql, | ||
37 | .ignore_errors = GNUNET_NO | ||
38 | }; | ||
39 | |||
40 | return es; | ||
41 | } | ||
42 | |||
43 | |||
44 | /** | ||
45 | * Create a `struct GNUNET_PQ_ExecuteStatement` where errors should | ||
46 | * be tolerated. | ||
47 | * | ||
48 | * @param sql actual SQL statement | ||
49 | * @return initialized struct | ||
50 | */ | ||
51 | struct GNUNET_PQ_ExecuteStatement | ||
52 | GNUNET_PQ_make_try_execute (const char *sql) | ||
53 | { | ||
54 | struct GNUNET_PQ_ExecuteStatement es = { | ||
55 | .sql = sql, | ||
56 | .ignore_errors = GNUNET_YES | ||
57 | }; | ||
58 | |||
59 | return es; | ||
60 | } | ||
61 | |||
62 | |||
63 | /** | ||
64 | * Request execution of an array of statements @a es from Postgres. | ||
65 | * | ||
66 | * @param connection connection to execute the statements over | ||
67 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | ||
68 | * statements. | ||
69 | * @return #GNUNET_OK on success (modulo statements where errors can be ignored) | ||
70 | * #GNUNET_SYSERR on error | ||
71 | */ | ||
72 | int | ||
73 | GNUNET_PQ_exec_statements (PGconn *connection, | ||
74 | const struct GNUNET_PQ_ExecuteStatement *es) | ||
75 | { | ||
76 | for (unsigned int i=0; NULL != es[i].sql; i++) | ||
77 | { | ||
78 | PGresult *result; | ||
79 | |||
80 | result = PQexec (connection, | ||
81 | es[i].sql); | ||
82 | |||
83 | if ( (GNUNET_NO == es[i].ignore_errors) && | ||
84 | (PGRES_COMMAND_OK != PQresultStatus (result)) ) | ||
85 | { | ||
86 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
87 | "pq", | ||
88 | "Failed to execute `%s': %s/%s/%s/%s/%s", | ||
89 | es[i].sql, | ||
90 | PQresultErrorField (result, | ||
91 | PG_DIAG_MESSAGE_PRIMARY), | ||
92 | PQresultErrorField (result, | ||
93 | PG_DIAG_MESSAGE_DETAIL), | ||
94 | PQresultErrorMessage (result), | ||
95 | PQresStatus (PQresultStatus (result)), | ||
96 | PQerrorMessage (connection)); | ||
97 | PQclear (result); | ||
98 | return GNUNET_SYSERR; | ||
99 | } | ||
100 | PQclear (result); | ||
101 | } | ||
102 | return GNUNET_OK; | ||
103 | } | ||
104 | |||
105 | |||
106 | /* end of pq/pq_exec.c */ | ||
diff --git a/src/pq/pq_prepare.c b/src/pq/pq_prepare.c new file mode 100644 index 000000000..f533cb564 --- /dev/null +++ b/src/pq/pq_prepare.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify it under the | ||
6 | terms of the GNU General Public License as published by the Free Software | ||
7 | Foundation; either version 3, or (at your option) any later version. | ||
8 | |||
9 | GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
11 | A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License along with | ||
14 | GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> | ||
15 | */ | ||
16 | /** | ||
17 | * @file pq/pq_prepare.c | ||
18 | * @brief functions to connect to libpq (PostGres) | ||
19 | * @author Christian Grothoff | ||
20 | */ | ||
21 | #include "platform.h" | ||
22 | #include "gnunet_util_lib.h" | ||
23 | #include "gnunet_pq_lib.h" | ||
24 | |||
25 | |||
26 | /** | ||
27 | * Create a `struct GNUNET_PQ_PreparedStatement`. | ||
28 | * | ||
29 | * @param name name of the statement | ||
30 | * @param sql actual SQL statement | ||
31 | * @param num_args number of arguments in the statement | ||
32 | * @return initialized struct | ||
33 | */ | ||
34 | struct GNUNET_PQ_PreparedStatement | ||
35 | GNUNET_PQ_make_prepare (const char *name, | ||
36 | const char *sql, | ||
37 | unsigned int num_args) | ||
38 | { | ||
39 | struct GNUNET_PQ_PreparedStatement ps = { | ||
40 | .name = name, | ||
41 | .sql = sql, | ||
42 | .num_arguments = num_args | ||
43 | }; | ||
44 | |||
45 | return ps; | ||
46 | } | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Request creation of prepared statements @a ps from Postgres. | ||
51 | * | ||
52 | * @param connection connection to prepare the statements for | ||
53 | * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | ||
54 | * statements. | ||
55 | * @return #GNUNET_OK on success, | ||
56 | * #GNUNET_SYSERR on error | ||
57 | */ | ||
58 | int | ||
59 | GNUNET_PQ_prepare_statements (PGconn *connection, | ||
60 | const struct GNUNET_PQ_PreparedStatement *ps) | ||
61 | { | ||
62 | for (unsigned int i=0;NULL != ps[i].name;i++) | ||
63 | { | ||
64 | PGresult *ret; | ||
65 | |||
66 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
67 | "pq", | ||
68 | "Preparing SQL statement `%s' as `%s'\n", | ||
69 | ps[i].sql, | ||
70 | ps[i].name); | ||
71 | ret = PQprepare (connection, | ||
72 | ps[i].name, | ||
73 | ps[i].sql, | ||
74 | ps[i].num_arguments, | ||
75 | NULL); | ||
76 | if (PGRES_COMMAND_OK != PQresultStatus (ret)) | ||
77 | { | ||
78 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
79 | "pq", | ||
80 | _("PQprepare (`%s' as `%s') failed with error: %s\n"), | ||
81 | ps[i].sql, | ||
82 | ps[i].name, | ||
83 | PQerrorMessage (connection)); | ||
84 | PQclear (ret); | ||
85 | return GNUNET_SYSERR; | ||
86 | } | ||
87 | } | ||
88 | return GNUNET_OK; | ||
89 | } | ||
90 | |||
91 | |||
92 | /* end of pq/pq_prepare.c */ | ||
diff --git a/src/psycstore/plugin_psycstore_postgres.c b/src/psycstore/plugin_psycstore_postgres.c index 273ab4e80..f410e2737 100644 --- a/src/psycstore/plugin_psycstore_postgres.c +++ b/src/psycstore/plugin_psycstore_postgres.c | |||
@@ -84,117 +84,96 @@ struct Plugin | |||
84 | * as needed as well). | 84 | * as needed as well). |
85 | * | 85 | * |
86 | * @param plugin the plugin context (state for this module) | 86 | * @param plugin the plugin context (state for this module) |
87 | * @return GNUNET_OK on success | 87 | * @return #GNUNET_OK on success |
88 | */ | 88 | */ |
89 | static int | 89 | static int |
90 | database_setup (struct Plugin *plugin) | 90 | database_setup (struct Plugin *plugin) |
91 | { | 91 | { |
92 | struct GNUNET_PQ_ExecuteStatement es[] = { | ||
93 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS channels (\n" | ||
94 | " id SERIAL,\n" | ||
95 | " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n" | ||
96 | " max_state_message_id BIGINT,\n" | ||
97 | " state_hash_message_id BIGINT,\n" | ||
98 | " PRIMARY KEY(id)\n" | ||
99 | ")" | ||
100 | "WITH OIDS"), | ||
101 | GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS channel_pub_key_idx \n" | ||
102 | " ON channels (pub_key)"), | ||
103 | GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_chan_id(BYTEA) RETURNS INTEGER AS \n" | ||
104 | " 'SELECT id FROM channels WHERE pub_key=$1;' LANGUAGE SQL STABLE \n" | ||
105 | "RETURNS NULL ON NULL INPUT"), | ||
106 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS slaves (\n" | ||
107 | " id SERIAL,\n" | ||
108 | " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n" | ||
109 | " PRIMARY KEY(id)\n" | ||
110 | ")" | ||
111 | "WITH OIDS"), | ||
112 | GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS slaves_pub_key_idx \n" | ||
113 | " ON slaves (pub_key)"), | ||
114 | GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_slave_id(BYTEA) RETURNS INTEGER AS \n" | ||
115 | " 'SELECT id FROM slaves WHERE pub_key=$1;' LANGUAGE SQL STABLE \n" | ||
116 | "RETURNS NULL ON NULL INPUT"), | ||
117 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS membership (\n" | ||
118 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
119 | " slave_id BIGINT NOT NULL REFERENCES slaves(id),\n" | ||
120 | " did_join INT NOT NULL,\n" | ||
121 | " announced_at BIGINT NOT NULL,\n" | ||
122 | " effective_since BIGINT NOT NULL,\n" | ||
123 | " group_generation BIGINT NOT NULL\n" | ||
124 | ")" | ||
125 | "WITH OIDS"), | ||
126 | GNUNET_PQ_make_execute ("CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id " | ||
127 | "ON membership (channel_id, slave_id)"), | ||
128 | /** @todo messages table: add method_name column */ | ||
129 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS messages (\n" | ||
130 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
131 | " hop_counter INT NOT NULL,\n" | ||
132 | " signature BYTEA CHECK (LENGTH(signature)=64),\n" | ||
133 | " purpose BYTEA CHECK (LENGTH(purpose)=8),\n" | ||
134 | " fragment_id BIGINT NOT NULL,\n" | ||
135 | " fragment_offset BIGINT NOT NULL,\n" | ||
136 | " message_id BIGINT NOT NULL,\n" | ||
137 | " group_generation BIGINT NOT NULL,\n" | ||
138 | " multicast_flags INT NOT NULL,\n" | ||
139 | " psycstore_flags INT NOT NULL,\n" | ||
140 | " data BYTEA,\n" | ||
141 | " PRIMARY KEY (channel_id, fragment_id),\n" | ||
142 | " UNIQUE (channel_id, message_id, fragment_offset)\n" | ||
143 | ")" | ||
144 | "WITH OIDS"), | ||
145 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state (\n" | ||
146 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
147 | " name TEXT NOT NULL,\n" | ||
148 | " value_current BYTEA,\n" | ||
149 | " value_signed BYTEA,\n" | ||
150 | " PRIMARY KEY (channel_id, name)\n" | ||
151 | ")" | ||
152 | "WITH OIDS"), | ||
153 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state_sync (\n" | ||
154 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
155 | " name TEXT NOT NULL,\n" | ||
156 | " value BYTEA,\n" | ||
157 | " PRIMARY KEY (channel_id, name)\n" | ||
158 | ")" | ||
159 | "WITH OIDS"), | ||
160 | GNUNET_PQ_EXECUTE_STATEMENT_END | ||
161 | }; | ||
162 | |||
92 | /* Open database and precompile statements */ | 163 | /* Open database and precompile statements */ |
93 | plugin->dbh = GNUNET_POSTGRES_connect (plugin->cfg, | 164 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, |
94 | "psycstore-postgres"); | 165 | "psycstore-postgres"); |
95 | if (NULL == plugin->dbh) | 166 | if (NULL == plugin->dbh) |
96 | return GNUNET_SYSERR; | 167 | return GNUNET_SYSERR; |
97 | 168 | if (GNUNET_OK != | |
98 | /* Create tables */ | 169 | GNUNET_PQ_exec_statements (plugin->dbh, |
99 | if ((GNUNET_OK != | 170 | es)) |
100 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
101 | "CREATE TABLE IF NOT EXISTS channels (\n" | ||
102 | " id SERIAL,\n" | ||
103 | " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n" | ||
104 | " max_state_message_id BIGINT,\n" | ||
105 | " state_hash_message_id BIGINT,\n" | ||
106 | " PRIMARY KEY(id)\n" | ||
107 | ")" "WITH OIDS")) || | ||
108 | |||
109 | (GNUNET_OK != | ||
110 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
111 | "CREATE UNIQUE INDEX IF NOT EXISTS channel_pub_key_idx \n" | ||
112 | " ON channels (pub_key)")) || | ||
113 | |||
114 | (GNUNET_OK != | ||
115 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
116 | "CREATE OR REPLACE FUNCTION get_chan_id(BYTEA) RETURNS INTEGER AS \n" | ||
117 | " 'SELECT id FROM channels WHERE pub_key=$1;' LANGUAGE SQL STABLE \n" | ||
118 | "RETURNS NULL ON NULL INPUT")) || | ||
119 | |||
120 | (GNUNET_OK != | ||
121 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
122 | "CREATE TABLE IF NOT EXISTS slaves (\n" | ||
123 | " id SERIAL,\n" | ||
124 | " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n" | ||
125 | " PRIMARY KEY(id)\n" | ||
126 | ")" "WITH OIDS")) || | ||
127 | |||
128 | (GNUNET_OK != | ||
129 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
130 | "CREATE UNIQUE INDEX IF NOT EXISTS slaves_pub_key_idx \n" | ||
131 | " ON slaves (pub_key)")) || | ||
132 | |||
133 | (GNUNET_OK != | ||
134 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
135 | "CREATE OR REPLACE FUNCTION get_slave_id(BYTEA) RETURNS INTEGER AS \n" | ||
136 | " 'SELECT id FROM slaves WHERE pub_key=$1;' LANGUAGE SQL STABLE \n" | ||
137 | "RETURNS NULL ON NULL INPUT")) || | ||
138 | |||
139 | (GNUNET_OK != | ||
140 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
141 | "CREATE TABLE IF NOT EXISTS membership (\n" | ||
142 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
143 | " slave_id BIGINT NOT NULL REFERENCES slaves(id),\n" | ||
144 | " did_join INT NOT NULL,\n" | ||
145 | " announced_at BIGINT NOT NULL,\n" | ||
146 | " effective_since BIGINT NOT NULL,\n" | ||
147 | " group_generation BIGINT NOT NULL\n" | ||
148 | ")" "WITH OIDS")) || | ||
149 | |||
150 | (GNUNET_OK != | ||
151 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
152 | "CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id " | ||
153 | "ON membership (channel_id, slave_id)")) || | ||
154 | |||
155 | /** @todo messages table: add method_name column */ | ||
156 | (GNUNET_OK != | ||
157 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
158 | "CREATE TABLE IF NOT EXISTS messages (\n" | ||
159 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
160 | " hop_counter INT NOT NULL,\n" | ||
161 | " signature BYTEA CHECK (LENGTH(signature)=64),\n" | ||
162 | " purpose BYTEA CHECK (LENGTH(purpose)=8),\n" | ||
163 | " fragment_id BIGINT NOT NULL,\n" | ||
164 | " fragment_offset BIGINT NOT NULL,\n" | ||
165 | " message_id BIGINT NOT NULL,\n" | ||
166 | " group_generation BIGINT NOT NULL,\n" | ||
167 | " multicast_flags INT NOT NULL,\n" | ||
168 | " psycstore_flags INT NOT NULL,\n" | ||
169 | " data BYTEA,\n" | ||
170 | " PRIMARY KEY (channel_id, fragment_id),\n" | ||
171 | " UNIQUE (channel_id, message_id, fragment_offset)\n" | ||
172 | ")" "WITH OIDS")) || | ||
173 | |||
174 | (GNUNET_OK != | ||
175 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
176 | "CREATE TABLE IF NOT EXISTS state (\n" | ||
177 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
178 | " name TEXT NOT NULL,\n" | ||
179 | " value_current BYTEA,\n" | ||
180 | " value_signed BYTEA,\n" | ||
181 | " PRIMARY KEY (channel_id, name)\n" | ||
182 | ")" "WITH OIDS")) || | ||
183 | (GNUNET_OK != | ||
184 | GNUNET_POSTGRES_exec(plugin->dbh, | ||
185 | "CREATE TABLE IF NOT EXISTS state_sync (\n" | ||
186 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
187 | " name TEXT NOT NULL,\n" | ||
188 | " value BYTEA,\n" | ||
189 | " PRIMARY KEY (channel_id, name)\n" | ||
190 | ")" "WITH OIDS"))) | ||
191 | { | 171 | { |
192 | PQfinish (plugin->dbh); | 172 | PQfinish (plugin->dbh); |
193 | plugin->dbh = NULL; | 173 | plugin->dbh = NULL; |
194 | return GNUNET_SYSERR; | 174 | return GNUNET_SYSERR; |
195 | } | 175 | } |
196 | 176 | ||
197 | |||
198 | /* Prepare statements */ | 177 | /* Prepare statements */ |
199 | if ((GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, | 178 | if ((GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, |
200 | "transaction_begin", | 179 | "transaction_begin", |
@@ -842,7 +821,6 @@ fragment_row (struct Plugin *plugin, | |||
842 | void *purpose = NULL; | 821 | void *purpose = NULL; |
843 | size_t signature_size; | 822 | size_t signature_size; |
844 | size_t purpose_size; | 823 | size_t purpose_size; |
845 | |||
846 | uint64_t fragment_id; | 824 | uint64_t fragment_id; |
847 | uint64_t fragment_offset; | 825 | uint64_t fragment_offset; |
848 | uint64_t message_id; | 826 | uint64_t message_id; |
@@ -852,9 +830,7 @@ fragment_row (struct Plugin *plugin, | |||
852 | size_t buf_size; | 830 | size_t buf_size; |
853 | int ret = GNUNET_SYSERR; | 831 | int ret = GNUNET_SYSERR; |
854 | struct GNUNET_MULTICAST_MessageHeader *mp; | 832 | struct GNUNET_MULTICAST_MessageHeader *mp; |
855 | |||
856 | uint32_t msg_flags; | 833 | uint32_t msg_flags; |
857 | |||
858 | struct GNUNET_PQ_ResultSpec results[] = { | 834 | struct GNUNET_PQ_ResultSpec results[] = { |
859 | GNUNET_PQ_result_spec_uint32 ("hop_counter", &hop_counter), | 835 | GNUNET_PQ_result_spec_uint32 ("hop_counter", &hop_counter), |
860 | GNUNET_PQ_result_spec_variable_size ("signature", &signature, &signature_size), | 836 | GNUNET_PQ_result_spec_variable_size ("signature", &signature, &signature_size), |
@@ -964,8 +940,6 @@ fragment_get (void *cls, | |||
964 | void *cb_cls) | 940 | void *cb_cls) |
965 | { | 941 | { |
966 | struct Plugin *plugin = cls; | 942 | struct Plugin *plugin = cls; |
967 | *returned_fragments = 0; | ||
968 | |||
969 | struct GNUNET_PQ_QueryParam params_select[] = { | 943 | struct GNUNET_PQ_QueryParam params_select[] = { |
970 | GNUNET_PQ_query_param_auto_from_type (channel_key), | 944 | GNUNET_PQ_query_param_auto_from_type (channel_key), |
971 | GNUNET_PQ_query_param_uint64 (&first_fragment_id), | 945 | GNUNET_PQ_query_param_uint64 (&first_fragment_id), |
@@ -973,7 +947,12 @@ fragment_get (void *cls, | |||
973 | GNUNET_PQ_query_param_end | 947 | GNUNET_PQ_query_param_end |
974 | }; | 948 | }; |
975 | 949 | ||
976 | return fragment_select (plugin, "select_fragments", params_select, returned_fragments, cb, cb_cls); | 950 | *returned_fragments = 0; |
951 | return fragment_select (plugin, | ||
952 | "select_fragments", | ||
953 | params_select, | ||
954 | returned_fragments, | ||
955 | cb, cb_cls); | ||
977 | } | 956 | } |
978 | 957 | ||
979 | 958 | ||
@@ -1002,7 +981,11 @@ fragment_get_latest (void *cls, | |||
1002 | GNUNET_PQ_query_param_end | 981 | GNUNET_PQ_query_param_end |
1003 | }; | 982 | }; |
1004 | 983 | ||
1005 | return fragment_select (plugin, "select_latest_fragments", params_select, returned_fragments, cb, cb_cls); | 984 | return fragment_select (plugin, |
985 | "select_latest_fragments", | ||
986 | params_select, | ||
987 | returned_fragments, | ||
988 | cb, cb_cls); | ||
1006 | } | 989 | } |
1007 | 990 | ||
1008 | 991 | ||
@@ -1024,11 +1007,6 @@ message_get (void *cls, | |||
1024 | void *cb_cls) | 1007 | void *cb_cls) |
1025 | { | 1008 | { |
1026 | struct Plugin *plugin = cls; | 1009 | struct Plugin *plugin = cls; |
1027 | *returned_fragments = 0; | ||
1028 | |||
1029 | if (0 == fragment_limit) | ||
1030 | fragment_limit = INT64_MAX; | ||
1031 | |||
1032 | struct GNUNET_PQ_QueryParam params_select[] = { | 1010 | struct GNUNET_PQ_QueryParam params_select[] = { |
1033 | GNUNET_PQ_query_param_auto_from_type (channel_key), | 1011 | GNUNET_PQ_query_param_auto_from_type (channel_key), |
1034 | GNUNET_PQ_query_param_uint64 (&first_message_id), | 1012 | GNUNET_PQ_query_param_uint64 (&first_message_id), |
@@ -1037,7 +1015,14 @@ message_get (void *cls, | |||
1037 | GNUNET_PQ_query_param_end | 1015 | GNUNET_PQ_query_param_end |
1038 | }; | 1016 | }; |
1039 | 1017 | ||
1040 | return fragment_select (plugin, "select_messages", params_select, returned_fragments, cb, cb_cls); | 1018 | if (0 == fragment_limit) |
1019 | fragment_limit = INT64_MAX; | ||
1020 | *returned_fragments = 0; | ||
1021 | return fragment_select (plugin, | ||
1022 | "select_messages", | ||
1023 | params_select, | ||
1024 | returned_fragments, | ||
1025 | cb, cb_cls); | ||
1041 | } | 1026 | } |
1042 | 1027 | ||
1043 | 1028 | ||
@@ -1057,8 +1042,6 @@ message_get_latest (void *cls, | |||
1057 | void *cb_cls) | 1042 | void *cb_cls) |
1058 | { | 1043 | { |
1059 | struct Plugin *plugin = cls; | 1044 | struct Plugin *plugin = cls; |
1060 | *returned_fragments = 0; | ||
1061 | |||
1062 | struct GNUNET_PQ_QueryParam params_select[] = { | 1045 | struct GNUNET_PQ_QueryParam params_select[] = { |
1063 | GNUNET_PQ_query_param_auto_from_type (channel_key), | 1046 | GNUNET_PQ_query_param_auto_from_type (channel_key), |
1064 | GNUNET_PQ_query_param_auto_from_type (channel_key), | 1047 | GNUNET_PQ_query_param_auto_from_type (channel_key), |
@@ -1066,7 +1049,12 @@ message_get_latest (void *cls, | |||
1066 | GNUNET_PQ_query_param_end | 1049 | GNUNET_PQ_query_param_end |
1067 | }; | 1050 | }; |
1068 | 1051 | ||
1069 | return fragment_select (plugin, "select_latest_messages", params_select, returned_fragments, cb, cb_cls); | 1052 | *returned_fragments = 0; |
1053 | return fragment_select (plugin, | ||
1054 | "select_latest_messages", | ||
1055 | params_select, | ||
1056 | returned_fragments, | ||
1057 | cb, cb_cls); | ||
1070 | } | 1058 | } |
1071 | 1059 | ||
1072 | 1060 | ||
@@ -1255,7 +1243,8 @@ state_assign (struct Plugin *plugin, const char *stmt, | |||
1255 | 1243 | ||
1256 | 1244 | ||
1257 | static int | 1245 | static int |
1258 | update_message_id (struct Plugin *plugin, const char *stmt, | 1246 | update_message_id (struct Plugin *plugin, |
1247 | const char *stmt, | ||
1259 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | 1248 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, |
1260 | uint64_t message_id) | 1249 | uint64_t message_id) |
1261 | { | 1250 | { |