Changeset: 9484bd536799 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=9484bd536799
Modified Files:
        sql/backends/monet5/sql.c
        sql/backends/monet5/sql_cat.c
        sql/include/sql_catalog.h
        sql/server/rel_propagate.c
        sql/server/rel_propagate.h
        sql/server/rel_schema.c
        sql/server/rel_updates.c
        sql/server/sql_mvc.c
        sql/server/sql_parser.h
        sql/server/sql_parser.y
        sql/storage/sql_catalog.c
        sql/storage/store.c
        sql/test/merge-partitions/Tests/mergepart00.sql
        sql/test/merge-partitions/Tests/mergepart00.stable.err
        sql/test/merge-partitions/Tests/mergepart00.stable.out
        sql/test/merge-partitions/Tests/mergepart01.sql
        sql/test/merge-partitions/Tests/mergepart02.sql
        sql/test/merge-partitions/Tests/mergepart03.sql
        sql/test/merge-partitions/Tests/mergepart03.stable.err
        sql/test/merge-partitions/Tests/mergepart04.sql
        sql/test/merge-partitions/Tests/mergepart04.stable.err
        sql/test/merge-partitions/Tests/mergepart05.sql
        sql/test/merge-partitions/Tests/mergepart05.stable.err
        sql/test/merge-partitions/Tests/mergepart06.sql
        sql/test/merge-partitions/Tests/mergepart07.sql
        sql/test/merge-partitions/Tests/mergepart07.stable.err
        sql/test/merge-partitions/Tests/mergepart08.sql
        sql/test/merge-partitions/Tests/mergepart09.sql
        sql/test/merge-partitions/Tests/mergepart10.sql
        sql/test/merge-partitions/Tests/mergepart11.sql
        sql/test/merge-partitions/Tests/mergepart12.sql
        sql/test/merge-partitions/Tests/mergepart13.sql
        sql/test/merge-partitions/Tests/mergepart14.sql
        sql/test/merge-partitions/Tests/mergepart14.stable.err
        sql/test/merge-partitions/Tests/mergepart15.sql
        sql/test/merge-partitions/Tests/mergepart15.stable.err
        sql/test/merge-partitions/Tests/mergepart16.sql
        sql/test/merge-partitions/Tests/mergepart17.sql
        sql/test/merge-partitions/Tests/mergepart17.stable.err
        sql/test/merge-partitions/Tests/mergepart18.sql
        sql/test/merge-partitions/Tests/mergepart18.stable.err
        sql/test/merge-partitions/Tests/mergepart19.sql
        sql/test/merge-partitions/Tests/mergepart19.stable.err
Branch: merge-partitions
Log Message:

Starting to implement partitioning using an expression. Instead of looking at 
the value directly (done in the column case), we will also give the possibility 
to evaluate an expression, and then partition based on the result of the value 
evaluated against the expression.

Examples of the SQL grammar:

CREATE MERGE TABLE mt1 (a int, b varchar(32)) PARTITION BY RANGE ON (a);        
    --by column
CREATE MERGE TABLE mt2 (a int, b varchar(32)) PARTITION BY RANGE USING 
(sha256(a)); --by expression

Now all left to do is everything related to expressions :)


diffs (truncated from 1531 to 300 lines):

diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c
--- a/sql/backends/monet5/sql.c
+++ b/sql/backends/monet5/sql.c
@@ -334,8 +334,8 @@ create_table_or_view(mvc *sql, char *sna
 
                if (copied == NULL)
                        throw(SQL, "sql.catalog", SQLSTATE(42000) "CREATE 
TABLE: %s_%s_%s conflicts", s->base.name, t->base.name, c->base.name);
-               if(c == t->pcol)
-                       nt->pcol = copied;
+               if(isPartitionedByColumnTable(t) && c == t->part.pcol)
+                       nt->part.pcol = copied;
        }
        if(sql_trans_set_partition_table(sql->session->tr, nt))
                throw(SQL, "sql.catalog", SQLSTATE(42000) "CREATE TABLE: %s_%s: 
an internal error occurred", s->base.name, t->base.name);
diff --git a/sql/backends/monet5/sql_cat.c b/sql/backends/monet5/sql_cat.c
--- a/sql/backends/monet5/sql_cat.c
+++ b/sql/backends/monet5/sql_cat.c
@@ -189,16 +189,16 @@ alter_table_add_range_partition(mvc *sql
        sql_table *mt = NULL, *pt = NULL;
        sql_part *err = NULL;
        str msg = MAL_SUCCEED, err_min = NULL, err_max = NULL, escaped_min = 
NULL, escaped_max = NULL;
-       sql_column *col = NULL;
        int tp1 = 0, errcode = 0;
        ptr pmin = NULL, pmax = NULL;
        size_t smin = 0, smax = 0, serr_min = 0, serr_max = 0;
        ssize_t (*atomtostr)(str *, size_t *, const void *);
        int free_pmin = 1, free_pmax = 1;
+       sql_subtype tpe;
 
        if((msg = validate_alter_table_add_table(sql, 
"sql.alter_table_add_range_partition", msname, mtname, psname, ptname, &mt, 
&pt, update))) {
                return msg;
-       } else if(mt->type != tt_range_partition) {
+       } else if(!isRangePartitionTable(mt)) {
                msg = 
createException(SQL,"sql.alter_table_add_range_partition",SQLSTATE(42000)
                                                                        "ALTER 
TABLE: cannot add range partition into a %s table",
                                                                        
(mt->type == tt_merge_table)?"merge":"list partition");
@@ -210,8 +210,8 @@ alter_table_add_range_partition(mvc *sql
                goto finish;
        }
 
-       col = mt->pcol;
-       tp1 = col->type.type->localtype;
+       find_partition_type(&tpe, mt);
+       tp1 = tpe.type->localtype;
        if(ATOMcmp(TYPE_str, min, ATOMnilptr(TYPE_str))) {
                if (tp1 == TYPE_str) {
                        if ((escaped_min = add_quotes(min)) == NULL) {
@@ -275,7 +275,7 @@ alter_table_add_range_partition(mvc *sql
                free_pmax = 0;
        }
 
-       errcode = sql_trans_add_range_partition(sql->session->tr, mt, pt, 
col->type, pmin, smin, pmax, smax, with_nills, update, &err);
+       errcode = sql_trans_add_range_partition(sql->session->tr, mt, pt, tpe, 
pmin, smin, pmax, smax, with_nills, update, &err);
        switch(errcode) {
                case 0:
                        break;
@@ -336,14 +336,14 @@ alter_table_add_value_partition(mvc *sql
 {
        sql_table *mt = NULL, *pt = NULL;
        str msg = MAL_SUCCEED, escaped = NULL;
-       sql_column *col = NULL;
        sql_part *err = NULL;
        int tp1 = 0, errcode = 0, i = 0, ninserts = 0;
        list *values = list_new(sql->sa, (fdestroy) NULL);
+       sql_subtype tpe;
 
        if((msg = validate_alter_table_add_table(sql, 
"sql.alter_table_add_value_partition", msname, mtname, psname, ptname, &mt, 
&pt, update))) {
                return msg;
-       } else if(mt->type != tt_list_partition) {
+       } else if(!isListPartitionTable(mt)) {
                msg = 
createException(SQL,"sql.alter_table_add_value_partition",SQLSTATE(42000)
                                                                        "ALTER 
TABLE: cannot add value partition into a %s table",
                                                                        
(mt->type == tt_merge_table)?"merge":"range partition");
@@ -355,8 +355,8 @@ alter_table_add_value_partition(mvc *sql
                goto finish;
        }
 
-       col = mt->pcol;
-       tp1 = col->type.type->localtype;
+       find_partition_type(&tpe, mt);
+       tp1 = tpe.type->localtype;
        ninserts = pci->argc - pci->retc - 6;
        if(ninserts <= 0 && !with_nills) {
                msg = 
createException(SQL,"sql.alter_table_add_value_partition",SQLSTATE(42000) 
"ALTER TABLE: no values in the list");
@@ -400,7 +400,7 @@ alter_table_add_value_partition(mvc *sql
                }
 
                nextv = SA_ZNEW(sql->session->tr->sa, sql_part_value); /* 
instantiate the part value */
-               nextv->tpe = col->type;
+               nextv->tpe = tpe;
                nextv->value = sa_alloc(sql->session->tr->sa, len);
                memcpy(nextv->value, pnext, len);
                nextv->length = len;
@@ -414,7 +414,7 @@ alter_table_add_value_partition(mvc *sql
                GDKfree(pnext);
        }
 
-       errcode = sql_trans_add_value_partition(sql->session->tr, mt, pt, 
col->type, values, with_nills, update, &err);
+       errcode = sql_trans_add_value_partition(sql->session->tr, mt, pt, tpe, 
values, with_nills, update, &err);
        switch(errcode) {
                case 0:
                        break;
diff --git a/sql/include/sql_catalog.h b/sql/include/sql_catalog.h
--- a/sql/include/sql_catalog.h
+++ b/sql/include/sql_catalog.h
@@ -132,8 +132,10 @@ typedef enum temp_t {
        SQL_STREAM = 5,
        SQL_REMOTE = 6,
        SQL_REPLICA_TABLE = 7,
-       SQL_MERGE_LIST_PARTITION = 8,
-       SQL_MERGE_RANGE_PARTITION = 9
+       SQL_MERGE_LIST_PARTITION_COL = 8,
+       SQL_MERGE_RANGE_PARTITION_COL = 9,
+       SQL_MERGE_LIST_PARTITION_EXP = 10,
+       SQL_MERGE_RANGE_PARTITION_EXP = 11
 } temp_t;
 
 typedef enum comp_type {
@@ -492,16 +494,20 @@ typedef enum table_types {
        tt_stream = 4,          /* stream */
        tt_remote = 5,          /* stored on a remote server */
        tt_replica_table = 6,   /* multiple replica of the same table */
-       tt_list_partition = 7,
-       tt_range_partition = 8
+       tt_list_partition_col = 7, /* partitioned by a list of values on a 
column */
+       tt_range_partition_col = 8, /* partitioned by a range of values on a 
column */
+       tt_list_partition_exp = 9, /* partitioned by a list of values on an 
expression */
+       tt_range_partition_exp = 10 /* partitioned by a range of values on an 
expression */
 } table_types;
 
 #define isTable(x)       (x->type==tt_table)
 #define isView(x)        (x->type==tt_view)
-#define isMergeTable(x)   (x->type==tt_merge_table || 
x->type==tt_list_partition || x->type==tt_range_partition)
 #define isNonPartitionedTable(x) (x->type==tt_merge_table)
-#define isRangePartitionTable(x) (x->type==tt_range_partition)
-#define isListPartitionTable(x)  (x->type==tt_list_partition)
+#define isRangePartitionTable(x) (x->type==tt_range_partition_col || 
x->type==tt_range_partition_exp)
+#define isListPartitionTable(x)  (x->type==tt_list_partition_col || 
x->type==tt_list_partition_exp)
+#define isPartitionedByColumnTable(x)     (x->type==tt_range_partition_col || 
x->type==tt_list_partition_col)
+#define isPartitionedByExpressionTable(x) (x->type==tt_list_partition_exp || 
x->type==tt_range_partition_exp)
+#define isMergeTable(x)   (x->type==tt_merge_table || isListPartitionTable(x) 
|| isRangePartitionTable(x))
 #define isStream(x)      (x->type==tt_stream)
 #define isRemote(x)      (x->type==tt_remote)
 #define isReplicaTable(x) (x->type==tt_replica_table)
@@ -521,7 +527,7 @@ typedef struct sql_part_value {
 typedef struct sql_part {
        sql_base base;
        struct sql_table *t; /* cached value of the merge table */
-       sql_subtype tpe;     /* the column type */
+       sql_subtype tpe;     /* the column/expression type */
        sht part_type;       /* by range, list/values or none */
        int with_nills;
        union {
@@ -559,7 +565,10 @@ typedef struct sql_table {
        struct sql_table *po;   /* the outer transactions table */
 
        struct sql_table *p;     /* The table is part of this merge table */
-       struct sql_column *pcol; /* If it is partitioned on a column */
+       union {
+               struct sql_column *pcol;  /* If it is partitioned on a column */
+               struct sql_subfunc *pexp; /* If it is partitioned by an 
expression */
+       } part;
 } sql_table;
 
 typedef struct res_col {
@@ -613,6 +622,8 @@ extern node *list_find_name(list *l, con
 extern node *list_find_id(list *l, int id);
 extern node *list_find_base_id(list *l, int id);
 
+extern void find_partition_type(sql_subtype *res, sql_table *t);
+
 extern sql_key *find_sql_key(sql_table *t, const char *kname);
 
 extern sql_idx *find_sql_idx(sql_table *t, const char *kname);
diff --git a/sql/server/rel_propagate.c b/sql/server/rel_propagate.c
--- a/sql/server/rel_propagate.c
+++ b/sql/server/rel_propagate.c
@@ -14,9 +14,218 @@
 #include "rel_dump.h"
 #include "rel_select.h"
 #include "rel_updates.h"
-#include "rel_schema.h"
 #include "sql_mvc.h"
 
+extern sql_rel *rel_list(sql_allocator *sa, sql_rel *l, sql_rel *r);
+
+static sql_exp*
+rel_get_anti_expression(sql_rel *anti_rel, sql_table *t)
+{
+       if(isPartitionedByColumnTable(t)) {
+               int colr = t->part.pcol->colnr;
+               return list_fetch(anti_rel->exps, colr);
+       } else if(isPartitionedByExpressionTable(t)) {
+               //TODO
+               return NULL;
+       } else {
+               assert(0);
+       }
+}
+
+static sql_exp*
+find_anti_expression(sql_rel *dup, sql_table *t)
+{
+       if(isPartitionedByColumnTable(t)) {
+               int colr = t->part.pcol->colnr;
+               return list_fetch(dup->exps, colr);
+       } else if(isPartitionedByExpressionTable(t)) {
+               //TODO
+               return NULL;
+       } else {
+               assert(0);
+       }
+}
+
+static void
+generate_alter_table_error_message(char* buf, sql_table *mt)
+{
+       char *s1 = isRangePartitionTable(mt) ? "range":"list of values";
+       if(isPartitionedByColumnTable(mt)) {
+               sql_column* col = mt->part.pcol;
+               snprintf(buf, BUFSIZ, "ALTER TABLE: there are values in the 
column %s outside the partition %s", col->base.name, s1);
+       } else if(isPartitionedByExpressionTable(mt)) {
+               snprintf(buf, BUFSIZ, "ALTER TABLE: there are values in the 
expression outside the partition %s", s1);
+       } else {
+               assert(0);
+       }
+}
+
+sql_rel *
+rel_alter_table_add_partition_range(mvc* sql, sql_table *mt, sql_table *pt, 
char *sname, char *tname, char *sname2,
+                                                                       char 
*tname2, atom* min, atom* max, int with_nills, int update)
+{
+       sql_rel *rel_psm = rel_create(sql->sa), *anti_rel;
+       list *exps = new_exp_list(sql->sa);
+       sql_exp *exception, *aggr, *anti_exp = NULL, *anti_le, *e1, *e2, 
*anti_nils;
+       sql_subaggr *cf = sql_bind_aggr(sql->sa, sql->session->schema, "count", 
NULL);
+       char buf[BUFSIZ], *pmin = min ? atom2string(sql->sa, min): NULL, *pmax 
= max ? atom2string(sql->sa, max) : NULL;
+       sql_subtype tpe;
+
+       if(!rel_psm || !exps)
+               return NULL;
+
+       find_partition_type(&tpe, mt);
+
+       anti_rel = rel_basetable(sql, pt, tname2);
+       anti_le = rel_get_anti_expression(anti_rel, mt);
+       anti_le = exp_column(sql->sa, exp_relname(anti_le), exp_name(anti_le), 
exp_subtype(anti_le),
+                                                anti_le->card, 
has_nil(anti_le), is_intern(anti_le));
+       anti_rel->exps = new_exp_list(sql->sa);
+       append(anti_rel->exps, anti_le);
+       anti_nils = rel_unop_(sql, anti_le, NULL, "isnull", card_value);
+
+       assert((!min && !max && with_nills) || (min && max));
+       if(min && max) {
+               e1 = create_table_part_atom_exp(sql, min->tpe, 
VALget(&min->data));
+               if (subtype_cmp(&e1->tpe, &tpe) != 0)
+                       e1 = exp_convert(sql->sa, e1, &e1->tpe, &tpe);
+
+               e2 = create_table_part_atom_exp(sql, max->tpe, 
VALget(&max->data));
+               if (subtype_cmp(&e2->tpe, &tpe) != 0)
+                       e2 = exp_convert(sql->sa, e2, &e2->tpe, &tpe);
+
+               anti_exp = exp_compare2(sql->sa, anti_le, e1, e2, 3);
+               set_anti(anti_exp);
+               if(!with_nills) {
+                       anti_nils = exp_compare(sql->sa, anti_nils, 
exp_atom_bool(sql->sa, 1), cmp_equal);
+                       anti_exp = exp_or(sql->sa, 
list_append(new_exp_list(sql->sa), anti_exp),
+                                                         
list_append(new_exp_list(sql->sa), anti_nils), 0);
+               }
+       } else {
+               anti_exp = exp_compare(sql->sa, anti_nils, 
exp_atom_bool(sql->sa, 1), cmp_notequal);
+       }
+
+       anti_rel = rel_select(sql->sa, anti_rel, anti_exp);
+       anti_rel = rel_groupby(sql, anti_rel, NULL);
+       aggr = exp_aggr(sql->sa, NULL, cf, 0, 0, anti_rel->card, 0);
+       (void) rel_groupby_add_aggr(sql, anti_rel, aggr);
+       exp_label(sql->sa, aggr, ++sql->label);
+
+       //generate the exception
+       aggr = exp_column(sql->sa, exp_relname(aggr), exp_name(aggr), 
exp_subtype(aggr), aggr->card, has_nil(aggr),
+                                         is_intern(aggr));
+       generate_alter_table_error_message(buf, mt);
+       exception = exp_exception(sql->sa, aggr, buf);
+
+       //generate the psm statement
+       append(exps, exp_atom_clob(sql->sa, sname));
+       append(exps, exp_atom_clob(sql->sa, tname));
+       assert((sname2 && tname2) || (!sname2 && !tname2));
+       if (sname2) {
+               append(exps, exp_atom_clob(sql->sa, sname2));
+               append(exps, exp_atom_clob(sql->sa, tname2));
+       }
+       append(exps, exp_atom_clob(sql->sa, pmin));
+       append(exps, exp_atom_clob(sql->sa, pmax));
+       append(exps, exp_atom_int(sql->sa, with_nills));
+       append(exps, exp_atom_int(sql->sa, update));
+       rel_psm->l = NULL;
+       rel_psm->r = NULL;
+       rel_psm->op = op_ddl;
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to