summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--demo/sql.urp1
-rw-r--r--include/urweb.h25
-rw-r--r--src/c/urweb.c44
-rw-r--r--src/cjr_print.sml4
-rw-r--r--tests/aborter2.ur7
-rw-r--r--tests/aborter2.urp5
6 files changed, 73 insertions, 13 deletions
diff --git a/demo/sql.urp b/demo/sql.urp
index 7894da95..06fbbd24 100644
--- a/demo/sql.urp
+++ b/demo/sql.urp
@@ -1,3 +1,4 @@
+debug
database dbname=test
sql sql.sql
diff --git a/include/urweb.h b/include/urweb.h
index 5a6c7178..6ac7df15 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -19,6 +19,8 @@ failure_kind uw_begin(uw_context, char *path);
__attribute__((noreturn)) void uw_error(uw_context, failure_kind, const char *fmt, ...);
char *uw_error_message(uw_context);
+void uw_push_cleanup(uw_context, void (*func)(void *), void *arg);
+void uw_pop_cleanup(uw_context);
void *uw_malloc(uw_context, size_t);
void uw_begin_region(uw_context);
@@ -38,29 +40,28 @@ char *uw_Basis_htmlifyFloat(uw_context, uw_Basis_float);
char *uw_Basis_htmlifyString(uw_context, uw_Basis_string);
char *uw_Basis_htmlifyBool(uw_context, uw_Basis_bool);
-void uw_Basis_htmlifyInt_w(uw_context, uw_Basis_int);
-void uw_Basis_htmlifyFloat_w(uw_context, uw_Basis_float);
-void uw_Basis_htmlifyString_w(uw_context, uw_Basis_string);
-void uw_Basis_htmlifyBool_w(uw_context, uw_Basis_bool);
+uw_unit uw_Basis_htmlifyInt_w(uw_context, uw_Basis_int);
+uw_unit uw_Basis_htmlifyFloat_w(uw_context, uw_Basis_float);
+uw_unit uw_Basis_htmlifyString_w(uw_context, uw_Basis_string);
+uw_unit uw_Basis_htmlifyBool_w(uw_context, uw_Basis_bool);
char *uw_Basis_attrifyInt(uw_context, uw_Basis_int);
char *uw_Basis_attrifyFloat(uw_context, uw_Basis_float);
char *uw_Basis_attrifyString(uw_context, uw_Basis_string);
-void uw_Basis_attrifyInt_w(uw_context, uw_Basis_int);
-void uw_Basis_attrifyFloat_w(uw_context, uw_Basis_float);
-void uw_Basis_attrifyString_w(uw_context, uw_Basis_string);
-
+uw_unit uw_Basis_attrifyInt_w(uw_context, uw_Basis_int);
+uw_unit uw_Basis_attrifyFloat_w(uw_context, uw_Basis_float);
+uw_unit uw_Basis_attrifyString_w(uw_context, uw_Basis_string);
char *uw_Basis_urlifyInt(uw_context, uw_Basis_int);
char *uw_Basis_urlifyFloat(uw_context, uw_Basis_float);
char *uw_Basis_urlifyString(uw_context, uw_Basis_string);
char *uw_Basis_urlifyBool(uw_context, uw_Basis_bool);
-void uw_Basis_urlifyInt_w(uw_context, uw_Basis_int);
-void uw_Basis_urlifyFloat_w(uw_context, uw_Basis_float);
-void uw_Basis_urlifyString_w(uw_context, uw_Basis_string);
-void uw_Basis_urlifyBool_w(uw_context, uw_Basis_bool);
+uw_unit uw_Basis_urlifyInt_w(uw_context, uw_Basis_int);
+uw_unit uw_Basis_urlifyFloat_w(uw_context, uw_Basis_float);
+uw_unit uw_Basis_urlifyString_w(uw_context, uw_Basis_string);
+uw_unit uw_Basis_urlifyBool_w(uw_context, uw_Basis_bool);
uw_Basis_int uw_Basis_unurlifyInt(uw_context, char **);
uw_Basis_float uw_Basis_unurlifyFloat(uw_context, char **);
diff --git a/src/c/urweb.c b/src/c/urweb.c
index d4fd1844..039ba119 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -15,6 +15,11 @@ typedef struct regions {
struct regions *next;
} regions;
+typedef struct {
+ void (*func)(void*);
+ void *arg;
+} cleanup;
+
struct uw_context {
char *page, *page_front, *page_back;
char *heap, *heap_front, *heap_back;
@@ -26,6 +31,8 @@ struct uw_context {
regions *regions;
+ cleanup *cleanup, *cleanup_front, *cleanup_back;
+
char error_message[ERROR_BUF_LEN];
};
@@ -46,6 +53,8 @@ uw_context uw_init(size_t page_len, size_t heap_len) {
ctx->regions = NULL;
+ ctx->cleanup_front = ctx->cleanup_back = ctx->cleanup = malloc(0);
+
ctx->error_message[0] = 0;
return ctx;
@@ -63,6 +72,7 @@ void uw_free(uw_context ctx) {
free(ctx->page);
free(ctx->heap);
free(ctx->inputs);
+ free(ctx->cleanup);
free(ctx);
}
@@ -70,6 +80,7 @@ void uw_reset_keep_request(uw_context ctx) {
ctx->page_front = ctx->page;
ctx->heap_front = ctx->heap;
ctx->regions = NULL;
+ ctx->cleanup_front = ctx->cleanup;
ctx->error_message[0] = 0;
}
@@ -78,6 +89,7 @@ void uw_reset_keep_error_message(uw_context ctx) {
ctx->page_front = ctx->page;
ctx->heap_front = ctx->heap;
ctx->regions = NULL;
+ ctx->cleanup_front = ctx->cleanup;
}
void uw_reset(uw_context ctx) {
@@ -107,14 +119,46 @@ failure_kind uw_begin(uw_context ctx, char *path) {
}
__attribute__((noreturn)) void uw_error(uw_context ctx, failure_kind fk, const char *fmt, ...) {
+ cleanup *cl;
+
va_list ap;
va_start(ap, fmt);
vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap);
+ for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
+ cl->func(cl->arg);
+
+ ctx->cleanup_front = ctx->cleanup;
+
longjmp(ctx->jmp_buf, fk);
}
+void uw_push_cleanup(uw_context ctx, void (*func)(void *), void *arg) {
+ if (ctx->cleanup_front >= ctx->cleanup_back) {
+ int len = ctx->cleanup_back - ctx->cleanup, newLen;
+ if (len == 0)
+ newLen = 1;
+ else
+ newLen *= 2;
+ ctx->cleanup = realloc(ctx->cleanup, newLen);
+ ctx->cleanup_front = ctx->cleanup + len;
+ ctx->cleanup_back = ctx->cleanup + newLen;
+ }
+
+ ctx->cleanup_front->func = func;
+ ctx->cleanup_front->arg = arg;
+ ++ctx->cleanup_front;
+}
+
+void uw_pop_cleanup(uw_context ctx) {
+ if (ctx->cleanup_front == ctx->cleanup)
+ uw_error(ctx, FATAL, "Attempt to pop from empty cleanup action stack");
+
+ --ctx->cleanup_front;
+ ctx->cleanup_front->func(ctx->cleanup_front->arg);
+}
+
char *uw_error_message(uw_context ctx) {
return ctx->error_message;
}
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 7d74376e..26f6149e 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -850,6 +850,8 @@ fun p_exp' par env (e, loc) =
string "uw_end_region(ctx);",
newline,
+ string "uw_push_cleanup(ctx, (void (*)(void *))PQclear, res);",
+ newline,
string "n = PQntuples(res);",
newline,
string "for (i = 0; i < n; ++i) {",
@@ -906,7 +908,7 @@ fun p_exp' par env (e, loc) =
string "}",
newline,
newline,
- string "PQclear(res);",
+ string "uw_pop_cleanup(ctx);",
newline,
if wontLeakAnything then
box [string "uw_end_region(ctx);",
diff --git a/tests/aborter2.ur b/tests/aborter2.ur
new file mode 100644
index 00000000..a7270ba1
--- /dev/null
+++ b/tests/aborter2.ur
@@ -0,0 +1,7 @@
+table t : { X : int }
+
+fun main () : transaction page =
+ v <- query (SELECT * FROM t)
+ (fn r (_ : int) => return (error <xml>Shot down!</xml>))
+ 0;
+ return <xml>Result: {[v]}</xml>
diff --git a/tests/aborter2.urp b/tests/aborter2.urp
new file mode 100644
index 00000000..edc6c7da
--- /dev/null
+++ b/tests/aborter2.urp
@@ -0,0 +1,5 @@
+debug
+database dbname=aborter
+sql aborter2.sql
+
+aborter2