private VxSchemaErrors ApplyChangedColumn(VxSchemaTable table, VxSchemaTableElement oldelem, VxSchemaTableElement newelem, VxSchemaError expected_err, VxPutOpts opts) { VxSchemaErrors errs = new VxSchemaErrors(); log.print("Altering {0}\n", newelem.ToString()); bool destructive = (opts & VxPutOpts.Destructive) != 0; string colname = newelem.GetParam("name"); // Remove any old default constraint; even if it doesn't change, it // can get in the way of modifying the column. We'll add it again // later if needed. if (oldelem.HasDefault()) { string defquery = wv.fmt("ALTER TABLE [{0}] DROP CONSTRAINT {1}", table.name, table.GetDefaultDefaultName(colname)); log.print("Executing {0}\n", defquery); dbi.execute(defquery); } bool did_default_constraint = false; // Don't try to alter the table if we know it won't work. if (expected_err == null) { string query = wv.fmt("ALTER TABLE [{0}] ALTER COLUMN {1}", table.name, table.ColumnToSql(newelem, false)); log.print("Executing {0}\n", query); dbi.execute(query); } else { // Some table attributes can't be changed by ALTER TABLE, // such as changing identity values, or data type changes that // would truncate data. If the client has set the Destructive // flag though, we can try to drop and re-add the column. if (destructive) { log.print("Alter column would fail, dropping and adding.\n"); log.print("Expected error message: {0} ({1})\n", expected_err.msg, expected_err.errnum); string delquery = wv.fmt("ALTER TABLE [{0}] " + "DROP COLUMN [{1}]", table.name, colname); // We need to include the default value here (the second // parameter to ColumnToSql), otherwise adding a column to a // table with data in it might not work. string addquery = wv.fmt("ALTER TABLE [{0}] ADD {1}", table.name, table.ColumnToSql(newelem, true)); log.print("Executing {0}\n", delquery); dbi.execute(delquery); log.print("Executing {0}\n", addquery); dbi.execute(addquery); did_default_constraint = true; } else { // Error 515: Can't modify a column because it contains nulls // and the column requires non-nulls. if (expected_err.errnum == 515) { log.print("Couldn't modify column due to null " + "restriction. Making column nullable.\n"); var nullable = GetNullableColumn(newelem); string query = wv.fmt("ALTER TABLE [{0}] ALTER COLUMN {1}", table.name, table.ColumnToSql(nullable, false)); log.print("Executing {0}\n", query); dbi.execute(query); } else { log.print("Can't alter table and destructive flag " + "not set. Giving up.\n"); string key = table.key; string errmsg = wv.fmt("Refusing to drop and re-add " + "column [{0}] when the destructive option " + "is not set. Error when altering was: '{1}'", colname, expected_err.msg); errs.Add(key, new VxSchemaError(key, errmsg, -1)); } } } // No errors so far, let's try to add the new default values if we // didn't do it already. // FIXME: Check for actual errors, don't care about warnings. if (errs.Count == 0 && newelem.HasDefault() && !did_default_constraint) { string defquery = wv.fmt("ALTER TABLE [{0}] ADD CONSTRAINT {1} " + "DEFAULT {2} FOR {3}", table.name, table.GetDefaultDefaultName(colname), newelem.GetParam("default"), colname); log.print("Executing {0}\n", defquery); dbi.execute(defquery); } if (errs.Count != 0) log.print("Altering column had errors: " + errs.ToString()); return errs; }
// Create a new table element that allows nulls private VxSchemaTableElement GetNullableColumn(VxSchemaTableElement elem) { var nullable = new VxSchemaTableElement(elem.elemtype); foreach (var kvp in elem.parameters) if (kvp.Key == "null") nullable.AddParam("null", "1"); else nullable.AddParam(kvp.Key, kvp.Value); return nullable; }
private void DropTableColumn(VxSchemaTable table, VxSchemaTableElement col) { string colname = col.GetParam("name"); if (col.HasDefault()) { string defquery = wv.fmt("ALTER TABLE [{0}] " + "DROP CONSTRAINT {1}", table.name, table.GetDefaultDefaultName(colname)); dbi.execute(defquery); } string query = wv.fmt("ALTER TABLE [{0}] DROP COLUMN [{1}]", table.name, colname); dbi.execute(query); }
private VxSchemaError PutSchemaTableIndex(string key, VxSchemaTable table, VxSchemaTableElement elem) { string query = ""; if (elem.elemtype == "primary-key") query = table.PrimaryKeyToSql(elem); else if (elem.elemtype == "index") query = table.IndexToSql(elem); else return new VxSchemaError(key, wv.fmt( "Unknown table element '{0}'.", elem.elemtype), -1); try { if (query != "") dbi.execute(query); } catch (SqlException e) { return new VxSchemaError(key, e); } return null; }