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