Changeset: d512d2e5bbc1 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=d512d2e5bbc1
Modified Files:
        sql/server/rel_psm.c
        sql/server/sql_parser.y
Branch: statistics-analytics
Log Message:

Parser cleanup.

Don't repeat code for each function type for each language implementation.
Allow to create window functions via MAL for now.


diffs (truncated from 476 to 300 lines):

diff --git a/sql/server/rel_psm.c b/sql/server/rel_psm.c
--- a/sql/server/rel_psm.c
+++ b/sql/server/rel_psm.c
@@ -789,27 +789,65 @@ rel_create_func(sql_query *query, dlist 
        int deps = (sql->emode == m_deps);
        int create = (!instantiate && !deps);
        bit vararg = FALSE;
-
-       char is_table = (res && res->token == SQL_TABLE);
-       char is_aggr = (type == F_AGGR);
-       char is_func = (type != F_PROC);
-       char is_loader = (type == F_LOADER);
+       char *F, *fn, is_func;
 
-       char *F = 
is_loader?"LOADER":(is_aggr?"AGGREGATE":(is_func?"FUNCTION":"PROCEDURE"));
-       char *fn = is_loader?"loader":(is_aggr ? "aggregate" : (is_func ? 
"function" : "procedure"));
-       char *KF = type==F_FILT?"FILTER ": type==F_UNION?"UNION ": "";
-       char *kf = type == F_FILT ? "filter " : type == F_UNION ? "union " : "";
-
-       assert(res || type == F_PROC || type == F_FILT || type == F_LOADER);
-
-       if (is_table)
+       if (res && res->token == SQL_TABLE)
                type = F_UNION;
 
-       if (STORE_READONLY && create) 
+       switch (type) {
+               case F_FUNC:
+                       F = "FUNCTION";
+                       fn = "function";
+                       break;
+               case F_PROC:
+                       F = "PROCEDURE";
+                       fn = "procedure";
+                       break;
+               case F_AGGR:
+                       F = "AGGREGATE";
+                       fn = "aggregate";
+                       break;
+               case F_FILT:
+                       F = "FILTER FUNCTION";
+                       fn = "filter function";
+                       break;
+               case F_UNION:
+                       F = "UNION FUNCTION";
+                       fn = "union function";
+                       break;
+               case F_ANALYTIC:
+                       F = "WINDOW FUNCTION";
+                       fn = "window function";
+                       break;
+               case F_LOADER:
+                       F = "LOADER FUNCTION";
+                       fn = "loader function";
+                       break;
+               default:
+                       assert(0);
+       }
+
+       is_func = (type != F_PROC);
+       assert(lang != FUNC_LANG_INT);
+
+       if (STORE_READONLY && create)
                return sql_error(sql, 06, SQLSTATE(42000) "Schema statements 
cannot be executed on a readonly database.");
-                       
+
+       if (res && type == F_PROC)
+               return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s: 
procedures cannot have return parameters", F);
+       else if (res && (type == F_FILT || type == F_LOADER))
+               return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s: %s 
functions don't have to specify a return type", F, fn);
+       else if (!res && !(type == F_PROC || type == F_FILT || type == 
F_LOADER))
+               return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s: %ss 
require a return type", F, fn);
+       else if (lang == FUNC_LANG_MAL && type == F_LOADER)
+               return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s: %s 
functions creation via MAL not supported", F, fn);
+       else if (lang == FUNC_LANG_SQL && !(type == F_FUNC || type == F_PROC || 
type == F_UNION))
+               return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s: %s 
functions creation via SQL not supported", F, fn);
+       else if (LANG_EXT(lang) && !(type == F_FUNC || type == F_AGGR || type 
== F_UNION || type == F_LOADER))
+               return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s: %ss 
creation via external programming languages not supported", F, fn);
+
        if (sname && !(s = mvc_bind_schema(sql, sname)))
-               return sql_error(sql, 02, SQLSTATE(3F000) "CREATE %s%s: no such 
schema '%s'", KF, F, sname);
+               return sql_error(sql, 02, SQLSTATE(3F000) "CREATE %s: no such 
schema '%s'", F, sname);
        if (s == NULL)
                s = cur_schema(sql);
 
@@ -818,11 +856,11 @@ rel_create_func(sql_query *query, dlist 
                if (replace) {
                        sql_func *func = sf->func;
                        if (!mvc_schema_privs(sql, s))
-                               return sql_error(sql, 02, SQLSTATE(42000) 
"CREATE OR REPLACE %s%s: access denied for %s to schema '%s'", KF, F, 
stack_get_string(sql, "current_user"), s->base.name);
+                               return sql_error(sql, 02, SQLSTATE(42000) 
"CREATE OR REPLACE %s: access denied for %s to schema '%s'", F, 
stack_get_string(sql, "current_user"), s->base.name);
                        if (mvc_check_dependency(sql, func->base.id, 
!IS_PROC(func) ? FUNC_DEPENDENCY : PROC_DEPENDENCY, NULL))
-                               return sql_error(sql, 02, SQLSTATE(42000) 
"CREATE OR REPLACE %s%s: there are database objects dependent on %s%s %s;", KF, 
F, kf, fn, func->base.name);
+                               return sql_error(sql, 02, SQLSTATE(42000) 
"CREATE OR REPLACE %s: there are database objects dependent on %s %s;", F, fn, 
func->base.name);
                        if (!func->s)
-                               return sql_error(sql, 02, SQLSTATE(42000) 
"CREATE OR REPLACE %s%s: not allowed to replace system %s%s %s;", KF, F, kf, 
fn, func->base.name);
+                               return sql_error(sql, 02, SQLSTATE(42000) 
"CREATE OR REPLACE %s: not allowed to replace system %s %s;", F, fn, 
func->base.name);
                        if (mvc_drop_func(sql, s, func, 0))
                                return sql_error(sql, 02, SQLSTATE(HY013) 
MAL_MALLOC_FAIL);
                        sf = NULL;
@@ -843,19 +881,19 @@ rel_create_func(sql_query *query, dlist 
                                                arg_list = tpe;
                                        }
                                }
-                               (void)sql_error(sql, 02, SQLSTATE(42000) 
"CREATE %s%s: name '%s' (%s) already in use", KF, F, fname, arg_list ? arg_list 
: "");
+                               (void)sql_error(sql, 02, SQLSTATE(42000) 
"CREATE %s: name '%s' (%s) already in use", F, fname, arg_list ? arg_list : "");
                                _DELETE(arg_list);
                                list_destroy(type_list);
                                return NULL;
                        } else {
                                list_destroy(type_list);
-                               return sql_error(sql, 02, SQLSTATE(42000) 
"CREATE %s%s: name '%s' already in use", KF, F, fname);
+                               return sql_error(sql, 02, SQLSTATE(42000) 
"CREATE %s: name '%s' already in use", F, fname);
                        }
                }
        }
        list_destroy(type_list);
        if (create && !mvc_schema_privs(sql, s)) {
-               return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: 
insufficient privileges for user '%s' in schema '%s'", KF, F,
+               return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s: 
insufficient privileges for user '%s' in schema '%s'", F,
                                                 stack_get_string(sql, 
"current_user"), s->base.name);
        } else {
                char *q = QUERY(sql->scanner);
@@ -881,7 +919,7 @@ rel_create_func(sql_query *query, dlist 
                if (res) {
                        restype = result_type(sql, res);
                        if (!restype)
-                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s%s: failed to get restype", KF, F);
+                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s: failed to get restype", F);
                }
                if (body && LANG_EXT(lang)) {
                        char *lang_body = body->h->data.sval, *mod = NULL, 
*slang = NULL;
@@ -903,24 +941,32 @@ rel_create_func(sql_query *query, dlist 
                                        slang = "Javascript";
                                        break;
                                case FUNC_LANG_PY:
+                               case FUNC_LANG_PY2:
+                               case FUNC_LANG_PY3:
                                        mod = "pyapi";
                                        slang = "Python";
                                        break;
                                case FUNC_LANG_MAP_PY:
+                               case FUNC_LANG_MAP_PY2:
+                               case FUNC_LANG_MAP_PY3:
                                        mod = "pyapimap";
                                        slang = "Python";
                                        break;
                                default:
                                        assert(0);
                        }
+
+                       if (type == F_LOADER && !(lang == FUNC_LANG_PY || lang 
== FUNC_LANG_PY2 || lang == FUNC_LANG_PY3))
+                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s: Language name \"Python[{2|3}]\" expected", F);
+
                        sql->params = NULL;
                        if (create) {
                                f = mvc_create_func(sql, sql->sa, s, fname, l, 
restype, type, lang, mod, fname, lang_body, (type == F_LOADER)?TRUE:FALSE, 
vararg, FALSE);
                        } else if (!sf) {
-                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s%s: %s function %s.%s not bound", KF, F, slang, s->base.name, fname);
+                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s: %s function %s.%s not bound", F, slang, s->base.name, fname);
                        }
                } else if (body) { /* SQL implementation */
-                       sql_arg *ra = (restype && 
!is_table)?restype->h->data:NULL;
+                       sql_arg *ra = (restype && type != 
F_UNION)?restype->h->data:NULL;
                        list *b = NULL;
                        sql_schema *old_schema = cur_schema(sql);
 
@@ -939,9 +985,9 @@ rel_create_func(sql_query *query, dlist 
                
                        /* check if we have a return statement */
                        if (is_func && restype && !has_return(b))
-                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s%s: missing return statement", KF, F);
+                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s: missing return statement", F);
                        if (!is_func && !restype && has_return(b))
-                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s%s: procedures cannot have return statements", KF, F);
+                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s: procedures cannot have return statements", F);
                        /* in execute mode we instantiate the function */
                        if (instantiate || deps)
                                return rel_psm_block(sql->sa, b);
@@ -957,7 +1003,7 @@ rel_create_func(sql_query *query, dlist 
                                f = mvc_create_func(sql, sql->sa, s, fname, l, 
restype, type, lang, fmod, fnme, q, FALSE, vararg, FALSE);
                                GDKfree(q);
                        } else if (!sf) {
-                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s%s: external name %s.%s not bound (%s.%s)", KF, F, fmod, fnme, 
s->base.name, fname );
+                               return sql_error(sql, 01, SQLSTATE(42000) 
"CREATE %s: external name %s.%s not bound (%s.%s)", F, fmod, fnme, 
s->base.name, fname );
                        } else {
                                sql_func *f = sf->func;
                                if (!f->mod || strcmp(f->mod, fmod))
@@ -967,7 +1013,7 @@ rel_create_func(sql_query *query, dlist 
                                if (!f->mod || !f->imp) {
                                        _DELETE(f->mod);
                                        _DELETE(f->imp);
-                                       return sql_error(sql, 02, 
SQLSTATE(HY013) "CREATE %s%s: could not allocate space", KF, F);
+                                       return sql_error(sql, 02, 
SQLSTATE(HY013) "CREATE %s: could not allocate space", F);
                                }
                                f->sql = 0; /* native */
                                f->lang = FUNC_LANG_INT;
@@ -976,7 +1022,7 @@ rel_create_func(sql_query *query, dlist 
                                f = sf->func;
                        assert(f);
                        if (!backend_resolve_function(sql, f))
-                               return sql_error(sql, 01, SQLSTATE(3F000) 
"CREATE %s%s: external name %s.%s not bound (%s.%s)", KF, F, fmod, fnme, 
s->base.name, fname );
+                               return sql_error(sql, 01, SQLSTATE(3F000) 
"CREATE %s: external name %s.%s not bound (%s.%s)", F, fmod, fnme, 
s->base.name, fname );
                }
        }
        return rel_create_function(sql->sa, s->base.name, f);
diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y
--- a/sql/server/sql_parser.y
+++ b/sql/server/sql_parser.y
@@ -93,7 +93,6 @@ UTF8_strlen(const char *val)
        return pos;
 }
 
-
 static char *
 uescape_xform(char *restrict s, const char *restrict esc)
 {
@@ -325,6 +324,7 @@ int yydebug=1;
        trigger_procedure_statement
        if_opt_else
        func_data_type
+       func_def_opt_return
        with_list_element
        window_definition
        window_function
@@ -579,6 +579,7 @@ int yydebug=1;
        window_frame_exclusion
        subgeometry_type
        partition_type
+       func_def_type
 
 %type <l_val>
        lngval
@@ -2086,63 +2087,79 @@ function_body:
 |      string
 ;
 
+func_def_type:
+       FUNCTION                        { $$ = F_FUNC; }
+|      PROCEDURE                       { $$ = F_PROC; }
+|      AGGREGATE                       { $$ = F_AGGR; }
+|      AGGREGATE FUNCTION      { $$ = F_AGGR; }
+|      FILTER                          { $$ = F_FILT; }
+|      FILTER FUNCTION         { $$ = F_FILT; }
+|      WINDOW                          { $$ = F_ANALYTIC; }
+|      WINDOW FUNCTION         { $$ = F_ANALYTIC; }
+|      sqlLOADER                       { $$ = F_LOADER; }
+|      sqlLOADER FUNCTION      { $$ = F_LOADER; }
+
+func_def_opt_return:
+       RETURNS func_data_type  { $$ = $2; }
+|                                                      { $$ = NULL; }
+
 func_def:
-    create_or_replace FUNCTION qname
+    create_or_replace func_def_type qname
        '(' opt_paramlist ')'
-    RETURNS func_data_type
-    EXTERNAL sqlNAME external_function_name    
+    func_def_opt_return
+    EXTERNAL sqlNAME external_function_name
                        { dlist *f = L();
                                append_list(f, $3);
                                append_list(f, $5);
-                               append_symbol(f, $8);
-                               append_list(f, $11);
+                               append_symbol(f, $7);
+                               append_list(f, $10);
                                append_list(f, NULL);
-                               append_int(f, F_FUNC);
+                               append_int(f, $2);
                                append_int(f, FUNC_LANG_MAL);
                                append_int(f, $1);
                          $$ = _symbol_create_list( SQL_CREATE_FUNC, f ); }
- |  create_or_replace FUNCTION qname
+ |  create_or_replace func_def_type qname
        '(' opt_paramlist ')'
-    RETURNS func_data_type
+    func_def_opt_return
     routine_body
                        { dlist *f = L();
                                append_list(f, $3);
                                append_list(f, $5);
-                               append_symbol(f, $8);
+                               append_symbol(f, $7);
                                append_list(f, NULL);
-                               append_list(f, $9);
-                               append_int(f, F_FUNC);
+                               append_list(f, $8);
+                               append_int(f, $2);
                                append_int(f, FUNC_LANG_SQL);
                                append_int(f, $1);
                          $$ = _symbol_create_list( SQL_CREATE_FUNC, f ); }
-  | create_or_replace FUNCTION qname
+  | create_or_replace func_def_type qname
        '(' opt_paramlist ')'
-    RETURNS func_data_type
+    func_def_opt_return
     LANGUAGE IDENT function_body
                {
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to