aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <grothoff@gnunet.org>2022-07-24 11:32:21 +0200
committerChristian Grothoff <grothoff@gnunet.org>2022-07-24 11:32:21 +0200
commit233ec61118e6dad85c1eb9199f4e74daf65338f2 (patch)
tree69b57e71020f33eb63a726d0831597b5e7d00499 /src
parent6f88c10084ec4966410d555cdfc90eb8607031eb (diff)
downloadgnunet-233ec61118e6dad85c1eb9199f4e74daf65338f2.tar.gz
gnunet-233ec61118e6dad85c1eb9199f4e74daf65338f2.zip
enable non-numbered sql statement execution
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_configuration_lib.h9
-rw-r--r--src/include/gnunet_pq_lib.h17
-rw-r--r--src/pq/pq.h5
-rw-r--r--src/pq/pq_connect.c136
4 files changed, 97 insertions, 70 deletions
diff --git a/src/include/gnunet_configuration_lib.h b/src/include/gnunet_configuration_lib.h
index 570546b68..3384c6d45 100644
--- a/src/include/gnunet_configuration_lib.h
+++ b/src/include/gnunet_configuration_lib.h
@@ -317,11 +317,10 @@ GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
317 * @param iter_cls closure for @a iter 317 * @param iter_cls closure for @a iter
318 */ 318 */
319void 319void
320GNUNET_CONFIGURATION_iterate_sections (const struct 320GNUNET_CONFIGURATION_iterate_sections (
321 GNUNET_CONFIGURATION_Handle *cfg, 321 const struct GNUNET_CONFIGURATION_Handle *cfg,
322 GNUNET_CONFIGURATION_Section_Iterator 322 GNUNET_CONFIGURATION_Section_Iterator iter,
323 iter, 323 void *iter_cls);
324 void *iter_cls);
325 324
326 325
327/** 326/**
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h
index f7bf59212..2263704aa 100644
--- a/src/include/gnunet_pq_lib.h
+++ b/src/include/gnunet_pq_lib.h
@@ -920,6 +920,21 @@ GNUNET_PQ_connect (const char *config_str,
920 920
921 921
922/** 922/**
923 * Execute SQL statements from @a buf against @a db.
924 * The given filename infix in @a buf is prefixed with
925 * the "load_path" and ".sql" is appended to construct
926 * the full filename.
927 *
928 * @param db database context to use
929 * @param buf filename infix (!) with the SQL code to run
930 * @return #GNUNET_OK on success, #GNUNET_NO if patch @a buf does not exist, #GNUNET_SYSERR on error
931 */
932enum GNUNET_GenericReturnValue
933GNUNET_PQ_exec_sql (struct GNUNET_PQ_Context *db,
934 const char *buf);
935
936
937/**
923 * Create a connection to the Postgres database using @a config_str for the 938 * Create a connection to the Postgres database using @a config_str for the
924 * configuration. Initialize logging via GNUnet's log routines and disable 939 * configuration. Initialize logging via GNUnet's log routines and disable
925 * Postgres's logger. Also ensures that the statements in @a load_path and @a 940 * Postgres's logger. Also ensures that the statements in @a load_path and @a
@@ -936,6 +951,7 @@ GNUNET_PQ_connect (const char *config_str,
936 * 951 *
937 * @param config_str configuration to use 952 * @param config_str configuration to use
938 * @param load_path path to directory with SQL transactions to run, can be NULL 953 * @param load_path path to directory with SQL transactions to run, can be NULL
954 * @param auto_suffix infix of SQL series to run on every reconnect; runs multiple (!) files, of the form auto_suffix-XXXX where XXXX is from 0 to 9999 (consequtive).
939 * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated 955 * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated
940 * array of statements to execute upon EACH connection, can be NULL 956 * array of statements to execute upon EACH connection, can be NULL
941 * @param ps array of prepared statements to prepare, can be NULL 957 * @param ps array of prepared statements to prepare, can be NULL
@@ -945,6 +961,7 @@ GNUNET_PQ_connect (const char *config_str,
945struct GNUNET_PQ_Context * 961struct GNUNET_PQ_Context *
946GNUNET_PQ_connect2 (const char *config_str, 962GNUNET_PQ_connect2 (const char *config_str,
947 const char *load_path, 963 const char *load_path,
964 const char *auto_suffix,
948 const struct GNUNET_PQ_ExecuteStatement *es, 965 const struct GNUNET_PQ_ExecuteStatement *es,
949 const struct GNUNET_PQ_PreparedStatement *ps, 966 const struct GNUNET_PQ_PreparedStatement *ps,
950 enum GNUNET_PQ_Options flags); 967 enum GNUNET_PQ_Options flags);
diff --git a/src/pq/pq.h b/src/pq/pq.h
index 354d85a9f..9f7e45f62 100644
--- a/src/pq/pq.h
+++ b/src/pq/pq.h
@@ -60,6 +60,11 @@ struct GNUNET_PQ_Context
60 char *load_path; 60 char *load_path;
61 61
62 /** 62 /**
63 * Suffix to append to path to load on startup.
64 */
65 char *auto_suffix;
66
67 /**
63 * Map managing event subscriptions. 68 * Map managing event subscriptions.
64 */ 69 */
65 struct GNUNET_CONTAINER_MultiShortmap *channel_map; 70 struct GNUNET_CONTAINER_MultiShortmap *channel_map;
diff --git a/src/pq/pq_connect.c b/src/pq/pq_connect.c
index a8c552407..2e36f58f1 100644
--- a/src/pq/pq_connect.c
+++ b/src/pq/pq_connect.c
@@ -72,6 +72,9 @@ GNUNET_PQ_connect (const char *config_str,
72{ 72{
73 return GNUNET_PQ_connect2 (config_str, 73 return GNUNET_PQ_connect2 (config_str,
74 load_path, 74 load_path,
75 NULL == load_path
76 ? NULL
77 : "",
75 es, 78 es,
76 ps, 79 ps,
77 GNUNET_PQ_FLAG_NONE); 80 GNUNET_PQ_FLAG_NONE);
@@ -81,6 +84,7 @@ GNUNET_PQ_connect (const char *config_str,
81struct GNUNET_PQ_Context * 84struct GNUNET_PQ_Context *
82GNUNET_PQ_connect2 (const char *config_str, 85GNUNET_PQ_connect2 (const char *config_str,
83 const char *load_path, 86 const char *load_path,
87 const char *auto_suffix,
84 const struct GNUNET_PQ_ExecuteStatement *es, 88 const struct GNUNET_PQ_ExecuteStatement *es,
85 const struct GNUNET_PQ_PreparedStatement *ps, 89 const struct GNUNET_PQ_PreparedStatement *ps,
86 enum GNUNET_PQ_Options flags) 90 enum GNUNET_PQ_Options flags)
@@ -101,6 +105,8 @@ GNUNET_PQ_connect2 (const char *config_str,
101 db->config_str = GNUNET_strdup (config_str); 105 db->config_str = GNUNET_strdup (config_str);
102 if (NULL != load_path) 106 if (NULL != load_path)
103 db->load_path = GNUNET_strdup (load_path); 107 db->load_path = GNUNET_strdup (load_path);
108 if (NULL != auto_suffix)
109 db->auto_suffix = GNUNET_strdup (auto_suffix);
104 if (0 != elen) 110 if (0 != elen)
105 { 111 {
106 db->es = GNUNET_new_array (elen + 1, 112 db->es = GNUNET_new_array (elen + 1,
@@ -124,6 +130,7 @@ GNUNET_PQ_connect2 (const char *config_str,
124 { 130 {
125 GNUNET_CONTAINER_multishortmap_destroy (db->channel_map); 131 GNUNET_CONTAINER_multishortmap_destroy (db->channel_map);
126 GNUNET_free (db->load_path); 132 GNUNET_free (db->load_path);
133 GNUNET_free (db->auto_suffix);
127 GNUNET_free (db->config_str); 134 GNUNET_free (db->config_str);
128 GNUNET_free (db); 135 GNUNET_free (db);
129 return NULL; 136 return NULL;
@@ -132,34 +139,32 @@ GNUNET_PQ_connect2 (const char *config_str,
132} 139}
133 140
134 141
135/** 142enum GNUNET_GenericReturnValue
136 * Apply patch number @a from path @a load_path. 143GNUNET_PQ_exec_sql (struct GNUNET_PQ_Context *db,
137 * 144 const char *buf)
138 * @param db database context to use
139 * @param load_path where to find the SQL code to run
140 * @param i patch number to append to the @a load_path
141 * @return #GNUNET_OK on success, #GNUNET_NO if patch @a i does not exist, #GNUNET_SYSERR on error
142 */
143static enum GNUNET_GenericReturnValue
144apply_patch (struct GNUNET_PQ_Context *db,
145 const char *load_path,
146 unsigned int i)
147{ 145{
148 struct GNUNET_OS_Process *psql; 146 struct GNUNET_OS_Process *psql;
149 enum GNUNET_OS_ProcessStatusType type; 147 enum GNUNET_OS_ProcessStatusType type;
150 unsigned long code; 148 unsigned long code;
151 size_t slen = strlen (load_path) + 10;
152 char buf[slen];
153 enum GNUNET_GenericReturnValue ret; 149 enum GNUNET_GenericReturnValue ret;
154 150 char *fn;
155 GNUNET_snprintf (buf, 151
156 sizeof (buf), 152 GNUNET_asprintf (&fn,
157 "%s%04u.sql", 153 "%s%s.sql",
158 load_path, 154 db->load_path,
159 i); 155 buf);
156 if (GNUNET_YES !=
157 GNUNET_DISK_file_test (fn))
158 {
159 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
160 "SQL resource `%s' does not exist\n",
161 fn);
162 GNUNET_free (fn);
163 return GNUNET_NO;
164 }
160 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 165 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
161 "Applying SQL file `%s' on database %s\n", 166 "Applying SQL file `%s' on database %s\n",
162 buf, 167 fn,
163 db->config_str); 168 db->config_str);
164 psql = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR, 169 psql = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR,
165 NULL, 170 NULL,
@@ -169,7 +174,7 @@ apply_patch (struct GNUNET_PQ_Context *db,
169 "psql", 174 "psql",
170 db->config_str, 175 db->config_str,
171 "-f", 176 "-f",
172 buf, 177 fn,
173 "-q", 178 "-q",
174 "--set", 179 "--set",
175 "ON_ERROR_STOP=1", 180 "ON_ERROR_STOP=1",
@@ -179,6 +184,7 @@ apply_patch (struct GNUNET_PQ_Context *db,
179 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 184 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
180 "exec", 185 "exec",
181 "psql"); 186 "psql");
187 GNUNET_free (fn);
182 return GNUNET_SYSERR; 188 return GNUNET_SYSERR;
183 } 189 }
184 ret = GNUNET_OS_process_wait_status (psql, 190 ret = GNUNET_OS_process_wait_status (psql,
@@ -188,12 +194,13 @@ apply_patch (struct GNUNET_PQ_Context *db,
188 { 194 {
189 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 195 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
190 "psql on file %s did not finish, killed it!\n", 196 "psql on file %s did not finish, killed it!\n",
191 buf); 197 fn);
192 /* can happen if we got a signal, like CTRL-C, before 198 /* can happen if we got a signal, like CTRL-C, before
193 psql was complete */ 199 psql was complete */
194 (void) GNUNET_OS_process_kill (psql, 200 (void) GNUNET_OS_process_kill (psql,
195 SIGKILL); 201 SIGKILL);
196 GNUNET_OS_process_destroy (psql); 202 GNUNET_OS_process_destroy (psql);
203 GNUNET_free (fn);
197 return GNUNET_SYSERR; 204 return GNUNET_SYSERR;
198 } 205 }
199 GNUNET_OS_process_destroy (psql); 206 GNUNET_OS_process_destroy (psql);
@@ -202,10 +209,12 @@ apply_patch (struct GNUNET_PQ_Context *db,
202 { 209 {
203 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 210 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
204 "Could not run PSQL on file %s: psql exit code was %d\n", 211 "Could not run PSQL on file %s: psql exit code was %d\n",
205 buf, 212 fn,
206 (int) code); 213 (int) code);
214 GNUNET_free (fn);
207 return GNUNET_SYSERR; 215 return GNUNET_SYSERR;
208 } 216 }
217 GNUNET_free (fn);
209 return GNUNET_OK; 218 return GNUNET_OK;
210} 219}
211 220
@@ -219,31 +228,18 @@ GNUNET_PQ_run_sql (struct GNUNET_PQ_Context *db,
219 228
220 load_path_suffix = strrchr (load_path, '/'); 229 load_path_suffix = strrchr (load_path, '/');
221 if (NULL == load_path_suffix) 230 if (NULL == load_path_suffix)
222 { 231 load_path_suffix = load_path;
223 GNUNET_break (0); 232 else
224 return GNUNET_SYSERR; 233 load_path_suffix++; /* skip '/' */
225 }
226 load_path_suffix++; /* skip '/' */
227 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 234 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
228 "Loading SQL resources from `%s'\n", 235 "Loading SQL resources from `%s'\n",
229 load_path); 236 load_path);
230 for (unsigned int i = 1; i<10000; i++) 237 for (unsigned int i = 1; i<10000; i++)
231 { 238 {
232 char patch_name[slen]; 239 char patch_name[slen];
233 char buf[slen];
234 enum GNUNET_DB_QueryStatus qs; 240 enum GNUNET_DB_QueryStatus qs;
235 241
236 /* First, check patch actually exists */ 242 /* Check with DB versioning schema if this patch was already applied,
237 GNUNET_snprintf (buf,
238 sizeof (buf),
239 "%s%04u.sql",
240 load_path,
241 i);
242 if (GNUNET_YES !=
243 GNUNET_DISK_file_test (buf))
244 return GNUNET_OK; /* We are done */
245
246 /* Second, check with DB versioning schema if this patch was already applied,
247 if so, skip it. */ 243 if so, skip it. */
248 GNUNET_snprintf (patch_name, 244 GNUNET_snprintf (patch_name,
249 sizeof (patch_name), 245 sizeof (patch_name),
@@ -296,9 +292,13 @@ GNUNET_PQ_run_sql (struct GNUNET_PQ_Context *db,
296 /* patch not yet applied, run it! */ 292 /* patch not yet applied, run it! */
297 enum GNUNET_GenericReturnValue ret; 293 enum GNUNET_GenericReturnValue ret;
298 294
299 ret = apply_patch (db, 295 GNUNET_snprintf (patch_name,
300 load_path, 296 sizeof (patch_name),
301 i); 297 "%s%04u",
298 load_path,
299 i);
300 ret = GNUNET_PQ_exec_sql (db,
301 patch_name);
302 if (GNUNET_NO == ret) 302 if (GNUNET_NO == ret)
303 break; 303 break;
304 if (GNUNET_SYSERR == ret) 304 if (GNUNET_SYSERR == ret)
@@ -336,8 +336,8 @@ GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db)
336 "pq", 336 "pq",
337 "Database connection to '%s' failed: %s\n", 337 "Database connection to '%s' failed: %s\n",
338 db->config_str, 338 db->config_str,
339 (NULL != db->conn) ? 339 (NULL != db->conn)
340 PQerrorMessage (db->conn) 340 ? PQerrorMessage (db->conn)
341 : "PQconnectdb returned NULL"); 341 : "PQconnectdb returned NULL");
342 if (NULL != db->conn) 342 if (NULL != db->conn)
343 { 343 {
@@ -352,7 +352,7 @@ GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db)
352 PQsetNoticeProcessor (db->conn, 352 PQsetNoticeProcessor (db->conn,
353 &pq_notice_processor_cb, 353 &pq_notice_processor_cb,
354 db); 354 db);
355 if (NULL != db->load_path) 355 if (NULL != db->auto_suffix)
356 { 356 {
357 PGresult *res; 357 PGresult *res;
358 358
@@ -379,10 +379,9 @@ GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db)
379 return; 379 return;
380 } 380 }
381 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 381 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
382 "Failed to prepare statement to check patch level. Likely versioning schema does not exist yet, loading patch level 0000!\n"); 382 "Failed to prepare statement to check patch level. Likely versioning schema does not exist yet, loading versioning!\n");
383 ret = apply_patch (db, 383 ret = GNUNET_PQ_exec_sql (db,
384 db->load_path, 384 "versioning");
385 0);
386 if (GNUNET_NO == ret) 385 if (GNUNET_NO == ret)
387 { 386 {
388 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 387 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
@@ -425,11 +424,11 @@ GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db)
425 424
426 if (GNUNET_SYSERR == 425 if (GNUNET_SYSERR ==
427 GNUNET_PQ_run_sql (db, 426 GNUNET_PQ_run_sql (db,
428 db->load_path)) 427 db->auto_suffix))
429 { 428 {
430 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 429 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
431 "Failed to load SQL statements from `%s*'\n", 430 "Failed to load SQL statements from `%s*'\n",
432 db->load_path); 431 db->auto_suffix);
433 PQfinish (db->conn); 432 PQfinish (db->conn);
434 db->conn = NULL; 433 db->conn = NULL;
435 return; 434 return;
@@ -485,7 +484,6 @@ GNUNET_PQ_connect_with_cfg2 (const struct GNUNET_CONFIGURATION_Handle *cfg,
485 struct GNUNET_PQ_Context *db; 484 struct GNUNET_PQ_Context *db;
486 char *conninfo; 485 char *conninfo;
487 char *load_path; 486 char *load_path;
488 char *sp;
489 487
490 if (GNUNET_OK != 488 if (GNUNET_OK !=
491 GNUNET_CONFIGURATION_get_value_string (cfg, 489 GNUNET_CONFIGURATION_get_value_string (cfg,
@@ -494,24 +492,31 @@ GNUNET_PQ_connect_with_cfg2 (const struct GNUNET_CONFIGURATION_Handle *cfg,
494 &conninfo)) 492 &conninfo))
495 conninfo = NULL; 493 conninfo = NULL;
496 load_path = NULL; 494 load_path = NULL;
497 sp = NULL; 495 if (GNUNET_OK !=
496 GNUNET_CONFIGURATION_get_value_filename (cfg,
497 section,
498 "SQL_DIR",
499 &load_path))
500 {
501 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO,
502 section,
503 "SQL_DIR");
504 }
498 if ( (NULL != load_path_suffix) && 505 if ( (NULL != load_path_suffix) &&
499 (GNUNET_OK == 506 (NULL == load_path) )
500 GNUNET_CONFIGURATION_get_value_filename (cfg, 507 {
501 section, 508 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
502 "SQL_DIR", 509 section,
503 &sp)) ) 510 "SQL_DIR");
504 GNUNET_asprintf (&load_path, 511 return NULL;
505 "%s%s", 512 }
506 sp,
507 load_path_suffix);
508 db = GNUNET_PQ_connect2 (conninfo == NULL ? "" : conninfo, 513 db = GNUNET_PQ_connect2 (conninfo == NULL ? "" : conninfo,
509 load_path, 514 load_path,
515 load_path_suffix,
510 es, 516 es,
511 ps, 517 ps,
512 flags); 518 flags);
513 GNUNET_free (load_path); 519 GNUNET_free (load_path);
514 GNUNET_free (sp);
515 GNUNET_free (conninfo); 520 GNUNET_free (conninfo);
516 return db; 521 return db;
517} 522}
@@ -528,6 +533,7 @@ GNUNET_PQ_disconnect (struct GNUNET_PQ_Context *db)
528 GNUNET_free (db->es); 533 GNUNET_free (db->es);
529 GNUNET_free (db->ps); 534 GNUNET_free (db->ps);
530 GNUNET_free (db->load_path); 535 GNUNET_free (db->load_path);
536 GNUNET_free (db->auto_suffix);
531 GNUNET_free (db->config_str); 537 GNUNET_free (db->config_str);
532 PQfinish (db->conn); 538 PQfinish (db->conn);
533 GNUNET_free (db); 539 GNUNET_free (db);