# HG changeset patch # User Adam Chlipala # Date 1283864773 14400 # Node ID 929981850d9da2792486267a4c770d0081e76974 # Parent b4480a56cab774dc8f2a1739f151ab475d700cf4 'tryDml' works with Postgres diff -r b4480a56cab7 -r 929981850d9d include/urweb.h --- a/include/urweb.h Tue Sep 07 08:28:07 2010 -0400 +++ b/include/urweb.h Tue Sep 07 09:06:13 2010 -0400 @@ -44,6 +44,7 @@ __attribute__((noreturn)) void uw_error(uw_context, failure_kind, const char *fmt, ...); char *uw_error_message(uw_context); void uw_set_error_message(uw_context, const char *fmt, ...); +uw_Basis_string uw_dup_and_clear_error_message(uw_context); int uw_has_error(uw_context); void uw_push_cleanup(uw_context, void (*func)(void *), void *arg); void uw_pop_cleanup(uw_context); diff -r b4480a56cab7 -r 929981850d9d src/c/urweb.c --- a/src/c/urweb.c Tue Sep 07 08:28:07 2010 -0400 +++ b/src/c/urweb.c Tue Sep 07 09:06:13 2010 -0400 @@ -2175,6 +2175,15 @@ return s; } +uw_Basis_string uw_dup_and_clear_error_message(uw_context ctx) { + if (ctx->error_message[0]) { + char *s = uw_strdup(ctx, ctx->error_message); + ctx->error_message[0] = 0; + return s; + } else + return NULL; +} + uw_Basis_string uw_maybe_strdup(uw_context ctx, uw_Basis_string s1) { if (s1) return uw_strdup(ctx, s1); diff -r b4480a56cab7 -r 929981850d9d src/cjr_print.sml --- a/src/cjr_print.sml Tue Sep 07 08:28:07 2010 -0400 +++ b/src/cjr_print.sml Tue Sep 07 09:06:13 2010 -0400 @@ -1794,10 +1794,7 @@ end | EDml {dml, prepared, mode} => - box [case mode of - Settings.Error => box [] - | Settings.None => string "({const char *uw_errmsg = NULL;", - string "(uw_begin_region(ctx), ({", + box [string "(uw_begin_region(ctx), ({", newline, case prepared of NONE => box [string "char *dml = ", @@ -1838,13 +1835,10 @@ case mode of Settings.Error => string "uw_unit_v;" - | Settings.None => string "uw_errmsg ? uw_strdup(ctx, uw_errmsg) : NULL;", + | Settings.None => string "uw_dup_and_clear_error_message(ctx);", newline, - string "}))", - case mode of - Settings.Error => box [] - | Settings.None => string ";})"] + string "}))"] | ENextval {seq, prepared} => box [string "({", diff -r b4480a56cab7 -r 929981850d9d src/mysql.sml --- a/src/mysql.sml Tue Sep 07 08:28:07 2010 -0400 +++ b/src/mysql.sml Tue Sep 07 09:06:13 2010 -0400 @@ -1,4 +1,4 @@ -(* Copyright (c) 2009, Adam Chlipala +(* Copyright (c) 2009-2010, Adam Chlipala * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1202,7 +1202,7 @@ string ": Error executing DML: %s\\n%s\", ", dml, string ", mysql_error(conn->conn));"] - | Settings.None => string "uw_errmsg = mysql_error(conn->conn);", + | Settings.None => string "uw_set_error_message(ctx, mysql_error(conn->conn));", newline, newline] diff -r b4480a56cab7 -r 929981850d9d src/postgres.sml --- a/src/postgres.sml Tue Sep 07 08:28:07 2010 -0400 +++ b/src/postgres.sml Tue Sep 07 09:06:13 2010 -0400 @@ -1,4 +1,4 @@ -(* Copyright (c) 2008-2009, Adam Chlipala +(* Copyright (c) 2008-2010, Adam Chlipala * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -731,19 +731,95 @@ string ": DML failed:\\n%s\\n%s\", ", dml, string ", PQerrorMessage(conn));"] - | Settings.None => string "uw_errmsg = PQerrorMessage(conn);", + | Settings.None => box [string "uw_set_error_message(ctx, PQerrorMessage(conn));", + newline, + newline, + + string "res = PQexec(conn, \"ROLLBACK TO s\");", + newline, + string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating DML result.\");", + newline, + newline, + + string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {", + newline, + box [string "PQclear(res);", + newline, + string "uw_error(ctx, FATAL, \"", + string (ErrorMsg.spanToString loc), + string ": ROLLBACK TO failed:\\n%s\\n%s\", ", + dml, + string ", PQerrorMessage(conn));", + newline, + string "}"], + newline, + + string "PQclear(res);", + newline], newline], string "}", - newline, - newline, - string "PQclear(res);", - newline] + case mode of + Error => box [newline, + newline, + string "PQclear(res);", + newline] + | None => box[string " else {", + newline, + box [string "PQclear(res);", + newline, + string "res = PQexec(conn, \"RELEASE s\");", + newline, + string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating DML result.\");", + newline, + newline, + + string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {", + newline, + box [string "PQclear(res);", + newline, + string "uw_error(ctx, FATAL, \"", + string (ErrorMsg.spanToString loc), + string ": RELEASE failed:\\n%s\\n%s\", ", + dml, + string ", PQerrorMessage(conn));", + newline], + string "}", + newline, + string "PQclear(res);", + newline], + string "}", + newline]] + +fun makeSavepoint mode = + case mode of + Error => box [] + | None => box [string "res = PQexec(conn, \"SAVEPOINT s\");", + newline, + string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating DML result.\");", + newline, + newline, + string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {", + box [newline, + string "PQclear(res);", + newline, + string "uw_error(ctx, FATAL, \"Error creating SAVEPOINT\");", + newline], + string "}", + newline, + string "PQclear(res);", + newline, + newline] fun dml (loc, mode) = box [string "PGconn *conn = uw_get_db(ctx);", newline, - string "PGresult *res = PQexecParams(conn, dml, 0, NULL, NULL, NULL, NULL, 0);", + string "PGresult *res;", + newline, + + makeSavepoint mode, + + string "res = PQexecParams(conn, dml, 0, NULL, NULL, NULL, NULL, 0);", newline, newline, dmlCommon {loc = loc, dml = string "dml", mode = mode}] @@ -772,7 +848,13 @@ string " };", newline, newline, - string "PGresult *res = ", + string "PGresult *res;", + newline, + newline, + + makeSavepoint mode, + + string "res = ", if #persistent (Settings.currentProtocol ()) then box [string "PQexecPrepared(conn, \"uw", string (Int.toString id), diff -r b4480a56cab7 -r 929981850d9d src/sqlite.sml --- a/src/sqlite.sml Tue Sep 07 08:28:07 2010 -0400 +++ b/src/sqlite.sml Tue Sep 07 09:06:13 2010 -0400 @@ -1,4 +1,4 @@ -(* Copyright (c) 2009, Adam Chlipala +(* Copyright (c) 2009-2010, Adam Chlipala * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -708,7 +708,7 @@ string ": DML step failed: %s
%s\", ", dml, string ", sqlite3_errmsg(conn->conn));"] - | Settings.None => string "uw_errmsg = sqlite3_errmsg(conn->conn);", + | Settings.None => string "uw_set_error_message(ctx, sqlite3_errmsg(conn->conn));", newline] fun dml (loc, mode) = diff -r b4480a56cab7 -r 929981850d9d tests/tryDml.ur --- a/tests/tryDml.ur Tue Sep 07 08:28:07 2010 -0400 +++ b/tests/tryDml.ur Tue Sep 07 09:06:13 2010 -0400 @@ -5,8 +5,10 @@ dml (INSERT INTO t (Id) VALUES (0)); o1 <- tryDml (INSERT INTO t (Id) VALUES (0)); dml (INSERT INTO t (Id) VALUES (1)); - o2 <- tryDml (INSERT INTO t (Id) VALUES (1)); - return {[o1]}; {[o2]} + o2 <- tryDml (INSERT INTO t (Id) VALUES (2)); + dml (INSERT INTO t (Id) VALUES (3)); + o3 <- tryDml (INSERT INTO t (Id) VALUES (3)); + return {[o1]}; {[o2]}; {[o3]} fun main () = return