Changeset: 36c8b75d135f for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=36c8b75d135f
Modified Files:
        sql/server/rel_schema.c
        sql/server/sql_partition.c
        sql/test/merge-partitions/Tests/mergepart27.sql
        sql/test/merge-partitions/Tests/mergepart27.stable.err
        sql/test/merge-partitions/Tests/mergepart27.stable.out
Branch: Apr2019
Log Message:

Changes to partitioned merge tables:

- We will allow foreign keys on non-partitioned columns, however the constraint 
that foreign keys definition must exactly be the same in all tables in the 
hierarchy still remains.
- SQL constraints cannot be added or dropped on a table while is part of a 
partitioned merge table.

Also fixed validation of SQL_DROP_CONSTRAINT statements.


diffs (truncated from 412 to 300 lines):

diff --git a/sql/server/rel_schema.c b/sql/server/rel_schema.c
--- a/sql/server/rel_schema.c
+++ b/sql/server/rel_schema.c
@@ -917,7 +917,8 @@ table_element(mvc *sql, symbol *s, sql_s
                }
        }       break;
        case SQL_DROP_CONSTRAINT:
-               assert(0);
+               res = SQL_OK;
+               break;
        default:
                res = SQL_ERR;
        }
@@ -1457,15 +1458,6 @@ sql_alter_table(mvc *sql, dlist *dl, dli
                sql_exp ** updates, *e;
 
                assert(te);
-               if (t && te && te->token == SQL_DROP_CONSTRAINT) {
-                       dlist *l = te->data.lval;
-                       char *kname = l->h->data.sval;
-                       int drop_action = l->h->next->data.i_val;
-                       
-                       sname = get_schema_name(sql, sname, tname);
-                       return rel_drop(sql->sa, DDL_DROP_CONSTRAINT, sname, 
kname, drop_action, 0);
-               }
-
                if (t->persistence != SQL_DECLARED_TABLE)
                        sname = s->base.name;
 
@@ -1555,6 +1547,15 @@ sql_alter_table(mvc *sql, dlist *dl, dli
                if (!nt || (te && table_element(sql, te, s, nt, 1) == SQL_ERR)) 
                        return NULL;
 
+               if (te->token == SQL_DROP_CONSTRAINT) {
+                       dlist *l = te->data.lval;
+                       char *kname = l->h->data.sval;
+                       int drop_action = l->h->next->data.i_val;
+
+                       sname = get_schema_name(sql, sname, tname);
+                       return rel_drop(sql->sa, DDL_DROP_CONSTRAINT, sname, 
kname, drop_action, 0);
+               }
+
                if (t->s && !nt->s)
                        nt->s = t->s;
 
diff --git a/sql/server/sql_partition.c b/sql/server/sql_partition.c
--- a/sql/server/sql_partition.c
+++ b/sql/server/sql_partition.c
@@ -32,41 +32,50 @@ table_column_colnr(int *colnr)
 str
 sql_partition_validate_key(mvc *sql, sql_table *nt, sql_key *k, const char* op)
 {
-       if(isPartitionedByColumnTable(nt)) {
-               assert(nt->part.pcol);
-               if(list_length(k->columns) != 1) {
-                       throw(SQL, "sql.partition", SQLSTATE(42000) "%s TABLE: 
%s.%s: in a partitioned table the keys must match "
-                                                                          "the 
columns used in the partition definition", op, nt->s->base.name, nt->base.name);
-               } else {
-                       sql_kc *kcol = k->columns->h->data;
-                       if(kcol->c->colnr != nt->part.pcol->colnr)
-                               throw(SQL, "sql.partition", SQLSTATE(42000) "%s 
TABLE: %s.%s: in a partitioned table the keys must "
-                                                                          
"match the columns used in the partition definition", op, nt->s->base.name, 
nt->base.name);
-               }
-       } else if(isPartitionedByExpressionTable(nt)) {
-               list *kcols, *pcols;
-               sql_allocator *p1, *p2;
+       if (k->type != fkey) {
+               const char *keys = (k->type == pkey) ? "primary" : "unique";
+               assert(k->type == pkey || k->type == ukey);
+
+               if (isPartitionedByColumnTable(nt)) {
+                       assert(nt->part.pcol);
+                       if (list_length(k->columns) != 1) {
+                               throw(SQL, "sql.partition", SQLSTATE(42000) "%s 
TABLE: %s.%s: in a partitioned table, the %s key's "
+                                         "columns must match the columns used 
in the partition definition", op, nt->s->base.name,
+                                         nt->base.name, keys);
+                       } else {
+                               sql_kc *kcol = k->columns->h->data;
+                               if (kcol->c->colnr != nt->part.pcol->colnr)
+                                       throw(SQL, "sql.partition", 
SQLSTATE(42000) "%s TABLE: %s.%s: in a partitioned table, the %s key's "
+                                                 "columns must match the 
columns used in the partition definition", op, nt->s->base.name,
+                                                 nt->base.name, keys);
+                       }
+               } else if (isPartitionedByExpressionTable(nt)) {
+                       list *kcols, *pcols;
+                       sql_allocator *p1, *p2;
 
-               assert(nt->part.pexp->cols);
-               if(list_length(k->columns) != list_length(nt->part.pexp->cols))
-                       throw(SQL, "sql.partition", SQLSTATE(42000) "%s TABLE: 
%s.%s: in a partitioned table the keys must match "
-                                                                          "the 
columns used in the partition definition", op, nt->s->base.name, nt->base.name);
+                       assert(nt->part.pexp->cols);
+                       if (list_length(k->columns) != 
list_length(nt->part.pexp->cols))
+                               throw(SQL, "sql.partition", SQLSTATE(42000) "%s 
TABLE: %s.%s: in a partitioned table, the %s key's "
+                                         "columns must match the columns used 
in the partition definition", op, nt->s->base.name,
+                                         nt->base.name, keys);
 
-               p1 = k->columns->sa; /* save the original sql allocators */
-               p2 = nt->part.pexp->cols->sa;
-               k->columns->sa = sql->sa;
-               nt->part.pexp->cols->sa = sql->sa;
-               kcols = list_sort(k->columns, (fkeyvalue)&key_column_colnr, 
NULL);
-               pcols = list_sort(nt->part.pexp->cols, 
(fkeyvalue)&table_column_colnr, NULL);
-               k->columns->sa = p1;
-               nt->part.pexp->cols->sa = p2;
+                       p1 = k->columns->sa; /* save the original sql 
allocators */
+                       p2 = nt->part.pexp->cols->sa;
+                       k->columns->sa = sql->sa;
+                       nt->part.pexp->cols->sa = sql->sa;
+                       kcols = list_sort(k->columns, 
(fkeyvalue)&key_column_colnr, NULL);
+                       pcols = list_sort(nt->part.pexp->cols, 
(fkeyvalue)&table_column_colnr, NULL);
+                       k->columns->sa = p1;
+                       nt->part.pexp->cols->sa = p2;
 
-               for (node *nn = kcols->h, *mm = pcols->h; nn && mm; nn = 
nn->next, mm = mm->next) {
-                       sql_kc *kcol = nn->data;
-                       int *colnr = mm->data;
-                       if (kcol->c->colnr != *colnr)
-                               throw(SQL, "sql.partition", SQLSTATE(42000) "%s 
TABLE: %s.%s: in a partitioned table the keys must match "
-                                                                          "the 
columns used in the partition definition", op, nt->s->base.name, nt->base.name);
+                       for (node *nn = kcols->h, *mm = pcols->h; nn && mm; nn 
= nn->next, mm = mm->next) {
+                               sql_kc *kcol = nn->data;
+                               int *colnr = mm->data;
+                               if (kcol->c->colnr != *colnr)
+                                       throw(SQL, "sql.partition", 
SQLSTATE(42000) "%s TABLE: %s.%s: in a partitioned table, the %s key's "
+                                                 "columns must match the 
columns used in the partition definition", op, nt->s->base.name,
+                                                 nt->base.name, keys);
+                       }
                }
        }
        return NULL;
diff --git a/sql/test/merge-partitions/Tests/mergepart27.sql 
b/sql/test/merge-partitions/Tests/mergepart27.sql
--- a/sql/test/merge-partitions/Tests/mergepart27.sql
+++ b/sql/test/merge-partitions/Tests/mergepart27.sql
@@ -31,39 +31,45 @@ DROP TABLE checkdefault;
 DROP TABLE subt1;
 DROP TABLE subt2;
 
-CREATE MERGE TABLE checkkeys (a int PRIMARY KEY, b varchar(32)) PARTITION BY 
RANGE USING (b || 'ups'); --error
-CREATE MERGE TABLE checkkeys (a int, b varchar(32) PRIMARY KEY) PARTITION BY 
RANGE USING (a + 1); --error
+CREATE MERGE TABLE checkkeys (a int PRIMARY KEY, b varchar(32)) PARTITION BY 
RANGE USING (b || 'ups'); --error, primary not on a partitioned column
+CREATE MERGE TABLE checkkeys (a int, b varchar(32) PRIMARY KEY) PARTITION BY 
RANGE USING (a + 1); --error, primary not on a partitioned column
 
-CREATE MERGE TABLE checkkeys (a int, b int, PRIMARY KEY(a, b)) PARTITION BY 
RANGE USING (a + 1); --error
+CREATE MERGE TABLE checkkeys (a int, b int, PRIMARY KEY(a, b)) PARTITION BY 
RANGE USING (a + 1); --error, primary not on a partitioned column
 CREATE MERGE TABLE checkkeys (a int, b int, PRIMARY KEY(a, b)) PARTITION BY 
RANGE USING (a + b + 1);
 DROP TABLE checkkeys;
 
-CREATE MERGE TABLE checkkeys (a int PRIMARY KEY, b varchar(32)) PARTITION BY 
RANGE ON (b); --error
-CREATE MERGE TABLE checkkeys (a int, b varchar(32) PRIMARY KEY) PARTITION BY 
RANGE ON (a); --error
+CREATE MERGE TABLE checkkeys (a int PRIMARY KEY, b varchar(32)) PARTITION BY 
RANGE ON (b); --error, primary not on a partitioned column
+CREATE MERGE TABLE checkkeys (a int, b varchar(32) PRIMARY KEY) PARTITION BY 
RANGE ON (a); --error, primary not on a partitioned column
 CREATE MERGE TABLE checkkeys (a int PRIMARY KEY, b varchar(32)) PARTITION BY 
RANGE ON (a);
 CREATE TABLE referenceme (mememe int PRIMARY KEY);
 CREATE TABLE otherref (othermeme varchar(32) PRIMARY KEY);
 
 ALTER TABLE checkkeys ADD FOREIGN KEY (a) REFERENCES referenceme (mememe);
-ALTER TABLE checkkeys ADD FOREIGN KEY (b) REFERENCES otherref (othermeme); 
--error not compatible key with partition
+ALTER TABLE checkkeys ADD FOREIGN KEY (b) REFERENCES otherref (othermeme); 
--foreign keys on non-partitioned columns is allowed
 ALTER TABLE checkkeys DROP CONSTRAINT checkkeys_a_fkey;
 
 CREATE TABLE subt1 (a int PRIMARY KEY, b varchar(32));
 CREATE TABLE subt2 (a int, b varchar(32) PRIMARY KEY);
 
+ALTER TABLE checkkeys ADD TABLE subt1 AS PARTITION BETWEEN 1 AND 100; --error, 
doesn't have the same foreign key
+ALTER TABLE subt1 ADD FOREIGN KEY (b) REFERENCES otherref (othermeme);
 ALTER TABLE checkkeys ADD TABLE subt1 AS PARTITION BETWEEN 1 AND 100;
-ALTER TABLE checkkeys ADD TABLE subt2 AS PARTITION BETWEEN 101 AND 200; --error
+ALTER TABLE subt1 DROP CONSTRAINT subt1_b_fkey; --error, cannot drop SQL 
constraints while the table is part of a merge table
+ALTER TABLE subt1 ADD FOREIGN KEY (a) REFERENCES referenceme (mememe); 
--error, cannot add SQL constraints while the table is part of a merge table
+ALTER TABLE checkkeys ADD TABLE subt2 AS PARTITION BETWEEN 101 AND 200; 
--error, primary keys don't match
 
-ALTER TABLE checkkeys ADD FOREIGN KEY (a) REFERENCES referenceme (mememe); 
--error
-ALTER TABLE checkkeys ADD FOREIGN KEY (b) REFERENCES otherref (othermeme); 
--error
+ALTER TABLE checkkeys ADD FOREIGN KEY (a) REFERENCES referenceme (mememe); 
--error, merge table has child tables
+ALTER TABLE checkkeys ADD FOREIGN KEY (b) REFERENCES otherref (othermeme); 
--error, merge table has child tables
 
 ALTER TABLE checkkeys DROP TABLE subt1;
+ALTER TABLE subt1 DROP CONSTRAINT subt1_b_fkey;
 
 CREATE TABLE subt3 (a int PRIMARY KEY, b varchar(32), FOREIGN KEY (a) 
REFERENCES referenceme(mememe));
 CREATE TABLE another (mememe int PRIMARY KEY);
 
-ALTER TABLE checkkeys ADD TABLE subt3 AS PARTITION BETWEEN 1 AND 100; --error 
checkkeys does not have the foreign key
+ALTER TABLE checkkeys ADD TABLE subt3 AS PARTITION BETWEEN 1 AND 100; --error 
checkkeys does not have the foreign key b
 ALTER TABLE checkkeys ADD FOREIGN KEY (a) REFERENCES referenceme (mememe);
+ALTER TABLE checkkeys DROP CONSTRAINT checkkeys_b_fkey;
 ALTER TABLE checkkeys ADD TABLE subt3 AS PARTITION BETWEEN 1 AND 100;
 ALTER TABLE checkkeys DROP TABLE subt3;
 ALTER TABLE checkkeys DROP CONSTRAINT checkkeys_a_fkey;
@@ -72,10 +78,22 @@ ALTER TABLE subt3 DROP CONSTRAINT subt3_
 ALTER TABLE subt3 ADD FOREIGN KEY (a) REFERENCES another (mememe);
 ALTER TABLE checkkeys ADD TABLE subt3 AS PARTITION BETWEEN 1 AND 100; --error 
foreign keys reference different tables
 
+CREATE MERGE TABLE checkunique (a int unique, b varchar(32)) PARTITION BY 
RANGE ON (b); --error, partition by on a not unique column
+CREATE MERGE TABLE checkunique (a int unique, b varchar(32)) PARTITION BY 
RANGE ON (a);
+CREATE TABLE subt4 (a int, b varchar(32) unique);
+ALTER TABLE checkunique ADD TABLE subt4 AS PARTITION BETWEEN 1 AND 2; --error, 
the partition is not on the unique column
+DROP TABLE subt4;
+
+CREATE TABLE subt4 (a int unique , b varchar(32));
+ALTER TABLE checkunique ADD TABLE subt4 AS PARTITION BETWEEN 1 AND 2;
+ALTER TABLE checkunique DROP TABLE subt4;
+
 DROP TABLE checkkeys;
+DROP TABLE checkunique;
 DROP TABLE subt1;
 DROP TABLE subt2;
 DROP TABLE subt3;
+DROP TABLE subt4;
 DROP TABLE referenceme;
 DROP TABLE otherref;
 DROP TABLE another;
diff --git a/sql/test/merge-partitions/Tests/mergepart27.stable.err 
b/sql/test/merge-partitions/Tests/mergepart27.stable.err
--- a/sql/test/merge-partitions/Tests/mergepart27.stable.err
+++ b/sql/test/merge-partitions/Tests/mergepart27.stable.err
@@ -40,50 +40,66 @@ MAPI  = (monetdb) /var/tmp/mtest-12261/.
 QUERY = ALTER TABLE checkdefault ADD TABLE subt1 AS PARTITION BETWEEN 1 AND 
100; --error not compatible defaults
 ERROR = !ALTER RANGE PARTITION TABLE: to be added table column DEFAULT value 
doesn't match RANGE PARTITION TABLE definition
 CODE  = 3F000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = CREATE MERGE TABLE checkkeys (a int PRIMARY KEY, b varchar(32)) 
PARTITION BY RANGE USING (b || 'ups'); --error
-ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table the keys must 
match the columns used in the partition definition
+MAPI  = (monetdb) /var/tmp/mtest-31182/.s.monetdb.34419
+QUERY = CREATE MERGE TABLE checkkeys (a int PRIMARY KEY, b varchar(32)) 
PARTITION BY RANGE USING (b || 'ups'); --error, primary not on a partitioned 
column
+ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table, the primary 
key's columns must match the columns used in the partition definition
+CODE  = 42000
+MAPI  = (monetdb) /var/tmp/mtest-31182/.s.monetdb.34419
+QUERY = CREATE MERGE TABLE checkkeys (a int, b varchar(32) PRIMARY KEY) 
PARTITION BY RANGE USING (a + 1); --error, primary not on a partitioned column
+ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table, the primary 
key's columns must match the columns used in the partition definition
 CODE  = 42000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = CREATE MERGE TABLE checkkeys (a int, b varchar(32) PRIMARY KEY) 
PARTITION BY RANGE USING (a + 1); --error
-ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table the keys must 
match the columns used in the partition definition
+MAPI  = (monetdb) /var/tmp/mtest-31182/.s.monetdb.34419
+QUERY = CREATE MERGE TABLE checkkeys (a int, b int, PRIMARY KEY(a, b)) 
PARTITION BY RANGE USING (a + 1); --error, primary not on a partitioned column
+ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table, the primary 
key's columns must match the columns used in the partition definition
 CODE  = 42000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = CREATE MERGE TABLE checkkeys (a int, b int, PRIMARY KEY(a, b)) 
PARTITION BY RANGE USING (a + 1); --error
-ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table the keys must 
match the columns used in the partition definition
+MAPI  = (monetdb) /var/tmp/mtest-31182/.s.monetdb.34419
+QUERY = CREATE MERGE TABLE checkkeys (a int PRIMARY KEY, b varchar(32)) 
PARTITION BY RANGE ON (b); --error, primary not on a partitioned column
+ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table, the primary 
key's columns must match the columns used in the partition definition
 CODE  = 42000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = CREATE MERGE TABLE checkkeys (a int PRIMARY KEY, b varchar(32)) 
PARTITION BY RANGE ON (b); --error
-ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table the keys must 
match the columns used in the partition definition
+MAPI  = (monetdb) /var/tmp/mtest-31182/.s.monetdb.34419
+QUERY = CREATE MERGE TABLE checkkeys (a int, b varchar(32) PRIMARY KEY) 
PARTITION BY RANGE ON (a); --error, primary not on a partitioned column
+ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table, the primary 
key's columns must match the columns used in the partition definition
 CODE  = 42000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = CREATE MERGE TABLE checkkeys (a int, b varchar(32) PRIMARY KEY) 
PARTITION BY RANGE ON (a); --error
-ERROR = !CREATE TABLE: sys.checkkeys: in a partitioned table the keys must 
match the columns used in the partition definition
+MAPI  = (monetdb) /var/tmp/mtest-8822/.s.monetdb.32314
+QUERY = ALTER TABLE checkkeys ADD TABLE subt1 AS PARTITION BETWEEN 1 AND 100; 
--error, doesn't have the same foreign key
+ERROR = !ALTER RANGE PARTITION TABLE: to be added table key doesn't match 
RANGE PARTITION TABLE definition
+CODE  = 3F000
+MAPI  = (monetdb) /var/tmp/mtest-31522/.s.monetdb.37006
+QUERY = ALTER TABLE subt1 DROP CONSTRAINT subt1_b_fkey; --error, cannot drop 
SQL constraints while the table is part of a merge table
+ERROR = !ALTER TABLE: cannot drop constraint from a PARTITION of a MERGE or 
REPLICA TABLE 'subt1'
 CODE  = 42000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = ALTER TABLE checkkeys ADD FOREIGN KEY (b) REFERENCES otherref 
(othermeme); --error not compatible key with partition
-ERROR = !ALTER TABLE: sys.checkkeys: in a partitioned table the keys must 
match the columns used in the partition definition
+MAPI  = (monetdb) /var/tmp/mtest-31522/.s.monetdb.37006
+QUERY = ALTER TABLE subt1 ADD FOREIGN KEY (a) REFERENCES referenceme (mememe); 
--error, cannot add SQL constraints while the table is part of a merge table
+ERROR = !ALTER TABLE: cannot add constraint to a PARTITION of a MERGE or 
REPLICA TABLE 'subt1'
 CODE  = 42000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = ALTER TABLE checkkeys ADD TABLE subt2 AS PARTITION BETWEEN 101 AND 
200; --error
+MAPI  = (monetdb) /var/tmp/mtest-31522/.s.monetdb.37006
+QUERY = ALTER TABLE checkkeys ADD TABLE subt2 AS PARTITION BETWEEN 101 AND 
200; --error, primary keys don't match
 ERROR = !ALTER RANGE PARTITION TABLE: to be added table column NULL check 
doesn't match RANGE PARTITION TABLE definition
 CODE  = 3F000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = ALTER TABLE checkkeys ADD FOREIGN KEY (a) REFERENCES referenceme 
(mememe); --error
+MAPI  = (monetdb) /var/tmp/mtest-31182/.s.monetdb.34419
+QUERY = ALTER TABLE checkkeys ADD FOREIGN KEY (a) REFERENCES referenceme 
(mememe); --error, merge table has child tables
 ERROR = !ALTER TABLE: cannot add constraint to MERGE TABLE 'checkkeys'
 CODE  = 42000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = ALTER TABLE checkkeys ADD FOREIGN KEY (b) REFERENCES otherref 
(othermeme); --error
+MAPI  = (monetdb) /var/tmp/mtest-31182/.s.monetdb.34419
+QUERY = ALTER TABLE checkkeys ADD FOREIGN KEY (b) REFERENCES otherref 
(othermeme); --error, merge table has child tables
 ERROR = !ALTER TABLE: cannot add constraint to MERGE TABLE 'checkkeys'
 CODE  = 42000
-MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
-QUERY = ALTER TABLE checkkeys ADD TABLE subt3 AS PARTITION BETWEEN 1 AND 100; 
--error checkkeys does not have the foreign key
-ERROR = !ALTER RANGE PARTITION TABLE: to be added table key doesn't match 
RANGE PARTITION TABLE definition
+MAPI  = (monetdb) /var/tmp/mtest-8822/.s.monetdb.32314
+QUERY = ALTER TABLE checkkeys ADD TABLE subt3 AS PARTITION BETWEEN 1 AND 100; 
--error checkkeys does not have the foreign key b
+ERROR = !ALTER RANGE PARTITION TABLE: to be added table key's columns doesn't 
match RANGE PARTITION TABLE definition
 CODE  = 3F000
 MAPI  = (monetdb) /var/tmp/mtest-12261/.s.monetdb.38633
 QUERY = ALTER TABLE checkkeys ADD TABLE subt3 AS PARTITION BETWEEN 1 AND 100; 
--error foreign keys reference different tables
 ERROR = !ALTER RANGE PARTITION TABLE: to be added table key doesn't match 
RANGE PARTITION TABLE definition
 CODE  = 3F000
+MAPI  = (monetdb) /var/tmp/mtest-10136/.s.monetdb.37062
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to