aboutsummaryrefslogtreecommitdiff
path: root/src/plugin/namestore/plugin_namestore_sqlite.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugin/namestore/plugin_namestore_sqlite.c')
-rw-r--r--src/plugin/namestore/plugin_namestore_sqlite.c196
1 files changed, 78 insertions, 118 deletions
diff --git a/src/plugin/namestore/plugin_namestore_sqlite.c b/src/plugin/namestore/plugin_namestore_sqlite.c
index ada9ca25b..c38e9e08f 100644
--- a/src/plugin/namestore/plugin_namestore_sqlite.c
+++ b/src/plugin/namestore/plugin_namestore_sqlite.c
@@ -26,7 +26,6 @@
26 26
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_namestore_plugin.h" 28#include "gnunet_namestore_plugin.h"
29#include "gnunet_namestore_service.h"
30#include "gnunet_gnsrecord_lib.h" 29#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_sq_lib.h" 30#include "gnunet_sq_lib.h"
32#include <sqlite3.h> 31#include <sqlite3.h>
@@ -50,13 +49,13 @@
50 * with the message given by strerror(errno). 49 * with the message given by strerror(errno).
51 */ 50 */
52#define LOG_SQLITE(db, level, cmd) do { \ 51#define LOG_SQLITE(db, level, cmd) do { \
53 GNUNET_log_from (level, \ 52 GNUNET_log_from (level, \
54 "namestore-sqlite", _ ( \ 53 "namestore-sqlite", _ ( \
55 "`%s' failed at %s:%d with error: %s\n"), \ 54 "`%s' failed at %s:%d with error: %s\n"), \
56 cmd, \ 55 cmd, \
57 __FILE__, __LINE__, \ 56 __FILE__, __LINE__, \
58 sqlite3_errmsg ( \ 57 sqlite3_errmsg ( \
59 db->dbh)); \ 58 db->dbh)); \
60} while (0) 59} while (0)
61 60
62#define LOG(kind, ...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__) 61#define LOG(kind, ...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__)
@@ -142,32 +141,35 @@ database_prepare (struct Plugin *plugin)
142 }; 141 };
143 struct GNUNET_SQ_PrepareStatement ps[] = { 142 struct GNUNET_SQ_PrepareStatement ps[] = {
144 GNUNET_SQ_make_prepare ("INSERT INTO ns098records " 143 GNUNET_SQ_make_prepare ("INSERT INTO ns098records "
145 "(zone_private_key,pkey,rvalue,record_count,record_data,label)" 144 "(zone_private_key,pkey,rvalue,record_count,record_data,"
146 " VALUES (?, ?, ?, ?, ?, ?)", 145 "label,editor_hint)"
146 " VALUES (?, ?, ?, ?, ?, ?, '')",
147 &plugin->store_records), 147 &plugin->store_records),
148 GNUNET_SQ_make_prepare ("DELETE FROM ns098records " 148 GNUNET_SQ_make_prepare ("DELETE FROM ns098records "
149 "WHERE zone_private_key=? AND label=?", 149 "WHERE zone_private_key=? AND label=?",
150 &plugin->delete_records), 150 &plugin->delete_records),
151 GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label" 151 GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label,editor_hint"
152 " FROM ns098records" 152 " FROM ns098records"
153 " WHERE zone_private_key=? AND pkey=?", 153 " WHERE zone_private_key=? AND pkey=?",
154 &plugin->zone_to_name), 154 &plugin->zone_to_name),
155 GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label" 155 GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label,editor_hint"
156 " FROM ns098records" 156 " FROM ns098records"
157 " WHERE zone_private_key=? AND uid > ?" 157 " WHERE zone_private_key=? AND uid > ?"
158 " ORDER BY uid ASC" 158 " ORDER BY uid ASC"
159 " LIMIT ?", 159 " LIMIT ?",
160 &plugin->iterate_zone), 160 &plugin->iterate_zone),
161 GNUNET_SQ_make_prepare ( 161 GNUNET_SQ_make_prepare (
162 "SELECT uid,record_count,record_data,label,zone_private_key" 162 "SELECT uid,record_count,record_data,label,editor_hint,zone_private_key"
163 " FROM ns098records" 163 " FROM ns098records"
164 " WHERE uid > ?" 164 " WHERE uid > ?"
165 " ORDER BY uid ASC" 165 " ORDER BY uid ASC"
166 " LIMIT ?", 166 " LIMIT ?",
167 &plugin->iterate_all_zones), 167 &plugin->iterate_all_zones),
168 GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label" 168 GNUNET_SQ_make_prepare ("UPDATE ns098records"
169 " FROM ns098records" 169 " SET editor_hint=?"
170 " WHERE zone_private_key=? AND label=?", 170 " FROM ns098records AS old_ns098records"
171 " WHERE ns098records.zone_private_key=? AND ns098records.label=?"
172 " RETURNING ns098records.uid,ns098records.record_count,ns098records.record_data,ns098records.label,editor_hint ",
171 &plugin->lookup_label), 173 &plugin->lookup_label),
172 GNUNET_SQ_PREPARE_END 174 GNUNET_SQ_PREPARE_END
173 }; 175 };
@@ -460,6 +462,7 @@ get_records_and_call_iterator (struct Plugin *plugin,
460 size_t data_size; 462 size_t data_size;
461 void *data; 463 void *data;
462 char *label; 464 char *label;
465 char *editor_hint;
463 struct GNUNET_CRYPTO_PrivateKey zk; 466 struct GNUNET_CRYPTO_PrivateKey zk;
464 struct GNUNET_SQ_ResultSpec rs[] = { 467 struct GNUNET_SQ_ResultSpec rs[] = {
465 GNUNET_SQ_result_spec_uint64 (&seq), 468 GNUNET_SQ_result_spec_uint64 (&seq),
@@ -467,6 +470,7 @@ get_records_and_call_iterator (struct Plugin *plugin,
467 GNUNET_SQ_result_spec_variable_size (&data, 470 GNUNET_SQ_result_spec_variable_size (&data,
468 &data_size), 471 &data_size),
469 GNUNET_SQ_result_spec_string (&label), 472 GNUNET_SQ_result_spec_string (&label),
473 GNUNET_SQ_result_spec_string (&editor_hint),
470 GNUNET_SQ_result_spec_end 474 GNUNET_SQ_result_spec_end
471 }; 475 };
472 struct GNUNET_SQ_ResultSpec rsx[] = { 476 struct GNUNET_SQ_ResultSpec rsx[] = {
@@ -475,6 +479,7 @@ get_records_and_call_iterator (struct Plugin *plugin,
475 GNUNET_SQ_result_spec_variable_size (&data, 479 GNUNET_SQ_result_spec_variable_size (&data,
476 &data_size), 480 &data_size),
477 GNUNET_SQ_result_spec_string (&label), 481 GNUNET_SQ_result_spec_string (&label),
482 GNUNET_SQ_result_spec_string (&editor_hint),
478 GNUNET_SQ_result_spec_auto_from_type (&zk), 483 GNUNET_SQ_result_spec_auto_from_type (&zk),
479 GNUNET_SQ_result_spec_end 484 GNUNET_SQ_result_spec_end
480 }; 485 };
@@ -514,6 +519,7 @@ get_records_and_call_iterator (struct Plugin *plugin,
514 if (NULL != iter) 519 if (NULL != iter)
515 iter (iter_cls, 520 iter (iter_cls,
516 seq, 521 seq,
522 editor_hint,
517 &zk, 523 &zk,
518 label, 524 label,
519 record_count, 525 record_count,
@@ -540,16 +546,18 @@ get_records_and_call_iterator (struct Plugin *plugin,
540 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR 546 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
541 */ 547 */
542static enum GNUNET_GenericReturnValue 548static enum GNUNET_GenericReturnValue
543namestore_sqlite_lookup_records (void *cls, 549lookup_records (void *cls,
544 const struct 550 const struct
545 GNUNET_CRYPTO_PrivateKey *zone, 551 GNUNET_CRYPTO_PrivateKey *zone,
546 const char *label, 552 const char *label,
547 GNUNET_NAMESTORE_RecordIterator iter, 553 GNUNET_NAMESTORE_RecordIterator iter,
548 void *iter_cls) 554 void *iter_cls,
555 const char *editor_hint)
549{ 556{
550 struct Plugin *plugin = cls; 557 struct Plugin *plugin = cls;
551 GNUNET_assert (GNUNET_OK == database_prepare (plugin)); 558 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
552 struct GNUNET_SQ_QueryParam params[] = { 559 struct GNUNET_SQ_QueryParam params[] = {
560 GNUNET_SQ_query_param_string (editor_hint),
553 GNUNET_SQ_query_param_auto_from_type (zone), 561 GNUNET_SQ_query_param_auto_from_type (zone),
554 GNUNET_SQ_query_param_string (label), 562 GNUNET_SQ_query_param_string (label),
555 GNUNET_SQ_query_param_end 563 GNUNET_SQ_query_param_end
@@ -580,6 +588,51 @@ namestore_sqlite_lookup_records (void *cls,
580 588
581 589
582/** 590/**
591 * Lookup records in the datastore for which we are the authority.
592 *
593 * @param cls closure (internal context for the plugin)
594 * @param zone private key of the zone
595 * @param label name of the record in the zone
596 * @param iter function to call with the result
597 * @param iter_cls closure for @a iter
598 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
599 */
600static enum GNUNET_GenericReturnValue
601namestore_sqlite_lookup_records (void *cls,
602 const struct
603 GNUNET_CRYPTO_PrivateKey *zone,
604 const char *label,
605 GNUNET_NAMESTORE_RecordIterator iter,
606 void *iter_cls)
607{
608 return lookup_records (cls, zone, label, iter, iter_cls, "");
609}
610
611
612/**
613 * Lookup records in the datastore for which we are the authority.
614 *
615 * @param cls closure (internal context for the plugin)
616 * @param zone private key of the zone
617 * @param label name of the record in the zone
618 * @param iter function to call with the result
619 * @param iter_cls closure for @a iter
620 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
621 */
622static enum GNUNET_GenericReturnValue
623namestore_sqlite_edit_records (void *cls,
624 const char *editor_hint,
625 const struct
626 GNUNET_CRYPTO_PrivateKey *zone,
627 const char *label,
628 GNUNET_NAMESTORE_RecordIterator iter,
629 void *iter_cls)
630{
631 return lookup_records (cls, zone, label, iter, iter_cls, editor_hint);
632}
633
634
635/**
583 * Iterate over the results for a particular key and zone in the 636 * Iterate over the results for a particular key and zone in the
584 * datastore. Will return at most one result to the iterator. 637 * datastore. Will return at most one result to the iterator.
585 * 638 *
@@ -698,92 +751,6 @@ namestore_sqlite_zone_to_name (void *cls,
698} 751}
699 752
700 753
701/**
702 * Begin a transaction for a client.
703 * This locks the database. SQLite is unable to discern between different
704 * rows with a specific zone key but the API looks like this anyway.
705 * https://www.sqlite.org/lang_transaction.html
706 *
707 * @param cls closure (internal context for the plugin)
708 * @param emsg error message set of return code is #GNUNET_SYSERR
709 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
710 */
711static enum GNUNET_GenericReturnValue
712namestore_sqlite_transaction_begin (void *cls,
713 char **emsg)
714{
715 struct Plugin *plugin = cls;
716 int rc;
717 char *sqlEmsg;
718
719 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
720 rc = sqlite3_exec (plugin->dbh, "BEGIN IMMEDIATE TRANSACTION;",
721 NULL, NULL, &sqlEmsg);
722 if (SQLITE_OK != rc)
723 {
724 *emsg = GNUNET_strdup (sqlEmsg);
725 sqlite3_free (sqlEmsg);
726 }
727 return (SQLITE_OK != rc) ? GNUNET_SYSERR : GNUNET_YES;
728}
729
730
731/**
732 * Commit a transaction for a client.
733 * This releases the lock on the database.
734 *
735 * @param cls closure (internal context for the plugin)
736 * @param emsg error message set of return code is #GNUNET_SYSERR
737 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
738 */
739static enum GNUNET_GenericReturnValue
740namestore_sqlite_transaction_rollback (void *cls,
741 char **emsg)
742{
743 struct Plugin *plugin = cls;
744 int rc;
745 char *sqlEmsg;
746
747 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
748 rc = sqlite3_exec (plugin->dbh, "ROLLBACK;",
749 NULL, NULL, &sqlEmsg);
750 if (SQLITE_OK != rc)
751 {
752 *emsg = GNUNET_strdup (sqlEmsg);
753 sqlite3_free (sqlEmsg);
754 }
755 return (SQLITE_OK != rc) ? GNUNET_SYSERR : GNUNET_YES;
756}
757
758
759/**
760 * Roll back a transaction for a client.
761 * This releases the lock on the database.
762 *
763 * @param cls closure (internal context for the plugin)
764 * @param emsg error message set of return code is #GNUNET_SYSERR
765 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
766 */
767static enum GNUNET_GenericReturnValue
768namestore_sqlite_transaction_commit (void *cls,
769 char **emsg)
770{
771 struct Plugin *plugin = cls;
772 int rc;
773 char *sqlEmsg;
774
775 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
776 rc = sqlite3_exec (plugin->dbh, "END TRANSACTION;",
777 NULL, NULL, &sqlEmsg);
778 if (SQLITE_OK != rc)
779 {
780 *emsg = GNUNET_strdup (sqlEmsg);
781 sqlite3_free (sqlEmsg);
782 }
783 return (SQLITE_OK != rc) ? GNUNET_SYSERR : GNUNET_YES;
784}
785
786
787static enum GNUNET_GenericReturnValue 754static enum GNUNET_GenericReturnValue
788namestore_sqlite_create_tables (void *cls) 755namestore_sqlite_create_tables (void *cls)
789{ 756{
@@ -804,7 +771,8 @@ namestore_sqlite_create_tables (void *cls)
804 " rvalue INT8 NOT NULL," 771 " rvalue INT8 NOT NULL,"
805 " record_count INT NOT NULL," 772 " record_count INT NOT NULL,"
806 " record_data BLOB NOT NULL," 773 " record_data BLOB NOT NULL,"
807 " label TEXT NOT NULL" 774 " label TEXT NOT NULL,"
775 " editor_hint TEXT NOT NULL"
808 ")"), 776 ")"),
809 GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_reverse " 777 GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_reverse "
810 "ON ns098records (zone_private_key,pkey)"), 778 "ON ns098records (zone_private_key,pkey)"),
@@ -940,17 +908,9 @@ libgnunet_plugin_namestore_sqlite_init (void *cls)
940 api->iterate_records = &namestore_sqlite_iterate_records; 908 api->iterate_records = &namestore_sqlite_iterate_records;
941 api->zone_to_name = &namestore_sqlite_zone_to_name; 909 api->zone_to_name = &namestore_sqlite_zone_to_name;
942 api->lookup_records = &namestore_sqlite_lookup_records; 910 api->lookup_records = &namestore_sqlite_lookup_records;
943 api->transaction_begin = &namestore_sqlite_transaction_begin;
944 api->transaction_commit = &namestore_sqlite_transaction_commit;
945 api->transaction_rollback = &namestore_sqlite_transaction_rollback;
946 api->create_tables = &namestore_sqlite_create_tables; 911 api->create_tables = &namestore_sqlite_create_tables;
947 api->drop_tables = &namestore_sqlite_drop_tables; 912 api->drop_tables = &namestore_sqlite_drop_tables;
948 /** 913 api->edit_records = &namestore_sqlite_edit_records;
949 * NOTE: Since SQlite does not support SELECT ... FOR UPDATE this is
950 * just an alias to lookup_records. The BEGIN IMMEDIATE mechanic currently
951 * implicitly ensures this API behaves as it should
952 */
953 api->edit_records = &namestore_sqlite_lookup_records;
954 LOG (GNUNET_ERROR_TYPE_DEBUG, 914 LOG (GNUNET_ERROR_TYPE_DEBUG,
955 _ ("SQlite database running\n")); 915 _ ("SQlite database running\n"));
956 return api; 916 return api;