diff options
author | Adam Chlipala <adamc@hcoop.net> | 2009-06-27 10:50:45 -0400 |
---|---|---|
committer | Adam Chlipala <adamc@hcoop.net> | 2009-06-27 10:50:45 -0400 |
commit | 756283988dd7d7235c228b3b99e6c7f6c73bf122 (patch) | |
tree | ce2e6f57c5abbacefb996b3bae88a1bf2802dc1e | |
parent | 35cfed265b313d645c850f1ed24f6e8f937a410c (diff) |
Avoid using prepared statements for non-persistent protocols
-rw-r--r-- | src/cgi.sig | 30 | ||||
-rw-r--r-- | src/cgi.sml | 36 | ||||
-rw-r--r-- | src/cjr.sml | 6 | ||||
-rw-r--r-- | src/cjr_print.sml | 630 | ||||
-rw-r--r-- | src/prepare.sml | 28 | ||||
-rw-r--r-- | src/scriptcheck.sml | 2 | ||||
-rw-r--r-- | src/settings.sig | 4 | ||||
-rw-r--r-- | src/settings.sml | 7 | ||||
-rw-r--r-- | src/sources | 3 |
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 |