changeset 424:b10132434adc

Transactions seem to be working
author Adam Chlipala <adamc@hcoop.net>
date Fri, 24 Oct 2008 16:47:18 -0400
parents 82067ea6e723
children 7009b0ac1501
files .hgignore src/c/driver.c src/cjr_print.sml tests/aborter.sql tests/aborter.ur tests/aborter.urp
diffstat 6 files changed, 144 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Oct 24 16:13:53 2008 -0400
+++ b/.hgignore	Fri Oct 24 16:47:18 2008 -0400
@@ -24,3 +24,5 @@
 
 demo/out/*.html
 demo/demo.*
+
+*.sql
--- a/src/c/driver.c	Fri Oct 24 16:13:53 2008 -0400
+++ b/src/c/driver.c	Fri Oct 24 16:47:18 2008 -0400
@@ -51,6 +51,24 @@
 
 #define MAX_RETRIES 5
 
+int uw_db_begin(uw_context);
+int uw_db_commit(uw_context);
+int uw_db_rollback(uw_context);
+
+static int try_rollback(uw_context ctx) {
+  int r = uw_db_rollback(ctx);
+
+  if (r) {
+    printf("Error running SQL ROLLBACK\n");
+    uw_reset(ctx);
+    uw_write(ctx, "HTTP/1.1 500 Internal Server Error\n\r");
+    uw_write(ctx, "Content-type: text/plain\r\n\r\n");
+    uw_write(ctx, "Error running SQL ROLLBACK\n");
+  }
+
+  return r;
+}
+
 static void *worker(void *data) {
   int me = *(int *)data, retries_left = MAX_RETRIES;
   uw_context ctx = uw_init(1024, 0);
@@ -116,6 +134,7 @@
       *back = 0;
     
       if (s = strstr(buf, "\r\n\r\n")) {
+        failure_kind fk;
         char *cmd, *path, path_copy[uw_bufsize+1], *inputs;
 
         *s = 0;
@@ -169,7 +188,20 @@
         printf("Serving URI %s....\n", path);
 
         while (1) {
-          failure_kind fk;
+          if (uw_db_begin(ctx)) {
+            printf("Error running SQL BEGIN\n");
+            if (retries_left)
+              --retries_left;
+            else {
+              fk = FATAL;
+              uw_reset(ctx);
+              uw_write(ctx, "HTTP/1.1 500 Internal Server Error\n\r");
+              uw_write(ctx, "Content-type: text/plain\r\n\r\n");
+              uw_write(ctx, "Error running SQL BEGIN\n");
+
+              break;
+            }
+          }
 
           uw_write(ctx, "HTTP/1.1 200 OK\r\n");
           uw_write(ctx, "Content-type: text/html\r\n\r\n");
@@ -179,6 +211,17 @@
           fk = uw_begin(ctx, path_copy);
           if (fk == SUCCESS) {
             uw_write(ctx, "</html>");
+
+            if (uw_db_commit(ctx)) {
+              fk = FATAL;
+
+              printf("Error running SQL COMMIT\n");
+              uw_reset(ctx);
+              uw_write(ctx, "HTTP/1.1 500 Internal Server Error\n\r");
+              uw_write(ctx, "Content-type: text/plain\r\n\r\n");
+              uw_write(ctx, "Error running SQL COMMIT\n");
+            }
+
             break;
           } else if (fk == BOUNDED_RETRY) {
             if (retries_left) {
@@ -194,6 +237,10 @@
               uw_write(ctx, "Fatal error (out of retries): ");
               uw_write(ctx, uw_error_message(ctx));
               uw_write(ctx, "\n");
+
+              try_rollback(ctx);
+
+              break;
             }
           } else if (fk == UNLIMITED_RETRY)
             printf("Error triggers unlimited retry: %s\n", uw_error_message(ctx));
@@ -207,6 +254,8 @@
             uw_write(ctx, uw_error_message(ctx));
             uw_write(ctx, "\n");
 
+            try_rollback(ctx);
+
             break;
           } else {
             printf("Unknown uw_handle return code!\n");
@@ -216,10 +265,15 @@
             uw_write(ctx, "Content-type: text/plain\r\n\r\n");
             uw_write(ctx, "Unknown uw_handle return code!\n");
 
+            try_rollback(ctx);
+
             break;
           }
 
           uw_reset_keep_request(ctx);
+
+          if (try_rollback(ctx))
+            break;
         }
 
         uw_send(ctx, sock);
--- a/src/cjr_print.sml	Fri Oct 24 16:13:53 2008 -0400
+++ b/src/cjr_print.sml	Fri Oct 24 16:47:18 2008 -0400
@@ -1268,6 +1268,75 @@
                             string "PQfinish(uw_get_db(ctx));",
                             newline,
                             string "}",
+                            newline,
+                            newline,
+
+                            string "int uw_db_begin(uw_context ctx) {",
+                            newline,
+                            string "PGconn *conn = uw_get_db(ctx);",
+                            newline,
+                            string "PGresult *res = PQexec(conn, \"BEGIN\");",
+                            newline,
+                            newline,
+                            string "if (res == NULL) return 1;",
+                            newline,
+                            newline,
+                            string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {",
+                            box [string "PQclear(res);",
+                                 newline,
+                                 string "return 1;",
+                                 newline],
+                            string "}",
+                            newline,
+                            string "return 0;",
+                            newline,
+                            string "}",
+                            newline,
+                            newline,
+
+                            string "int uw_db_commit(uw_context ctx) {",
+                            newline,
+                            string "PGconn *conn = uw_get_db(ctx);",
+                            newline,
+                            string "PGresult *res = PQexec(conn, \"COMMIT\");",
+                            newline,
+                            newline,
+                            string "if (res == NULL) return 1;",
+                            newline,
+                            newline,
+                            string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {",
+                            box [string "PQclear(res);",
+                                 newline,
+                                 string "return 1;",
+                                 newline],
+                            string "}",
+                            newline,
+                            string "return 0;",
+                            newline,
+                            string "}",
+                            newline,
+                            newline,
+
+                            string "int uw_db_rollback(uw_context ctx) {",
+                            newline,
+                            string "PGconn *conn = uw_get_db(ctx);",
+                            newline,
+                            string "PGresult *res = PQexec(conn, \"ROLLBACK\");",
+                            newline,
+                            newline,
+                            string "if (res == NULL) return 1;",
+                            newline,
+                            newline,
+                            string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {",
+                            box [string "PQclear(res);",
+                                 newline,
+                                 string "return 1;",
+                                 newline],
+                            string "}",
+                            newline,
+                            string "return 0;",
+                            newline,
+                            string "}",
                             newline]
 
       | DPreparedStatements ss =>
@@ -2158,6 +2227,12 @@
              else
                  box [newline,
                       string "void uw_db_init(uw_context ctx) { };",
+                      newline,
+                      string "int uw_db_begin(uw_context ctx) { return 0; };",
+                      newline,
+                      string "int uw_db_commit(uw_context ctx) { return 0; };",
+                      newline,
+                      string "int uw_db_rollback(uw_context ctx) { return 0; };",
                       newline]]
     end
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/aborter.sql	Fri Oct 24 16:47:18 2008 -0400
@@ -0,0 +1,3 @@
+CREATE TABLE uw_Aborter_t(uw_a int8 NOT NULL);
+ 
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/aborter.ur	Fri Oct 24 16:47:18 2008 -0400
@@ -0,0 +1,5 @@
+table t : {A : int}
+
+fun main () : transaction page =
+    () <- dml (INSERT INTO t (A) VALUES (0));
+    return (error <xml>No way, Jose!</xml>)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/aborter.urp	Fri Oct 24 16:47:18 2008 -0400
@@ -0,0 +1,4 @@
+database dbname=aborter
+sql aborter.sql
+
+aborter