changeset 272:4d80d6122df1

Initializing database connection
author Adam Chlipala <adamc@hcoop.net>
date Tue, 02 Sep 2008 11:57:25 -0400
parents 42dfb0d61cf0
children 09c66a30ef32
files include/urweb.h src/c/driver.c src/c/urweb.c src/cjr_print.sml src/compiler.sml
diffstat 5 files changed, 104 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/include/urweb.h	Tue Sep 02 10:51:41 2008 -0400
+++ b/include/urweb.h	Tue Sep 02 11:57:25 2008 -0400
@@ -7,10 +7,14 @@
 extern lw_unit lw_unit_v;
 
 lw_context lw_init(size_t page_len, size_t heap_len);
+void lw_set_db(lw_context, void*);
+void *lw_get_db(lw_context);
 void lw_free(lw_context);
 void lw_reset(lw_context);
 void lw_reset_keep_request(lw_context);
 void lw_reset_keep_error_message(lw_context);
+
+failure_kind lw_begin_init(lw_context);
 failure_kind lw_begin(lw_context, char *path);
 
 void lw_error(lw_context, failure_kind, const char *fmt, ...);
--- a/src/c/driver.c	Tue Sep 02 10:51:41 2008 -0400
+++ b/src/c/driver.c	Tue Sep 02 11:57:25 2008 -0400
@@ -52,8 +52,37 @@
 #define MAX_RETRIES 5
 
 static void *worker(void *data) {
-  int me = *(int *)data;
+  int me = *(int *)data, retries_left = MAX_RETRIES;;
   lw_context ctx = lw_init(1024, 1024);
+  
+  while (1) {
+    failure_kind fk = lw_begin_init(ctx);
+
+    if (fk == SUCCESS) {
+      lw_db_init(ctx);
+      printf("Database connection initialized.\n");
+      break;
+    } else if (fk == BOUNDED_RETRY) {
+      if (retries_left) {
+        printf("Initialization error triggers bounded retry: %s\n", lw_error_message(ctx));
+        --retries_left;
+      } else {
+        printf("Fatal initialization error (out of retries): %s\n", lw_error_message(ctx));
+        lw_free(ctx);
+        return NULL;
+      }
+    } else if (fk == UNLIMITED_RETRY)
+      printf("Initialization error triggers unlimited retry: %s\n", lw_error_message(ctx));
+    else if (fk == FATAL) {
+      printf("Fatal initialization error: %s\n", lw_error_message(ctx));
+      lw_free(ctx);
+      return NULL;
+    } else {
+      printf("Unknown lw_handle return code!\n");
+      lw_free(ctx);
+      return NULL;
+    }
+  }
 
   while (1) {
     char buf[lw_bufsize+1], *back = buf, *s;
--- a/src/c/urweb.c	Tue Sep 02 10:51:41 2008 -0400
+++ b/src/c/urweb.c	Tue Sep 02 11:57:25 2008 -0400
@@ -16,6 +16,8 @@
   char *heap, *heap_front, *heap_back;
   char **inputs;
 
+  void *db;
+
   jmp_buf jmp_buf;
 
   char error_message[ERROR_BUF_LEN];
@@ -34,11 +36,21 @@
 
   ctx->inputs = calloc(lw_inputs_len, sizeof(char *));
 
+  ctx->db = NULL;
+
   ctx->error_message[0] = 0;
 
   return ctx;
 }
 
+void lw_set_db(lw_context ctx, void *db) {
+  ctx->db = db;
+}
+
+void *lw_get_db(lw_context ctx) {
+  return ctx->db;
+}
+
 void lw_free(lw_context ctx) {
   free(ctx->page);
   free(ctx->heap);
@@ -63,8 +75,18 @@
   memset(ctx->inputs, 0, lw_inputs_len * sizeof(char *));
 }
 
+void lw_db_init(lw_context);
 void lw_handle(lw_context, char *);
 
+failure_kind lw_begin_init(lw_context ctx) {
+  int r = setjmp(ctx->jmp_buf);
+
+  if (r == 0)
+    lw_db_init(ctx);
+
+  return r;
+}
+
 failure_kind lw_begin(lw_context ctx, char *path) {
   int r = setjmp(ctx->jmp_buf);
 
--- a/src/cjr_print.sml	Tue Sep 02 10:51:41 2008 -0400
+++ b/src/cjr_print.sml	Tue Sep 02 11:57:25 2008 -0400
@@ -533,7 +533,10 @@
                                     newline,
                                     p_typ env t,
                                     space,
-                                    p_rel env 0,
+                                    string "__lwr_",
+                                    string x,
+                                    string "_",
+                                    string (Int.toString (E.countERels env)),
                                     space,
                                     string "=",
                                     space,
@@ -546,31 +549,7 @@
                                     string "})"]
 
       | EQuery {exps, tables, rnum, state, query, body, initial} =>
-        box [string "query[",
-             p_list (fn (x, t) => box [string x, space, string ":", space, p_typ env t]) exps,
-             string "] [",
-             p_list (fn (x, xts) => box [string x,
-                                         space,
-                                         string ":",
-                                         space,
-                                         string "{",
-                                         p_list (fn (x, t) => box [string x, space, string ":", space, p_typ env t]) xts,
-                                         string "}"]) tables,
-             string "] [",
-             p_typ env state,
-             string "] [",
-             string (Int.toString rnum),
-             string "]",
-             space,
-             p_exp env query,
-             space,
-             string "initial",
-             space,
-             p_exp env initial,
-             space,
-             string "in",
-             space,
-             p_exp (E.pushERel (E.pushERel env "r" dummyt) "acc" dummyt) body]
+        string "(lw_error(ctx, FATAL, \"I would have run a query.\"), NULL)"
 
 and p_exp env = p_exp' false env
 
@@ -709,9 +688,41 @@
                  p_list_sep newline (p_fun env) vis,
                  newline]
         end
