Changeset: ef5d870af9d2 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=ef5d870af9d2
Modified Files:
        sql/backends/monet5/sql_gencode.c
        sql/test/BugTracker-2012/Tests/create_function.Bug-3172.sql
        sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.err
        sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.out
        
sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.sql
        
sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.stable.err
Branch: Apr2019
Log Message:

Check for backend of SQL function defined in MAL at runtime, when the function 
first gets compiled

This happens once per client connection, so the performance penalty it's not 
large.
The "imp" field of a MAL function is not set in load_func in store.c. So 
determine it during compilation.
Also check for authentication at "monet5_resolve_function".


diffs (245 lines):

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
@@ -838,7 +838,7 @@ backend_call(backend *be, Client c, cq *
                        sql_subtype *pt = cq->params + i;
 
                        if (!atom_cast(m->sa, a, pt)) {
-                               sql_error(m, 003, SQLSTATE(42000) "wrong type 
for argument %d of " "function call: %s, expected %s\n", i + 1, 
atom_type(a)->type->sqlname, pt->type->sqlname);
+                               sql_error(m, 003, SQLSTATE(42000) "wrong type 
for argument %d of function call: %s, expected %s\n", i + 1, 
atom_type(a)->type->sqlname, pt->type->sqlname);
                                break;
                        }
                        if (atom_null(a)) {
@@ -860,31 +860,33 @@ backend_call(backend *be, Client c, cq *
 int
 monet5_resolve_function(ptr M, sql_func *f)
 {
+       Client c;
+       Module m;
+       mvc *sql = (mvc *) M;
        str mname = getName(f->mod), fname = getName(f->imp);
-       (void) M;
 
        if (!mname || !fname)
                return 0;
 
-       for (Module m = getModule(mname); m; m = m->link) {
+       /* Some SQL functions MAL mapping such as count(*) aggregate, the 
number or arguments don't match */
+       if (mname == calcRef && fname == getName("="))
+               return 1;
+       if (mname == aggrRef && fname == countRef)
+               return 1;
+       if (mname == sqlRef && (fname == first_valueRef || fname ==  minRef || 
fname == maxRef))
+               return 1;
+
+       c = MCgetClient(sql->clientid);
+       for (m = findModule(c->usermodule, mname); m; m = m->link) {
                for (Symbol s = findSymbolInModule(m, fname); s; s = s->peer) {
                        InstrPtr sig = getSignature(s);
-                       int argc = sig->argc - sig->retc;
+                       int argc = sig->argc - sig->retc, fargs = 
list_length(f->ops);
 
-                       if ((!f->ops && argc == 0) || list_length(f->ops) == 
argc || (sig->varargs & VARARGS) == VARARGS)
+                       if (fargs == argc || (sig->varargs & VARARGS) == 
VARARGS)
                                return 1;
                }
        }
        return 0;
-/*
-       node *n;
-       newFcnCall(f->mod, f->imp);
-       for (n = f->ops->h; n; n = n->next) {
-               sql_arg *a = n->data;
-
-               q = push ?type? (mb, q, a->);
-       }
-*/
 }
 
 static int
@@ -1020,6 +1022,83 @@ backend_create_c_func(backend *be, sql_f
        return 0;
 }
 
+/* Parse the SQL query from the function, and extract the MAL function from 
the generated abstract syntax tree */
+static int
+mal_function_find_implementation_address(mvc *m, sql_func *f)
+{
+       mvc *o = m;
+       buffer *b = NULL;
+       bstream *bs = NULL;
+       stream *buf = NULL;
+       char *n = NULL;
+       int len = _strlen(f->query);
+       sql_schema *s = cur_schema(m);
+       dlist *l, *ext_name;
+
+       if (!(m = ZNEW(mvc))) {
+               (void) sql_error(o, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
+               goto bailout;
+       }
+       m->type = Q_PARSE;
+       m->user_id = m->role_id = USER_MONETDB;
+
+       if (!(m->session = sql_session_create(0, 0))) {
+               (void) sql_error(o, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
+               goto bailout;
+       }
+       if (s)
+               m->session->schema = s;
+
+       if (!(m->sa = sa_create())) {
+               (void) sql_error(o, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
+               goto bailout;
+       }
+       if (!(b = (buffer*)GDKmalloc(sizeof(buffer)))) {
+               (void) sql_error(o, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
+               goto bailout;
+       }
+       if (!(n = GDKmalloc(len + 2))) {
+               (void) sql_error(o, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
+               goto bailout;
+       }
+       snprintf(n, len + 2, "%s\n", f->query);
+       len++;
+       buffer_init(b, n, len);
+       if (!(buf = buffer_rastream(b, "sqlstatement"))) {
+               (void) sql_error(o, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
+               goto bailout;
+       }
+       if (!(bs = bstream_create(buf, b->len))) {
+               (void) sql_error(o, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
+               goto bailout;
+       }
+       scanner_init(&m->scanner, bs, NULL);
+       m->scanner.mode = LINE_1; 
+       bstream_next(m->scanner.rs);
+
+       (void) sqlparse(m); /* blindly ignore errors */
+       assert(m->sym->token == SQL_CREATE_FUNC);
+       l = m->sym->data.lval;
+       ext_name = l->h->next->next->next->data.lval;
+       f->imp = sa_strdup(f->sa, qname_fname(ext_name)); /* found the 
implementation, set it */
+
+bailout:
+       if (m) {
+               bstream_destroy(m->scanner.rs);
+               if (m->session)
+                       sql_session_destroy(m->session); 
+               if (m->sa)
+                       sa_destroy(m->sa);
+               _DELETE(m);
+       }
+       m = o;
+       if (n)
+               GDKfree(n);
+       if (b)
+               GDKfree(b);
+       return m->errstr[0] == '\0'; /* m was set back to o */
+}
+
 static int
 backend_create_sql_func(backend *be, sql_func *f, list *restypes, list *ops)
 {
@@ -1031,7 +1110,18 @@ backend_create_sql_func(backend *be, sql
        int i, retseen = 0, sideeffects = 0, vararg = (f->varres || f->vararg), 
no_inline = 0;
        sql_rel *r;
 
-       /* nothing to do for internal and ready (not recompiling) functions */
+       /* nothing to do for internal and ready (not recompiling) functions, 
besides finding respective MAL implementation */
+       if (!f->sql && (f->lang == FUNC_LANG_INT || f->lang == FUNC_LANG_MAL)) {
+               if (f->lang == FUNC_LANG_MAL && !f->imp && 
!mal_function_find_implementation_address(m, f))
+                       return -1;
+               if (!backend_resolve_function(be->mvc, f)) {
+                       if (f->lang == FUNC_LANG_INT)
+                               (void) sql_error(m, 02, SQLSTATE(HY005) 
"Implementation for function %s.%s not found", f->mod, f->imp);
+                       else
+                               (void) sql_error(m, 02, SQLSTATE(HY005) 
"Implementation for function %s.%s not found (%s.%s)", f->mod, f->imp, 
f->s->base.name, f->base.name);
+                       return -1;
+               }
+       }
        if (!f->sql || (!vararg && f->sql > 1))
                return 0;
        if (!vararg)
diff --git a/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.sql 
b/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.sql
--- a/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.sql
+++ b/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.sql
@@ -1,5 +1,6 @@
-create function x(a int, b int) 
-  returns table (c int,d int)
-  external name sql.x;
+create function x(a int, b int) returns table (c int,d int) external name 
sql.x; --error, sql.x doesn't exist
 
+start transaction;
+create function x(a int, b int) returns table (c int,d int) begin return 
select a, b; end;
 select * from x((select id from _tables), (select schema_id from _tables));
+rollback;
diff --git a/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.err 
b/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.err
--- a/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.err
+++ b/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.err
@@ -29,7 +29,11 @@ stderr of test 'create_function.Bug-3172
 # 16:07:20 >  "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e" 
"--host=/var/tmp/mtest-27661" "--port=38365"
 # 16:07:20 >  
 
-MAPI  = (monetdb) /var/tmp/mtest-27483/.s.monetdb.35395
+MAPI  = (monetdb) /var/tmp/mtest-23748/.s.monetdb.37404
+QUERY = create function x(a int, b int) returns table (c int,d int) external 
name sql.x; --error, sql.x doesn't exist
+ERROR = !CREATE FUNCTION: external name sql.x not bound (sys.x)
+CODE  = 3F000
+MAPI  = (monetdb) /var/tmp/mtest-23748/.s.monetdb.37404
 QUERY = select * from x((select id from _tables), (select schema_id from 
_tables));
 ERROR = !SELECT: 'x' requires a single sub query
 CODE  = 42000
diff --git a/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.out 
b/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.out
--- a/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.out
+++ b/sql/test/BugTracker-2012/Tests/create_function.Bug-3172.stable.out
@@ -15,10 +15,6 @@ stdout of test 'create_function.Bug-3172
 # Visit http://www.monetdb.org/ for further information
 # Listening for connection requests on mapi:monetdb://lodz.ins.cwi.nl:38620/
 # MonetDB/GIS module loaded
-# MonetDB/JAQL module loaded
-# MonetDB/SQL module loaded
-
-Ready.
 # SQL catalog created, loading sql scripts once
 # loading sql script: 09_like.sql
 # loading sql script: 10_math.sql
@@ -41,6 +37,9 @@ Ready.
 # loading sql script: 40_geom.sql
 # loading sql script: 80_udf.sql
 # loading sql script: 99_system.sql
+# MonetDB/SQL module loaded
+
+Ready.
 
 # 13:24:28 >  
 # 13:24:28 >  "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e" "--host=lodz" 
"--port=38620"
diff --git 
a/sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.sql
 
b/sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.sql
--- 
a/sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.sql
+++ 
b/sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.sql
@@ -1,7 +1,6 @@
+create function x(a int, b int) returns table (c int,d int) external name 
sql.x; --error, sql.x doesn't exist
 
 start transaction;
-create function x(a int, b int) 
-  returns table (c int,d int)
-  external name sql.x;
+create function x(a int, b int) returns table (c int,d int) begin return 
select a, b; end;
 select * from x((select id from _tables), (select schema_id from _tables));
 rollback;
diff --git 
a/sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.stable.err
 
b/sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.stable.err
--- 
a/sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.stable.err
+++ 
b/sql/test/BugTracker-2012/Tests/table_function_with_column_subselects.Bug-3172.stable.err
@@ -27,7 +27,11 @@ stderr of test 'table_function_with_colu
 # 13:48:49 >  "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e" "--host=niels" 
"--port=32735"
 # 13:48:49 >  
 
-MAPI  = (monetdb) /var/tmp/mtest-27483/.s.monetdb.35395
+MAPI  = (monetdb) /var/tmp/mtest-23419/.s.monetdb.31192
+QUERY = create function x(a int, b int) returns table (c int,d int) external 
name sql.x; --error, sql.x doesn't exist
+ERROR = !CREATE FUNCTION: external name sql.x not bound (sys.x)
+CODE  = 3F000
+MAPI  = (monetdb) /var/tmp/mtest-23419/.s.monetdb.31192
 QUERY = select * from x((select id from _tables), (select schema_id from 
_tables));
 ERROR = !SELECT: 'x' requires a single sub query
 CODE  = 42000
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to