001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.ColumnDefinitionNode
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.services.loader.ClassInspector;
025:
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027: import org.apache.derby.iapi.services.io.StoredFormatIds;
028: import org.apache.derby.iapi.reference.Limits;
029: import org.apache.derby.iapi.error.StandardException;
030:
031: import org.apache.derby.iapi.sql.compile.CompilerContext;
032: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
033:
034: import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;
035: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
036: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
037:
038: import org.apache.derby.iapi.types.DataTypeDescriptor;
039: import org.apache.derby.iapi.types.DataValueDescriptor;
040: import org.apache.derby.iapi.types.TypeId;
041:
042: import org.apache.derby.iapi.sql.depend.DependencyManager;
043: import org.apache.derby.iapi.sql.depend.ProviderList;
044: import org.apache.derby.iapi.sql.depend.ProviderInfo;
045:
046: import org.apache.derby.iapi.reference.SQLState;
047:
048: import org.apache.derby.impl.sql.execute.ColumnInfo;
049:
050: import org.apache.derby.catalog.AliasInfo;
051: import org.apache.derby.catalog.DefaultInfo;
052: import org.apache.derby.catalog.UUID;
053:
054: import org.apache.derby.catalog.types.DefaultInfoImpl;
055:
056: import java.util.Vector;
057: import java.sql.Types;
058:
059: /**
060: * A ColumnDefinitionNode represents a column definition in a DDL statement.
061: * There will be a ColumnDefinitionNode for each column in a CREATE TABLE
062: * statement, and for the column in an ALTER TABLE ADD COLUMN statement.
063: *
064: * @author Jeff Lichtman
065: */
066:
067: public class ColumnDefinitionNode extends TableElementNode {
068: boolean isAutoincrement;
069: DataTypeDescriptor dataTypeServices;
070: DataValueDescriptor defaultValue;
071: DefaultInfoImpl defaultInfo;
072: DefaultNode defaultNode;
073: long autoincrementIncrement;
074: long autoincrementStart;
075: //This variable tells if the autoincrement column is participating
076: //in create or alter table. And if it is participating in alter
077: //table, then it further knows if it is represting a change in
078: //increment value or a change in start value.
079: //This information is later used to make sure that the autoincrement
080: //column's increment value is not 0 at the time of create, or is not
081: //getting set to 0 at the time of increment value modification.
082: long autoinc_create_or_modify_Start_Increment;
083: boolean autoincrementVerify;
084:
085: //autoinc_create_or_modify_Start_Increment will be set to one of the
086: //following 3 values.
087: //CREATE_AUTOINCREMENT - this autoincrement column definition is for create table
088: public static final int CREATE_AUTOINCREMENT = 0;
089: //MODIFY_AUTOINCREMENT_RESTART_VALUE - this column definition is for
090: //alter table command to change the start value of the column
091: public static final int MODIFY_AUTOINCREMENT_RESTART_VALUE = 1;
092: //MODIFY_AUTOINCREMENT_INC_VALUE - this column definition is for
093: //alter table command to change the increment value of the column
094: public static final int MODIFY_AUTOINCREMENT_INC_VALUE = 2;
095:
096: /**
097: * Initializer for a ColumnDefinitionNode
098: *
099: * @param name The name of the column
100: * @param defaultNode The default value of the column
101: * @param dataTypeServices A DataTypeServices telling the type
102: * of the column
103: * @param autoIncrementInfo Info for autoincrement columns
104: *
105: */
106:
107: public void init(Object name, Object defaultNode,
108: Object dataTypeServices, Object autoIncrementInfo)
109: throws StandardException {
110: super .init(name);
111: this .dataTypeServices = (DataTypeDescriptor) dataTypeServices;
112: if (defaultNode instanceof UntypedNullConstantNode) {
113: /* No DTS yet for MODIFY DEFAULT */
114: if (dataTypeServices != null) {
115: defaultValue = ((UntypedNullConstantNode) defaultNode)
116: .convertDefaultNode(this .dataTypeServices);
117: }
118: } else {
119: if (SanityManager.DEBUG) {
120: if (defaultNode != null
121: && !(defaultNode instanceof DefaultNode)) {
122: SanityManager
123: .THROWASSERT("defaultNode expected to be instanceof DefaultNode, not "
124: + defaultNode.getClass().getName());
125: }
126: }
127: this .defaultNode = (DefaultNode) defaultNode;
128: if (autoIncrementInfo != null) {
129: long[] aii = (long[]) autoIncrementInfo;
130: autoincrementStart = aii[QueryTreeNode.AUTOINCREMENT_START_INDEX];
131: autoincrementIncrement = aii[QueryTreeNode.AUTOINCREMENT_INC_INDEX];
132: //Parser has passed the info about autoincrement column's status in the
133: //following array element. It will tell if the autoinc column is part of
134: //a create table or if is a part of alter table. And if it is part of
135: //alter table, is it for changing the increment value or for changing
136: //the start value?
137: autoinc_create_or_modify_Start_Increment = aii[QueryTreeNode.AUTOINCREMENT_CREATE_MODIFY];
138:
139: /*
140: * If using DB2 syntax to set increment value, will need to check if column
141: * is already created for autoincrement.
142: */
143: autoincrementVerify = (aii[QueryTreeNode.AUTOINCREMENT_IS_AUTOINCREMENT_INDEX] > 0) ? false
144: : true;
145: isAutoincrement = true;
146: // an autoincrement column cannot be null-- setting
147: // non-nullability for this column is needed because
148: // you could create a column with ai default, add data, drop
149: // the default, and try to add it back again you'll get an
150: // error because the column is marked nullable.
151: if (dataTypeServices != null)
152: (this .dataTypeServices).setNullability(false);
153: }
154: }
155: }
156:
157: /**
158: * Convert this object to a String. See comments in QueryTreeNode.java
159: * for how this should be done for tree printing.
160: *
161: * @return This object as a String
162: */
163:
164: public String toString() {
165: if (SanityManager.DEBUG) {
166: return "dataTypeServices: " + dataTypeServices.toString()
167: + "\n" + "defaultValue: " + defaultValue + "\n"
168: + super .toString();
169: } else {
170: return "";
171: }
172: }
173:
174: /**
175: * Returns the unqualified name of the column being defined.
176: *
177: * @return the name of the column
178: */
179: public String getColumnName() {
180: return this .name;
181: }
182:
183: /**
184: * Returns the data type services of the column being defined.
185: *
186: * @return the data type services of the column
187: */
188: public DataTypeDescriptor getDataTypeServices() {
189: return this .dataTypeServices;
190: }
191:
192: /**
193: * Return the DataValueDescriptor containing the default value for this
194: * column
195: *
196: * @return The default value of the column
197: */
198:
199: public DataValueDescriptor getDefaultValue() {
200: return this .defaultValue;
201: }
202:
203: /**
204: * Return the DefaultInfo containing the default information for this
205: * column
206: *
207: * @return The default info for the column
208: */
209:
210: public DefaultInfo getDefaultInfo() {
211: return defaultInfo;
212: }
213:
214: /**
215: * Return the DefaultNode, if any, associated with this node.
216: *
217: * @return The DefaultNode, if any, associated with this node.
218: */
219: public DefaultNode getDefaultNode() {
220: return defaultNode;
221: }
222:
223: /**
224: * Is this an autoincrement column?
225: *
226: * @return Whether or not this is an autoincrement column.
227: */
228: public boolean isAutoincrementColumn() {
229: if (SanityManager.DEBUG) {
230: //increment value for autoincrement column can't be 0 if the autoinc column
231: //is part of create table or it is part of alter table to change the
232: //increment value.
233: if (isAutoincrement
234: && autoincrementIncrement == 0
235: && (autoinc_create_or_modify_Start_Increment == ColumnDefinitionNode.CREATE_AUTOINCREMENT || autoinc_create_or_modify_Start_Increment == ColumnDefinitionNode.MODIFY_AUTOINCREMENT_INC_VALUE)) {
236: SanityManager
237: .THROWASSERT("autoincrementIncrement expected to be non-zero");
238: }
239: if ((!isAutoincrement)
240: && (autoincrementStart != 0 || autoincrementIncrement != 0)) {
241: SanityManager
242: .THROWASSERT("both autoincrementStart and autoincrementIncrement expected to be 0");
243: }
244: }
245: return isAutoincrement;
246: }
247:
248: /**
249: * Get the autoincrement start value
250: *
251: * @return Autoincrement start value.
252: */
253: long getAutoincrementStart() {
254: if (SanityManager.DEBUG) {
255: SanityManager.ASSERT(isAutoincrement,
256: "isAutoincrement expected to be true");
257: }
258: return autoincrementStart;
259: }
260:
261: /**
262: * Get the autoincrement increment value
263: *
264: * @return Autoincrement increment value.
265: */
266: long getAutoincrementIncrement() {
267: if (SanityManager.DEBUG) {
268: SanityManager.ASSERT(isAutoincrement,
269: "isAutoincrement expected to be true");
270: }
271: return autoincrementIncrement;
272: }
273:
274: /**
275: * Get the status of this autoincrement column
276: *
277: * @return ColumnDefinitionNode.CREATE_AUTOINCREMENT -
278: * if this definition is for autoincrement column creatoin
279: * ColumnDefinitionNode.MODIFY_AUTOINCREMENT_RESTART_VALUE -
280: * if this definition is for alter sutoincrement column to change the start value
281: * ColumnDefinitionNode.MODIFY_AUTOINCREMENT_INC_VALUE
282: * if this definition is for alter autoincrement column to change the increment value
283: */
284: long getAutoinc_create_or_modify_Start_Increment() {
285: if (SanityManager.DEBUG) {
286: SanityManager.ASSERT(isAutoincrement,
287: "isAutoincrement expected to be true");
288: }
289: return autoinc_create_or_modify_Start_Increment;
290: }
291:
292: /**
293: * Check the validity of a user type. Checks whether this column
294: * definition describes a user type that either doesn't exist or is
295: * inaccessible, or that doesn't implement Serializable.
296: *
297: * @exception StandardException Thrown on error
298: */
299:
300: public void checkUserType(TableDescriptor td)
301: throws StandardException {
302: String columnTypeName;
303:
304: /* Built-in types need no checking */
305: if (!dataTypeServices.getTypeId().userType())
306: return;
307:
308: ClassInspector classInspector = getClassFactory()
309: .getClassInspector();
310:
311: columnTypeName = dataTypeServices.getTypeId()
312: .getCorrespondingJavaTypeName();
313:
314: /* User type - We first check for the columnTypeName as a java class.
315: * If that fails, then we treat it as a class alias.
316: */
317:
318: boolean foundMatch = false;
319: Throwable reason = null;
320: try {
321: foundMatch = classInspector.accessible(columnTypeName);
322: } catch (ClassNotFoundException cnfe) {
323: reason = cnfe;
324: }
325:
326: if (!foundMatch) {
327: throw StandardException.newException(
328: SQLState.LANG_TYPE_DOESNT_EXIST, reason,
329: columnTypeName, name);
330: }
331:
332: if (!classInspector.assignableTo(columnTypeName,
333: "java.io.Serializable")
334: &&
335: // Before Java2, SQLData is not defined, assignableTo call returns false
336: !classInspector.assignableTo(columnTypeName,
337: "java.sql.SQLData")) {
338: getCompilerContext().addWarning(
339: StandardException.newWarning(
340: SQLState.LANG_TYPE_NOT_SERIALIZABLE,
341: columnTypeName, name));
342: }
343: }
344:
345: /**
346: * Get the UUID of the old column default.
347: *
348: * @return The UUID of the old column default.
349: */
350: UUID getOldDefaultUUID() {
351: return null;
352: }
353:
354: /**
355: * Get the action associated with this node.
356: *
357: * @return The action associated with this node.
358: */
359: int getAction() {
360: return ColumnInfo.CREATE;
361: }
362:
363: /**
364: * Check the validity of the default, if any, for this node.
365: *
366: * @param dd The DataDictionary.
367: * @param td The TableDescriptor.
368: *
369: * @exception StandardException Thrown on error
370: */
371: void bindAndValidateDefault(DataDictionary dd, TableDescriptor td)
372: throws StandardException {
373: /* DB2 requires non-nullable columns to have a default in ALTER TABLE */
374: if (td != null && !dataTypeServices.isNullable()
375: && defaultNode == null) {
376: if (!isAutoincrement)
377: throw StandardException
378: .newException(
379: SQLState.LANG_DB2_NOT_NULL_COLUMN_INVALID_DEFAULT,
380: getColumnName());
381: }
382:
383: // No work to do if no user specified default
384: if (defaultNode == null) {
385: return;
386: }
387:
388: // No work to do if user specified NULL
389: if (defaultValue != null) {
390: return;
391: }
392:
393: // Now validate the default
394: validateDefault(dd, td);
395: }
396:
397: /**
398: * Check the validity of the autoincrement values for this node.
399: * The following errors are thrown by this routine.
400: * 1. 42z21 Invalid Increment; i.e 0.
401: * 2. 42z22 Invalid Type; autoincrement created on a non-exact-numeric type
402: * 3. 42995 The requested function does not apply to global temporary tables
403: *
404: * @param dd DataDictionary.
405: * @param td table descriptor.
406: * @param tableType base table or declared global temporary table.
407: *
408: * @exception StandardException if autoincrement default is incorrect; i.e
409: * if increment is 0 or if initial or increment values are out
410: * of range for the datatype.
411: */
412: public void validateAutoincrement(DataDictionary dd,
413: TableDescriptor td, int tableType) throws StandardException {
414: if (isAutoincrement == false)
415: return;
416:
417: if (tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE)
418: throw StandardException
419: .newException(SQLState.LANG_NOT_ALLOWED_FOR_DECLARED_GLOBAL_TEMP_TABLE);
420:
421: //increment value for autoincrement column can't be 0 if the autoinc column
422: //is part of create table or it is part of alter table to change the
423: //increment value.
424: if (autoincrementIncrement == 0
425: && (autoinc_create_or_modify_Start_Increment == ColumnDefinitionNode.CREATE_AUTOINCREMENT || autoinc_create_or_modify_Start_Increment == ColumnDefinitionNode.MODIFY_AUTOINCREMENT_INC_VALUE))
426: throw StandardException
427: .newException(SQLState.LANG_AI_INVALID_INCREMENT,
428: getColumnName());
429: int jdbctype = dataTypeServices.getTypeId().getJDBCTypeId();
430: switch (jdbctype) {
431: case Types.TINYINT:
432: autoincrementCheckRange((long) Byte.MIN_VALUE,
433: (long) Byte.MAX_VALUE, TypeId.TINYINT_NAME);
434: break;
435: case Types.SMALLINT:
436: autoincrementCheckRange((long) Short.MIN_VALUE,
437: (long) Short.MAX_VALUE, TypeId.SMALLINT_NAME);
438: break;
439: case Types.INTEGER:
440: autoincrementCheckRange((long) Integer.MIN_VALUE,
441: (long) Integer.MAX_VALUE, TypeId.INTEGER_NAME);
442: break;
443: case Types.BIGINT:
444: autoincrementCheckRange(Long.MIN_VALUE, Long.MAX_VALUE,
445: TypeId.LONGINT_NAME);
446: break;
447: default:
448: throw StandardException.newException(
449: SQLState.LANG_AI_INVALID_TYPE, getColumnName());
450: }
451: }
452:
453: /**
454: * checks to see if autoincrementIncrement and autoincrementInitial
455: * are within the bounds of the type whose min and max values are
456: * passed into this routine.
457: */
458: private void autoincrementCheckRange(long minValue, long maxValue,
459: String typeName) throws StandardException {
460: if ((minValue > autoincrementIncrement)
461: || (maxValue < autoincrementIncrement)) {
462: throw StandardException.newException(
463: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, typeName);
464: }
465: if ((minValue > autoincrementStart)
466: || (maxValue < autoincrementStart)) {
467: throw StandardException.newException(
468: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, typeName);
469: }
470: }
471:
472: /**
473: * Check the validity of the default for this node.
474: *
475: * @param td The TableDescriptor.
476: *
477: * @exception StandardException Thrown on error
478: */
479: void validateDefault(DataDictionary dd, TableDescriptor td)
480: throws StandardException {
481: if (defaultNode == null)
482: return;
483:
484: //Examin whether default value is autoincrement.
485: if (isAutoincrement) {
486: defaultInfo = createDefaultInfoOfAutoInc();
487: return;
488: }
489:
490: //Judged as default value is constant value.
491:
492: CompilerContext cc = getCompilerContext();
493:
494: ValueNode defaultTree = defaultNode.getDefaultTree();
495:
496: /* bind the default.
497: * Verify that it does not contain any ColumnReferences or subqueries
498: * and that it is type compatable with the column.
499: */
500: final int previousReliability = cc.getReliability();
501: try {
502: /*
503: Defaults cannot have dependencies as they
504: should just be constants. Code used to exist
505: to handle dependencies in defaults, now this
506: is under sanity to ensure no dependencies exist.
507: */
508: ProviderList apl = null;
509: ProviderList prevAPL = null;
510:
511: if (SanityManager.DEBUG) {
512: apl = new ProviderList();
513: prevAPL = cc.getCurrentAuxiliaryProviderList();
514: cc.setCurrentAuxiliaryProviderList(apl);
515: }
516:
517: // Tell the compiler context to only allow deterministic nodes
518: cc.setReliability(CompilerContext.DEFAULT_RESTRICTION);
519: defaultTree = defaultTree.bindExpression(
520: (FromList) getNodeFactory().getNode(
521: C_NodeTypes.FROM_LIST,
522: getNodeFactory().doJoinOrderOptimization(),
523: getContextManager()), (SubqueryList) null,
524: (Vector) null);
525:
526: TypeId columnTypeId = (TypeId) dataTypeServices.getTypeId();
527: TypeId defaultTypeId = defaultTree.getTypeId();
528:
529: // Check for 'invalid default' errors (42894)
530: // before checking for 'not storable' errors (42821).
531: if (!defaultTypeIsValid(columnTypeId, dataTypeServices,
532: defaultTypeId, defaultTree, defaultNode
533: .getDefaultText())) {
534: throw StandardException.newException(
535: SQLState.LANG_DB2_INVALID_DEFAULT_VALUE,
536: this .name);
537: }
538:
539: // Now check 'not storable' errors.
540: if (!getTypeCompiler(columnTypeId).storable(defaultTypeId,
541: getClassFactory())) {
542: throw StandardException.newException(
543: SQLState.LANG_NOT_STORABLE, columnTypeId
544: .getSQLTypeName(), defaultTypeId
545: .getSQLTypeName());
546: }
547:
548: // Save off the default text
549: // RESOLVEDEFAULT - Convert to constant if possible
550: defaultInfo = new DefaultInfoImpl(false, defaultNode
551: .getDefaultText(), defaultValue);
552:
553: if (SanityManager.DEBUG) {
554: /* Save the APL off in the constraint node */
555: if (apl.size() > 0) {
556:
557: SanityManager
558: .THROWASSERT("DEFAULT clause has unexpected dependencies");
559: }
560: // Restore the previous AuxiliaryProviderList
561: cc.setCurrentAuxiliaryProviderList(prevAPL);
562: }
563:
564: } finally {
565: cc.setReliability(previousReliability);
566: }
567: }
568:
569: private static DefaultInfoImpl createDefaultInfoOfAutoInc() {
570: return new DefaultInfoImpl(true, null, null);
571: }
572:
573: /**
574: * Check the validity of the default for this node
575: *
576: * @param columnType TypeId of the target column.
577: * @param columnDesc Description of the type of the
578: * target column.
579: * @param defaultType TypeId of the default node.
580: * @param defaultNode Parsed ValueNode for the default value.
581: * @param defaultText Unparsed default value (as entered
582: * by user).
583: * @return True if the defaultNode abides by the restrictions
584: * imposed by DB2 on default constants; false otherwise.
585: *
586: */
587:
588: public boolean defaultTypeIsValid(TypeId columnType,
589: DataTypeDescriptor columnDesc, TypeId defaultType,
590: ValueNode defaultNode, String defaultText)
591: throws StandardException {
592:
593: if (defaultText.length() > Limits.DB2_CHAR_MAXWIDTH)
594: // DB2 spec says this isn't allowed.
595: return false;
596:
597: /* We can use info about the way the parser works
598: * to guide this process a little (see the getNumericNode()
599: * method in sqlgrammar.jj):
600: *
601: * 1) Tinyint and Smallints are both parsed as "INT" types,
602: * while integers larger than a basic "INT" are parsed into
603: * "LONGINT" or, if needed, "DECIMAL".
604: * 2) Floats, doubles, and decimals with fractional parts
605: * are all parsed as "DECIMAL".
606: * 3) All strings are parsed as "CHAR" constants (no varchar
607: * or any others; see stringLiteral() method in
608: * sqlgrammar.jj).
609: */
610:
611: int colType = columnType.getTypeFormatId();
612: int defType = (defaultType == null ? -1 : defaultType
613: .getTypeFormatId());
614:
615: if (!defaultNode.isConstantExpression()) {
616: // then we have a built-in function, such as "user"
617: // or "current schema". If the function is a datetime
618: // value function, then we don't need any special
619: // action; however, if it's a "user" or "current schema"
620: // function, then the column must be a char type with
621: // minimum lengths matching those of DB2 (note that
622: // such limits are ONLY enforced on defaults, not at
623: // normal insertion time).
624:
625: boolean charCol = ((colType == StoredFormatIds.CHAR_TYPE_ID)
626: || (colType == StoredFormatIds.VARCHAR_TYPE_ID) || (colType == StoredFormatIds.LONGVARCHAR_TYPE_ID));
627:
628: if (defaultNode instanceof SpecialFunctionNode) {
629:
630: switch (defaultNode.getNodeType()) {
631: case C_NodeTypes.USER_NODE:
632: case C_NodeTypes.CURRENT_USER_NODE:
633: case C_NodeTypes.SESSION_USER_NODE:
634: case C_NodeTypes.SYSTEM_USER_NODE:
635: // DB2 enforces min length of 8.
636: // Note also: any size under 30 gives a warning in DB2.
637: return (charCol && (columnDesc.getMaximumWidth() >= Limits.DB2_MIN_COL_LENGTH_FOR_CURRENT_USER));
638:
639: case C_NodeTypes.CURRENT_SCHEMA_NODE:
640: // DB2 enforces min length of 128.
641: return (charCol && (columnDesc.getMaximumWidth() >= Limits.DB2_MIN_COL_LENGTH_FOR_CURRENT_SCHEMA));
642: default:
643: // else, function not allowed.
644: return false;
645: }
646: }
647:
648: }
649:
650: switch (colType) {
651:
652: case StoredFormatIds.INT_TYPE_ID:
653: // DB2 doesn't allow floating point values to be used
654: // as defaults for integer columns (they ARE allowed
655: // as part of normal insertions, but not as defaults).
656: // If the default is an integer that's too big, then
657: // it won't have type INT_TYPE_ID (it'll be either
658: // LONGINT or DECIMAL)--so we only allow the default
659: // value if it's integer.
660: return (defType == StoredFormatIds.INT_TYPE_ID);
661:
662: case StoredFormatIds.LONGINT_TYPE_ID:
663: // This is a BIGINT column: we allow smallints, ints,
664: // and big int constants. Smallint and int literals
665: // are both covered by INT_TYPE; big int literals are
666: // covered by LONG_INT type.
667: return ((defType == StoredFormatIds.INT_TYPE_ID) || (defType == StoredFormatIds.LONGINT_TYPE_ID));
668:
669: case StoredFormatIds.DECIMAL_TYPE_ID:
670: if (defType == StoredFormatIds.DECIMAL_TYPE_ID) {
671: // only valid if scale and precision are within
672: // those of the column. Note that scale here should
673: // exclude any trailing 0's after the decimal
674: DataTypeDescriptor defDesc = defaultNode
675: .getTypeServices();
676: int len = defaultText.length();
677: int precision = defDesc.getPrecision();
678: int scale = defDesc.getScale();
679: for (int i = 1; i <= scale; scale--, precision--) {
680: if (defaultText.charAt(len - i) != '0')
681: break;
682: }
683: return ((scale <= columnDesc.getScale()) && ((precision - scale) <= (columnDesc
684: .getPrecision() - columnDesc.getScale())));
685: } else if ((defType == StoredFormatIds.LONGINT_TYPE_ID)
686: || (defType == StoredFormatIds.INT_TYPE_ID)) {
687: // only valid if number of digits is within limits of
688: // the decimal column. We'll check this at insertion time;
689: // see Beetle 5585 regarding the need to move that check to
690: // here instead of waiting until insert time. Until that's
691: // done, just allow this and wait for insertion...
692: return true;
693: } else
694: // no other types allowed.
695: return false;
696:
697: case StoredFormatIds.CHAR_TYPE_ID:
698: case StoredFormatIds.VARCHAR_TYPE_ID:
699: case StoredFormatIds.LONGVARCHAR_TYPE_ID:
700: // only valid if the default type is a character string.
701: // That's not to say that all character defaults are
702: // valid, but we only check for character string here;
703: // further checking will be done at insertion time. See
704: // beetle 5585 regarding the need to move that check
705: // to here instead of waiting until insert time.
706: return (defType == StoredFormatIds.CHAR_TYPE_ID);
707:
708: case StoredFormatIds.BIT_TYPE_ID:
709: case StoredFormatIds.VARBIT_TYPE_ID:
710: case StoredFormatIds.LONGVARBIT_TYPE_ID:
711: // only valid if the default type is a BIT string.
712: return (defType == StoredFormatIds.BIT_TYPE_ID);
713:
714: case StoredFormatIds.USERDEFINED_TYPE_ID_V3:
715: // default is only valid if it's the same type as the column.
716: return (defType == colType);
717:
718: case StoredFormatIds.BLOB_TYPE_ID:
719: case StoredFormatIds.CLOB_TYPE_ID:
720: case StoredFormatIds.SMALLINT_TYPE_ID:
721: case StoredFormatIds.REAL_TYPE_ID:
722: case StoredFormatIds.DOUBLE_TYPE_ID:
723: case StoredFormatIds.DATE_TYPE_ID:
724: case StoredFormatIds.TIME_TYPE_ID:
725: case StoredFormatIds.TIMESTAMP_TYPE_ID:
726: // For these types, validity checks will be performed
727: // by Cloudscape at insertion time--see beetle 5585 regarding
728: // the need to do such checks here instead of later. For now,
729: // just assume we're okay.
730: return true;
731:
732: default:
733: // All other default type checks either
734: // (TINYINT, NATIONAL_CHAR, etc), or 2) require a DB2 cast-
735: // function (ex. blob(...), which Cloudscape doesn't
736: // support yet--see Beetle 5281), and so they are not
737: // valid for Cloudscape running in DB2 compatibility mode.
738: return false;
739:
740: }
741:
742: }
743:
744: }
|