Changeset: 8e77a42eae7d for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=8e77a42eae7d
Modified Files:
        sql/server/rel_optimizer.c
        sql/server/rel_rel.h
        sql/server/rel_select.c
        sql/server/rel_unnest.c
Branch: default
Log Message:

Merged with Oct2020


diffs (truncated from 1260 to 300 lines):

diff --git a/clients/mapiclient/ReadlineTools.c 
b/clients/mapiclient/ReadlineTools.c
--- a/clients/mapiclient/ReadlineTools.c
+++ b/clients/mapiclient/ReadlineTools.c
@@ -88,7 +88,7 @@ sql_tablename_generator(const char *text
 static char *
 sql_command_generator(const char *text, int state)
 {
-       static int idx, len;
+       static size_t idx, len;
        const char *name;
 
        if (!state) {
@@ -303,20 +303,43 @@ readline_show_error(const char *msg) {
 #define BUFFER_SIZE 1024
 #endif
 
+#ifdef WIN32
+#define unlink _unlink
+#endif
+
 static int
 invoke_editor(int cnt, int key) {
-       char template[] = "/tmp/mclient_temp_XXXXXX";
        char editor_command[BUFFER_SIZE];
        char *read_buff = NULL;
        char *editor = NULL;
        FILE *fp;
        size_t content_len;
        size_t read_bytes, idx;
+#ifdef WIN32
+       char *mytemp;
+       char template[] = "mclient_temp_XXXXXX";
+#else
+       int mytemp;
+       char template[] = "/tmp/mclient_temp_XXXXXX";
+#endif
 
        (void) cnt;
        (void) key;
 
-       if ((fp = fdopen(mkstemp(template), "r+")) == NULL) {
+#ifdef WIN32
+       if ((mytemp = _mktemp(template)) == NULL) {
+#else
+       if ((mytemp = mkstemp(template)) == 0) {
+#endif
+               readline_show_error("invoke_editor: Cannot create temp file\n");
+               goto bailout;
+       }
+
+#ifdef WIN32
+       if ((fp = fopen(mytemp, "r+")) == NULL) {
+#else
+       if ((fp = fdopen(mytemp, "r+")) == NULL) {
+#endif
                // Notify the user that we cannot create temp file
                readline_show_error("invoke_editor: Cannot create temp file\n");
                goto bailout;
@@ -367,7 +390,7 @@ invoke_editor(int cnt, int key) {
                }
 
                rl_replace_line(read_buff, 0);
-               rl_point = idx + 1;  // place the point one character after the 
end of the string
+               rl_point = (int)(idx + 1);  // place the point one character 
after the end of the string
 
                free(read_buff);
        } else {
diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c
--- a/sql/server/rel_optimizer.c
+++ b/sql/server/rel_optimizer.c
@@ -8931,8 +8931,13 @@ rel_merge_table_rewrite(visitor *v, sql_
                                                                                
                                if (!next->semantics && ((lval && lval->isnull) 
|| (hval && hval->isnull))) {
                                                                                
                                        skip = 1; /* NULL values don't match, 
skip them */
                                                                                
                                } else if (!next->semantics) {
-                                                                               
                                        if (next->flag == cmp_equal || hval != 
lval) {
-                                                                               
                                                skip |= next->anti ? 
exp_range_overlap(cmin, cmax, lval, hval, false, false) != 0 : 
exp_range_overlap(cmin, cmax, lval, hval, false, false) == 0;
+                                                                               
                                        if (next->flag == cmp_equal) {
+                                                                               
                                                skip |= next->anti ? 
exp_range_overlap(cmin, cmax, lval, hval, false, false) != 0 :
+                                                                               
                                                                                
         exp_range_overlap(cmin, cmax, lval, hval, false, false) == 0;
+                                                                               
                                        } else if (hval != lval) { /* range 
case */
+                                                                               
                                                comp_type lower = 
range2lcompare(next->flag), higher = range2rcompare(next->flag);
+                                                                               
                                                skip |= next->anti ? 
exp_range_overlap(cmin, cmax, lval, hval, higher == cmp_lt, lower == cmp_gt) != 
0 :
+                                                                               
                                                                                
         exp_range_overlap(cmin, cmax, lval, hval, higher == cmp_lt, lower == 
cmp_gt) == 0;
                                                                                
                                        } else {
                                                                                
                                                switch (next->flag) {
                                                                                
                                                        case cmp_gt:
@@ -8985,7 +8990,8 @@ rel_merge_table_rewrite(visitor *v, sql_
                                                                                
                                        /* otherwise it holds all values in the 
range, cannot be pruned */
                                                                                
                                } else if (rmin->isnull) { /* MINVALUE to limit 
*/
                                                                                
                                        if (lval) {
-                                                                               
                                                if (hval != lval) { /* For the 
between case */
+                                                                               
                                                if (hval != lval) { /* range 
case */
+                                                                               
                                                        /* There's need to call 
range2lcompare, because the partition's upper limit is always exclusive */
                                                                                
                                                        skip |= next->anti ? 
VALcmp(&(lval->data), &(rmax->data)) < 0 : VALcmp(&(lval->data), &(rmax->data)) 
>= 0;
                                                                                
                                                } else {
                                                                                
                                                        switch (next->flag) { 
/* upper limit always exclusive */
@@ -9011,8 +9017,15 @@ rel_merge_table_rewrite(visitor *v, sql_
                                                                                
                                        }
                                                                                
                                } else if (rmax->isnull) { /* limit to MAXVALUE 
*/
                                                                                
                                        if (lval) {
-                                                                               
                                                if (hval != lval) { /* For the 
between case */
-                                                                               
                                                        skip |= next->anti ? 
VALcmp(&(rmin->data), &(hval->data)) <= 0 : VALcmp(&(rmin->data), 
&(hval->data)) > 0;
+                                                                               
                                                if (hval != lval) { /* range 
case */
+                                                                               
                                                        comp_type higher = 
range2rcompare(next->flag);
+                                                                               
                                                        if (higher == cmp_lt) {
+                                                                               
                                                                skip |= 
next->anti ? VALcmp(&(rmin->data), &(hval->data)) < 0 : VALcmp(&(rmin->data), 
&(hval->data)) >= 0;
+                                                                               
                                                        } else if (higher == 
cmp_lte) {
+                                                                               
                                                                skip |= 
next->anti ? VALcmp(&(rmin->data), &(hval->data)) <= 0 : VALcmp(&(rmin->data), 
&(hval->data)) > 0;
+                                                                               
                                                        } else {
+                                                                               
                                                                assert(0);
+                                                                               
                                                        }
                                                                                
                                                } else {
                                                                                
                                                        switch (next->flag) {
                                                                                
                                                                case cmp_lt:
@@ -9039,8 +9052,13 @@ rel_merge_table_rewrite(visitor *v, sql_
                                                                                
                                        }
                                                                                
                                } else { /* limit1 to limit2 (general case), 
limit2 is exclusive */
                                                                                
                                        if (lval) {
-                                                                               
                                                if (next->flag == cmp_equal || 
hval != lval) {
-                                                                               
                                                        skip |= next->anti ? 
exp_range_overlap(rmin, rmax, lval, hval, false, true) != 0 : 
exp_range_overlap(rmin, rmax, lval, hval, false, true) == 0;
+                                                                               
                                                if (next->flag == cmp_equal) {
+                                                                               
                                                        skip |= next->anti ? 
exp_range_overlap(rmin, rmax, lval, hval, false, true) != 0 :
+                                                                               
                                                                                
                 exp_range_overlap(rmin, rmax, lval, hval, false, true) == 0;
+                                                                               
                                                } else if (hval != lval) { /* 
For the between case */
+                                                                               
                                                        comp_type higher = 
range2rcompare(next->flag);
+                                                                               
                                                        skip |= next->anti ? 
exp_range_overlap(rmin, rmax, lval, hval, higher == cmp_lt, true) != 0 :
+                                                                               
                                                                                
                 exp_range_overlap(rmin, rmax, lval, hval, higher == cmp_lt, 
true) == 0;
                                                                                
                                                } else {
                                                                                
                                                        switch (next->flag) {
                                                                                
                                                                case cmp_gt:
diff --git a/sql/server/rel_rel.c b/sql/server/rel_rel.c
--- a/sql/server/rel_rel.c
+++ b/sql/server/rel_rel.c
@@ -2347,3 +2347,25 @@ rel_rebind_exp(mvc *sql, sql_rel *rel, s
        /* problems are passed via changes */
        return (v.changes==0);
 }
+
+
+
+static sql_exp *
+_exp_freevar_offset(visitor *v, sql_rel *rel, sql_exp *e, int depth)
+{
+       (void)rel; (void)depth;
+       /* visitor will handle recursion, ie only need to check columns here */
+       int vf = is_freevar(e);
+       if (v->changes < vf)
+               v->changes=vf;
+       return e;
+}
+
+int
+exp_freevar_offset(mvc *sql, sql_exp *e)
+{
+       visitor v = { .sql = sql };
+       exp_visitor(&v, NULL, e, 0, &_exp_freevar_offset, true, true);
+       /* freevar offset is passed via changes */
+       return (v.changes);
+}
diff --git a/sql/server/rel_rel.h b/sql/server/rel_rel.h
--- a/sql/server/rel_rel.h
+++ b/sql/server/rel_rel.h
@@ -127,6 +127,7 @@ typedef struct visitor {
        int depth;              /* depth of the current relation */
        sql_rel *parent;
        mvc *sql;
+       void *data;
 } visitor;
 
 typedef sql_exp *(*exp_rewrite_fptr)(visitor *v, sql_rel *rel, sql_exp *e, int 
depth /* depth of the nested expression */);
@@ -145,4 +146,6 @@ extern sql_rel *rel_visitor_bottomup(vis
 /* validate that all parts of the expression e can be bound to the relation 
rel (or are atoms) */
 extern bool rel_rebind_exp(mvc *sql, sql_rel *rel, sql_exp *e);
 
+extern int exp_freevar_offset(mvc *sql, sql_exp *e);
+
 #endif /* _REL_REL_H_ */
diff --git a/sql/server/rel_select.c b/sql/server/rel_select.c
--- a/sql/server/rel_select.c
+++ b/sql/server/rel_select.c
@@ -2738,7 +2738,6 @@ rel_unop_(mvc *sql, sql_rel *rel, sql_ex
                        /* reset error */
                        sql->session->status = 0;
                        sql->errstr[0] = '\0';
-                               //f = NULL;
                }
        }
        if (f && check_card(card, f)) {
@@ -3206,6 +3205,55 @@ rel_nop(sql_query *query, sql_rel **rel,
        return _rel_nop(sql, s, fname, tl, rel ? *rel : NULL, exps, ek);
 }
 
+typedef struct aggr_input {
+       sql_query *query;
+       int groupby;
+       char *err;
+} aggr_input;
+
+static sql_exp *
+exp_valid(visitor *v, sql_rel *rel, sql_exp *e, int depth)
+{
+       aggr_input *ai = v->data;
+       (void)rel; (void)depth;
+
+       int vf = is_freevar(e);
+       if (!v->changes && vf && vf < ai->groupby) { /* check need with outer 
query */
+               sql_rel *sq = query_fetch_outer(ai->query, vf-1);
+
+               /* problem freevar have cardinality CARD_ATOM */
+               if (sq->card <= CARD_AGGR && exp_card(e) != CARD_AGGR && 
is_alias(e->type)) {
+                       if (!exps_bind_column(sq->exps, e->l, e->r, NULL, 0)) {
+                               v->changes = 1;
+                               ai->err = SQLSTATE(42000) "SELECT: subquery 
uses ungrouped column from outer query";
+                       }
+               }
+       } else if (!v->changes && vf && vf == ai->groupby) {
+               sql_rel *sq = query_fetch_outer(ai->query, vf-1);
+
+               /* problem freevar have cardinality CARD_ATOM */
+               if (sq->card <= CARD_AGGR && is_alias(e->type)) {
+                       if (exps_bind_column(sq->exps, e->l, e->r, NULL, 0)) { 
/* aggregate */
+                               v->changes = 1;
+                               ai->err = SQLSTATE(42000) "SELECT: aggregate 
function calls cannot be nested";
+                       }
+               }
+       }
+       return e;
+}
+
+static char *
+exps_valid(sql_query *query, list *exps, int groupby)
+{
+       aggr_input ai = { .query = query, .groupby = groupby };
+       visitor v = { .sql = query->sql, .data = &ai };
+
+       exps_exp_visitor_topdown(&v, NULL, exps, 0, &exp_valid, true);
+       if (v.changes)
+               return ai.err;
+       return NULL;
+}
+
 static sql_exp *
 _rel_aggr(sql_query *query, sql_rel **rel, int distinct, sql_schema *s, char 
*aname, dnode *args, int f)
 {
@@ -3253,7 +3301,7 @@ static sql_exp *
        exps = sa_list(sql->sa);
        if (args && args->data.sym) {
                int i, all_aggr = query_has_outer(query);
-               bool found_nested_aggr = false, arguments_correlated = true, 
all_const = true;
+               bool arguments_correlated = true, all_const = true;
                list *ungrouped_cols = NULL;
 
                all_freevar = 1;
@@ -3282,13 +3330,11 @@ static sql_exp *
                        }
 
                        all_aggr &= (exp_card(e) <= CARD_AGGR && 
!exp_is_atom(e) && is_aggr(e->type) && !is_func(e->type) && (!groupby || 
!is_groupby(groupby->op) || !groupby->r || !exps_find_exp(groupby->r, e)));
-                       exp_only_freevar(query, e, &arguments_correlated, 
&found_one_freevar, &found_nested_aggr, &ungrouped_cols);
+                       exp_only_freevar(query, e, &arguments_correlated, 
&found_one_freevar, &ungrouped_cols);
                        all_freevar &= (arguments_correlated && 
found_one_freevar) || (is_atom(e->type)?all_freevar:0); /* no uncorrelated 
variables must be found, plus at least one correlated variable to push this 
aggregate to an outer query */
                        all_const &= is_atom(e->type);
                        list_append(exps, e);
                }
-               if (all_aggr || ((arguments_correlated || all_freevar) && 
found_nested_aggr))
-                       return sql_error(sql, 05, SQLSTATE(42000) "SELECT: 
aggregate function calls cannot be nested");
                if (all_const)
                        all_freevar = 0;
                if (!all_freevar) {
@@ -3339,17 +3385,25 @@ static sql_exp *
        if (all_freevar) { /* case 2, ie use outer */
                int card;
                sql_exp *exp = NULL;
-               /* find proper relation, base on freevar (stack hight) */
+               /* find proper groupby relation */
                for (node *n = exps->h; n; n = n->next) {
                        sql_exp *e = n->data;
 
-                       if (all_freevar<is_freevar(e))
-                               all_freevar = is_freevar(e);
+                       int vf = exp_freevar_offset(sql, e);
+                       if (vf > (int)all_freevar)
+                               all_freevar = vf;
                        exp = e;
                }
                int sql_state = query_fetch_outer_state(query,all_freevar-1);
                res = groupby = query_fetch_outer(query, all_freevar-1);
                card = query_outer_used_card(query, all_freevar-1);
+               /* given groupby validate all input expressions */
+               char *err;
+               if ((err = exps_valid(query, exps, all_freevar)) != NULL) {
+                       strcpy(sql->errstr, err);
+                       sql->session->status = -ERR_GROUPBY;
+                       return NULL;
+               }
                if (exp && !is_groupby_col(res, exp)) {
                        if (is_sql_groupby(sql_state))
                                return sql_error(sql, 05, SQLSTATE(42000) 
"SELECT: aggregate function '%s' not allowed in GROUP BY clause", aname);
diff --git a/sql/server/rel_unnest.c b/sql/server/rel_unnest.c
--- a/sql/server/rel_unnest.c
+++ b/sql/server/rel_unnest.c
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to