001: /* Copyright (c) 2001-2005, The HSQL Development Group
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the HSQL Development Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package org.hsqldb;
032:
033: import org.hsqldb.HsqlNameManager.HsqlName;
034: import org.hsqldb.index.RowIterator;
035: import org.hsqldb.lib.ArrayUtil;
036: import org.hsqldb.lib.HashSet;
037:
038: /**
039: * The methods in this class perform alterations to the structure of an
040: * existing table which may result in a new Table object
041: *
042: * @author fredt@users
043: * @version 1.8.0
044: * @since 1.7.0
045: */
046: class TableWorks {
047:
048: private Table table;
049: private Session session;
050:
051: TableWorks(Session session, Table table) {
052: this .table = table;
053: this .session = session;
054: }
055:
056: Table getTable() {
057: return table;
058: }
059:
060: /**
061: * Creates a foreign key according to current sql.strict_fk or
062: * sql.strong_fk settings. Foreign keys are enforced via indexes on both
063: * the referencing (child) and referenced (parent) tables.
064: * <p>
065: * In versions 1.7.0 and 1.7.1 some non-standard features were supported
066: * for compatibility with older databases. These allowed foreign keys
067: * to be created without the prior existence of a unique constraint on
068: * the referenced columns.
069: * <p>
070: * In version 1.7.2, a unique constraint on the referenced columns must
071: * exist.
072: *
073: * The non-unique index on the referencing table is now always created
074: * whether or not a PK or unique constraint index on the columns exist.
075: * This closes the loopholes opened by the introduction of ALTER TABLE
076: * for adding foreign keys.
077: *
078: * Foriegn keys on temp tables can reference other temp tables with the
079: * same rules above. Foreign keys on permanent tables cannot reference
080: * temp tables.
081: *
082: * Duplicate foreign keys are now disallowed.
083: *
084: * -- The unique index on the referenced table must always belong to a
085: * constraint (PK or UNIQUE). Otherwise after a SHUTDOWN and restart the
086: * index will not exist at the time of creation of the foreign key when
087: * the foreign key is referencing the same table.
088: *
089: * -- The non-unique index on the referencing table is always created
090: * regardless of any existing index. This allows the foreign key
091: * constraint to be dropped when required.
092: *
093: *
094: * (fred@users)
095: *
096: * @param fkcol
097: * @param expcol
098: * @param name foreign key name
099: * @param expTable
100: * @param deleteAction
101: * @param updateAction
102: * @throws HsqlException
103: */
104: void createForeignKey(int[] fkcol, int[] expcol, HsqlName name,
105: Table mainTable, int deleteAction, int updateAction)
106: throws HsqlException {
107:
108: table.database.schemaManager.checkConstraintExists(name.name,
109: table.getSchemaName(), false);
110:
111: // name check
112: if (table.getConstraint(name.name) != null) {
113: throw Trace.error(Trace.CONSTRAINT_ALREADY_EXISTS);
114: }
115:
116: // existing FK check
117: if (table.getConstraintForColumns(mainTable, expcol, fkcol) != null) {
118: throw Trace.error(Trace.CONSTRAINT_ALREADY_EXISTS);
119: }
120:
121: if (mainTable.isTemp() != table.isTemp()) {
122: throw Trace.error(Trace.FOREIGN_KEY_NOT_ALLOWED);
123: }
124:
125: boolean isSelf = table == mainTable;
126: int offset = table.database.schemaManager.getTableIndex(table);
127: boolean isforward = offset != -1
128: && offset < table.database.schemaManager
129: .getTableIndex(mainTable);
130: Index exportindex = mainTable
131: .getUniqueConstraintIndexForColumns(expcol);
132:
133: if (exportindex == null) {
134: throw Trace.error(Trace.SQL_CONSTRAINT_REQUIRED, mainTable
135: .getName().statementName);
136: }
137:
138: // existing rows, value checks
139: Constraint.checkReferencedRows(session, table, fkcol,
140: exportindex);
141:
142: // create
143: HsqlName iname = table.database.nameManager.newAutoName("IDX");
144: Index fkindex = createIndex(fkcol, iname, false, true,
145: isforward);
146: HsqlName pkname = table.database.nameManager.newAutoName("REF",
147: name.name);
148:
149: if (isSelf) {
150:
151: // in case createIndex resulted in new Table object
152: mainTable = table;
153: }
154:
155: Constraint c = new Constraint(pkname, name, mainTable, table,
156: expcol, fkcol, exportindex, fkindex, deleteAction,
157: updateAction);
158:
159: table.addConstraint(c);
160: mainTable.addConstraint(new Constraint(pkname, c));
161: table.database.schemaManager.registerConstraintName(name.name,
162: table.getName());
163: }
164:
165: /**
166: * Because of the way indexes and column data are held in memory and
167: * on disk, it is necessary to recreate the table when an index is added
168: * to a non-empty table cached table.<p>
169: *
170: * With empty tables, Index objects are simply added<p>
171: *
172: * With MEOMRY and TEXT tables, a new index is built up and nodes for
173: * earch row are interlinked (fredt@users)
174: *
175: * @param col
176: * @param name
177: * @param unique
178: * @param constraint
179: * @param forward
180: * @return new index
181: * @throws HsqlException normally for lack of resources
182: */
183: Index createIndex(int[] col, HsqlName name, boolean unique,
184: boolean constraint, boolean forward) throws HsqlException {
185:
186: Index newindex;
187:
188: if (table.isEmpty(session) || table.isIndexingMutable()) {
189: newindex = table.createIndex(session, col, name, unique,
190: constraint, forward);
191:
192: table.database.schemaManager
193: .clearTempTables(session, table);
194: } else {
195: Table tn = table.moveDefinition(null, null, -1, 0);
196:
197: newindex = tn.createIndexStructure(col, name, unique,
198: constraint, forward);
199:
200: tn.moveData(session, table, -1, 0);
201: tn.updateConstraintsTables(session, table, -1, 0);
202:
203: int index = table.database.schemaManager
204: .getTableIndex(table);
205:
206: table.database.schemaManager.setTable(index, tn);
207:
208: table = tn;
209: }
210:
211: table.database.schemaManager.clearTempTables(session, table);
212: table.database.schemaManager.registerIndexName(newindex
213: .getName().name, table.getName());
214: table.database.schemaManager.recompileViews(table);
215:
216: return newindex;
217: }
218:
219: void addPrimaryKey(int[] cols, HsqlName name) throws HsqlException {
220:
221: if (name == null) {
222: name = table.makeSysPKName();
223: }
224:
225: table.database.schemaManager.checkConstraintExists(name.name,
226: table.getSchemaName(), false);
227: addOrDropPrimaryKey(cols, false);
228:
229: Constraint newconstraint = new Constraint(name, table, table
230: .getPrimaryIndex(), Constraint.PRIMARY_KEY);
231:
232: table.addConstraint(newconstraint);
233: table.database.schemaManager.registerConstraintName(name.name,
234: table.getName());
235: }
236:
237: void addOrDropPrimaryKey(int[] cols, boolean identity)
238: throws HsqlException {
239:
240: if (cols == null) {
241: table.checkDropIndex(table.getIndexes()[0].getName().name,
242: null, true);
243: }
244:
245: Table tn = table.moveDefinitionPK(cols, identity);
246:
247: tn.moveData(session, table, -1, 0);
248: tn.updateConstraintsTables(session, table, -1, 0);
249:
250: int index = table.database.schemaManager.getTableIndex(table);
251:
252: table.database.schemaManager.setTable(index, tn);
253:
254: table = tn;
255:
256: table.database.schemaManager.recompileViews(table);
257: }
258:
259: /**
260: * A unique constraint relies on a unique indexe on the table. It can
261: * cover a single column or multiple columns.
262: * <p>
263: * All unique constraint names are generated by Database.java as unique
264: * within the database. Duplicate constraints (more than one unique
265: * constriant on the same set of columns are still allowed but the
266: * names will be different. (fredt@users)
267: *
268: * @param col
269: * @param name
270: * @throws HsqlException
271: */
272: void createUniqueConstraint(int[] col, HsqlName name)
273: throws HsqlException {
274:
275: table.database.schemaManager.checkConstraintExists(name.name,
276: table.getSchemaName(), false);
277:
278: Constraint[] constraints = table.getConstraints();
279:
280: for (int i = 0, size = constraints.length; i < size; i++) {
281: Constraint c = constraints[i];
282:
283: if (c.isEquivalent(col, Constraint.UNIQUE)
284: || c.getName().name.equals(name.name)) {
285: throw Trace.error(Trace.CONSTRAINT_ALREADY_EXISTS);
286: }
287: }
288:
289: // create an autonamed index
290: HsqlName indexname = table.database.nameManager.newAutoName(
291: "IDX", name.name);
292: Index index = createIndex(col, indexname, true, true, false);
293: Constraint newconstraint = new Constraint(name, table, index,
294: Constraint.UNIQUE);
295:
296: table.addConstraint(newconstraint);
297: table.database.schemaManager.registerConstraintName(name.name,
298: table.getName());
299: }
300:
301: void createCheckConstraint(Constraint c, HsqlName name)
302: throws HsqlException {
303:
304: table.database.schemaManager.checkConstraintExists(name.name,
305: table.getSchemaName(), false);
306:
307: // check the existing rows
308: Expression e = c.core.check;
309:
310: // this workaround is here to stop LIKE optimisation (for proper scripting)
311: e.setLikeOptimised();
312:
313: Select s = Expression.getCheckSelect(session, table, e);
314: Result r = s.getResult(session, 1);
315:
316: c.core.checkFilter = s.tFilter[0];
317: c.core.mainTable = table;
318:
319: if (r.getSize() != 0) {
320: throw Trace.error(Trace.CHECK_CONSTRAINT_VIOLATION);
321: }
322:
323: // getDDL() is here to ensure no subselects etc. are in condition
324: e.getDDL();
325:
326: // removes reference to the Index object in filter
327: c.core.checkFilter.setAsCheckFilter();
328: table.addConstraint(c);
329: table.database.schemaManager.registerConstraintName(name.name,
330: table.getName());
331: }
332:
333: /**
334: * Because of the way indexes and column data are held in memory and
335: * on disk, it is necessary to recreate the table when an index is added
336: * to a non-empty table.<p>
337: * Originally, this method would break existing foreign keys as the
338: * table order in the DB was changed. The new table is now linked
339: * in place of the old table (fredt@users)
340: *
341: * @param indexname
342: * @throws HsqlException
343: */
344: void dropIndex(String indexname) throws HsqlException {
345:
346: if (table.isIndexingMutable()) {
347: table.dropIndex(session, indexname);
348: } else {
349: int[] removeIndex = new int[] { table
350: .getIndexIndex(indexname) };
351: Table tn = table.moveDefinition(removeIndex, null, -1, 0);
352:
353: tn.moveData(session, table, -1, 0);
354: tn.updateConstraintsTables(session, table, -1, 0);
355:
356: int i = table.database.schemaManager.getTableIndex(table);
357:
358: table.database.schemaManager.setTable(i, tn);
359:
360: table = tn;
361: }
362:
363: table.database.schemaManager.removeIndexName(indexname, table
364: .getName());
365: table.database.schemaManager.recompileViews(table);
366: }
367:
368: /**
369: *
370: * @param column
371: * @param colindex
372: * @throws HsqlException
373: */
374: void retypeColumn(Column column, int colindex) throws HsqlException {
375:
376: if (table.isText() && !table.isEmpty(session)) {
377: throw Trace.error(Trace.OPERATION_NOT_SUPPORTED);
378: }
379:
380: table.database.schemaManager.checkColumnIsInView(table, table
381: .getColumn(colindex).columnName.name);
382: table
383: .checkColumnInCheckConstraint(table.getColumn(colindex).columnName.name);
384:
385: int[] dropIndexes = null;
386: Table tn = table.moveDefinition(dropIndexes, column, colindex,
387: 0);
388:
389: tn.moveData(session, table, colindex, 0);
390: tn.updateConstraintsTables(session, table, colindex, 0);
391:
392: int i = table.database.schemaManager.getTableIndex(table);
393:
394: table.database.schemaManager.setTable(i, tn);
395:
396: table = tn;
397:
398: table.database.schemaManager.recompileViews(table);
399: }
400:
401: /**
402: *
403: * @param colIndex
404: * @throws HsqlException
405: */
406: void dropColumn(int colIndex) throws HsqlException {
407:
408: HsqlName constNameRemove = null;
409:
410: if (table.isText() && !table.isEmpty(session)) {
411: throw Trace.error(Trace.OPERATION_NOT_SUPPORTED);
412: }
413:
414: table.database.schemaManager.checkColumnIsInView(table, table
415: .getColumn(colIndex).columnName.name);
416: table
417: .checkColumnInCheckConstraint(table.getColumn(colIndex).columnName.name);
418:
419: Table tn = table;
420: int[] dropIndexes = null;
421: String colName = tn.getColumn(colIndex).columnName.name;
422:
423: tn.checkColumnInFKConstraint(colIndex);
424:
425: if (table.getPrimaryKey().length == 1
426: && table.getPrimaryKey()[0] == colIndex) {
427: table.checkDropIndex(table.getIndex(0).getName().name,
428: null, true);
429:
430: constNameRemove = table.constraintList[0].getName();
431: tn = table.moveDefinitionPK(null, false);
432: }
433:
434: Constraint c = tn
435: .getUniqueConstraintForColumns(new int[] { colIndex });
436:
437: if (c != null) {
438: Index idx = c.getMainIndex();
439:
440: dropIndexes = new int[] { tn
441: .getIndexIndex(idx.getName().name) };
442: constNameRemove = c.getName();
443: }
444:
445: tn = tn.moveDefinition(dropIndexes, null, colIndex, -1);
446:
447: tn.moveData(session, table, colIndex, -1);
448: tn.updateConstraintsTables(session, table, colIndex, -1);
449:
450: int i = table.database.schemaManager.getTableIndex(table);
451:
452: table.database.schemaManager.setTable(i, tn);
453:
454: table = tn;
455:
456: table.database.schemaManager.recompileViews(table);
457:
458: if (constNameRemove != null) {
459: table.removeConstraint(constNameRemove.name);
460: table.database.schemaManager.removeConstraintName(
461: constNameRemove.name, table.getName());
462: }
463: }
464:
465: /**
466: *
467: * @param column
468: * @param colIndex
469: * @throws HsqlException
470: */
471: void addColumn(Column column, int colIndex) throws HsqlException {
472:
473: if (table.isText() && !table.isEmpty(session)) {
474: throw Trace.error(Trace.OPERATION_NOT_SUPPORTED);
475: }
476:
477: Table tn = table;
478:
479: tn = tn.moveDefinition(null, column, colIndex, 1);
480:
481: if (column.isPrimaryKey()) {
482: tn = tn.moveDefinitionPK(new int[] { colIndex }, true);
483: }
484:
485: tn.moveData(session, table, colIndex, 1);
486: tn.updateConstraintsTables(session, table, colIndex, 1);
487:
488: int i = table.database.schemaManager.getTableIndex(table);
489:
490: table.database.schemaManager.setTable(i, tn);
491:
492: table = tn;
493:
494: table.database.schemaManager.recompileViews(table);
495:
496: if (column.isPrimaryKey()) {
497: HsqlName pkNameAdd = tn.makeSysPKName();
498: Constraint newconstraint = new Constraint(pkNameAdd, table,
499: table.getPrimaryIndex(), Constraint.PRIMARY_KEY);
500:
501: table.addConstraint(newconstraint);
502: table.database.schemaManager.registerConstraintName(
503: pkNameAdd.name, table.getName());
504: }
505: }
506:
507: /**
508: * Drop a named constraint
509: *
510: */
511: void dropConstraint(String name) throws HsqlException {
512:
513: Constraint c = table.getConstraint(name);
514: int ctype;
515:
516: if (c == null) {
517: throw Trace.error(Trace.CONSTRAINT_NOT_FOUND,
518: Trace.TableWorks_dropConstraint, new Object[] {
519: name, table.getName().name });
520: }
521:
522: ctype = c.getType();
523:
524: if (ctype == Constraint.MAIN) {
525: throw Trace.error(Trace.DROP_SYSTEM_CONSTRAINT);
526: }
527:
528: if (ctype == Constraint.PRIMARY_KEY) {
529: addOrDropPrimaryKey(null, false);
530: table.removeConstraint(name);
531: } else if (ctype == Constraint.FOREIGN_KEY) {
532: dropFKConstraint(c);
533: } else if (ctype == Constraint.UNIQUE) {
534: HashSet cset = new HashSet();
535:
536: cset.add(c);
537:
538: // throw if the index for unique constraint is shared
539: table.checkDropIndex(c.getMainIndex().getName().name, cset,
540: false);
541:
542: // all is well if dropIndex throws for lack of resources
543: dropIndex(c.getMainIndex().getName().name);
544: table.removeConstraint(name);
545: } else if (ctype == Constraint.CHECK) {
546: table.removeConstraint(name);
547: }
548:
549: table.database.schemaManager.removeConstraintName(name, table
550: .getName());
551: }
552:
553: void dropFKConstraint(Constraint c) throws HsqlException {
554:
555: // drop the reference index, which is automatic and unused elsewhere
556: Index constIndex = c.getRefIndex();
557:
558: // all is well if dropIndex throws for lack of resources
559: dropIndex(constIndex.getName().name);
560:
561: Table mainTable = c.getMain();
562:
563: // MAIN constraint was created after REF, so delete first
564: mainTable.removeConstraint(c.getPkName());
565: table.removeConstraint(c.getFkName());
566: }
567:
568: void reTypeColumn(Column oldCol, Column newCol)
569: throws HsqlException {
570:
571: boolean notallowed = false;
572: int oldtype = oldCol.getType();
573: int newtype = newCol.getType();
574:
575: switch (newtype) {
576:
577: case Types.BINARY:
578: case Types.VARBINARY:
579: case Types.LONGVARBINARY:
580: case Types.OTHER:
581: case Types.JAVA_OBJECT:
582: notallowed = !(newtype == oldtype || table.isEmpty(session));
583: }
584:
585: switch (oldtype) {
586:
587: case Types.BINARY:
588: case Types.VARBINARY:
589: case Types.LONGVARBINARY:
590: case Types.OTHER:
591: case Types.JAVA_OBJECT:
592: notallowed = !(newtype == oldtype || table.isEmpty(session));
593: break;
594:
595: case Types.TINYINT:
596: case Types.SMALLINT:
597: case Types.INTEGER:
598: case Types.BIGINT:
599: case Types.REAL:
600: case Types.FLOAT:
601: case Types.DOUBLE:
602: case Types.NUMERIC:
603: case Types.DECIMAL:
604: switch (newtype) {
605:
606: case Types.DATE:
607: case Types.TIME:
608: case Types.TIMESTAMP:
609: notallowed = !table.isEmpty(session);
610: default:
611: }
612: break;
613:
614: case Types.DATE:
615: case Types.TIME:
616: case Types.TIMESTAMP:
617: switch (newtype) {
618:
619: case Types.TINYINT:
620: case Types.SMALLINT:
621: case Types.INTEGER:
622: case Types.BIGINT:
623: case Types.REAL:
624: case Types.FLOAT:
625: case Types.DOUBLE:
626: case Types.NUMERIC:
627: case Types.DECIMAL:
628: notallowed = !table.isEmpty(session);
629: default:
630: }
631: break;
632: }
633:
634: if (notallowed) {
635: throw Trace.error(Trace.INVALID_CONVERSION);
636: }
637:
638: int colIndex = table.getColumnNr(oldCol.columnName.name);
639:
640: if (table.getPrimaryKey().length > 1) {
641:
642: // if there is a multi-column PK, do not change the PK attributes
643: if (newCol.isIdentity()) {
644: throw Trace.error(Trace.SECOND_PRIMARY_KEY);
645: }
646:
647: newCol.setPrimaryKey(oldCol.isPrimaryKey());
648:
649: if (ArrayUtil.find(table.getPrimaryKey(), colIndex) != -1) {
650: newCol.setNullable(false);
651: }
652: } else if (table.hasPrimaryKey()) {
653: if (oldCol.isPrimaryKey()) {
654: newCol.setPrimaryKey(true);
655: newCol.setNullable(false);
656: } else if (newCol.isPrimaryKey()) {
657: throw Trace.error(Trace.SECOND_PRIMARY_KEY);
658: }
659: } else if (newCol.isPrimaryKey()) {
660: throw Trace.error(Trace.PRIMARY_KEY_NOT_ALLOWED);
661: }
662:
663: // apply and return if only metadata change is required
664: if (newtype == oldtype
665: && oldCol.isNullable() == newCol.isNullable()
666: && oldCol.getScale() == newCol.getScale()
667: && oldCol.isIdentity() == newCol.isIdentity()
668: && oldCol.identityIncrement == newCol.identityIncrement
669: && (oldCol.getSize() == newCol.getSize() || (oldCol
670: .getSize() < newCol.getSize() && (oldtype == Types.VARCHAR
671: || oldtype == Types.DECIMAL || oldtype == Types.NUMERIC)))) {
672:
673: // size of some types may be increased with this command
674: // default expressions can change
675: oldCol.setType(newCol);
676: oldCol.setDefaultExpression(newCol.getDefaultExpression());
677: table.setColumnTypeVars(colIndex);
678: table.resetDefaultsFlag();
679:
680: return;
681: }
682:
683: table.database.schemaManager.checkColumnIsInView(table, table
684: .getColumn(colIndex).columnName.name);
685: table
686: .checkColumnInCheckConstraint(table.getColumn(colIndex).columnName.name);
687: table.checkColumnInFKConstraint(colIndex);
688: checkConvertColDataType(oldCol, newCol);
689: retypeColumn(newCol, colIndex);
690: }
691:
692: void checkConvertColDataType(Column oldCol, Column newCol)
693: throws HsqlException {
694:
695: int colIndex = table.getColumnNr(oldCol.columnName.name);
696: RowIterator it = table.getPrimaryIndex().firstRow(session);
697:
698: while (it.hasNext()) {
699: Row row = it.next();
700: Object o = row.getData()[colIndex];
701:
702: Column.convertObject(session, o, newCol.getType(), newCol
703: .getSize(), newCol.getScale());
704: }
705: }
706:
707: /**
708: * performs the work for changing the nullability of a column
709: */
710: void setColNullability(Column column, boolean nullable)
711: throws HsqlException {
712:
713: int colIndex = table.getColumnNr(column.columnName.name);
714:
715: if (nullable) {
716: if (column.isPrimaryKey()) {
717: throw Trace.error(Trace.TRY_TO_INSERT_NULL);
718: }
719:
720: table.checkColumnInFKConstraint(colIndex,
721: Constraint.SET_NULL);
722: } else {
723: RowIterator it = table.getPrimaryIndex().firstRow(session);
724:
725: while (it.hasNext()) {
726: Row row = it.next();
727: Object o = row.getData()[colIndex];
728:
729: if (o == null) {
730: throw Trace.error(Trace.TRY_TO_INSERT_NULL);
731: }
732: }
733: }
734:
735: column.setNullable(nullable);
736: table.setColumnTypeVars(colIndex);
737: }
738:
739: /**
740: * performs the work for changing the default value of a column
741: */
742: void setColDefaultExpression(int colIndex, Expression def)
743: throws HsqlException {
744:
745: if (def == null) {
746: table.checkColumnInFKConstraint(colIndex,
747: Constraint.SET_DEFAULT);
748: }
749:
750: table.setDefaultExpression(colIndex, def);
751: }
752: }
|