murphy-db: mql transaction support
authorJanos Kovacs <jankovac503@gmail.com>
Sun, 15 Apr 2012 20:45:26 +0000 (23:45 +0300)
committerKrisztian Litkey <krisztian.litkey@intel.com>
Wed, 18 Apr 2012 13:33:33 +0000 (16:33 +0300)
Use of transaction names (eg. BEGIN foo; COMMIT foo; etc)
precompiled transaction statements (begin, commit and rollback).

configure.ac
src/murphy-db/include/murphy-db/mqi.h
src/murphy-db/mql/Makefile.am
src/murphy-db/mql/mql-parser.y
src/murphy-db/mql/statement.c
src/murphy-db/mql/transaction.c [new file with mode: 0644]
src/murphy-db/tests/check-libmql.c

index f9e6da6..924694a 100644 (file)
@@ -1,3 +1,4 @@
+
 #                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
 
index 71cd306..5ed4386 100644 (file)
@@ -91,7 +91,7 @@
     }
 
 #define MQI_BEGIN                                               \
-    mqi_begin_transaction();
+    mqi_begin_transaction()
 
 #define MQI_COMMIT(id)                                          \
     mqi_commit_transaction(id)
index a88f507..c5f6910 100644 (file)
@@ -4,6 +4,7 @@ PARSER_PREFIX   = yy_mql_
 AM_YFLAGS       = -p $(PARSER_PREFIX)
 LEX_OUTPUT_ROOT = ./lex.$(PARSER_PREFIX)
 
+
 libmql_la_CFLAGS = -I../include
 
 libmql_la_SOURCES = ../include/murphy-db/mql.h \
@@ -11,7 +12,7 @@ libmql_la_SOURCES = ../include/murphy-db/mql.h \
                     ../include/murphy-db/mql-result.h \
                     ../include/murphy-db/mql-trigger.h \
                     mql-scanner.l mql-parser.y \
-                    statement.c result.c trigger.c
+                    statement.c result.c trigger.c transaction.c
 
 mql-parser.h mql-parser.c: mql-parser.y
        $(YACCCOMPILE) $<
index a65a7d4..0a64fc7 100644 (file)
@@ -226,6 +226,8 @@ static FILE        *mqlout;
 
     mql_statement_t *mql_make_show_tables_statement(uint32_t);
     mql_statement_t *mql_make_describe_statement(mqi_handle_t);
+    mql_statement_t *mql_make_transaction_statement(mql_statement_type_t,
+                                                    char *);
     mql_statement_t *mql_make_insert_statement(mqi_handle_t, int, int,
                                                mqi_data_type_t*,
                                                mqi_column_desc_t*, void*);
@@ -283,6 +285,10 @@ static FILE        *mqlout;
                                mqi_data_type_t *, int *, int);
     int mql_create_table_trigger(char *, mql_callback_t *);
     int mql_create_transaction_trigger(char *, mql_callback_t *);
+
+    int mql_begin_transaction(char *);
+    int mql_rollback_transaction(char *);
+    int mql_commit_transaction(char *);
 }
 
 
