summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Adam Chlipala <adamc@hcoop.net>2009-06-27 10:50:45 -0400
committerGravatar Adam Chlipala <adamc@hcoop.net>2009-06-27 10:50:45 -0400
commit756283988dd7d7235c228b3b99e6c7f6c73bf122 (patch)
treece2e6f57c5abbacefb996b3bae88a1bf2802dc1e
parent35cfed265b313d645c850f1ed24f6e8f937a410c (diff)
Avoid using prepared statements for non-persistent protocols
-rw-r--r--src/cgi.sig30
-rw-r--r--src/cgi.sml36
-rw-r--r--src/cjr.sml6
-rw-r--r--src/cjr_print.sml630
-rw-r--r--src/prepare.sml28
-rw-r--r--src/scriptcheck.sml2
-rw-r--r--src/settings.sig4
-rw-r--r--src/settings.sml7
-rw-r--r--src/sources3
9 files changed, 427 insertions, 319 deletions
diff --git a/src/cgi.sig b/src/cgi.sig
new file mode 100644
index 00000000..ae6549a1
--- /dev/null
+++ b/src/cgi.sig
@@ -0,0 +1,30 @@
+(* Copyright (c) 2008-2009, Adam Chlipala
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - The names of contributors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *)
+
+signature CGI = sig
+
+end
diff --git a/src/cgi.sml b/src/cgi.sml
new file mode 100644
index 00000000..f57cd845
--- /dev/null
+++ b/src/cgi.sml
@@ -0,0 +1,36 @@
+(* Copyright (c) 2008-2009, Adam Chlipala
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - The names of contributors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *)
+
+structure Cgi :> CGI = struct
+
+open Settings
+
+val () = addProtocol {name = "cgi",
+ link = clibFile "request.o" ^ " " ^ clibFile "cgi.o",
+ persistent = false}
+
+end
diff --git a/src/cjr.sml b/src/cjr.sml
index 2b81de1a..a5931a55 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -89,11 +89,11 @@ datatype exp' =
query : exp,
body : exp,
initial : exp,
- prepared : int option }
+ prepared : (int * string) option }
| EDml of { dml : exp,
- prepared : int option }
+ prepared : (int * string) option }
| ENextval of { seq : exp,
- prepared : int option }
+ prepared : (int * string) option }
| EUnurlify of exp * typ
withtype exp = exp' located
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 683c2ddf..b8db23e8 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1641,11 +1641,19 @@ fun p_exp' par env (e, loc) =
string "PGresult *res = ",
case prepared of
NONE => string "PQexecParams(conn, query, 0, NULL, NULL, NULL, NULL, 0);"
- | SOME n => box [string "PQexecPrepared(conn, \"uw",
- string (Int.toString n),
- string "\", ",
- string (Int.toString (length (getPargs query))),
- string ", paramValues, paramLengths, paramFormats, 0);"],
+ | SOME (n, s) =>
+ if #persistent (Settings.currentProtocol ()) then
+ box [string "PQexecPrepared(conn, \"uw",
+ string (Int.toString n),
+ string "\", ",
+ string (Int.toString (length (getPargs query))),
+ string ", paramValues, paramLengths, paramFormats, 0);"]
+ else
+ box [string "PQexecParams(conn, \"",
+ string (String.toString s),
+ string "\", ",
+ string (Int.toString (length (getPargs query))),
+ string ", NULL, paramValues, paramLengths, paramFormats, 0);"],
newline,
newline,
@@ -1820,11 +1828,19 @@ fun p_exp' par env (e, loc) =
string "PGresult *res = ",
case prepared of
NONE => string "PQexecParams(conn, dml, 0, NULL, NULL, NULL, NULL, 0);"
- | SOME n => box [string "PQexecPrepared(conn, \"uw",
- string (Int.toString n),
- string "\", ",
- string (Int.toString (length (getPargs dml))),
- string ", paramValues, paramLengths, paramFormats, 0);"],
+ | SOME (n, s) =>
+ if #persistent (Settings.currentProtocol ()) then
+ box [string "PQexecPrepared(conn, \"uw",
+ string (Int.toString n),
+ string "\", ",
+ string (Int.toString (length (getPargs dml))),
+ string ", paramValues, paramLengths, paramFormats, 0);"]
+ else
+ box [string "PQexecParams(conn, \"",
+ string (String.toString s),
+ string "\", ",
+ string (Int.toString (length (getPargs dml))),
+ string ", NULL, paramValues, paramLengths, paramFormats, 0);"],
newline,
newline,
@@ -1892,9 +1908,15 @@ fun p_exp' par env (e, loc) =
string "PGresult *res = ",
case prepared of
NONE => string "PQexecParams(conn, query, 0, NULL, NULL, NULL, NULL, 0);"
- | SOME n => box [string "PQexecPrepared(conn, \"uw",
- string (Int.toString n),
- string "\", 0, NULL, NULL, NULL, 0);"],
+ | SOME (n, s) =>
+ if #persistent (Settings.currentProtocol ()) then
+ box [string "PQexecPrepared(conn, \"uw",
+ string (Int.toString n),
+ string "\", 0, NULL, NULL, NULL, 0);"]
+ else
+ box [string "PQexecParams(conn, \"uw",
+ string (Int.toString n),
+ string "\", 0, NULL, NULL, NULL, NULL, 0);"],
newline,
string "uw_Basis_int n;",
newline,
@@ -2306,46 +2328,49 @@ fun p_decl env (dAll as (d, _) : decl) =
newline,
string "}"]
| DPreparedStatements ss =>
- box [string "static void uw_db_prepare(uw_context ctx) {",
- newline,
- string "PGconn *conn = uw_get_db(ctx);",
- newline,
- string "PGresult *res;",
- newline,
- newline,
+ if #persistent (Settings.currentProtocol ()) then
+ box [string "static void uw_db_prepare(uw_context ctx) {",
+ newline,
+ string "PGconn *conn = uw_get_db(ctx);",
+ newline,
+ string "PGresult *res;",
+ newline,
+ newline,
- p_list_sepi newline (fn i => fn (s, n) =>
- box [string "res = PQprepare(conn, \"uw",
- string (Int.toString i),
- string "\", \"",
- string (String.toString s),
- string "\", ",
- string (Int.toString n),
- string ", NULL);",
- newline,
- string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {",
- newline,
- box [string "char msg[1024];",
- newline,
- string "strncpy(msg, PQerrorMessage(conn), 1024);",
- newline,
- string "msg[1023] = 0;",
- newline,
- string "PQclear(res);",
- newline,
- string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Unable to create prepared statement:\\n",
- string (String.toString s),
- string "\\n%s\", msg);",
- newline],
- string "}",
- newline,
- string "PQclear(res);",
- newline])
- ss,
-
- string "}"]
+ p_list_sepi newline (fn i => fn (s, n) =>
+ box [string "res = PQprepare(conn, \"uw",
+ string (Int.toString i),
+ string "\", \"",
+ string (String.toString s),
+ string "\", ",
+ string (Int.toString n),
+ string ", NULL);",
+ newline,
+ string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {",
+ newline,
+ box [string "char msg[1024];",
+ newline,
+ string "strncpy(msg, PQerrorMessage(conn), 1024);",
+ newline,
+ string "msg[1023] = 0;",
+ newline,
+ string "PQclear(res);",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Unable to create prepared statement:\\n",
+ string (String.toString s),
+ string "\\n%s\", msg);",
+ newline],
+ string "}",
+ newline,
+ string "PQclear(res);",
+ newline])
+ ss,
+
+ string "}"]
+ else
+ string "static void uw_db_prepare(uw_context ctx) { }"
| DJavaScript s => box [string "static char jslib[] = \"",
string (String.toString s),
@@ -2928,256 +2953,259 @@ fun p_file env (ds, ps) =
| _ => NONE) ds
val validate =
- box [string "static void uw_db_validate(uw_context ctx) {",
- newline,
- string "PGconn *conn = uw_get_db(ctx);",
- newline,
- string "PGresult *res;",
- newline,
- newline,
- p_list_sep newline
- (fn (s, xts) =>
- let
- val sl = CharVector.map Char.toLower s
-
- val q = "SELECT COUNT(*) FROM pg_class WHERE relname = '"
- ^ sl ^ "'"
-
- val q' = String.concat ["SELECT COUNT(*) FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '",
- sl,
- "') AND (",
- String.concatWith " OR "
- (map (fn (x, t) =>
- String.concat ["(attname = 'uw_",
- CharVector.map
- Char.toLower (ident x),
- "' AND atttypid = (SELECT oid FROM pg_type",
- " WHERE typname = '",
- p_sqltype_base' env t,
- "') AND attnotnull = ",
- if is_not_null t then
- "TRUE"
- else
- "FALSE",
- ")"]) xts),
- ")"]
-
- val q'' = String.concat ["SELECT COUNT(*) FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '",
- sl,
- "') AND attname LIKE 'uw_%'"]
- in
- box [string "res = PQexec(conn, \"",
- string q,
- string "\");",
- newline,
- newline,
- string "if (res == NULL) {",
- newline,
- box [string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Out of memory allocating query result.\");",
- newline],
- string "}",
- newline,
- newline,
- string "if (PQresultStatus(res) != PGRES_TUPLES_OK) {",
- newline,
- box [string "char msg[1024];",
- newline,
- string "strncpy(msg, PQerrorMessage(conn), 1024);",
- newline,
- string "msg[1023] = 0;",
- newline,
- string "PQclear(res);",
- newline,
- string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Query failed:\\n",
- string q,
- string "\\n%s\", msg);",
- newline],
- string "}",
- newline,
- newline,
- string "if (strcmp(PQgetvalue(res, 0, 0), \"1\")) {",
- newline,
- box [string "PQclear(res);",
- newline,
- string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Table '",
- string s,
- string "' does not exist.\");",
- newline],
- string "}",
- newline,
- newline,
- string "PQclear(res);",
- newline,
-
- string "res = PQexec(conn, \"",
- string q',
- string "\");",
- newline,
- newline,
- string "if (res == NULL) {",
- newline,
- box [string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Out of memory allocating query result.\");",
- newline],
- string "}",
- newline,
- newline,
- string "if (PQresultStatus(res) != PGRES_TUPLES_OK) {",
- newline,
- box [string "char msg[1024];",
- newline,
- string "strncpy(msg, PQerrorMessage(conn), 1024);",
- newline,
- string "msg[1023] = 0;",
- newline,
- string "PQclear(res);",
- newline,
- string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Query failed:\\n",
- string q',
- string "\\n%s\", msg);",
- newline],
- string "}",
- newline,
- newline,
- string "if (strcmp(PQgetvalue(res, 0, 0), \"",
- string (Int.toString (length xts)),
- string "\")) {",
- newline,
- box [string "PQclear(res);",
- newline,
- string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Table '",
- string s,
- string "' has the wrong column types.\");",
- newline],
- string "}",
- newline,
- newline,
- string "PQclear(res);",
- newline,
- newline,
-
- string "res = PQexec(conn, \"",
- string q'',
- string "\");",
- newline,
- newline,
- string "if (res == NULL) {",
- newline,
- box [string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Out of memory allocating query result.\");",
- newline],
- string "}",
- newline,
- newline,
- string "if (PQresultStatus(res) != PGRES_TUPLES_OK) {",
- newline,
- box [string "char msg[1024];",
- newline,
- string "strncpy(msg, PQerrorMessage(conn), 1024);",
- newline,
- string "msg[1023] = 0;",
- newline,
- string "PQclear(res);",
- newline,
- string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Query failed:\\n",
- string q'',
- string "\\n%s\", msg);",
- newline],
- string "}",
- newline,
- newline,
- string "if (strcmp(PQgetvalue(res, 0, 0), \"",
- string (Int.toString (length xts)),
- string "\")) {",
- newline,
- box [string "PQclear(res);",
- newline,
- string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Table '",
- string s,
- string "' has extra columns.\");",
- newline],
- string "}",
- newline,
- newline,
- string "PQclear(res);",
- newline]
- end) tables,
-
- p_list_sep newline
- (fn s =>
- let
- val sl = CharVector.map Char.toLower s
-
- val q = "SELECT COUNT(*) FROM pg_class WHERE relname = '"
- ^ sl ^ "' AND relkind = 'S'"
- in
- box [string "res = PQexec(conn, \"",
- string q,
- string "\");",
- newline,
- newline,
- string "if (res == NULL) {",
- newline,
- box [string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Out of memory allocating query result.\");",
- newline],
- string "}",
- newline,
- newline,
- string "if (PQresultStatus(res) != PGRES_TUPLES_OK) {",
- newline,
- box [string "char msg[1024];",
- newline,
- string "strncpy(msg, PQerrorMessage(conn), 1024);",
- newline,
- string "msg[1023] = 0;",
- newline,
- string "PQclear(res);",
- newline,
- string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Query failed:\\n",
- string q,
- string "\\n%s\", msg);",
- newline],
- string "}",
- newline,
- newline,
- string "if (strcmp(PQgetvalue(res, 0, 0), \"1\")) {",
- newline,
- box [string "PQclear(res);",
- newline,
- string "PQfinish(conn);",
- newline,
- string "uw_error(ctx, FATAL, \"Sequence '",
- string s,
- string "' does not exist.\");",
- newline],
- string "}",
- newline,
- newline,
- string "PQclear(res);",
- newline]
- end) sequences,
+ if #persistent (Settings.currentProtocol ()) then
+ box [string "static void uw_db_validate(uw_context ctx) {",
+ newline,
+ string "PGconn *conn = uw_get_db(ctx);",
+ newline,
+ string "PGresult *res;",
+ newline,
+ newline,
+ p_list_sep newline
+ (fn (s, xts) =>
+ let
+ val sl = CharVector.map Char.toLower s
+
+ val q = "SELECT COUNT(*) FROM pg_class WHERE relname = '"
+ ^ sl ^ "'"
+
+ val q' = String.concat ["SELECT COUNT(*) FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '",
+ sl,
+ "') AND (",
+ String.concatWith " OR "
+ (map (fn (x, t) =>
+ String.concat ["(attname = 'uw_",
+ CharVector.map
+ Char.toLower (ident x),
+ "' AND atttypid = (SELECT oid FROM pg_type",
+ " WHERE typname = '",
+ p_sqltype_base' env t,
+ "') AND attnotnull = ",
+ if is_not_null t then
+ "TRUE"
+ else
+ "FALSE",
+ ")"]) xts),
+ ")"]
+
+ val q'' = String.concat ["SELECT COUNT(*) FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '",
+ sl,
+ "') AND attname LIKE 'uw_%'"]
+ in
+ box [string "res = PQexec(conn, \"",
+ string q,
+ string "\");",
+ newline,
+ newline,
+ string "if (res == NULL) {",
+ newline,
+ box [string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Out of memory allocating query result.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "if (PQresultStatus(res) != PGRES_TUPLES_OK) {",
+ newline,
+ box [string "char msg[1024];",
+ newline,
+ string "strncpy(msg, PQerrorMessage(conn), 1024);",
+ newline,
+ string "msg[1023] = 0;",
+ newline,
+ string "PQclear(res);",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Query failed:\\n",
+ string q,
+ string "\\n%s\", msg);",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "if (strcmp(PQgetvalue(res, 0, 0), \"1\")) {",
+ newline,
+ box [string "PQclear(res);",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Table '",
+ string s,
+ string "' does not exist.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "PQclear(res);",
+ newline,
- string "}"]
+ string "res = PQexec(conn, \"",
+ string q',
+ string "\");",
+ newline,
+ newline,
+ string "if (res == NULL) {",
+ newline,
+ box [string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Out of memory allocating query result.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "if (PQresultStatus(res) != PGRES_TUPLES_OK) {",
+ newline,
+ box [string "char msg[1024];",
+ newline,
+ string "strncpy(msg, PQerrorMessage(conn), 1024);",
+ newline,
+ string "msg[1023] = 0;",
+ newline,
+ string "PQclear(res);",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Query failed:\\n",
+ string q',
+ string "\\n%s\", msg);",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "if (strcmp(PQgetvalue(res, 0, 0), \"",
+ string (Int.toString (length xts)),
+ string "\")) {",
+ newline,
+ box [string "PQclear(res);",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Table '",
+ string s,
+ string "' has the wrong column types.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "PQclear(res);",
+ newline,
+ newline,
+
+ string "res = PQexec(conn, \"",
+ string q'',
+ string "\");",
+ newline,
+ newline,
+ string "if (res == NULL) {",
+ newline,
+ box [string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Out of memory allocating query result.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "if (PQresultStatus(res) != PGRES_TUPLES_OK) {",
+ newline,
+ box [string "char msg[1024];",
+ newline,
+ string "strncpy(msg, PQerrorMessage(conn), 1024);",
+ newline,
+ string "msg[1023] = 0;",
+ newline,
+ string "PQclear(res);",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Query failed:\\n",
+ string q'',
+ string "\\n%s\", msg);",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "if (strcmp(PQgetvalue(res, 0, 0), \"",
+ string (Int.toString (length xts)),
+ string "\")) {",
+ newline,
+ box [string "PQclear(res);",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Table '",
+ string s,
+ string "' has extra columns.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "PQclear(res);",
+ newline]
+ end) tables,
+
+ p_list_sep newline
+ (fn s =>
+ let
+ val sl = CharVector.map Char.toLower s
+
+ val q = "SELECT COUNT(*) FROM pg_class WHERE relname = '"
+ ^ sl ^ "' AND relkind = 'S'"
+ in
+ box [string "res = PQexec(conn, \"",
+ string q,
+ string "\");",
+ newline,
+ newline,
+ string "if (res == NULL) {",
+ newline,
+ box [string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Out of memory allocating query result.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "if (PQresultStatus(res) != PGRES_TUPLES_OK) {",
+ newline,
+ box [string "char msg[1024];",
+ newline,
+ string "strncpy(msg, PQerrorMessage(conn), 1024);",
+ newline,
+ string "msg[1023] = 0;",
+ newline,
+ string "PQclear(res);",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Query failed:\\n",
+ string q,
+ string "\\n%s\", msg);",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "if (strcmp(PQgetvalue(res, 0, 0), \"1\")) {",
+ newline,
+ box [string "PQclear(res);",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Sequence '",
+ string s,
+ string "' does not exist.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "PQclear(res);",
+ newline]
+ end) sequences,
+
+ string "}"]
+ else
+ string "static void uw_db_validate(uw_context ctx) { }"
val hasDb = List.exists (fn (DDatabase _, _) => true | _ => false) ds
diff --git a/src/prepare.sml b/src/prepare.sml
index 592b00bc..89a974db 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -196,18 +196,26 @@ fun prepExp (e as (_, loc), sns) =
initial = initial, prepared = NONE}, loc),
sns)
| SOME (ss, n) =>
- ((EQuery {exps = exps, tables = tables, rnum = rnum,
- state = state, query = query, body = body,
- initial = initial, prepared = SOME (#2 sns)}, loc),
- ((String.concat (rev ss), n) :: #1 sns, #2 sns + 1))
+ let
+ val s = String.concat (rev ss)
+ in
+ ((EQuery {exps = exps, tables = tables, rnum = rnum,
+ state = state, query = query, body = body,
+ initial = initial, prepared = SOME (#2 sns, s)}, loc),
+ ((s, n) :: #1 sns, #2 sns + 1))
+ end
end
| EDml {dml, ...} =>
(case prepString (dml, [], 0) of
NONE => (e, sns)
| SOME (ss, n) =>
- ((EDml {dml = dml, prepared = SOME (#2 sns)}, loc),
- ((String.concat (rev ss), n) :: #1 sns, #2 sns + 1)))
+ let
+ val s = String.concat (rev ss)
+ in
+ ((EDml {dml = dml, prepared = SOME (#2 sns, s)}, loc),
+ ((s, n) :: #1 sns, #2 sns + 1))
+ end)
| ENextval {seq, ...} =>
let
@@ -224,8 +232,12 @@ fun prepExp (e as (_, loc), sns) =
case prepString (s, [], 0) of
NONE => (e, sns)
| SOME (ss, n) =>
- ((ENextval {seq = seq, prepared = SOME (#2 sns)}, loc),
- ((String.concat (rev ss), n) :: #1 sns, #2 sns + 1))
+ let
+ val s = String.concat (rev ss)
+ in
+ ((ENextval {seq = seq, prepared = SOME (#2 sns, s)}, loc),
+ ((s, n) :: #1 sns, #2 sns + 1))
+ end
end
| EUnurlify (e, t) =>
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index e0b9f855..09e9e884 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -165,7 +165,7 @@ fun classify (ds, ps) =
val ps = map (fn (ek, x, n, ts, t, _) =>
(ek, x, n, ts, t,
if IS.member (push_ids, n) then
- (if not (#supportsPush proto) andalso not (!foundBad) then
+ (if not (#persistent proto) andalso not (!foundBad) then
(foundBad := true;
ErrorMsg.error ("This program needs server push, but the current protocol ("
^ #name proto ^ ") doesn't support that."))
diff --git a/src/settings.sig b/src/settings.sig
index 919fdf42..8259e519 100644
--- a/src/settings.sig
+++ b/src/settings.sig
@@ -89,7 +89,7 @@ signature SETTINGS = sig
type protocol = {
name : string, (* Call it this on the command line *)
link : string, (* Pass these linker arguments *)
- supportsPush : bool (* Is Ur/Web message-passing supported? *)
+ persistent : bool (* Multiple requests per process? *)
}
val addProtocol : protocol -> unit
val getProtocol : string -> protocol option
@@ -99,4 +99,6 @@ signature SETTINGS = sig
val setDebug : bool -> unit
val getDebug : unit -> bool
+ val clibFile : string -> string
+
end
diff --git a/src/settings.sml b/src/settings.sml
index a020f373..36521799 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -252,7 +252,7 @@ val checkMime = check
type protocol = {
name : string,
link : string,
- supportsPush : bool
+ persistent : bool
}
val protocols = ref ([] : protocol list)
fun addProtocol p = protocols := p :: !protocols
@@ -263,12 +263,9 @@ fun clibFile s = OS.Path.joinDirFile {dir = Config.libC,
val http = {name = "http",
link = clibFile "request.o" ^ " " ^ clibFile "http.o",
- supportsPush = true}
+ persistent = true}
val () = addProtocol http
-val () = addProtocol {name = "cgi",
- link = clibFile "request.o" ^ " " ^ clibFile "cgi.o",
- supportsPush = false}
val curProto = ref http
fun setProtocol name =
diff --git a/src/sources b/src/sources
index 0f39fc74..81b6f881 100644
--- a/src/sources
+++ b/src/sources
@@ -16,6 +16,9 @@ errormsg.sml
settings.sig
settings.sml
+cgi.sig
+cgi.sml
+
print.sig
print.sml