Changeset: 44006041fccf for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=44006041fccf
Modified Files:
monetdb5/optimizer/opt_append.c
sql/backends/monet5/sql.c
Branch: copybinary
Log Message:
Let sql.append_prep handle multiple columns at once
diffs (273 lines):
diff --git a/monetdb5/optimizer/opt_append.c b/monetdb5/optimizer/opt_append.c
--- a/monetdb5/optimizer/opt_append.c
+++ b/monetdb5/optimizer/opt_append.c
@@ -14,13 +14,21 @@
#include "mal_builder.h"
#include "opt_append.h"
-static str transform(MalBlkPtr mb, InstrPtr importTable);
+typedef struct parstate {
+ InstrPtr prep_stmt;
+} parstate;
+
+static str transform(parstate *state, MalBlkPtr mb, InstrPtr importTable);
+static int setup_append_prep(parstate *state, MalBlkPtr mb, InstrPtr old);
+
str
OPTparappendImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr
pci)
{
str msg = MAL_SUCCEED;
InstrPtr *old_mb_stmt = NULL;
+ parstate state = { NULL };
+
(void)cntxt;
(void)mb;
(void)stk;
@@ -47,8 +55,11 @@ OPTparappendImplementation(Client cntxt,
for (int i = 0; i < old_stop; i++) {
InstrPtr p = old_mb_stmt[i];
if (p->modname == sqlRef && p->fcnname == appendRef &&
isaBatType(getArgType(mb, p, 5))) {
- msg = transform(mb, p);
- } else {
+ msg = transform(&state, mb, p);
+ } else {
+ if (mayhaveSideEffects(cntxt, mb, p, false)) {
+ state = (parstate) { NULL };
+ }
pushInstruction(mb, p);
}
if (msg != MAL_SUCCEED)
@@ -62,14 +73,11 @@ end:
}
static str
-transform(MalBlkPtr mb, InstrPtr old)
+transform(parstate *state, MalBlkPtr mb, InstrPtr old)
{
-
// take the old instruction apart
assert(old->retc == 1);
assert(old->argc == 1 + 5);
- int chain_out_var = getArg(old, 0);
- int chain_in_var = getArg(old, 1);
int sname_var = getArg(old, 2);
int tname_var = getArg(old, 3);
int cname_var = getArg(old, 4);
@@ -85,16 +93,8 @@ transform(MalBlkPtr mb, InstrPtr old)
return MAL_SUCCEED;
}
- int cookie_var = newTmpVariable(mb, TYPE_ptr);
- str append_prepRef = putName("append_prep");
- InstrPtr p = newFcnCall(mb, sqlRef, append_prepRef);
- setReturnArgument(p, chain_out_var);
- pushReturn(mb, p, cookie_var);
- pushArgument(mb, p, chain_in_var);
- pushArgument(mb, p, sname_var);
- pushArgument(mb, p, tname_var);
- pushArgument(mb, p, cname_var);
+ int cookie_var = setup_append_prep(state, mb, old);
str append_execRef = putName("append_exec");
InstrPtr e = newFcnCall(mb, sqlRef, append_execRef);
@@ -105,3 +105,84 @@ transform(MalBlkPtr mb, InstrPtr old)
return MAL_SUCCEED;
}
+
+static int
+setup_append_prep(parstate *state, MalBlkPtr mb, InstrPtr old)
+{
+ // take the old instruction apart
+ assert(old->retc == 1);
+ assert(old->argc == 1 + 5);
+ int chain_out_var = getArg(old, 0);
+ int chain_in_var = getArg(old, 1);
+ int sname_var = getArg(old, 2);
+ int tname_var = getArg(old, 3);
+ int cname_var = getArg(old, 4);
+
+ // check if the state refers to a sql.append_prep statement that can be
+ // reused.
+ InstrPtr prep_stmt = NULL;
+ do {
+ if (state->prep_stmt == NULL)
+ break;
+
+ InstrPtr prev = state->prep_stmt;
+
+ int existing_sname_var = getArg(prev, prev->retc + 1);
+ int existing_tname_var = getArg(prev, prev->retc + 2);
+
+ const char *existing_sname = getVarConstant(mb,
existing_sname_var).val.sval;
+ const char *incoming_sname = getVarConstant(mb,
sname_var).val.sval;
+ if (strcmp(existing_sname, incoming_sname) != 0)
+ break;
+
+ const char *existing_tname = getVarConstant(mb,
existing_tname_var).val.sval;
+ const char *incoming_tname = getVarConstant(mb,
tname_var).val.sval;
+ if (strcmp(existing_tname, incoming_tname) != 0)
+ break;
+
+ const char *incoming_cname = getVarConstant(mb,
cname_var).val.sval;
+ int existing_cols = prev->retc - 1;
+ for (int i = prev->argc - existing_cols; i < prev->argc; i++) {
+ int var = getArg(prev, i);
+ const char *existing_cname = getVarConstant(mb,
var).val.sval;
+ if (strcmp(existing_cname, incoming_cname) == 0) {
+ // We're not prepared for the complications
that may arise
+ // when there are multiple appends to the same
column.
+ // In particular we would have to track down
where the previous
+ // cookie is used and make sure we execute the
next append
+ // after that use.
+ // This is unlikely to occur in practice, so
instead we just start over.
+ break;
+ }
+ }
+
+ // It seems there is no objection to reusing the existing
sql.append_prep.
+ prep_stmt = prev;
+ } while (0);
+
+ int cookie_var = newTmpVariable(mb, TYPE_ptr);
+ if (prep_stmt == NULL) {
+ str append_prepRef = putName("append_prep");
+ InstrPtr p = newFcnCall(mb, sqlRef, append_prepRef);
+ setReturnArgument(p, chain_out_var);
+ pushReturn(mb, p, cookie_var);
+ pushArgument(mb, p, chain_in_var);
+ pushArgument(mb, p, sname_var);
+ pushArgument(mb, p, tname_var);
+ pushArgument(mb, p, cname_var);
+ state->prep_stmt = p;
+ } else {
+ // Append to existing first, to ensure there is room
+ pushArgument(mb, prep_stmt, cname_var);
+ pushArgument(mb, prep_stmt, cookie_var);
+ // Now move the cookie_var to its proper location
+ for (int i = prep_stmt->argc - 1; i > prep_stmt->retc; i--)
+ setArg(prep_stmt, i, getArg(prep_stmt, i - 1));
+ setArg(prep_stmt, prep_stmt->retc, cookie_var);
+ prep_stmt->retc += 1;
+ // Always use the chain_out of the latest sql_append:
+ setArg(prep_stmt, 0, chain_out_var);
+ }
+
+ return cookie_var;
+}
diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c
--- a/sql/backends/monet5/sql.c
+++ b/sql/backends/monet5/sql.c
@@ -1764,34 +1764,34 @@ mvc_append_bat_wrap(Client cntxt, MalBlk
return MAL_SUCCEED;
}
-// tmp_1, cookie_1 := sql.append_prep(chain_0, s, t, c_1);
+// chain_out, cookie_1, ..., cookie_N := sql.append_prep(chain_in, s, t, c_1,
... c_N);
str
mvc_append_prep_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
int *chain_out = getArgReference_int(stk, pci, 0);
- ptr *cookie_out = getArgReference_ptr(stk, pci, 1);
- int chain_in = *getArgReference_int(stk, pci, 2);
+ int chain_in = *getArgReference_int(stk, pci, pci->retc);
mvc *m = NULL;
str msg;
- const char *sname = *getArgReference_str(stk, pci, 3);
- const char *tname = *getArgReference_str(stk, pci, 4);
- const char *cname = *getArgReference_str(stk, pci, 5);
+ const char *sname = *getArgReference_str(stk, pci, pci->retc + 1);
+ const char *tname = *getArgReference_str(stk, pci, pci->retc + 2);
sql_schema *s;
sql_table *t;
sql_column *c;
+ // for N columns, we ought to have N + 1 return values and N + 3
parameters.
+ int first_col = pci->retc + 3;
+ int first_ret = 1;
+ int ncolumns = pci->retc - first_ret;
+ if (pci->argc - first_col != ncolumns)
+ throw(SQL, "sql.append_prep",
+ SQLSTATE(42000) "sql.append_prep inconsistent argument
count argc=%d retc=%d", pci->argc, pci->retc);
+
*chain_out = chain_in;
- *cookie_out = NULL;
if (strNil(sname))
- throw(SQL, "sql.append_bat", SQLSTATE(42000) "sql.append_bat
schema name is nil");
+ throw(SQL, "sql.append_prep", SQLSTATE(42000) "schema name is
nil");
if (strNil(tname))
- throw(SQL, "sql.append_bat", SQLSTATE(42000) "sql.append_bat
table name is nil");
- if (strNil(cname))
- throw(SQL, "sql.append_bat", SQLSTATE(42000) "sql.append_bat
column name is nil");
-
- if (cname[0] == '%')
- throw(SQL, "sql.append_bat", SQLSTATE(42000) "sql.append_bat
not intended for indices: %s.%s.%s", sname, tname, cname);
+ throw(SQL, "sql.append_prep", SQLSTATE(42000) "table name is
nil");
if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
return msg;
@@ -1799,17 +1799,29 @@ mvc_append_prep_wrap(Client cntxt, MalBl
return msg;
s = mvc_bind_schema(m, sname);
if (s == NULL)
- throw(SQL, "sql.append_bat", SQLSTATE(3F000) "Schema missing
%s", sname);
+ throw(SQL, "sql.append_prep", SQLSTATE(3F000) "Schema missing
%s", sname);
t = mvc_bind_table(m, s, tname);
if (t == NULL)
- throw(SQL, "sql.append_bat", SQLSTATE(42S02) "Table missing
%s.%s", sname, tname);
- c = mvc_bind_column(m, t, cname);
- if (c == NULL)
- throw(SQL, "sql.append_bat", SQLSTATE(42S02) "Column missing
%s.%s.%s", sname, tname, cname);
-
- void *cookie = store_funcs.append_col_prep(m->session->tr, c);
-
- *cookie_out = cookie;
+ throw(SQL, "sql.append_prep", SQLSTATE(42S02) "Table missing
%s.%s", sname, tname);
+
+ for (int i = 0; i < ncolumns; i++) {
+ const char *cname = *getArgReference_str(stk, pci, first_col +
i);
+ ptr *cookie_out = getArgReference_ptr(stk, pci, first_ret + i);
+
+ if (strNil(cname))
+ throw(SQL, "sql.append_prep", SQLSTATE(42000) "column
name %d is nil", i);
+ if (cname[0] == '%')
+ throw(SQL, "sql.append_prep", SQLSTATE(42000)
"sql.append_prep not intended for indices: %s.%s.%s", sname, tname, cname);
+
+ c = mvc_bind_column(m, t, cname);
+ if (c == NULL)
+ throw(SQL, "sql.append_prep", SQLSTATE(42S02) "Column
missing %s.%s.%s", sname, tname, cname);
+
+ void *cookie = store_funcs.append_col_prep(m->session->tr, c);
+
+ *cookie_out = cookie;
+ }
+
return MAL_SUCCEED;
}
@@ -5392,7 +5404,10 @@ static mel_func sql_init_funcs[] = {
pattern("sql", "grow", mvc_grow_wrap, false, "Resize the tid column of a
declared table.", args(1,3, arg("",int),batarg("tid",oid),argany("",1))),
- pattern("sql", "append", mvc_append_wrap, false, "Append to the column
tname.cname (possibly optimized to replace the insert bat of tname.cname.
Returns sequence number for order dependence.", args(1,6,
arg("",int),arg("mvc",int),arg("sname",str),arg("tname",str),arg("cname",str),argany("ins",0))),
+ pattern("sql", "append", mvc_append_wrap, false, "Append to the column
tname.cname (possibly optimized to replace the insert bat of tname.cname.
Returns sequence number for order dependence.",
+ args(1,6,
+ arg("",int),
+
arg("mvc",int),arg("sname",str),arg("tname",str),arg("cname",str),argany("ins",0))),
pattern("sql", "append_bat", mvc_append_bat_wrap, false, "Append to the
column tname.cname (possibly optimized to replace the insert bat of
tname.cname. Returns sequence number for order dependence.",
args(1,6,
arg("",int),arg("mvc",int),arg("sname",str),arg("tname",str),arg("cname",str),batargany("ins",1))),
@@ -5400,8 +5415,8 @@ static mel_func sql_init_funcs[] = {
pattern("sql", "append_prep", mvc_append_prep_wrap, false,
"Prepare to append to the column. Return new mvc state and cookie to
pass to append_exec",
args(2,6,
- arg("",int),arg("",ptr),
-
arg("mvc",int),arg("sname",str),arg("tname",str),arg("cname",str))),
+ arg("",int),vararg("",ptr),
+
arg("mvc",int),arg("sname",str),arg("tname",str),vararg("cname",str))),
pattern("sql", "append_exec", mvc_append_exec_wrap, false, "Perform the
actual append",
args(1,3,
arg("",void),
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list