Changeset: 3230faec824a for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=3230faec824a Added Files: sql/test/miscellaneous/Tests/create_func_temp.sql sql/test/miscellaneous/Tests/create_func_temp.stable.err sql/test/miscellaneous/Tests/create_func_temp.stable.out Modified Files: clients/examples/perl/sqlsample.pl clients/odbc/driver/ODBCConvert.c clients/odbc/driver/ODBCUtil.c clients/odbc/driver/SQLPrepare.c sql/server/rel_psm.c sql/server/rel_rel.c sql/server/rel_select.c sql/server/rel_unnest.c sql/server/rel_unnest.h sql/server/sql_scan.c sql/server/sql_scan.h sql/storage/store.c sql/test/BugTracker-2014/Tests/copy-into.Bug-3481.SQL.py sql/test/BugTracker-2014/Tests/utf8bom.Bug-3436.SQL.py sql/test/BugTracker-2016/Tests/convert-function-test.Bug-3460.sql sql/test/BugTracker-2016/Tests/convert-function-test.Bug-3460.stable.out sql/test/BugTracker-2016/Tests/convert-function-test.Bug-3460.stable.out.int128 sql/test/BugTracker-2019/Tests/copy-into-from-stdin-empty-line.Bug-6669.sql sql/test/BugTracker-2019/Tests/insert-into-select.Bug-6718.sql sql/test/BugTracker-2019/Tests/python-loader-string.Bug-6759.py sql/test/Tests/unicode.sql sql/test/Tests/unicode.stable.out sql/test/Users/Tests/copyinto.SQL.py sql/test/Users/Tests/copyinto.stable.err sql/test/mapi/Tests/perl_dbi.stable.out sql/test/miscellaneous/Tests/All sql/test/subquery/Tests/subquery5.sql sql/test/subquery/Tests/subquery5.stable.err sql/test/subquery/Tests/subquery5.stable.out Branch: default Log Message:
Merged with Jun2020 diffs (truncated from 1712 to 300 lines): diff --git a/clients/examples/perl/sqlsample.pl b/clients/examples/perl/sqlsample.pl --- a/clients/examples/perl/sqlsample.pl +++ b/clients/examples/perl/sqlsample.pl @@ -48,6 +48,9 @@ my $dbh = DBI->connect( $dsn, $sth->bind_param( 1, 7 , DBI::SQL_INTEGER() ); $sth->bind_param( 2,'seven' ); $sth->execute; + $sth->bind_param( 1, 42 , DBI::SQL_INTEGER() ); + $sth->bind_param( 2, '\\n' ); + $sth->execute; } { my $sth = $dbh->prepare('select * from perl_table;'); diff --git a/clients/odbc/driver/ODBCConvert.c b/clients/odbc/driver/ODBCConvert.c --- a/clients/odbc/driver/ODBCConvert.c +++ b/clients/odbc/driver/ODBCConvert.c @@ -3197,6 +3197,7 @@ ODBCStore(ODBCStmt *stmt, case SQL_WCHAR: case SQL_WVARCHAR: case SQL_WLONGVARCHAR: + assign(buf, bufpos, buflen, 'r', stmt); /* RAW string */ assign(buf, bufpos, buflen, '\'', stmt); switch (ctype) { case SQL_C_CHAR: @@ -3205,22 +3206,11 @@ ODBCStore(ODBCStmt *stmt, for (i = 0; i < slen; i++) { unsigned char c = (unsigned char) sval[i]; - if (c == 0) { + if (c == 0) break; - } else if (c < 0x20 /* || c >= 0x7F */) { - assign(buf, bufpos, buflen, '\\', stmt); - assign(buf, bufpos, buflen, '0' + (c >> 6), stmt); - assign(buf, bufpos, buflen, '0' + ((c >> 3) & 0x7), stmt); - assign(buf, bufpos, buflen, '0' + (c & 0x7), stmt); - } else if (c == '\\') { - assign(buf, bufpos, buflen, '\\', stmt); - assign(buf, bufpos, buflen, '\\', stmt); - } else if (c == '\'') { - assign(buf, bufpos, buflen, '\\', stmt); + if (c == '\'') assign(buf, bufpos, buflen, '\'', stmt); - } else { - assign(buf, bufpos, buflen, c, stmt); - } + assign(buf, bufpos, buflen, c, stmt); } break; case SQL_C_BIT: diff --git a/clients/odbc/driver/ODBCUtil.c b/clients/odbc/driver/ODBCUtil.c --- a/clients/odbc/driver/ODBCUtil.c +++ b/clients/odbc/driver/ODBCUtil.c @@ -679,7 +679,7 @@ ODBCTranslateSQL(ODBCDbc *dbc, const SQL length = (size_t) sprintf(q, "%.*s ESCAPE '''' %s", n, nquery, p); break; case '\\': - length = (size_t) sprintf(q, "%.*s ESCAPE '\\\\' %s", n, nquery, p); + length = (size_t) sprintf(q, "%.*s ESCAPE r'\\' %s", n, nquery, p); break; default: length = (size_t) sprintf(q, "%.*s ESCAPE '%c' %s", n, nquery, esc, p); @@ -784,9 +784,7 @@ ODBCTranslateSQL(ODBCDbc *dbc, const SQL p++; } else if (*p == '\'') { while (*++p && *p != '\'') - if (*p == '\\' && - *++p == 0) - break; + ; if (*p) p++; } else { @@ -820,7 +818,7 @@ ODBCTranslateSQL(ODBCDbc *dbc, const SQL if (strncasecmp(func->name, scalarfunc, scalarfunclen) == 0 && func->name[scalarfunclen] == 0 && func->nargs == nargs) { if (func->repl) { const char *r; - q = malloc(length - pr + strlen(func->repl) - nargs + (nargs > 0 ? args[0].arglen : 0) + (nargs > 1 ? args[1].arglen : 0) + (nargs > 2 ? args[2].arglen : 0) + 1); + q = malloc(length - pr + strlen(func->repl) - nargs + (nargs > 0 ? args[0].arglen + 1 : 0) + (nargs > 1 ? args[1].arglen + 1 : 0) + (nargs > 2 ? args[2].arglen + 1 : 0) + 1); if (q == NULL) { free(nquery); return NULL; @@ -829,6 +827,8 @@ ODBCTranslateSQL(ODBCDbc *dbc, const SQL strncpy(q, nquery, pr); for (r = func->repl; *r; r++) { if (*r == '\1' || *r == '\2' || *r == '\3' || *r == '\4') { + if (args[*r - 1].argstart[0] == '\'') + q[pr++] = 'r'; strncpy(q + pr, args[*r - 1].argstart, args[*r - 1].arglen); pr += (int) args[*r - 1].arglen; } else { @@ -865,12 +865,17 @@ ODBCTranslateSQL(ODBCDbc *dbc, const SQL for (c = convert; c->odbc; c++) { if (strncasecmp(c->odbc, args[1].argstart, args[1].arglen) == 0 && c->odbc[args[1].arglen] == 0) { - q = malloc(length - pr + 11 + args[0].arglen + strlen(c->server)); + const char *raw; + q = malloc(length - pr + 11 + args[0].arglen + 1 + strlen(c->server)); if (q == NULL) { free(nquery); return NULL; } - length = (size_t) sprintf(q, "%.*scast(%.*s as %s)%s", n, nquery, (int) args[0].arglen, args[0].argstart, c->server, p); + if (args[0].argstart[0] == '\'') + raw = "r"; + else + raw = ""; + length = (size_t) sprintf(q, "%.*scast(%s%.*s as %s)%s", n, nquery, raw, (int) args[0].arglen, args[0].argstart, c->server, p); free(nquery); nquery = q; break; @@ -924,7 +929,7 @@ ODBCParsePV(const char *tab, const char if (*s == '\'' || *s == '\\') i++; } - i += strlen(tab) + strlen(col) + 25; /* ""."" like '' escape '\\' */ + i += strlen(tab) + strlen(col) + 25; /* ""."" like '' escape r'\' */ res = malloc(i + 1); if (res == NULL) return NULL; @@ -934,7 +939,7 @@ ODBCParsePV(const char *tab, const char res[i++] = *s; res[i++] = *s; } - for (s = "' escape '\\\\'"; *s; s++) + for (s = "' escape r'\\'"; *s; s++) res[i++] = *s; res[i] = 0; return res; diff --git a/clients/odbc/driver/SQLPrepare.c b/clients/odbc/driver/SQLPrepare.c --- a/clients/odbc/driver/SQLPrepare.c +++ b/clients/odbc/driver/SQLPrepare.c @@ -74,10 +74,6 @@ MNDBPrepare(ODBCStmt *stmt, } fixODBCstring(StatementText, TextLength, SQLINTEGER, addStmtError, stmt, return SQL_ERROR); - /* TODO: convert ODBC escape sequences ( {d 'value'} or {t - * 'value'} or {ts 'value'} or {escape 'e-char'} or {oj - * outer-join} or {fn scalar-function} etc. ) to MonetDB SQL - * syntax */ query = ODBCTranslateSQL(stmt->Dbc, StatementText, (size_t) TextLength, stmt->noScan); if (query == NULL) { 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 @@ -672,8 +672,10 @@ sequential_block (sql_query *query, sql_ case SQL_TRUNCATE: case SQL_MERGE: { sql_rel *r = rel_updates(query, s); - if (!r) + if (!r) { + stack_pop_frame(sql); return NULL; + } res = exp_rel(sql, r); } break; default: @@ -1310,8 +1312,11 @@ create_trigger(sql_query *query, dlist * if (old_name) stack_update_rel_view(sql, old_name, new_name?rel_dup(rel):rel); } - if (!(sq = sequential_block(query, NULL, NULL, stmts, NULL, 1))) + if (!(sq = sequential_block(query, NULL, NULL, stmts, NULL, 1))) { + if (!instantiate) + stack_pop_frame(sql); return NULL; + } r = rel_psm_block(sql->sa, sq); if (!instantiate) 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 @@ -122,17 +122,10 @@ rel_create( sql_allocator *sa ) if(!r) return NULL; + *r = (sql_rel) { + .card = CARD_ATOM, + }; sql_ref_init(&r->ref); - r->l = r->r = NULL; - r->exps = NULL; - r->nrcols = 0; - r->flag = 0; - r->card = CARD_ATOM; - r->distinct = 0; - r->processed = 0; - r->dependent = 0; - r->subquery = 0; - r->p = NULL; return r; } 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 @@ -3351,6 +3351,7 @@ static sql_exp * if (args && args->data.sym) { int ungrouped_col = -1, i, all_aggr = query_has_outer(query); all_freevar = 1; + bool found_nested_aggr = false; for (i = 0; args && args->data.sym; args = args->next, i++) { int base = (!groupby || !is_project(groupby->op) || is_base(groupby->op) || is_processed(groupby)); bool found_one = false; @@ -3359,7 +3360,7 @@ static sql_exp * has_args = true; if (gl && gl != ogl) { - if (groupby->grouped) { + if (gl->grouped) { char *uaname = GDKmalloc(strlen(aname) + 1); sql_exp *e = sql_error(sql, 02, SQLSTATE(42000) "%s: aggregate functions cannot be nested", uaname ? toUpperCopy(uaname, aname) : aname); @@ -3401,10 +3402,10 @@ static sql_exp * } else { 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))); } - all_freevar &= (exp_only_freevar(sql, e, &found_one) && found_one); + all_freevar &= (exp_only_freevar(query, e, &found_one, &found_nested_aggr) && found_one); list_append(exps, e); } - if (all_freevar && all_aggr) + if (all_freevar && (all_aggr || found_nested_aggr)) return sql_error(sql, 05, SQLSTATE(42000) "SELECT: aggregate function calls cannot be nested"); if (!all_freevar) { if (all_aggr) { 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 @@ -16,6 +16,7 @@ #include "rel_exp.h" #include "rel_select.h" #include "rel_rewriter.h" +#include "sql_query.h" #include "mal_errors.h" /* for SQLSTATE() */ static void @@ -170,41 +171,50 @@ rel_has_freevar(mvc *sql, sql_rel *rel) return 0; } -static int exps_only_freevar(mvc *sql, list *exps, bool *found_one); -static int rel_only_freevar(mvc *sql, sql_rel *rel, bool *found_one); +static int exps_only_freevar(sql_query *query, list *exps, bool *found_one, bool *found_aggr); +static int rel_only_freevar(sql_query *query, sql_rel *rel, bool *found_one, bool *found_aggr); int /* look for expressions with either only freevars or atoms */ -exp_only_freevar(mvc *sql, sql_exp *e, bool *found_one) +exp_only_freevar(sql_query *query, sql_exp *e, bool *found_one, bool *found_aggr) { if (THRhighwater()) { - (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space"); + (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space"); return 0; } if (is_freevar(e)) { + sql_rel *outer; + sql_exp *a; + *found_one = true; + if (e->type == e_column) { + if ((outer = query_fetch_outer(query, is_freevar(e)-1))) { + if ((a = rel_find_exp(outer, e)) && is_aggr(a->type)) + *found_aggr = true; + } + } return 1; } switch(e->type) { case e_cmp: if (e->flag == cmp_or || e->flag == cmp_filter) { - return (exps_only_freevar(sql, e->l, found_one) && exps_only_freevar(sql, e->r, found_one)); + return (exps_only_freevar(query, e->l, found_one, found_aggr) && exps_only_freevar(query, e->r, found_one, found_aggr)); } else if (e->flag == cmp_in || e->flag == cmp_notin) { - return (exp_only_freevar(sql, e->l, found_one) && exps_only_freevar(sql, e->r, found_one)); + return (exp_only_freevar(query, e->l, found_one, found_aggr) && exps_only_freevar(query, e->r, found_one, found_aggr)); } else { - return (exp_only_freevar(sql, e->l, found_one) && exp_only_freevar(sql, e->r, found_one) && - (!e->f || (e->f && exp_only_freevar(sql, e->f, found_one)))); + return (exp_only_freevar(query, e->l, found_one, found_aggr) && exp_only_freevar(query, e->r, found_one, found_aggr) && + (!e->f || (e->f && exp_only_freevar(query, e->f, found_one, found_aggr)))); } case e_convert: - return exp_only_freevar(sql, e->l, found_one); + return exp_only_freevar(query, e->l, found_one, found_aggr); case e_func: case e_aggr: if (e->l) - return exps_only_freevar(sql, e->l, found_one); + return exps_only_freevar(query, e->l, found_one, found_aggr); return 1; case e_psm: if (exp_is_rel(e)) - return rel_only_freevar(sql, e->l, found_one); + return rel_only_freevar(query, e->l, found_one, found_aggr); return 1; case e_atom: _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list