Changeset: 7e358a6f1fa0 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/7e358a6f1fa0
Modified Files:
gdk/gdk_bbp.c
sql/server/rel_distribute.c
testing/sqllogictest.py
Branch: default
Log Message:
Merged with Jul2021
diffs (truncated from 325 to 300 lines):
diff --git a/gdk/gdk_bbp.c b/gdk/gdk_bbp.c
--- a/gdk/gdk_bbp.c
+++ b/gdk/gdk_bbp.c
@@ -2899,16 +2899,24 @@ decref(bat i, bool logical, bool release
if (lock)
MT_lock_unset(&GDKswapLock(i));
- if (swap && b != NULL) {
- if (lrefs == 0 && (BBP_status(i) & BBPDELETED) == 0) {
- /* free memory (if loaded) and delete from
- * disk (if transient but saved) */
- BBPdestroy(b);
+ if (swap) {
+ if (b != NULL) {
+ if (lrefs == 0 && (BBP_status(i) & BBPDELETED) == 0) {
+ /* free memory (if loaded) and delete from
+ * disk (if transient but saved) */
+ BBPdestroy(b);
+ } else {
+ TRC_DEBUG(BAT_, "%s unload and free bat %d\n",
func, i);
+ /* free memory of transient */
+ if (BBPfree(b) != GDK_SUCCEED)
+ return -1; /* indicate failure */
+ }
+ } else if (lrefs == 0 && (BBP_status(i) & BBPDELETED) == 0) {
+ if ((b = BBP_desc(i)) != NULL)
+ BATdelete(b);
+ BBPclear(i, true);
} else {
- TRC_DEBUG(BAT_, "%s unload and free bat %d\n", func, i);
- /* free memory of transient */
- if (BBPfree(b) != GDK_SUCCEED)
- return -1; /* indicate failure */
+ BBP_status_off(i, BBPUNLOADING);
}
}
if (tp)
diff --git a/sql/include/sql_relation.h b/sql/include/sql_relation.h
--- a/sql/include/sql_relation.h
+++ b/sql/include/sql_relation.h
@@ -283,7 +283,13 @@ typedef struct relation {
outer:1, /* used as outer (ungrouped) */
grouped:1, /* groupby processed all the group by exps */
single:1,
- used:2; /* used by rewriters at rel_unnest and rel_dce, so a
relation is not modified twice */
+ /*
+ * Used by rewriters at rel_unnest, rel_optimizer and rel_distribute so
a relation is not modified twice
+ * The first two bits are used by rel_unnest modifiers and always reset
after.
+ * The first bit is also used by rel_dce and rel_merge_select_rse
optimizers.
+ * The third bit is used by rel_remote_func only and it's not reset.
+ */
+ used:3;
void *p; /* properties for the optimizer, distribution */
} sql_rel;
diff --git a/sql/server/rel_distribute.c b/sql/server/rel_distribute.c
--- a/sql/server/rel_distribute.c
+++ b/sql/server/rel_distribute.c
@@ -161,7 +161,8 @@ replica_rewrite(visitor *v, sql_table *t
static sql_rel *
replica(visitor *v, sql_rel *rel)
{
- if (rel_is_ref(rel)) {
+ /* for merge statement join, ignore the multiple references */
+ if (rel_is_ref(rel) && !(rel->flag&MERGE_LEFT)) {
if (has_remote_or_replica(rel)) {
sql_rel *nrel = rel_copy(v->sql, rel, 1);
@@ -192,7 +193,8 @@ distribute(visitor *v, sql_rel *rel)
sql_rel *l = rel->l, *r = rel->r;
prop *p, *pl, *pr;
- if (rel_is_ref(rel)) {
+ /* for merge statement join, ignore the multiple references */
+ if (rel_is_ref(rel) && !(rel->flag&MERGE_LEFT)) {
if (has_remote_or_replica(rel)) {
sql_rel *nrel = rel_copy(v->sql, rel, 1);
@@ -274,6 +276,9 @@ distribute(visitor *v, sql_rel *rel)
return NULL;
}
+ if (rel->flag&MERGE_LEFT) /* search for any remote tables but
don't propagate over to this relation */
+ return rel;
+
if (l && (pl = find_prop(l->p, PROP_REMOTE)) != NULL &&
r && (pr = find_prop(r->p, PROP_REMOTE)) != NULL &&
strcmp(pl->value, pr->value) == 0) {
@@ -330,6 +335,12 @@ rel_remote_func(visitor *v, sql_rel *rel
{
(void) v;
+ if (rel_is_ref(rel)) { /* Don't modify the same relation twice */
+ int rused = 1 << 2;
+ if (rel->used & rused)
+ return rel;
+ rel->used |= rused;
+ }
if (find_prop(rel->p, PROP_REMOTE) != NULL) {
list *exps = rel_projections(v->sql, rel, NULL, 1, 1);
rel = rel_relational_func(v->sql->sa, rel, exps);
diff --git a/sql/server/rel_dump.c b/sql/server/rel_dump.c
--- a/sql/server/rel_dump.c
+++ b/sql/server/rel_dump.c
@@ -936,7 +936,8 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re
char *tname = NULL, *cname = NULL, *var_cname = NULL, *e, *b = r +
*pos, *st;
sql_exp *exp = NULL;
list *exps = NULL;
- sql_subtype *tpe;
+ sql_type *t = NULL;
+ sql_subtype tpe;
quote = (r[*pos] == '"');
b += quote;
@@ -1060,8 +1061,11 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re
(*pos)++;
}
convertIdent(tname);
- if (!(tpe = sql_bind_subtype(sql->sa, tname, d, s)))
- return sql_error(sql, ERR_NOTFOUND,
SQLSTATE(42000) "SQL type %s(%d, %d) not found\n", tname, d, s);
+ if (!sql_find_subtype(&tpe, tname, d, s)) {
+ if (!(t = mvc_bind_type(sql, tname))) /* try an
external type */
+ return sql_error(sql, ERR_NOTFOUND,
SQLSTATE(42000) "SQL type %s(%d, %d) not found\n", tname, d, s);
+ sql_init_subtype(&tpe, t, d, s);
+ }
skipWS(r, pos);
*e = old;
if (r[*pos] == '[') { /* convert */
@@ -1073,13 +1077,13 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re
return sql_error(sql, -1,
SQLSTATE(42000) "Convert: missing ']'\n");
(*pos)++;
skipWS(r, pos);
- exp = exp_convert(sql->sa, exp,
exp_subtype(exp), tpe);
+ exp = exp_convert(sql->sa, exp,
exp_subtype(exp), &tpe);
} else {
st = readString(r,pos);
if (st && strcmp(st, "NULL") == 0)
- exp = exp_atom(sql->sa,
atom_general(sql->sa, tpe, NULL));
+ exp = exp_atom(sql->sa,
atom_general(sql->sa, &tpe, NULL));
else
- exp = exp_atom(sql->sa,
atom_general(sql->sa, tpe, st));
+ exp = exp_atom(sql->sa,
atom_general(sql->sa, &tpe, st));
skipWS(r, pos);
}
}
@@ -1088,13 +1092,16 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re
*e = 0;
tname = b;
convertIdent(tname);
- if (!(tpe = sql_bind_subtype(sql->sa, tname, 0, 0)))
- return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000)
"SQL type %s not found\n", tname);
+ if (!sql_find_subtype(&tpe, tname, 0, 0)) {
+ if (!(t = mvc_bind_type(sql, tname))) /* try an
external type */
+ return sql_error(sql, ERR_NOTFOUND,
SQLSTATE(42000) "SQL type %s not found\n", tname);
+ sql_init_subtype(&tpe, t, 0, 0);
+ }
st = readString(r,pos);
if (st && strcmp(st, "NULL") == 0)
- exp = exp_atom(sql->sa, atom_general(sql->sa, tpe,
NULL));
+ exp = exp_atom(sql->sa, atom_general(sql->sa, &tpe,
NULL));
else
- exp = exp_atom(sql->sa, atom_general(sql->sa, tpe, st));
+ exp = exp_atom(sql->sa, atom_general(sql->sa, &tpe,
st));
skipWS(r, pos);
break;
default:
diff --git a/sql/storage/bat/bat_storage.c b/sql/storage/bat/bat_storage.c
--- a/sql/storage/bat/bat_storage.c
+++ b/sql/storage/bat/bat_storage.c
@@ -4001,11 +4001,13 @@ temp_del_tab(sql_trans *tr, sql_table *t
{
ulng tid = tr->tid;
lock_table(tr->store, t->base.id);
+ table_retry:
for (storage *d = ATOMIC_PTR_GET(&t->data), *p = NULL, *n = NULL; d; d
= n) {
n = d->next;
if (d->cs.ts == tid) {
if (p == NULL) {
- ATOMIC_PTR_SET(&t->data, n);
+ if (!ATOMIC_PTR_CAS(&t->data, (void **) &d, n))
+ goto table_retry;
} else {
p->next = n;
}
@@ -4019,11 +4021,13 @@ temp_del_tab(sql_trans *tr, sql_table *t
for (node *nd = t->columns->l->h; nd; nd = nd->next) {
sql_column *c = nd->data;
lock_column(tr->store, c->base.id);
+ column_retry:
for (sql_delta *d = ATOMIC_PTR_GET(&c->data), *p = NULL, *n =
NULL; d; d = n) {
n = d->next;
if (d->cs.ts == tid) {
if (p == NULL) {
- ATOMIC_PTR_SET(&c->data, n);
+ if (!ATOMIC_PTR_CAS(&c->data, (void **)
&d, n))
+ goto column_retry;
} else {
p->next = n;
}
diff --git a/sql/test/SQLancer/Tests/All b/sql/test/SQLancer/Tests/All
--- a/sql/test/SQLancer/Tests/All
+++ b/sql/test/SQLancer/Tests/All
@@ -16,3 +16,4 @@ sqlancer15
sqlancer16
sqlancer17
sqlancer18
+sqlancer19
diff --git a/sql/test/SQLancer/Tests/sqlancer19.SQL.py
b/sql/test/SQLancer/Tests/sqlancer19.SQL.py
new file mode 100644
--- /dev/null
+++ b/sql/test/SQLancer/Tests/sqlancer19.SQL.py
@@ -0,0 +1,40 @@
+import os
+
+from MonetDBtesting.sqltest import SQLTestCase
+
+port = os.environ['MAPIPORT']
+db = os.environ['TSTDB']
+
+with SQLTestCase() as cli:
+ cli.connect(username="monetdb", password="monetdb")
+ cli.execute("""
+ START TRANSACTION;
+ CREATE TABLE "t0" ("c0" INTERVAL SECOND NOT NULL, "c1" JSON);
+ INSERT INTO "t0" VALUES (INTERVAL '9' SECOND, '""');
+
+ CREATE TABLE "t1" ("c0" BINARY LARGE OBJECT,"c1" BIGINT);
+ INSERT INTO "t1" VALUES (NULL, 1),(NULL, 6),(NULL, 0),(BINARY LARGE OBJECT
'50', NULL),(BINARY LARGE OBJECT 'ACBC2EDEF0', NULL),
+ (BINARY LARGE OBJECT '65', NULL),(BINARY LARGE OBJECT 'EF43C0',
NULL),(BINARY LARGE OBJECT '90', NULL),(BINARY LARGE OBJECT '', NULL);
+
+ CREATE TABLE "t3" ("c0" BIGINT,"c1" INTERVAL MONTH);
+ INSERT INTO "t3" VALUES (1, INTERVAL '9' MONTH),(5, INTERVAL '6'
MONTH),(5, NULL),(7, NULL),(2, INTERVAL '1' MONTH),(2, INTERVAL '1' MONTH);
+ COMMIT;
+
+ START TRANSACTION;
+ CREATE REMOTE TABLE "rt1" ("c0" BINARY LARGE OBJECT,"c1" BIGINT) ON
'mapi:monetdb://localhost:%s/%s/sys/t1';
+ CREATE REMOTE TABLE "rt3" ("c0" BIGINT,"c1" INTERVAL MONTH) ON
'mapi:monetdb://localhost:%s/%s/sys/t3';
+ COMMIT;""" % (port, db, port, db)).assertSucceeded()
+
+ cli.execute('SELECT json."integer"(JSON \'1\') FROM
rt3;').assertSucceeded().assertDataResultMatch([(1,),(1,),(1,),(1,),(1,),(1,)])
+
+ cli.execute('MERGE INTO t0 USING (SELECT 1 FROM rt1) AS mergejoined(c0) ON
TRUE WHEN NOT MATCHED THEN INSERT (c0) VALUES (INTERVAL \'5\' SECOND);') \
+ .assertSucceeded().assertRowCount(0)
+
+ cli.execute("""
+ START TRANSACTION;
+ DROP TABLE rt1;
+ DROP TABLE rt3;
+ DROP TABLE t0;
+ DROP TABLE t1;
+ DROP TABLE t3;
+ COMMIT;""").assertSucceeded()
diff --git a/testing/sqllogictest.py b/testing/sqllogictest.py
--- a/testing/sqllogictest.py
+++ b/testing/sqllogictest.py
@@ -218,12 +218,15 @@ class SQLLogic:
expected_err_code=None,
expected_err_msg=None,
expected_rowcount=None,
- conn=None):
+ conn=None,
+ verbose=False):
crs = conn.cursor() if conn else self.crs
if skipidx.search(statement) is not None:
# skip creation of ascending or descending index
return ['statement', 'ok']
try:
+ if verbose:
+ print(f'Executing:\n{err_stmt or statement}')
affected_rowcount = crs.execute(statement)
except (pymonetdb.Error, ValueError) as e:
msg = e.args[0]
@@ -352,10 +355,12 @@ class SQLLogic:
sep = '|'
print('', file=self.out)
- def exec_query(self, query, columns, sorting, pyscript, hashlabel,
nresult, hash, expected, conn=None) -> bool:
+ def exec_query(self, query, columns, sorting, pyscript, hashlabel,
nresult, hash, expected, conn=None, verbose=False) -> bool:
err = False
crs = conn.cursor() if conn else self.crs
try:
+ if verbose:
+ print(f'Executing:\n{query}')
crs.execute(query)
except (pymonetdb.Error, ValueError) as e:
self.query_error(query, 'query failed', e.args[0])
@@ -598,7 +603,7 @@ class SQLLogic:
self.raise_error('invalid connection parameters definition,
username or password missing!')
return res
- def parse(self, f, approve=None):
+ def parse(self, f, approve=None, verbose=False):
self.approve = approve
self.initfile(f)
if self.language == 'sql':
@@ -659,9 +664,9 @@ class SQLLogic:
if not skipping:
if is_copyfrom_stmt(statement):
stmt, stmt_less_data = prepare_copyfrom_stmt(statement)
- result = self.exec_statement(stmt, expectok,
err_stmt=stmt_less_data, expected_err_code=expected_err_code,
expected_err_msg=expected_err_msg, expected_rowcount=expected_rowcount,
conn=conn)
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list