-      | DDatabase s => box [string "database",
-                            space,
-                            string s]
+      | DDatabase s => box [string "void lw_db_init(lw_context ctx) {",
+                            newline,
+                            string "PGconn *conn = PQconnectdb(\"",
+                            string (String.toString s),
+                            string "\");",
+                            newline,
+                            string "if (conn == NULL) lw_error(ctx, BOUNDED_RETRY, ",
+                            string "\"libpq can't allocate a connection.\");",
+                            newline,
+                            string "if (PQstatus(conn) != CONNECTION_OK) {",
+                            newline,
+                            box [string "char msg[1024];",
+                                 newline,
+                                 string "strncpy(msg, PQerrorMessage(conn), 1024);",
+                                 newline,
+                                 string "msg[1023] = 0;",
+                                 newline,
+                                 string "PQfinish(conn);",
+                                 newline,
+                                 string "lw_error(ctx, BOUNDED_RETRY, ",
+                                 string "\"Connection to Postgres server failed: %s\", msg);"],
+                            newline,
+                            string "}",
+                            newline,
+                            string "lw_set_db(ctx, conn);",
+                            newline,
+                            string "}",
+                            newline,
+                            newline,
+                            string "void lw_db_close(lw_context ctx) {",
+                            newline,
+                            string "PQfinish(lw_get_db(ctx));",
+                            newline,
+                            string "}",
+                            newline]
 
 datatype 'a search =
          Found of 'a
@@ -1172,7 +1183,9 @@
                           string "(",
                           p_list_sep (box [string ",", space])
                                      (fn x => x)
-                                     (string "ctx" :: ListUtil.mapi (fn (i, _) => string ("arg" ^ Int.toString i)) ts),
+                                     (string "ctx"
+                                      :: ListUtil.mapi (fn (i, _) => string ("arg" ^ Int.toString i)) ts
+                                      @ [string "lw_unit_v"]),
                           inputsVar,
                           string ");",
                           newline,
@@ -1190,6 +1203,10 @@
              newline,
              string "#include <stdlib.h>",
              newline,
+             string "#include <string.h>",
+             newline,
+             string "#include <postgresql/libpq-fe.h>",
+             newline,
              newline,
              string "#include \"urweb.h\"",
              newline,
--- a/src/compiler.sml	Tue Sep 02 10:51:41 2008 -0400
+++ b/src/compiler.sml	Tue Sep 02 11:57:25 2008 -0400
@@ -417,7 +417,7 @@
 fun compileC {cname, oname, ename} =
     let
         val compile = "gcc -O3 -I include -c " ^ cname ^ " -o " ^ oname
-        val link = "gcc -pthread -O3 clib/urweb.o " ^ oname ^ " clib/driver.o -o " ^ ename
+        val link = "gcc -O3 -pthread -lpq clib/urweb.o " ^ oname ^ " clib/driver.o -o " ^ ename
     in
         if not (OS.Process.isSuccess (OS.Process.system compile)) then
             print "C compilation failed\n"