Changeset: 461c8f779f19 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/461c8f779f19
Modified Files:
sql/backends/monet5/UDF/pyapi3/Tests/pyloader3_01.test
sql/backends/monet5/rel_bin.c
sql/backends/monet5/sql_cat.c
sql/backends/monet5/sql_gencode.c
sql/backends/monet5/sql_gencode.h
sql/backends/monet5/sql_statement.c
sql/backends/monet5/sql_statement.h
sql/backends/monet5/sql_upgrades.c
sql/backends/monet5/sql_user.c
sql/common/sql_types.c
sql/common/sql_types.h
sql/include/sql_catalog.h
sql/server/rel_dump.c
sql/server/rel_exp.c
sql/server/rel_optimizer.c
sql/server/rel_psm.c
sql/server/sql_env.c
sql/server/sql_qc.c
sql/storage/store.c
sql/test/miscellaneous/Tests/select_groupby.stable.err
Branch: sqlfuncfix
Log Message:
Started function backend gencode cleanup. SQL and MAL functions require
instantiation before they can be used. Make sure a function is instantiated
before using the obtained MAL module and function names
diffs (truncated from 930 to 300 lines):
diff --git a/sql/backends/monet5/UDF/pyapi3/Tests/pyloader3_01.test
b/sql/backends/monet5/UDF/pyapi3/Tests/pyloader3_01.test
--- a/sql/backends/monet5/UDF/pyapi3/Tests/pyloader3_01.test
+++ b/sql/backends/monet5/UDF/pyapi3/Tests/pyloader3_01.test
@@ -29,7 +29,7 @@ SELECT name,func,mod,language,type,side_
----
myfunc
{@@_emit.emit({'a':42,'d':1})@}@;
-pyapi
+pyapi3
6
7
True
diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c
--- a/sql/backends/monet5/rel_bin.c
+++ b/sql/backends/monet5/rel_bin.c
@@ -1241,7 +1241,13 @@ exp_bin(backend *be, sql_exp *e, stmt *l
list *l = sa_list(sql->sa), *exps = e->l;
sql_subfunc *f = e->f;
stmt *rows = NULL;
- int push_cands = can_push_cands(sel, f);
+ const char *mod, *fimp;
+
+ /* attempt to instantiate nosql functions now, so we can know
if we can push candidate lists */
+ if (f->func->lang == FUNC_LANG_MAL &&
backend_create_mal_func(be->mvc, f->func) < 0)
+ return NULL;
+ mod = sql_func_mod(f->func);
+ fimp = sql_func_imp(f->func);
if (f->func->side_effect && left && left->nrcols > 0) {
sql_subfunc *f1 = NULL;
@@ -1258,17 +1264,19 @@ exp_bin(backend *be, sql_exp *e, stmt *l
sql->errstr[0] = '\0';
}
assert(!e->r);
- if (strcmp(sql_func_mod(f->func), "") == 0 &&
strcmp(sql_func_imp(f->func), "") == 0 && strcmp(f->func->base.name, "star") ==
0)
- return left->op4.lval->h->data;
- else if (!list_empty(exps)) {
+ if (strcmp(mod, "") == 0 && strcmp(fimp, "") == 0) {
+ if (strcmp(f->func->base.name, "star") == 0)
+ return left->op4.lval->h->data;
+ if (strcmp(f->func->base.name, "case") == 0)
+ return exp2bin_case(be, e, left, right, sel,
depth);
+ if (strcmp(f->func->base.name, "casewhen") == 0)
+ return exp2bin_casewhen(be, e, left, right,
sel, depth);
+ if (strcmp(f->func->base.name, "coalesce") == 0)
+ return exp2bin_coalesce(be, e, left, right,
sel, depth);
+ }
+ if (!list_empty(exps)) {
unsigned nrcols = 0;
-
- if (strcmp(sql_func_mod(f->func), "") == 0 &&
strcmp(sql_func_imp(f->func), "") == 0 && strcmp(f->func->base.name, "case") ==
0)
- return exp2bin_case(be, e, left, right, sel,
depth);
- if (strcmp(sql_func_mod(f->func), "") == 0 &&
strcmp(sql_func_imp(f->func), "") == 0 && strcmp(f->func->base.name,
"casewhen") == 0)
- return exp2bin_casewhen(be, e, left, right,
sel, depth);
- if (strcmp(sql_func_mod(f->func), "") == 0 &&
strcmp(sql_func_imp(f->func), "") == 0 && strcmp(f->func->base.name,
"coalesce") == 0)
- return exp2bin_coalesce(be, e, left, right,
sel, depth);
+ int push_cands = can_push_cands(sel, mod, fimp);
assert(list_length(exps) == list_length(f->func->ops)
|| f->func->type == F_ANALYTIC || f->func->type == F_LOADER || f->func->vararg
|| f->func->varres);
for (en = exps->h; en; en = en->next) {
@@ -2119,12 +2127,12 @@ rel2bin_table(backend *be, sql_rel *rel,
else
getArg(q, 0) =
newTmpVariable(be->mb, type);
}
+ if (backend_create_func(be, f->func,
NULL, ops) < 0)
+ return NULL;
str mod = sql_func_mod(f->func);
str fcn = sql_func_imp(f->func);
q = pushStr(be->mb, q, mod);
q = pushStr(be->mb, q, fcn);
- if (backend_create_func(be, f->func,
NULL, ops) < 0)
- return NULL;
psub = stmt_direct_func(be, q);
if (ids) /* push input rowids column */
diff --git a/sql/backends/monet5/sql_cat.c b/sql/backends/monet5/sql_cat.c
--- a/sql/backends/monet5/sql_cat.c
+++ b/sql/backends/monet5/sql_cat.c
@@ -957,7 +957,6 @@ create_func(mvc *sql, char *sname, char
sql_func *nf;
sql_subfunc *sf;
sql_schema *s = NULL;
- int clientid = sql->clientid;
char *F = NULL, *fn = NULL, *base = replace ? "CREATE OR REPLACE" :
"CREATE";
FUNC_TYPE_STR(f->type, F, fn)
@@ -967,8 +966,6 @@ create_func(mvc *sql, char *sname, char
throw(SQL,"sql.create_func", SQLSTATE(3F000) "%s %s: no such
schema '%s'", base, F, sname);
if (!mvc_schema_privs(sql, s))
throw(SQL,"sql.create_func", SQLSTATE(42000) "%s %s: access
denied for %s to schema '%s'", base, F, get_string_global_var(sql,
"current_user"), s->base.name);
- if (strlen(fname) >= IDLENGTH)
- throw(SQL,"sql.create_func", SQLSTATE(42000) "%s %s: name '%s'
too large for the backend", base, F, fname);
if (replace) {
list *tl = sa_list(sql->sa);
@@ -982,24 +979,14 @@ create_func(mvc *sql, char *sname, char
if ((sf = sql_bind_func_(sql, s->base.name, fname, tl,
f->type)) != NULL) {
sql_func *sff = sf->func;
- bool backend_ok = true;
char *fimp = NULL;
if (!sff->s || sff->system)
throw(SQL,"sql.create_func", SQLSTATE(42000)
"%s %s: not allowed to replace system %s %s;", base, F, fn, sff->base.name);
- if (sff->lang == FUNC_LANG_MAL &&
mal_function_find_implementation_address(&fimp, sql, sff) < 0) {
- backend_ok = false;
- sql->session->status = 0; /* clean the error */
- sql->errstr[0] = '\0';
- }
-
/* if all function parameters are the same, return */
- if (backend_ok && sff->lang == f->lang && sff->type ==
f->type &&
+ if (sff->lang == f->lang && sff->type == f->type &&
sff->varres == f->varres && sff->vararg ==
f->vararg &&
- strcmp(sff->s->base.name, s->base.name) == 0 &&
- ((!sff->mod && !f->mod) || (sff->mod && f->mod
&& strcmp(sff->mod, f->mod) == 0)) &&
- (sff->lang != FUNC_LANG_MAL || strcmp(fimp,
f->imp) == 0) &&
((!sff->query && !f->query) || (sff->query &&
f->query && strcmp(sff->query, f->query) == 0)) &&
list_cmp(sff->res, f->res, (fcmp) &args_cmp) ==
0 &&
list_cmp(sff->ops, f->ops, (fcmp) &args_cmp) ==
0) {
@@ -1035,18 +1022,24 @@ create_func(mvc *sql, char *sname, char
break;
}
switch (nf->lang) {
- case FUNC_LANG_INT:
- case FUNC_LANG_MAL: /* shouldn't be reachable, but leave it here */
- if (!backend_resolve_function(&clientid, nf))
- throw(SQL,"sql.create_func", SQLSTATE(3F000) "%s %s:
external name %s.%s not bound", base, F, nf->mod, nf->base.name);
- if (nf->query == NULL)
- break;
+ case FUNC_LANG_MAL:
+ /* instantiate MAL functions while being created */
+ if (backend_create_mal_func(sql, nf) < 0) {
+ if (strlen(sql->errstr) > 6 && sql->errstr[5] == '!')
+ throw(SQL, "sql.create_func", "%s",
sql->errstr);
+ else
+ throw(SQL, "sql.create_func", SQLSTATE(42000)
"%s", sql->errstr);
+ }
/* fall through */
case FUNC_LANG_SQL: {
char *buf;
sql_rel *r = NULL;
sql_allocator *sa = sql->sa;
+ /* for sql functions, this check is necessary here */
+ if (nf->lang == FUNC_LANG_SQL && strlen(fname) >= IDLENGTH)
+ throw(SQL,"sql.create_func", SQLSTATE(42000) "%s %s:
name '%s' too large for the backend", base, F, fname);
+
assert(nf->query);
if (!(sql->sa = sa_create(sql->pa))) {
sql->sa = sa;
diff --git a/sql/backends/monet5/sql_gencode.c
b/sql/backends/monet5/sql_gencode.c
--- a/sql/backends/monet5/sql_gencode.c
+++ b/sql/backends/monet5/sql_gencode.c
@@ -954,7 +954,7 @@ monet5_resolve_function(ptr M, sql_func
Client c;
Module m;
int clientID = *(int*) M;
- const char *mname = putName(f->mod), *fname = putName(f->imp);
+ const char *mname = putName(sql_func_mod(f)), *fname =
putName(sql_func_imp(f));
if (!mname || !fname)
return 0;
@@ -1016,95 +1016,9 @@ monet5_resolve_function(ptr M, sql_func
return 0;
}
-static int
-backend_create_r_func(backend *be, sql_func *f)
-{
- (void)be;
- _DELETE(f->mod);
- _DELETE(f->imp);
- f->mod = GDKstrdup("rapi");
- switch(f->type) {
- case F_AGGR:
- f->imp = GDKstrdup("eval_aggr");
- break;
- case F_PROC: /* no output */
- case F_FUNC:
- default: /* ie also F_FILT and F_UNION for now */
- f->imp = GDKstrdup("eval");
- break;
- }
- return 0;
-}
-
-/* Create the MAL block for a registered function and optimize it */
-static int
-backend_create_py_func(backend *be, sql_func *f)
-{
- (void)be;
- _DELETE(f->mod);
- _DELETE(f->imp);
- f->mod = GDKstrdup("pyapi3");
- switch(f->type) {
- case F_AGGR:
- f->imp = GDKstrdup("eval_aggr");
- break;
- case F_LOADER:
- f->imp = GDKstrdup("eval_loader");
- break;
- case F_PROC: /* no output */
- case F_FUNC:
- default: /* ie also F_FILT and F_UNION for now */
- f->imp = GDKstrdup("eval");
- break;
- }
- return 0;
-}
-
+/* Parse the SQL query from the function, and extract the MAL function from
the generated abstract syntax tree */
static int
-backend_create_map_py_func(backend *be, sql_func *f)
-{
- (void)be;
- _DELETE(f->mod);
- _DELETE(f->imp);
- f->mod = GDKstrdup("pyapi3map");
- switch(f->type) {
- case F_AGGR:
- f->imp = GDKstrdup("eval_aggr");
- break;
- case F_PROC: /* no output */
- case F_FUNC:
- default: /* ie also F_FILT and F_UNION for now */
- f->imp = GDKstrdup("eval");
- break;
- }
- return 0;
-}
-
-/* Create the MAL block for a registered function and optimize it */
-static int
-backend_create_c_func(backend *be, sql_func *f)
-{
- (void)be;
- _DELETE(f->mod);
- _DELETE(f->imp);
- f->mod = GDKstrdup("capi");
- switch(f->type) {
- case F_AGGR:
- f->imp = GDKstrdup("eval_aggr");
- break;
- case F_LOADER:
- case F_PROC: /* no output */
- case F_FUNC:
- default: /* ie also F_FILT and F_UNION for now */
- f->imp = GDKstrdup("eval");
- break;
- }
- return 0;
-}
-
-/* Parse the SQL query from the function, and extract the MAL function from
the generated abstract syntax tree */
-int
-mal_function_find_implementation_address(str *res, mvc *m, sql_func *f)
+mal_function_find_implementation_address(mvc *m, sql_func *f)
{
mvc o = *m;
buffer *b = NULL;
@@ -1152,7 +1066,12 @@ mal_function_find_implementation_address
} else {
l = m->sym->data.lval;
ext_name = l->h->next->next->next->data.lval;
- if (!(*res = _STRDUP(qname_schema_object(ext_name)))) /* found
the implementation, set it */
+ const char *imp = qname_schema_object(ext_name);
+
+ assert(!f->imp);
+ if (strlen(imp) >= IDLENGTH)
+ (void) sql_error(m, 02, SQLSTATE(42000) "MAL function
name '%s' too large for the backend", imp);
+ else if (!(f->imp = _STRDUP(imp))) /* found the implementation,
set it */
(void) sql_error(m, 02, SQLSTATE(HY013)
MAL_MALLOC_FAIL);
}
@@ -1179,6 +1098,27 @@ mal_function_find_implementation_address
return m->errstr[0] == '\0' ? 0 : -1; /* m was set back to o */
}
+int
+backend_create_mal_func(mvc *m, sql_func *f)
+{
+ if (!f->instantiated) {
+ if (strlen(f->mod) >= IDLENGTH) {
+ (void) sql_error(m, 01, SQLSTATE(42000) "MAL module
name '%s' too large for the backend", f->mod);
+ return -1;
+ }
+ if (mal_function_find_implementation_address(m, f) < 0)
+ return -1;
+ if (!backend_resolve_function(&(m->clientid), f)) {
+ (void) sql_error(m, 02, SQLSTATE(3F000) "MAL external
name %s.%s not bound (%s.%s)", f->mod, f->imp, f->s->base.name, f->base.name);
+ _DELETE(f->imp);
+ f->imp = NULL;
+ return -1;
+ }
+ f->instantiated = TRUE;
+ }
+ return 0;
+}
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list