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