Changeset: 075cac9cdbd4 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/075cac9cdbd4
Modified Files:
        sql/backends/monet5/sql_cat.c
        sql/server/rel_schema.c
        sql/server/sql_mvc.c
        sql/server/sql_mvc.h
        sql/server/sql_parser.y
        sql/storage/bat/bat_storage.c
        sql/storage/sql_storage.h
        sql/storage/store.c
Branch: Mar2025
Log Message:

add initial support for alter table tn alter column cn type;
ie alter the type of a column
(grafted from c039848dc29e5ab0b791594dfbad3e666263c5a5)


diffs (truncated from 320 to 300 lines):

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
@@ -1195,7 +1195,7 @@ alter_table(Client cntxt, mvc *sql, char
        }
 
        for (n = ol_first_node(t->columns); n; n = n->next) {
-               /* null or default value changes */
+               /* null, default value or type changes */
                sql_column *c = n->data;
 
                if (c->base.new)
@@ -1273,6 +1273,17 @@ alter_table(Client cntxt, mvc *sql, char
                                        break;
                        }
                }
+               if (subtype_cmp(&c->type, &nc->type) != 0) {
+                       switch (mvc_subtype(sql, nc, &c->type)) {
+                               case -1:
+                                       throw(SQL,"sql.alter_table", 
SQLSTATE(HY013) MAL_MALLOC_FAIL);
+                               case -2:
+                               case -3:
+                                       throw(SQL,"sql.alter_table", 
SQLSTATE(42000) "ALTER TYPE: transaction conflict detected");
+                               default:
+                                       break;
+                       }
+               }
        }
        /* handle new columns */
        for (; n; n = n->next) {
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
@@ -1178,6 +1178,9 @@ table_element(sql_query *query, symbol *
                case SQL_DROP_CONSTRAINT:
                        msg = "drop constraint from";
                        break;
+               case SQL_TYPE:
+                       msg = "alter column type";
+                       break;
                default:
                        sql_error(sql, 02, SQLSTATE(M0M03) "%s: Unknown table 
element (%p)->token = %s\n", action, s, token2string(s->token));
                        return SQL_ERR;
@@ -1440,6 +1443,39 @@ table_element(sql_query *query, symbol *
        case SQL_DROP_CONSTRAINT:
                res = SQL_OK;
                break;
+       case SQL_TYPE:
+       {
+               dlist *l = s->data.lval;
+               char *cname = l->h->data.sval;
+               sql_subtype *tv = &l->h->next->data.typeval;
+               sql_column *col = mvc_bind_column(sql, t, cname);
+
+               assert(l->h->next->type == type_type);
+               (void)tv;
+               if (col == NULL) {
+                       sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "ALTER 
TYPE: no such column '%s'\n", cname);
+                       return SQL_ERR;
+               }
+               if (t->system) {
+                       sql_error(sql, 02, SQLSTATE(42000) "ALTER TYPE: cannot 
alter type of column '%s': table is a system table\n", cname);
+                       return SQL_ERR;
+               }
+               if (mvc_check_dependency(sql, col->base.id, COLUMN_DEPENDENCY, 
NULL)) {
+                       sql_error(sql, 02, SQLSTATE(2BM37) "ALTER TYPE: cannot 
alter type of column '%s': there are database objects which depend on it\n", 
cname);
+                       return SQL_ERR;
+               }
+               switch (mvc_subtype(sql, col, tv)) {
+                       case -1:
+                               (void) sql_error(sql, 02, SQLSTATE(HY013) 
MAL_MALLOC_FAIL);
+                               return SQL_ERR;
+                       case -2:
+                       case -3:
+                               (void) sql_error(sql, 02, SQLSTATE(42000) "NULL 
CONSTRAINT: transaction conflict detected");
+                               return SQL_ERR;
+                       default:
+                               break;
+               }
+       } break;
        default:
                res = SQL_ERR;
        }
diff --git a/sql/server/sql_mvc.c b/sql/server/sql_mvc.c
--- a/sql/server/sql_mvc.c
+++ b/sql/server/sql_mvc.c
@@ -1529,6 +1529,18 @@ mvc_storage(mvc *m, sql_column *col, cha
 }
 
 int
+mvc_subtype(mvc *m, sql_column *col, sql_subtype *t)
+{
+       TRC_DEBUG(SQL_TRANS, "Type: %s %s\n", col->base.name, 
t->type->base.name);
+       if (col->t->persistence == SQL_DECLARED_TABLE) {
+               col->type = *t;
+               return 0;
+       } else {
+               return sql_trans_alter_type(m->session->tr, col, t);
+       }
+}
+
+int
 mvc_access(mvc *m, sql_table *t, sht access)
 {
        TRC_DEBUG(SQL_TRANS, "Access: %s %d\n", t->base.name, access);
diff --git a/sql/server/sql_mvc.h b/sql/server/sql_mvc.h
--- a/sql/server/sql_mvc.h
+++ b/sql/server/sql_mvc.h
@@ -229,6 +229,7 @@ extern int mvc_default(mvc *c, sql_colum
 extern int mvc_check(mvc *m, sql_column *col, char *check);
 extern int mvc_drop_default(mvc *c, sql_column *col);
 extern int mvc_storage(mvc *c, sql_column *col, char *storage);
+extern int mvc_subtype(mvc *m, sql_column *col, sql_subtype *t);
 extern int mvc_access(mvc *m, sql_table *t, sht access);
 extern int mvc_is_sorted(mvc *c, sql_column *col);
 extern int mvc_is_unique(mvc *m, sql_column *col);
diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y
--- a/sql/server/sql_parser.y
+++ b/sql/server/sql_parser.y
@@ -1450,6 +1450,11 @@ alter_table_element:
          append_string(l, $1);
          append_string(l, NULL);
          $$ = _symbol_create_list( SQL_STORAGE, l); }
+ |     column data_type
+       { dlist *l = L();
+         append_string(l, $1);
+         append_type(l, &$2);
+         $$ = _symbol_create_list( SQL_TYPE, l); }
  ;
 
 drop_table_element:
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
@@ -3009,6 +3009,62 @@ col_not_null(sql_trans *tr, sql_column *
 }
 
 static int
+swap_bats(sql_trans *tr, sql_column *col, BAT *bn)
+{
+       bool update_conflict = false;
+
+       if (segments_in_transaction(tr, col->t))
+               return LOG_CONFLICT;
+
+       sql_delta *d = NULL, *odelta = ATOMIC_PTR_GET(&col->data);
+
+       if ((d = bind_col_data(tr, col, &update_conflict)) == NULL)
+               return update_conflict ? LOG_CONFLICT : LOG_ERR;
+       assert(d && d->cs.ts == tr->tid);
+       if (odelta != d)
+               trans_add_obj(tr, &col->base, d, &tc_gc_col, 
&commit_update_col, NOT_TO_BE_LOGGED(col->t)?NULL:&log_update_col);
+       if (d->cs.bid)
+               temp_destroy(d->cs.bid);
+       if (d->cs.uibid)
+               temp_destroy(d->cs.uibid);
+       if (d->cs.uvbid)
+               temp_destroy(d->cs.uvbid);
+       bat_set_access(bn, BAT_READ);
+       d->cs.bid = temp_create(bn);
+       d->cs.uibid = 0;
+       d->cs.uvbid = 0;
+       d->cs.ucnt = 0;
+       d->cs.cleared = true;
+       d->cs.ts = tr->tid;
+       ATOMIC_INIT(&d->cs.refcnt, 1);
+       return LOG_OK;
+}
+
+static int
+col_subtype(sql_trans *tr, sql_column *col, sql_subtype *t)
+{
+       int res = LOG_ERR;
+       assert(tr->active);
+       if (!isTable(col->t) || !col->t->s)
+               return res;
+
+       if (col && ATOMIC_PTR_GET(&col->data)) {
+               BAT *b = bind_col(tr, col, RDONLY);
+
+               if (!b)
+                       return res;
+
+               BAT *bn = BATconvert(b, NULL /* could use tids, but need NILS 
*/, t->type->localtype, col->type.scale, t->scale, t->digits);
+               if (!bn)
+                       return res;
+               BBPreclaim(b);
+               res = swap_bats(tr, col, bn);
+               BBPreclaim(bn);
+       }
+       return res;
+}
+
+static int
 load_cs(sql_trans *tr, column_storage *cs, int type, sqlid id)
 {
        sqlstore *store = tr->store;
@@ -4974,38 +5030,6 @@ bind_cands(sql_trans *tr, sql_table *t, 
 }
 
 static int
-swap_bats(sql_trans *tr, sql_column *col, BAT *bn)
-{
-       bool update_conflict = false;
-
-       if (segments_in_transaction(tr, col->t))
-               return LOG_CONFLICT;
-
-       sql_delta *d = NULL, *odelta = ATOMIC_PTR_GET(&col->data);
-
-       if ((d = bind_col_data(tr, col, &update_conflict)) == NULL)
-               return update_conflict ? LOG_CONFLICT : LOG_ERR;
-       assert(d && d->cs.ts == tr->tid);
-       if (odelta != d)
-               trans_add_obj(tr, &col->base, d, &tc_gc_col, 
&commit_update_col, NOT_TO_BE_LOGGED(col->t)?NULL:&log_update_col);
-       if (d->cs.bid)
-               temp_destroy(d->cs.bid);
-       if (d->cs.uibid)
-               temp_destroy(d->cs.uibid);
-       if (d->cs.uvbid)
-               temp_destroy(d->cs.uvbid);
-       bat_set_access(bn, BAT_READ);
-       d->cs.bid = temp_create(bn);
-       d->cs.uibid = 0;
-       d->cs.uvbid = 0;
-       d->cs.ucnt = 0;
-       d->cs.cleared = true;
-       d->cs.ts = tr->tid;
-       ATOMIC_INIT(&d->cs.refcnt, 1);
-       return LOG_OK;
-}
-
-static int
 vacuum_col(sql_trans *tr, sql_column *c, bool force)
 {
        if (segments_in_transaction(tr, c->t))
@@ -5149,6 +5173,7 @@ bat_storage_init( store_functions *sf)
        sf->col_stats = &col_stats;
        sf->col_set_range = &col_set_range;
        sf->col_not_null = &col_not_null;
+       sf->col_subtype = &col_subtype;
 
        sf->col_dup = &col_dup;
        sf->idx_dup = &idx_dup;
diff --git a/sql/storage/sql_storage.h b/sql/storage/sql_storage.h
--- a/sql/storage/sql_storage.h
+++ b/sql/storage/sql_storage.h
@@ -152,6 +152,7 @@ typedef int (*prop_col_fptr) (sql_trans 
 typedef int (*proprec_col_fptr) (sql_trans *tr, sql_column *c, bool *nonil, 
bool *unique, double *unique_est, ValPtr min, ValPtr max);
 typedef int (*col_set_range_fptr) (sql_trans *tr, sql_column *c, sql_part *pt, 
bool add_range);
 typedef int (*col_not_null_fptr) (sql_trans *tr, sql_column *c, bool not_null);
+typedef int (*col_subtype_fptr) (sql_trans *tr, sql_column *c, sql_subtype *t);
 
 /*
 -- create the necessary storage resources for columns, indices and tables
@@ -242,6 +243,7 @@ typedef struct store_functions {
        proprec_col_fptr col_stats;
     col_set_range_fptr col_set_range; /* set range properties to the column 
low level structures */
        col_not_null_fptr col_not_null; /* switch not null property */
+       col_subtype_fptr col_subtype;   /* switch types */
 
        col_dup_fptr col_dup;
        idx_dup_fptr idx_dup;
@@ -400,6 +402,7 @@ extern int sql_trans_drop_column(sql_tra
 extern int sql_trans_alter_null(sql_trans *tr, sql_column *col, int isnull);
 extern int sql_trans_alter_default(sql_trans *tr, sql_column *col, char *val);
 extern int sql_trans_alter_storage(sql_trans *tr, sql_column *col, char 
*storage);
+extern int sql_trans_alter_type(sql_trans *tr, sql_column *col, sql_subtype 
*t);
 extern int sql_trans_alter_check(sql_trans *tr, sql_column *col, char *check);
 extern int sql_trans_is_sorted(sql_trans *tr, sql_column *col);
 extern int sql_trans_is_unique(sql_trans *tr, sql_column *col);
diff --git a/sql/storage/store.c b/sql/storage/store.c
--- a/sql/storage/store.c
+++ b/sql/storage/store.c
@@ -6494,6 +6494,45 @@ sql_trans_alter_storage(sql_trans *tr, s
 }
 
 int
+sql_trans_alter_type(sql_trans *tr, sql_column *col, sql_subtype *t)
+{
+       int res = LOG_OK;
+       sqlstore *store = tr->store;
+
+       if (subtype_cmp(&col->type, t) != 0) {
+               sql_schema *syss = find_sql_schema(tr, 
isGlobal(col->t)?"sys":"tmp");
+               sql_table *syscolumn = find_sql_table(tr, syss, "_columns");
+               sql_column *col_ids = find_sql_column(syscolumn, "id");
+               sql_column *col_type = find_sql_column(syscolumn, "type");
+               sql_column *col_digits = find_sql_column(syscolumn, 
"type_digits");
+               sql_column *col_scale = find_sql_column(syscolumn, 
"type_scale");
+               oid rid = store->table_api.column_find_row(tr, col_ids, 
&col->base.id, NULL);
+               sql_column *dup = NULL;
+               int digits = type_digits(t);
+               int scale = t->type->scale;
+
+               if (is_oid_nil(rid))
+                       return -1;
+               if ((res = store->table_api.column_update_value(tr, col_type, 
rid, t->type->base.name)))
+                       return res;
+               if ((res = store->table_api.column_update_value(tr, col_digits, 
rid, &digits)))
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to