@@ -593,29 +599,37 @@ drop_index: TKN_INDEX {
  * Begin/Commit/Rollback statement
  *
  */
-begin_statement: TKN_BEGIN transaction {
-    if (mqi_begin_transaction() == MQI_HANDLE_INVALID)
-        MQL_ERROR(errno, "Can't start transaction: %s", strerror(errno));
-    else
-        MQL_SUCCESS;
+begin_statement: TKN_BEGIN transaction TKN_IDENTIFIER {
+    if (mode == mql_mode_precompile)
+        statement = mql_make_transaction_statement(mql_statement_begin, $3);
+    else {
+        if (mql_begin_transaction($3) < 0)
+            MQL_ERROR(errno, "can't start transaction: %s", strerror(errno));
+        else
+            MQL_SUCCESS;
+    }
 };
 
-commit_statement: TKN_COMMIT transaction {
-    mqi_handle_t txh = mqi_get_transaction_handle();
-
-    if (txh == MQI_HANDLE_INVALID || mqi_commit_transaction(txh) < 0)
-        MQL_ERROR(errno, "failed to commit transaction: %s", strerror(errno));
-    else
-        MQL_SUCCESS;
+commit_statement: TKN_COMMIT transaction TKN_IDENTIFIER {
+    if (mode == mql_mode_precompile)
+        statement = mql_make_transaction_statement(mql_statement_commit, $3);
+    else {
+        if (mql_commit_transaction($3) < 0)
+            MQL_ERROR(errno, "can't commit transaction: %s", strerror(errno));
+        else
+            MQL_SUCCESS;
+    }
 };
 
-rollback_statement: TKN_ROLLBACK transaction {
-    mqi_handle_t txh = mqi_get_transaction_handle();
-
-    if (txh == MQI_HANDLE_INVALID || mqi_rollback_transaction(txh) < 0)
-        MQL_ERROR(errno, "can't rollback transaction: %s", strerror(errno));
-    else
-        MQL_SUCCESS;
+rollback_statement: TKN_ROLLBACK transaction TKN_IDENTIFIER {
+    if (mode == mql_mode_precompile)
+        statement = mql_make_transaction_statement(mql_statement_rollback, $3);
+    else {
+        if (mql_rollback_transaction($3) < 0)
+            MQL_ERROR(errno, "can't rollback transaction: %s",strerror(errno));
+        else
+            MQL_SUCCESS;
+    }
 };
 
 
index e32cdd4..961cde2 100644 (file)
@@ -32,6 +32,11 @@ typedef struct {
 
 typedef struct {
     mql_statement_type_t type;
+    char                 trnam[0];
+} transact_statement_t;
+
+typedef struct {
+    mql_statement_type_t type;
     mqi_handle_t         table;
     int                  ignore;
     int                  ncolumn;
@@ -72,6 +77,8 @@ typedef struct {
     value_t              values[0];
 } select_statement_t;
 
+
+
 static void count_condition_values(int, mqi_cond_entry_t *, int*, int*, int*);
 static void count_column_values(mqi_column_desc_t *, mqi_data_type_t*, void*,
                                 int *, int *, int *);
@@ -83,6 +90,9 @@ static void copy_conditions_and_values(int,mqi_cond_entry_t*,mqi_cond_entry_t*,
 
 static mql_result_t *exec_show_tables(mql_result_type_t, shtable_statement_t*);
 static mql_result_t *exec_describe(mql_result_type_t, describe_statement_t *);
+static mql_result_t *exec_begin(transact_statement_t *);
+static mql_result_t *exec_commit(transact_statement_t *);
+static mql_result_t *exec_rollback(transact_statement_t *);
 static mql_result_t *exec_insert(insert_statement_t *);
 static mql_result_t *exec_update(update_statement_t *);
 static mql_result_t *exec_delete(delete_statement_t *);
@@ -125,6 +135,27 @@ mql_statement_t *mql_make_describe_statement(mqi_handle_t table)
     return (mql_statement_t *)dis;
 }
 
+mql_statement_t *mql_make_transaction_statement(mql_statement_type_t  type,
+                                                char                 *trnam)
+{
+    transact_statement_t *tra;
+
+    MDB_CHECKARG((type == mql_statement_begin  ||
+                  type == mql_statement_commit ||
+                  type == mql_statement_rollback)
+                 && trnam && trnam[0], NULL);
+
+    if (!(tra = calloc(1, sizeof(transact_statement_t) + strlen(trnam) + 1))) {
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    tra->type = type;
+    strcpy(tra->trnam, trnam);
+
+    return (mql_statement_t *)tra;
+}
+
 
 mql_statement_t *mql_make_insert_statement(mqi_handle_t       table,
                                            int                ignore,
@@ -461,6 +492,18 @@ mql_result_t *mql_exec_statement(mql_result_type_t type, mql_statement_t *s)
         result = exec_describe(type, (describe_statement_t *)s);
         break;
 
+    case mql_statement_begin:
+        result = exec_begin((transact_statement_t *)s);
+        break;
+
+    case mql_statement_commit:
+        result = exec_commit((transact_statement_t *)s);
+        break;
+
+    case mql_statement_rollback:
+        result = exec_rollback((transact_statement_t *)s);
+        break;
+
     case mql_statement_insert:
         result = exec_insert((insert_statement_t *)s);
         break;
@@ -747,6 +790,51 @@ static mql_result_t *exec_describe(mql_result_type_t type,
     return rslt;
 }
 
+static mql_result_t *exec_begin(transact_statement_t *b)
+{
+    mql_result_t *rslt;
+
+    if (mql_begin_transaction(b->trnam) == 0)
+        rslt = mql_result_success_create();
+    else {
+        rslt = mql_result_error_create(errno, "begin failed: %s",
+                                       strerror(errno));
+    }
+
+    return rslt;
+}
+
+
+static mql_result_t *exec_commit(transact_statement_t *c)
+{
+    mql_result_t *rslt;
+
+    if (mql_commit_transaction(c->trnam) == 0)
+        rslt = mql_result_success_create();
+    else {
+        rslt = mql_result_error_create(errno, "commit failed: %s",
+                                       strerror(errno));
+    }
+
+    return rslt;
+}
+
+
+static mql_result_t *exec_rollback(transact_statement_t *r)
+{
+    mql_result_t *rslt;
+
+    if (mql_rollback_transaction(r->trnam) == 0)
+        rslt = mql_result_success_create();
+    else {
+        rslt = mql_result_error_create(errno, "rollback failed: %s",
+                                       strerror(errno));
+    }
+
+    return rslt;
+}
+
+
 static mql_result_t *exec_insert(insert_statement_t *i)
 {
     mql_result_t *rslt;
diff --git a/src/murphy-db/mql/transaction.c b/src/murphy-db/mql/transaction.c
new file mode 100644 (file)
index 0000000..d7bed56
--- /dev/null
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <alloca.h>
+#include <errno.h>
+
+#include <murphy-db/assert.h>
+#include <murphy-db/mqi.h>
+#include <murphy-db/hash.h>
+#include "mql-parser.h"
+
+/* Note: HANDLE_TO_PTR(MQI_HANDLE_INVALID) == NULL */
+#define HANDLE_TO_PTR(h)   (((void *)1) + (h))
+#define PTR_TO_HANDLE(p)   (mqi_handle_t)((p) - ((void *)1))
+
+static mdb_hash_t *transact_handles;
+
+static int init(void);
+static int add_handle(char *, mqi_handle_t);
+static mqi_handle_t delete_handle(char *);
+
+
+int mql_begin_transaction(char *name)
+{
+    mqi_handle_t h;
+
+    MDB_CHECKARG(name, -1);
+
+    if ((h = mqi_begin_transaction()) == MQI_HANDLE_INVALID)
+        return -1;
+
+    if (add_handle(name, h) < 0) {
+        mqi_rollback_transaction(h);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int mql_rollback_transaction(char *name)
+{
+    mqi_handle_t h;
+
+    MDB_CHECKARG(name, -1);
+
+    if ((h = delete_handle(name)) == MQI_HANDLE_INVALID)
+        return -1;
+
+    if (mqi_rollback_transaction(h) < 0)
+        return -1;
+
+    return 0;
+}
+
+int mql_commit_transaction(char *name)
+{
+    mqi_handle_t h;
+
+    MDB_CHECKARG(name, -1);
+
+    if ((h = delete_handle(name)) == MQI_HANDLE_INVALID)
+        return -1;
+
+    if (mqi_commit_transaction(h) < 0)
+        return -1;
+
+    return 0;
+}
+
+
+static int init(void)
+{
+    static bool done = false;
+
+    int sts = 0;
+
+    if (!done) {
+        if (!(transact_handles = MDB_HASH_TABLE_CREATE(string, 16)))
+            sts = -1;
+
+        done = true;
+    }
+     
+    return sts;
+}
+
+static int add_handle(char *name, mqi_handle_t handle)
+{
+    if (init() < 0)
+        return -1;
+
+    if (mdb_hash_add(transact_handles, 0,name, HANDLE_TO_PTR(handle)) < 0)
+        return -1;
+
+    return 0;
+}
+
+static mqi_handle_t delete_handle(char *name)
+{
+    void *ptr;
+
+    if (init() < 0)
+        return MQI_HANDLE_INVALID;
+
+    if (!(ptr = mdb_hash_delete(transact_handles, 0,name)))
+        return MQI_HANDLE_INVALID;
+
+    return PTR_TO_HANDLE(ptr);
+}
+
+
+
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
index 1478954..03ea1f9 100644 (file)
@@ -53,6 +53,9 @@ static int persons_nrow = MQI_DIMENSION(persons_rows);
 
 static int verbose;
 static struct {
+    mql_statement_t *begin;
+    mql_statement_t *commit;
+    mql_statement_t *rollback;
     mql_statement_t *filtered_select;
     mql_statement_t *full_select;
     mql_statement_t *update;
@@ -249,6 +252,42 @@ START_TEST(make_persons)
 }
 END_TEST
 
+START_TEST(precompile_transaction_statements)
+{
+#define TRID "transaction_1"
+
+    static char *string[] = {
+        "BEGIN "    TRID,
+        "COMMIT "   TRID,
+        "ROLLBACK " TRID
+    };
+
+    static mql_statement_t **stmnt[] = {
+        &persons.begin,
+        &persons.commit,
+        &persons.rollback
+    };
+
+    static int done;
+    
+    int i;
+
+    if (!done) {
+        fail_unless(MQI_DIMENSION(string) == MQI_DIMENSION(stmnt),
+                    "internal error: dimension mismatch in %s()", __FILE__);
+
+        for (i = 0;  i < MQI_DIMENSION(string);  i++) {
+            if (!(*(stmnt[i]) = mql_precompile(string[i]))) {
+                fail("precompilation error of '%s' (%s)",
+                     string[i], strerror(errno));
+            }
+        }
+    }
+
+#undef TRID
+}
+END_TEST
+
 
 START_TEST(precompile_filtered_person_select)
 {
@@ -725,16 +764,15 @@ START_TEST(row_trigger)
                           " SELECT id, first_name, family_name";
 
 
-    mqi_handle_t  t;
     mql_result_t *r;
-    int sts;
 
     PREREQUISITE(register_row_event_cb);
+    PREREQUISITE(precompile_transaction_statements);
 
-    t = mqi_begin_transaction();
+    r = mql_exec_statement(mql_result_string, persons.begin);
 
-    fail_if(t == MQI_HANDLE_INVALID, "failed to start transaction: %s",
-            strerror(errno));
+    fail_unless(mql_result_is_success(r), "failed to begin transaction: %s",
+                strerror(errno));
     
     r = mql_exec_string(mql_result_dontcare, mqlstr);
     
@@ -744,9 +782,10 @@ START_TEST(row_trigger)
     PREREQUISITE(exec_precompiled_insert_into_persons);
     PREREQUISITE(exec_precompiled_delete_from_persons);
 
-    sts = mqi_commit_transaction(t);
+    r = mql_exec_statement(mql_result_string, persons.commit);
 
-    fail_if(sts < 0, "commit failed: %s", strerror(errno));
+    fail_unless(mql_result_is_success(r), "failed to commit transaction: %s",
+                strerror(errno));
 }
 END_TEST
 
@@ -757,17 +796,15 @@ START_TEST(column_trigger)
                           " CALLBACK column_event_cb"
                           " SELECT id, first_name, family_name";
 
-
-    mqi_handle_t  t;
     mql_result_t *r;
-    int sts;
 
     PREREQUISITE(register_column_event_cb);
+    PREREQUISITE(precompile_transaction_statements);
 
-    t = mqi_begin_transaction();
+    r = mql_exec_statement(mql_result_string, persons.begin);
 
-    fail_if(t == MQI_HANDLE_INVALID, "failed to start transaction: %s",
-            strerror(errno));
+    fail_unless(mql_result_is_success(r), "failed to begin transaction: %s",
+                strerror(errno));
     
     r = mql_exec_string(mql_result_dontcare, mqlstr);
     
@@ -776,9 +813,10 @@ START_TEST(column_trigger)
 
     PREREQUISITE(exec_precompiled_update_persons);
 
-    sts = mqi_commit_transaction(t);
+    r = mql_exec_statement(mql_result_string, persons.commit);
 
-    fail_if(sts < 0, "commit failed: %s", strerror(errno));
+    fail_unless(mql_result_is_success(r), "failed to commit transaction: %s",
+                strerror(errno));
 }
 END_TEST
 
@@ -816,12 +854,12 @@ static TCase *basic_tests(void)
 {
     TCase *tc = tcase_create("basic tests");
 
-#if 0
     tcase_add_test(tc, open_db);
     tcase_add_test(tc, create_table_persons);
     tcase_add_test(tc, describe_persons);
     tcase_add_test(tc, create_index_on_persons);
     tcase_add_test(tc, insert_into_persons);
+    tcase_add_test(tc, precompile_transaction_statements);
     tcase_add_test(tc, precompile_filtered_person_select);
     tcase_add_test(tc, precompile_full_person_select);
     tcase_add_test(tc, precompile_update_persons);
@@ -839,7 +877,6 @@ static TCase *basic_tests(void)
     tcase_add_test(tc, table_trigger);
     tcase_add_test(tc, row_trigger);
     tcase_add_test(tc, column_trigger);
-#endif
     tcase_add_test(tc, transaction_trigger);
 
     return tc;