0001: /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
0002: * All rights reserved.
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * Redistributions of source code must retain the above copyright notice, this
0008: * list of conditions and the following disclaimer.
0009: *
0010: * Redistributions in binary form must reproduce the above copyright notice,
0011: * this list of conditions and the following disclaimer in the documentation
0012: * and/or other materials provided with the distribution.
0013: *
0014: * Neither the name of the Hypersonic SQL Group nor the names of its
0015: * contributors may be used to endorse or promote products derived from this
0016: * software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
0022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029: *
0030: * This software consists of voluntary contributions made by many individuals
0031: * on behalf of the Hypersonic SQL Group.
0032: *
0033: *
0034: * For work added by the HSQL Development Group:
0035: *
0036: * Copyright (c) 2001-2005, The HSQL Development Group
0037: * All rights reserved.
0038: *
0039: * Redistribution and use in source and binary forms, with or without
0040: * modification, are permitted provided that the following conditions are met:
0041: *
0042: * Redistributions of source code must retain the above copyright notice, this
0043: * list of conditions and the following disclaimer.
0044: *
0045: * Redistributions in binary form must reproduce the above copyright notice,
0046: * this list of conditions and the following disclaimer in the documentation
0047: * and/or other materials provided with the distribution.
0048: *
0049: * Neither the name of the HSQL Development Group nor the names of its
0050: * contributors may be used to endorse or promote products derived from this
0051: * software without specific prior written permission.
0052: *
0053: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0054: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0055: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0056: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
0057: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0058: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0059: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0060: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0061: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0062: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0063: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0064: */
0065:
0066: package org.hsqldb;
0067:
0068: import java.io.IOException;
0069: import java.io.Serializable;
0070: import java.math.BigDecimal;
0071: import java.math.BigInteger;
0072: import java.sql.Date;
0073: import java.sql.Time;
0074: import java.sql.Timestamp;
0075:
0076: import org.hsqldb.HsqlNameManager.HsqlName;
0077: import org.hsqldb.lib.StringConverter;
0078: import org.hsqldb.store.ValuePool;
0079: import org.hsqldb.types.Binary;
0080: import org.hsqldb.types.JavaObject;
0081: import org.hsqldb.lib.java.JavaSystem;
0082:
0083: // fredt@users 20020130 - patch 491987 by jimbag@users
0084: // fredt@users 20020320 - doc 1.7.0 - update
0085: // fredt@users 20020401 - patch 442993 by fredt - arithmetic expressions
0086: // to allow mixed type arithmetic expressions beginning with a narrower type
0087: // changes applied to several lines of code and not marked separately
0088: // consists of changes to arithmatic functions to allow promotion of
0089: // java.lang.Number values and new functions to choose type for promotion
0090: // fredt@users 20020401 - patch 455757 by galena@users (Michiel de Roo)
0091: // interpretation of TINYINT as Byte instead of Short
0092: // fredt@users 20020130 - patch 491987 by jimbag@users
0093: // support for sql standard char and varchar. size is maintained as
0094: // defined in the DDL and trimming and padding takes place accordingly
0095: // modified by fredt - trimming and padding are turned off by default but
0096: // can be applied accross the database by defining sql.enforce_size=true in
0097: // database.properties file
0098: // fredt@users 20020215 - patch 1.7.0 by fredt - quoted identifiers
0099: // applied to different parts to support the sql standard for
0100: // naming of columns and tables (use of quoted identifiers as names)
0101: // fredt@users 20020328 - patch 1.7.0 by fredt - change REAL to Double
0102: // fredt@users 20020402 - patch 1.7.0 by fredt - type conversions
0103: // frequently used type conversions are done without creating temporary
0104: // Strings to reduce execution time and garbage collection
0105: // fredt@users 20021013 - patch 1.7.1 by fredt - type conversions
0106: // scripting of Double.Nan and infinity values
0107: // fredt@users 20030715 - patch 1.7.2 - type narrowing for numeric values
0108: // fredt@users - patch 1.8.0 - enforcement of precision and scale
0109:
0110: /**
0111: * Implementation of SQL table columns as defined in DDL statements with
0112: * static methods to process their values.<p>
0113: *
0114: * Enhanced type checking and conversion by fredt@users
0115: *
0116: * @author Thomas Mueller (Hypersonic SQL Group)
0117: * @author fredt@users
0118: * @version 1.8.0
0119: * @since Hypersonic SQL
0120: */
0121: public class Column {
0122:
0123: // --------------------------------------------------
0124: // DDL name, size, scale, null, identity and default values
0125: // most variables are final but not declared so because of a bug in
0126: // JDK 1.1.8 compiler
0127: public HsqlName columnName;
0128: private int colType;
0129: private int colSize;
0130: private int colScale;
0131: private boolean isNullable;
0132: private boolean isIdentity;
0133: private boolean isPrimaryKey;
0134: private Expression defaultExpression;
0135: long identityStart;
0136: long identityIncrement;
0137: static final BigInteger MAX_LONG = BigInteger
0138: .valueOf(Long.MAX_VALUE);
0139: static final BigInteger MIN_LONG = BigInteger
0140: .valueOf(Long.MIN_VALUE);
0141: static final BigInteger MAX_INT = BigInteger
0142: .valueOf(Integer.MAX_VALUE);
0143: static final BigInteger MIN_INT = BigInteger
0144: .valueOf(Integer.MIN_VALUE);
0145: static final BigDecimal BIG_DECIMAL_0 = new BigDecimal(0.0);
0146: static final BigDecimal BIG_DECIMAL_1 = new BigDecimal(1.0);
0147:
0148: /**
0149: * Creates a column defined in DDL statement.
0150: *
0151: * @param name
0152: * @param nullable
0153: * @param type
0154: * @param size
0155: * @param scale
0156: * @param identity
0157: * @param startvalue
0158: * @param increment
0159: * @param primarykey
0160: * @param defstring
0161: */
0162: Column(HsqlName name, boolean nullable, int type, int size,
0163: int scale, boolean primarykey, Expression defexpression)
0164: throws HsqlException {
0165:
0166: columnName = name;
0167: isNullable = nullable;
0168: colType = type;
0169: colSize = size;
0170: colScale = scale;
0171: isPrimaryKey = primarykey;
0172: defaultExpression = defexpression;
0173: }
0174:
0175: void setIdentity(boolean identity, long startvalue, long increment)
0176: throws HsqlException {
0177:
0178: isIdentity = identity;
0179: identityStart = startvalue;
0180: identityIncrement = increment;
0181:
0182: if (isIdentity) {
0183: if (colType == Types.INTEGER) {
0184: if (identityStart > Integer.MAX_VALUE
0185: || identityIncrement > Integer.MAX_VALUE) {
0186: throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE,
0187: columnName.statementName);
0188: }
0189: }
0190: }
0191: }
0192:
0193: private Column() {
0194: }
0195:
0196: /**
0197: * Used for primary key changes.
0198: */
0199: Column duplicate(boolean withIdentity) throws HsqlException {
0200:
0201: Column newCol = new Column();
0202:
0203: newCol.columnName = columnName;
0204: newCol.isNullable = isNullable;
0205: newCol.colType = colType;
0206: newCol.colSize = colSize;
0207: newCol.colScale = colScale;
0208: newCol.defaultExpression = defaultExpression;
0209:
0210: if (withIdentity) {
0211: newCol.setIdentity(isIdentity, identityStart,
0212: identityIncrement);
0213: }
0214:
0215: return newCol;
0216: }
0217:
0218: void setType(Column other) {
0219:
0220: isNullable = other.isNullable;
0221: colType = other.colType;
0222: colSize = other.colSize;
0223: colScale = other.colScale;
0224: }
0225:
0226: /**
0227: * Is this the identity column in the table.
0228: *
0229: * @return boolean
0230: */
0231: boolean isIdentity() {
0232: return isIdentity;
0233: }
0234:
0235: /**
0236: * Is column nullable.
0237: *
0238: * @return boolean
0239: */
0240: boolean isNullable() {
0241: return isNullable;
0242: }
0243:
0244: /**
0245: * Set nullable.
0246: *
0247: */
0248: void setNullable(boolean value) {
0249: isNullable = value;
0250: }
0251:
0252: /**
0253: * Is this single column primary key of the table.
0254: *
0255: * @return boolean
0256: */
0257: public boolean isPrimaryKey() {
0258: return isPrimaryKey;
0259: }
0260:
0261: /**
0262: * Set primary key.
0263: *
0264: */
0265: void setPrimaryKey(boolean value) {
0266: isPrimaryKey = value;
0267: }
0268:
0269: /**
0270: * Returns default value in the session context.
0271: */
0272: Object getDefaultValue(Session session) throws HsqlException {
0273:
0274: return defaultExpression == null ? null : defaultExpression
0275: .getValue(session, colType);
0276: }
0277:
0278: /**
0279: * Returns DDL for default value.
0280: */
0281: String getDefaultDDL() {
0282:
0283: String ddl = null;
0284:
0285: try {
0286: ddl = defaultExpression == null ? null : defaultExpression
0287: .getDDL();
0288: } catch (HsqlException e) {
0289: }
0290:
0291: return ddl;
0292: }
0293:
0294: /**
0295: * Returns default expression for the column.
0296: */
0297: Expression getDefaultExpression() {
0298: return defaultExpression;
0299: }
0300:
0301: void setDefaultExpression(Expression expr) {
0302: defaultExpression = expr;
0303: }
0304:
0305: /**
0306: * Type of the column.
0307: *
0308: * @return java.sql.Types int value for the column
0309: */
0310: int getType() {
0311: return colType;
0312: }
0313:
0314: int getDIType() {
0315: return colType == Types.VARCHAR_IGNORECASE ? Types.VARCHAR
0316: : colType;
0317: }
0318:
0319: int getDITypeSub() {
0320:
0321: if (colType == Types.VARCHAR_IGNORECASE) {
0322: return Types.TYPE_SUB_IGNORECASE;
0323: }
0324:
0325: return Types.TYPE_SUB_DEFAULT;
0326: }
0327:
0328: /**
0329: * Size of the column in DDL (0 if not defined).
0330: *
0331: * @return DDL size of column
0332: */
0333: int getSize() {
0334: return colSize;
0335: }
0336:
0337: /**
0338: * Scale of the column in DDL (0 if not defined).
0339: *
0340: * @return DDL scale of column
0341: */
0342: int getScale() {
0343: return colScale;
0344: }
0345:
0346: /**
0347: * Add two object of a given type
0348: *
0349: * @param a
0350: * @param b
0351: * @param type
0352: * @return result
0353: * @throws HsqlException
0354: */
0355: static Object add(Object a, Object b, int type)
0356: throws HsqlException {
0357:
0358: if (a == null || b == null) {
0359: return null;
0360: }
0361:
0362: switch (type) {
0363:
0364: case Types.NULL:
0365: return null;
0366:
0367: case Types.REAL:
0368: case Types.FLOAT:
0369: case Types.DOUBLE: {
0370: double ad = ((Number) a).doubleValue();
0371: double bd = ((Number) b).doubleValue();
0372:
0373: return ValuePool
0374: .getDouble(Double.doubleToLongBits(ad + bd));
0375:
0376: // return new Double(ad + bd);
0377: }
0378: case Types.VARCHAR:
0379: case Types.CHAR:
0380: case Types.LONGVARCHAR:
0381: case Types.VARCHAR_IGNORECASE:
0382: return (String) a + (String) b;
0383:
0384: case Types.NUMERIC:
0385: case Types.DECIMAL: {
0386: BigDecimal abd = (BigDecimal) a;
0387: BigDecimal bbd = (BigDecimal) b;
0388:
0389: return abd.add(bbd);
0390: }
0391: case Types.TINYINT:
0392: case Types.SMALLINT:
0393: case Types.INTEGER: {
0394: int ai = ((Number) a).intValue();
0395: int bi = ((Number) b).intValue();
0396:
0397: return ValuePool.getInt(ai + bi);
0398: }
0399: case Types.BIGINT: {
0400: long longa = ((Number) a).longValue();
0401: long longb = ((Number) b).longValue();
0402:
0403: return ValuePool.getLong(longa + longb);
0404: }
0405: default:
0406: throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED, Types
0407: .getTypeString(type));
0408: }
0409: }
0410:
0411: /**
0412: * Concat two objects by turning them into strings first.
0413: *
0414: * @param a
0415: * @param b
0416: * @return result
0417: * @throws HsqlException
0418: */
0419: static Object concat(Object a, Object b) throws HsqlException {
0420:
0421: if (a == null || b == null) {
0422: return null;
0423: }
0424:
0425: return a.toString() + b.toString();
0426: }
0427:
0428: /**
0429: * Negate a numeric object.
0430: *
0431: * @param a
0432: * @param type
0433: * @return result
0434: * @throws HsqlException
0435: */
0436: static Object negate(Object a, int type) throws HsqlException {
0437:
0438: if (a == null) {
0439: return null;
0440: }
0441:
0442: switch (type) {
0443:
0444: case Types.NULL:
0445: return null;
0446:
0447: case Types.REAL:
0448: case Types.FLOAT:
0449: case Types.DOUBLE: {
0450: double ad = -((Number) a).doubleValue();
0451:
0452: return ValuePool.getDouble(Double.doubleToLongBits(ad));
0453: }
0454: case Types.NUMERIC:
0455: case Types.DECIMAL:
0456: return ((BigDecimal) a).negate();
0457:
0458: case Types.TINYINT:
0459: case Types.SMALLINT:
0460: case Types.INTEGER:
0461: return ValuePool.getInt(-((Number) a).intValue());
0462:
0463: case Types.BIGINT:
0464: return ValuePool.getLong(-((Number) a).longValue());
0465:
0466: default:
0467: throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED, Types
0468: .getTypeString(type));
0469: }
0470: }
0471:
0472: /**
0473: * Multiply two numeric objects.
0474: *
0475: * @param a
0476: * @param b
0477: * @param type
0478: * @return result
0479: * @throws HsqlException
0480: */
0481: static Object multiply(Object a, Object b, int type)
0482: throws HsqlException {
0483:
0484: if (a == null || b == null) {
0485: return null;
0486: }
0487:
0488: // fredt@users - type conversion - may need to apply to other arithmetic operations too
0489: if (!(a instanceof Number && b instanceof Number)) {
0490: a = Column.convertObject(a, type);
0491: b = Column.convertObject(b, type);
0492: }
0493:
0494: switch (type) {
0495:
0496: case Types.NULL:
0497: return null;
0498:
0499: case Types.REAL:
0500: case Types.FLOAT:
0501: case Types.DOUBLE: {
0502: double ad = ((Number) a).doubleValue();
0503: double bd = ((Number) b).doubleValue();
0504:
0505: return ValuePool
0506: .getDouble(Double.doubleToLongBits(ad * bd));
0507: }
0508: case Types.NUMERIC:
0509: case Types.DECIMAL: {
0510: BigDecimal abd = (BigDecimal) a;
0511: BigDecimal bbd = (BigDecimal) b;
0512:
0513: return abd.multiply(bbd);
0514: }
0515: case Types.TINYINT:
0516: case Types.SMALLINT:
0517: case Types.INTEGER: {
0518: int ai = ((Number) a).intValue();
0519: int bi = ((Number) b).intValue();
0520:
0521: return ValuePool.getInt(ai * bi);
0522: }
0523: case Types.BIGINT: {
0524: long longa = ((Number) a).longValue();
0525: long longb = ((Number) b).longValue();
0526:
0527: return ValuePool.getLong(longa * longb);
0528: }
0529: default:
0530: throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED, Types
0531: .getTypeString(type));
0532: }
0533: }
0534:
0535: /**
0536: * Divide numeric object a by object b.
0537: *
0538: * @param a
0539: * @param b
0540: * @param type
0541: * @return result
0542: * @throws HsqlException
0543: */
0544: static Object divide(Object a, Object b, int type)
0545: throws HsqlException {
0546:
0547: if (a == null || b == null) {
0548: return null;
0549: }
0550:
0551: switch (type) {
0552:
0553: case Types.NULL:
0554: return null;
0555:
0556: case Types.REAL:
0557: case Types.FLOAT:
0558: case Types.DOUBLE: {
0559: double ad = ((Number) a).doubleValue();
0560: double bd = ((Number) b).doubleValue();
0561:
0562: return ValuePool
0563: .getDouble(Double.doubleToLongBits(ad / bd));
0564: }
0565: case Types.NUMERIC:
0566: case Types.DECIMAL: {
0567: BigDecimal abd = (BigDecimal) a;
0568: BigDecimal bbd = (BigDecimal) b;
0569: int scale = abd.scale() > bbd.scale() ? abd.scale() : bbd
0570: .scale();
0571:
0572: return (bbd.signum() == 0) ? null : abd.divide(bbd, scale,
0573: BigDecimal.ROUND_HALF_DOWN);
0574: }
0575: case Types.TINYINT:
0576: case Types.SMALLINT:
0577: case Types.INTEGER: {
0578: int ai = ((Number) a).intValue();
0579: int bi = ((Number) b).intValue();
0580:
0581: if (bi == 0) {
0582: throw Trace.error(Trace.DIVISION_BY_ZERO);
0583: }
0584:
0585: return ValuePool.getInt(ai / bi);
0586: }
0587: case Types.BIGINT: {
0588: long longa = ((Number) a).longValue();
0589: long longb = ((Number) b).longValue();
0590:
0591: return (longb == 0) ? null : ValuePool.getLong(longa
0592: / longb);
0593: }
0594: default:
0595: throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED, Types
0596: .getTypeString(type));
0597: }
0598: }
0599:
0600: /**
0601: * Subtract numeric object b from object a.
0602: *
0603: * @param a
0604: * @param b
0605: * @param type
0606: * @return result
0607: * @throws HsqlException
0608: */
0609: static Object subtract(Object a, Object b, int type)
0610: throws HsqlException {
0611:
0612: if (a == null || b == null) {
0613: return null;
0614: }
0615:
0616: switch (type) {
0617:
0618: case Types.NULL:
0619: return null;
0620:
0621: case Types.REAL:
0622: case Types.FLOAT:
0623: case Types.DOUBLE: {
0624: double ad = ((Number) a).doubleValue();
0625: double bd = ((Number) b).doubleValue();
0626:
0627: return ValuePool
0628: .getDouble(Double.doubleToLongBits(ad - bd));
0629: }
0630: case Types.NUMERIC:
0631: case Types.DECIMAL: {
0632: BigDecimal abd = (BigDecimal) a;
0633: BigDecimal bbd = (BigDecimal) b;
0634:
0635: return abd.subtract(bbd);
0636: }
0637: case Types.TINYINT:
0638: case Types.SMALLINT:
0639: case Types.INTEGER: {
0640: int ai = ((Number) a).intValue();
0641: int bi = ((Number) b).intValue();
0642:
0643: return ValuePool.getInt(ai - bi);
0644: }
0645: case Types.BIGINT: {
0646: long longa = ((Number) a).longValue();
0647: long longb = ((Number) b).longValue();
0648:
0649: return ValuePool.getLong(longa - longb);
0650: }
0651: default:
0652: throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED, Types
0653: .getTypeString(type));
0654: }
0655: }
0656:
0657: // boucherb@users 2003-09-25
0658: // TODO: Maybe use //#ifdef tag or reflective static method attribute
0659: // instantiation to take advantage of String.compareToIgnoreCase when
0660: // available (JDK 1.2 and greater) during ANT build. That or perhaps
0661: // consider using either local character-wise comparison or first converting
0662: // to lower case and then to upper case. Sun states that the JDK 1.2 introduced
0663: // String.compareToIngnorCase() comparison involves calling
0664: // Character.toLowerCase(Character.toUpperCase()) on compared characters,
0665: // to correctly handle some caveats concering using only the one operation or
0666: // the other outside the ascii character range.
0667: // fredt@users 20020130 - patch 418022 by deforest@users
0668: // use of rtrim() to mimic SQL92 behaviour
0669:
0670: /**
0671: * Compare a with b and return int value as result.
0672: *
0673: * @param a instance of Java wrapper, depending on type, but always same for a & b (can be null)
0674: * @param b instance of Java wrapper, depending on type, but always same for a & b (can be null)
0675: * @param type one of the java.sql.Types
0676: * @return result 1 if a>b, 0 if a=b, -1 if b>a
0677: * @throws HsqlException
0678: */
0679: static int compare(Collation collation, Object a, Object b, int type) {
0680:
0681: int i = 0;
0682:
0683: if (a == b) {
0684: return 0;
0685: }
0686:
0687: // Current null handling here: null==null and smaller any value
0688: // Note, standard SQL null handling is handled by Expression.test() calling testNull() instead of this!
0689: // Attention, this is also used for grouping ('null' is one group)
0690: if (a == null) {
0691: return -1;
0692: }
0693:
0694: if (b == null) {
0695: return 1;
0696: }
0697:
0698: switch (type) {
0699:
0700: case Types.NULL:
0701: return 0;
0702:
0703: case Types.VARCHAR:
0704: case Types.LONGVARCHAR:
0705: return collation.compare((String) a, (String) b);
0706:
0707: case Types.CHAR:
0708: return collation.compare(Library.rtrim((String) a), Library
0709: .rtrim((String) b));
0710:
0711: case Types.VARCHAR_IGNORECASE:
0712: return collation.compareIgnoreCase(((String) a),
0713: ((String) b));
0714:
0715: case Types.TINYINT:
0716: case Types.SMALLINT:
0717: case Types.INTEGER: {
0718: int ai = ((Number) a).intValue();
0719: int bi = ((Number) b).intValue();
0720:
0721: return (ai > bi) ? 1 : (bi > ai ? -1 : 0);
0722: }
0723: case Types.BIGINT: {
0724: long longa = ((Number) a).longValue();
0725: long longb = ((Number) b).longValue();
0726:
0727: return (longa > longb) ? 1 : (longb > longa ? -1 : 0);
0728: }
0729: case Types.REAL:
0730: case Types.FLOAT:
0731: case Types.DOUBLE: {
0732: double ad = ((Number) a).doubleValue();
0733: double bd = ((Number) b).doubleValue();
0734:
0735: return (ad > bd) ? 1 : (bd > ad ? -1 : 0);
0736: }
0737: case Types.NUMERIC:
0738: case Types.DECIMAL:
0739: i = ((BigDecimal) a).compareTo((BigDecimal) b);
0740: break;
0741:
0742: case Types.DATE:
0743: return HsqlDateTime.compare((Date) a, (Date) b);
0744:
0745: case Types.TIME:
0746: return HsqlDateTime.compare((Time) a, (Time) b);
0747:
0748: case Types.TIMESTAMP:
0749: return HsqlDateTime.compare((Timestamp) a, (Timestamp) b);
0750:
0751: case Types.BOOLEAN: {
0752: boolean boola = ((Boolean) a).booleanValue();
0753: boolean boolb = ((Boolean) b).booleanValue();
0754:
0755: return (boola == boolb) ? 0 : (boolb ? -1 : 1);
0756: }
0757: case Types.BINARY:
0758: case Types.VARBINARY:
0759: case Types.LONGVARBINARY:
0760: if (a instanceof Binary && b instanceof Binary) {
0761: i = compareTo(((Binary) a).getBytes(), ((Binary) b)
0762: .getBytes());
0763: }
0764: break;
0765:
0766: case Types.OTHER:
0767: return 0;
0768: }
0769:
0770: return (i == 0) ? 0 : (i < 0 ? -1 : 1);
0771: }
0772:
0773: /**
0774: * Convert an object into a Java object that represents its SQL type.<p>
0775: * All internal type conversion operations start with
0776: * this method. If a direct conversion doesn't take place, the object
0777: * is converted into a string first and an attempt is made to convert
0778: * the string into the target type.<br>
0779: *
0780: * One objective of this mehod is to ensure the Object can be converted
0781: * to the given SQL type. For example, a very large BIGINT
0782: * value cannot be narrowed down to an INTEGER or SMALLINT.<br>
0783: *
0784: * Type conversion performed by this method has gradually evolved in 1.7.2
0785: * to allow narrowing of numeric types in all cases according to the SQL
0786: * standard.<br>
0787: *
0788: * Another new objective is to normalize DATETIME values.<br>
0789: *
0790: * Objects set via JDBC PreparedStatement use this method to convert
0791: * the data to the Java type that is required for custom serialization
0792: * by the engine. <br>
0793: *
0794: * @param o
0795: * @param type
0796: * @return result
0797: * @throws HsqlException
0798: */
0799: public static Object convertObject(Object o, int type)
0800: throws HsqlException {
0801:
0802: try {
0803: if (o == null) {
0804: return null;
0805: }
0806:
0807: switch (type) {
0808:
0809: case Types.NULL:
0810: return null;
0811:
0812: case Types.TINYINT:
0813: if (o instanceof java.lang.String) {
0814: o = Library.trim((String) o, " ", true, true);
0815:
0816: int val = Integer.parseInt((String) o);
0817:
0818: o = ValuePool.getInt(val);
0819: }
0820:
0821: if (o instanceof java.lang.Integer) {
0822: int temp = ((Number) o).intValue();
0823:
0824: if (Byte.MAX_VALUE < temp || temp < Byte.MIN_VALUE) {
0825: throw Trace
0826: .error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
0827: }
0828:
0829: return o;
0830: }
0831:
0832: if (o instanceof java.lang.Long) {
0833: long temp = ((Number) o).longValue();
0834:
0835: if (Byte.MAX_VALUE < temp || temp < Byte.MIN_VALUE) {
0836: throw Trace
0837: .error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
0838: }
0839:
0840: return ValuePool.getInt(((Number) o).intValue());
0841: }
0842:
0843: // fredt@users - direct conversion to optimise JDBC setObject(Byte)
0844: if (o instanceof java.lang.Byte) {
0845: return ValuePool.getInt(((Number) o).intValue());
0846: }
0847:
0848: // fredt@users - returns to this method for range checking
0849: if (o instanceof java.lang.Number) {
0850: return convertObject(convertToInt(o), type);
0851: }
0852:
0853: if (o instanceof java.lang.Boolean) {
0854: return ((Boolean) o).booleanValue() ? ValuePool
0855: .getInt(1) : ValuePool.getInt(0);
0856: }
0857: break;
0858:
0859: case Types.SMALLINT:
0860: if (o instanceof java.lang.String) {
0861: o = Library.trim((String) o, " ", true, true);
0862:
0863: int val = Integer.parseInt((String) o);
0864:
0865: o = ValuePool.getInt(val);
0866: }
0867:
0868: if (o instanceof java.lang.Integer) {
0869: int temp = ((Number) o).intValue();
0870:
0871: if (Short.MAX_VALUE < temp
0872: || temp < Short.MIN_VALUE) {
0873: throw Trace
0874: .error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
0875: }
0876:
0877: return o;
0878: }
0879:
0880: if (o instanceof java.lang.Long) {
0881: long temp = ((Number) o).longValue();
0882:
0883: if (Short.MAX_VALUE < temp
0884: || temp < Short.MIN_VALUE) {
0885: throw Trace
0886: .error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
0887: }
0888:
0889: return ValuePool.getInt(((Number) o).intValue());
0890: }
0891:
0892: // fredt@users - direct conversion for JDBC setObject(Short), etc.
0893: if (o instanceof Byte || o instanceof Short) {
0894: return ValuePool.getInt(((Number) o).intValue());
0895: }
0896:
0897: // fredt@users - returns to this method for range checking
0898: if (o instanceof Number) {
0899: return convertObject(convertToInt(o), type);
0900: }
0901:
0902: if (o instanceof java.lang.Boolean) {
0903: return ((Boolean) o).booleanValue() ? ValuePool
0904: .getInt(1) : ValuePool.getInt(0);
0905: }
0906: break;
0907:
0908: case Types.INTEGER:
0909: if (o instanceof java.lang.Integer) {
0910: return o;
0911: }
0912:
0913: if (o instanceof java.lang.String) {
0914: o = Library.trim((String) o, " ", true, true);
0915:
0916: int val = Integer.parseInt((String) o);
0917:
0918: return ValuePool.getInt(val);
0919: }
0920:
0921: if (o instanceof java.lang.Long) {
0922: long temp = ((Number) o).longValue();
0923:
0924: if (Integer.MAX_VALUE < temp
0925: || temp < Integer.MIN_VALUE) {
0926: throw Trace
0927: .error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
0928: }
0929:
0930: return ValuePool.getInt(((Number) o).intValue());
0931: }
0932:
0933: if (o instanceof Byte || o instanceof Short) {
0934: return ValuePool.getInt(((Number) o).intValue());
0935: }
0936:
0937: if (o instanceof java.lang.Number) {
0938: return convertToInt(o);
0939: }
0940:
0941: if (o instanceof java.lang.Boolean) {
0942: return ((Boolean) o).booleanValue() ? ValuePool
0943: .getInt(1) : ValuePool.getInt(0);
0944: }
0945: break;
0946:
0947: case Types.BIGINT:
0948: if (o instanceof java.lang.Long) {
0949: return o;
0950: }
0951:
0952: if (o instanceof java.lang.String) {
0953: o = Library.trim((String) o, " ", true, true);
0954:
0955: long val = Long.parseLong((String) o);
0956:
0957: return ValuePool.getLong(val);
0958: }
0959:
0960: if (o instanceof java.lang.Integer) {
0961: return ValuePool.getLong(((Integer) o).longValue());
0962: }
0963:
0964: if (o instanceof Byte || o instanceof Short) {
0965: return ValuePool.getLong(((Number) o).intValue());
0966: }
0967:
0968: if (o instanceof java.lang.Number) {
0969: return convertToLong(o);
0970: }
0971:
0972: if (o instanceof java.lang.Boolean) {
0973: return ((Boolean) o).booleanValue() ? ValuePool
0974: .getLong(1) : ValuePool.getLong(0);
0975: }
0976: break;
0977:
0978: case Types.REAL:
0979: case Types.FLOAT:
0980: case Types.DOUBLE:
0981: if (o instanceof java.lang.Double) {
0982: return o;
0983: }
0984:
0985: if (o instanceof java.lang.String) {
0986: o = Library.trim((String) o, " ", true, true);
0987:
0988: double d = JavaSystem.parseDouble((String) o);
0989: long l = Double.doubleToLongBits(d);
0990:
0991: return ValuePool.getDouble(l);
0992: }
0993:
0994: if (o instanceof java.lang.Number) {
0995: return convertToDouble(o);
0996: }
0997:
0998: if (o instanceof java.lang.Boolean) {
0999: return ((Boolean) o).booleanValue() ? ValuePool
1000: .getDouble(1) : ValuePool.getDouble(0);
1001: }
1002: break;
1003:
1004: case Types.NUMERIC:
1005: case Types.DECIMAL:
1006: if (o instanceof BigDecimal) {
1007: return o;
1008: }
1009:
1010: if (o instanceof Long) {
1011: return BigDecimal.valueOf(((Long) o).longValue());
1012: }
1013:
1014: if (o instanceof java.lang.Boolean) {
1015: return ((Boolean) o).booleanValue() ? BIG_DECIMAL_1
1016: : BIG_DECIMAL_0;
1017: }
1018: break;
1019:
1020: case Types.BOOLEAN:
1021: if (o instanceof java.lang.Boolean) {
1022: return (Boolean) o;
1023: }
1024:
1025: if (o instanceof java.lang.String) {
1026: o = Library.trim((String) o, " ", true, true);
1027:
1028: return ((String) o).equalsIgnoreCase("TRUE") ? Boolean.TRUE
1029: : Boolean.FALSE;
1030: }
1031:
1032: if (o instanceof Integer) {
1033: return ((Integer) o).intValue() == 0 ? Boolean.FALSE
1034: : Boolean.TRUE;
1035: }
1036:
1037: if (o instanceof Long) {
1038: return ((Long) o).longValue() == 0L ? Boolean.FALSE
1039: : Boolean.TRUE;
1040: }
1041:
1042: if (o instanceof java.lang.Double) {
1043: return ((Double) o).doubleValue() == 0.0 ? Boolean.FALSE
1044: : Boolean.TRUE;
1045: }
1046:
1047: if (o instanceof BigDecimal) {
1048: return ((BigDecimal) o).equals(BIG_DECIMAL_0) ? Boolean.FALSE
1049: : Boolean.TRUE;
1050: }
1051:
1052: throw Trace.error(Trace.WRONG_DATA_TYPE);
1053: case Types.VARCHAR_IGNORECASE:
1054: case Types.VARCHAR:
1055: case Types.CHAR:
1056: case Types.LONGVARCHAR:
1057: if (o instanceof java.lang.String) {
1058: return o;
1059: }
1060:
1061: if (o instanceof Time) {
1062: return HsqlDateTime.getTimeString((Time) o, null);
1063: }
1064:
1065: if (o instanceof Timestamp) {
1066: return HsqlDateTime.getTimestampString(
1067: (Timestamp) o, null);
1068: }
1069:
1070: if (o instanceof Date) {
1071: return HsqlDateTime.getDateString((Date) o, null);
1072: }
1073:
1074: if (o instanceof byte[]) {
1075: return StringConverter.byteToHex((byte[]) o);
1076: }
1077: break;
1078:
1079: case Types.TIME:
1080: if (o instanceof Time) {
1081: return HsqlDateTime.getNormalisedTime((Time) o);
1082: }
1083:
1084: if (o instanceof Timestamp) {
1085: return HsqlDateTime
1086: .getNormalisedTime((Timestamp) o);
1087: }
1088:
1089: if (o instanceof String) {
1090: return HsqlDateTime.timeValue((String) o);
1091: }
1092:
1093: if (o instanceof Date) {
1094: throw Trace.error(Trace.INVALID_CONVERSION, Types
1095: .getTypeString(type));
1096: }
1097: break;
1098:
1099: case Types.TIMESTAMP:
1100: if (o instanceof Timestamp) {
1101: return o;
1102: }
1103:
1104: if (o instanceof Time) {
1105: return HsqlDateTime
1106: .getNormalisedTimestamp((Time) o);
1107: }
1108:
1109: if (o instanceof Date) {
1110: return HsqlDateTime
1111: .getNormalisedTimestamp((Date) o);
1112: }
1113:
1114: if (o instanceof String) {
1115: return HsqlDateTime.timestampValue((String) o);
1116: }
1117: break;
1118:
1119: case Types.DATE:
1120: if (o instanceof Date) {
1121: return HsqlDateTime.getNormalisedDate((Date) o);
1122: }
1123:
1124: if (o instanceof Timestamp) {
1125: return HsqlDateTime
1126: .getNormalisedDate((Timestamp) o);
1127: }
1128:
1129: if (o instanceof String) {
1130: return HsqlDateTime.dateValue((String) o);
1131: }
1132:
1133: if (o instanceof Time) {
1134: throw Trace.error(Trace.INVALID_CONVERSION, Types
1135: .getTypeString(type));
1136: }
1137: break;
1138:
1139: case Types.BINARY:
1140: case Types.VARBINARY:
1141: case Types.LONGVARBINARY:
1142: if (o instanceof Binary) {
1143: return o;
1144: } else if (o instanceof byte[]) {
1145: return new Binary((byte[]) o, false);
1146: } else if (o instanceof String) {
1147:
1148: /**
1149: * @todo fredt - we need this for script processing only
1150: * handle the script separately and process normal
1151: * conversion according to rules in SQL
1152: * standard
1153: */
1154: return new Binary(StringConverter
1155: .hexToByte((String) o), false);
1156: }
1157:
1158: throw Trace.error(Trace.INVALID_CONVERSION, Types
1159: .getTypeString(type));
1160:
1161: // fredt@users 20030708 - patch 1.7.2 - OBJECT handling - superseded
1162: case Types.OTHER:
1163: if (o instanceof JavaObject) {
1164: return o;
1165: } else if (o instanceof String) {
1166:
1167: /**
1168: * @todo fredt - we need this for script processing only
1169: * handle the script separately and allow normal Sting
1170: * objects to be stored as JavaObject
1171: */
1172: return new JavaObject(StringConverter
1173: .hexToByte((String) o));
1174: } else if (o instanceof Binary) {
1175: return new JavaObject(((Binary) o).getBytes());
1176: }
1177:
1178: return new JavaObject((Serializable) o);
1179:
1180: default:
1181: }
1182:
1183: if (o instanceof JavaObject) {
1184: o = ((JavaObject) o).getObject();
1185:
1186: return convertObject(o, type);
1187: }
1188:
1189: return convertString(o.toString(), type);
1190: } catch (HsqlException e) {
1191: throw e;
1192: } catch (Exception e) {
1193: throw Trace.error(Trace.WRONG_DATA_TYPE, e.toString());
1194: }
1195: }
1196:
1197: /**
1198: * Return a java object based on a SQL string. This is called from
1199: * convertObject(Object o, int type).
1200: *
1201: * @param s
1202: * @param type
1203: * @return
1204: * @throws HsqlException
1205: */
1206: private static Object convertString(String s, int type)
1207: throws HsqlException {
1208:
1209: switch (type) {
1210:
1211: case Types.TINYINT:
1212: case Types.SMALLINT:
1213:
1214: // fredt - do maximumm / minimum checks on each type
1215: return convertObject(s, type);
1216:
1217: case Types.INTEGER:
1218: int val = Integer.parseInt(s);
1219:
1220: return ValuePool.getInt(val);
1221:
1222: case Types.BIGINT:
1223: return ValuePool.getLong(Long.parseLong(s));
1224:
1225: case Types.REAL:
1226: case Types.FLOAT:
1227: case Types.DOUBLE:
1228: double d = JavaSystem.parseDouble(s);
1229: long l = Double.doubleToLongBits(d);
1230:
1231: return ValuePool.getDouble(l);
1232:
1233: case Types.VARCHAR_IGNORECASE:
1234: case Types.VARCHAR:
1235: case Types.CHAR:
1236: case Types.LONGVARCHAR:
1237: return s;
1238:
1239: case Types.DATE:
1240: return HsqlDateTime.dateValue(s);
1241:
1242: case Types.TIME:
1243: return HsqlDateTime.timeValue(s);
1244:
1245: case Types.TIMESTAMP:
1246: return HsqlDateTime.timestampValue(s);
1247:
1248: case Types.NUMERIC:
1249: case Types.DECIMAL:
1250: s = Library.trim(s, " ", true, true);
1251:
1252: return new BigDecimal(s);
1253:
1254: case Types.BOOLEAN:
1255: return s.equalsIgnoreCase("TRUE") ? Boolean.TRUE
1256: : Boolean.FALSE;
1257:
1258: case Types.BINARY:
1259: case Types.VARBINARY:
1260: case Types.LONGVARBINARY:
1261: case Types.OTHER:
1262: default:
1263: throw Trace.error(Trace.INVALID_CONVERSION, Types
1264: .getTypeString(type));
1265: }
1266: }
1267:
1268: /**
1269: * Return an SQL representation of an object. Strings will be quoted
1270: * with single quotes, other objects will represented as in a SQL
1271: * statement.
1272: *
1273: * @param o
1274: * @param type
1275: * @return result
1276: * @throws HsqlException
1277: */
1278: static String createSQLString(Object o, int type)
1279: throws HsqlException {
1280:
1281: if (o == null) {
1282: return "NULL";
1283: }
1284:
1285: switch (type) {
1286:
1287: case Types.NULL:
1288: return "NULL";
1289:
1290: case Types.REAL:
1291: case Types.FLOAT:
1292: case Types.DOUBLE:
1293: return createSQLString(((Number) o).doubleValue());
1294:
1295: case Types.DATE:
1296: case Types.TIME:
1297: case Types.TIMESTAMP:
1298: return StringConverter.toQuotedString(o.toString(), '\'',
1299: false);
1300:
1301: case Types.BINARY:
1302: case Types.VARBINARY:
1303: case Types.LONGVARBINARY:
1304: if (!(o instanceof Binary)) {
1305: throw Trace.error(Trace.INVALID_CONVERSION);
1306: }
1307:
1308: return StringConverter.toQuotedString(StringConverter
1309: .byteToHex(((Binary) o).getBytes()), '\'', false);
1310:
1311: case Types.OTHER:
1312: if (!(o instanceof JavaObject)) {
1313: throw Trace.error(Trace.SERIALIZATION_FAILURE);
1314: }
1315:
1316: return StringConverter.toQuotedString(StringConverter
1317: .byteToHex(((JavaObject) o).getBytes()), '\'',
1318: false);
1319:
1320: case Types.VARCHAR_IGNORECASE:
1321: case Types.VARCHAR:
1322: case Types.CHAR:
1323: case Types.LONGVARCHAR:
1324: return createSQLString((String) o);
1325:
1326: default:
1327: return o.toString();
1328: }
1329: }
1330:
1331: public static String createSQLString(double x) {
1332:
1333: if (x == Double.NEGATIVE_INFINITY) {
1334: return "-1E0/0";
1335: }
1336:
1337: if (x == Double.POSITIVE_INFINITY) {
1338: return "1E0/0";
1339: }
1340:
1341: if (Double.isNaN(x)) {
1342: return "0E0/0E0";
1343: }
1344:
1345: String s = Double.toString(x);
1346:
1347: // ensure the engine treats the value as a DOUBLE, not DECIMAL
1348: if (s.indexOf('E') < 0) {
1349: s = s.concat("E0");
1350: }
1351:
1352: return s;
1353: }
1354:
1355: /**
1356: * Turns a java string into a quoted SQL string
1357: *
1358: * @param s java string
1359: * @return quoted SQL string
1360: */
1361: public static String createSQLString(String s) {
1362:
1363: if (s == null) {
1364: return "NULL";
1365: }
1366:
1367: return StringConverter.toQuotedString(s, '\'', true);
1368: }
1369:
1370: /**
1371: * Explicit casts are handled here. This is separate from the implicit
1372: * casts carried out when inserting/updating rows.
1373: * SQL standard 6.12 rules for enforcement of size, precision and scale
1374: * are implemented here are as follows:
1375: *
1376: * For no size, precision or scale, default to convertObject(Object)
1377: *
1378: * Right truncation is allowed only for CHAR to CHAR casts
1379: * (CHAR is generic for all string types).
1380: *
1381: * For other casts to CHAR, right truncation is not allowed.
1382: *
1383: * For numeric conversions, scale is always converted to target first,
1384: * then precision is imposed. No truncation is allowed. (fredt)
1385: */
1386: public static Object convertObject(Session session, Object o,
1387: int type, int precision, int scale) throws HsqlException {
1388:
1389: if (o == null) {
1390: return o;
1391: }
1392:
1393: if (precision == 0) {
1394: return convertObject(o, type);
1395: }
1396:
1397: boolean check = true;
1398:
1399: switch (type) {
1400:
1401: case Types.VARCHAR_IGNORECASE:
1402: case Types.LONGVARCHAR:
1403: type = Types.VARCHAR;
1404: case Types.VARCHAR:
1405: case Types.CHAR:
1406: if (o instanceof String) {
1407: check = false;
1408: } else {
1409: o = convertObject(o, Types.VARCHAR);
1410: }
1411:
1412: return enforceSize(o, type, precision, scale, check);
1413:
1414: case Types.NUMERIC:
1415: case Types.DECIMAL:
1416: if (!(o instanceof BigDecimal)) {
1417: o = convertObject(o, type);
1418: }
1419:
1420: return enforceSize(o, type, precision, scale, true);
1421:
1422: case Types.TIMESTAMP:
1423: if (o instanceof Time) {
1424: long millis = session.currentDate.getTime()
1425: + ((Time) o).getTime();
1426:
1427: o = HsqlDateTime.getTimestamp(millis);
1428: }
1429:
1430: if (o instanceof Timestamp) {
1431: return enforceSize(o, type, precision, scale, false);
1432: }
1433: }
1434:
1435: return convertObject(o, type);
1436: }
1437:
1438: static int[] tenPower = { 1000000000, 100000000, 10000000, 1000000,
1439: 100000, 10000, 1000 };
1440:
1441: /**
1442: * Check an object for type CHAR and VARCHAR and truncate/pad based on
1443: * the size
1444: *
1445: * @param obj object to check
1446: * @param type the object type
1447: * @param size size to enforce
1448: * @param check throw if too long
1449: * @return the altered object if the right type, else the object
1450: * passed in unaltered
1451: * @throws HsqlException if data too long
1452: */
1453: static Object enforceSize(Object obj, int type, int size,
1454: int scale, boolean check) throws HsqlException {
1455:
1456: if (obj == null) {
1457: return obj;
1458: }
1459:
1460: if (size == 0 && type != Types.TIMESTAMP) {
1461: return obj;
1462: }
1463:
1464: // todo: need to handle BINARY like this as well
1465: switch (type) {
1466:
1467: case Types.CHAR:
1468: return checkChar((String) obj, size, check);
1469:
1470: case Types.VARCHAR:
1471: case Types.VARCHAR_IGNORECASE:
1472: return checkVarchar((String) obj, size, check);
1473:
1474: case Types.NUMERIC:
1475: case Types.DECIMAL:
1476: BigDecimal dec = (BigDecimal) obj;
1477:
1478: dec = dec.setScale(scale, BigDecimal.ROUND_HALF_DOWN);
1479:
1480: BigInteger big = JavaSystem.getUnscaledValue(dec);
1481: int sign = big.signum() == -1 ? 1 : 0;
1482:
1483: if (big.toString().length() - sign > size) {
1484: throw Trace.error(Trace.STRING_DATA_TRUNCATION);
1485: }
1486:
1487: return dec;
1488:
1489: case Types.TIMESTAMP:
1490: if (size == 6) {
1491: return obj;
1492: }
1493:
1494: Timestamp ts = (Timestamp) obj;
1495: int nanos = ts.getNanos();
1496: int divisor = tenPower[size];
1497: int newNanos = (nanos / divisor) * divisor;
1498:
1499: ts.setNanos(newNanos);
1500:
1501: return ts;
1502:
1503: default:
1504: return obj;
1505: }
1506: }
1507:
1508: /**
1509: * Checks the length of a VARCHAR string.
1510: *
1511: * @param s the string to pad to truncate
1512: * @param len the len to make the string
1513: * @param check if true, throw an exception if truncation takes place
1514: * @return the string of size len
1515: */
1516: static String checkVarchar(String s, int len, boolean check)
1517: throws HsqlException {
1518:
1519: int slen = s.length();
1520:
1521: if (slen > len) {
1522: if (check) {
1523: throw Trace.error(Trace.STRING_DATA_TRUNCATION);
1524: }
1525:
1526: return s.substring(0, len);
1527: }
1528:
1529: return s;
1530: }
1531:
1532: /**
1533: * Checks and pads a CHARACTER string to len size
1534: *
1535: * @param s the string to pad to truncate
1536: * @param len the len to make the string
1537: * @param check if true, throw an exception if truncation takes place
1538: * @return the string of size len
1539: */
1540: static String checkChar(String s, int len, boolean check)
1541: throws HsqlException {
1542:
1543: int slen = s.length();
1544:
1545: if (slen == len) {
1546: return s;
1547: }
1548:
1549: if (slen > len) {
1550: if (check) {
1551: throw Trace.error(Trace.STRING_DATA_TRUNCATION);
1552: }
1553:
1554: return s.substring(0, len);
1555: }
1556:
1557: char[] b = new char[len];
1558:
1559: s.getChars(0, slen, b, 0);
1560:
1561: for (int i = slen; i < len; i++) {
1562: b[i] = ' ';
1563: }
1564:
1565: return new String(b);
1566: }
1567:
1568: /**
1569: * Type narrowing from DOUBLE/DECIMAL/NUMERIC to BIGINT / INT / SMALLINT / TINYINT
1570: * following the SQL rules. When conversion is from a non-integral type,
1571: * digits to the right of the decimal point are lost.
1572: */
1573:
1574: /**
1575: * Converter from a numeric object to Integer. Input is checked to be
1576: * within range represented by Integer.
1577: */
1578: static Integer convertToInt(Object o) throws HsqlException {
1579:
1580: if (o instanceof BigDecimal) {
1581: BigInteger bi = ((BigDecimal) o).toBigInteger();
1582:
1583: if (bi.compareTo(MAX_INT) > 0 || bi.compareTo(MIN_INT) < 0) {
1584: throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1585: }
1586:
1587: return ValuePool.getInt(bi.intValue());
1588: }
1589:
1590: if (o instanceof Double || o instanceof Float) {
1591: double d = ((Number) o).doubleValue();
1592:
1593: if (Double.isNaN(d) || d >= (double) Integer.MAX_VALUE + 1
1594: || d <= (double) Integer.MIN_VALUE - 1) {
1595: throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1596: }
1597:
1598: return ValuePool.getInt((int) d);
1599: }
1600:
1601: throw Trace.error(Trace.INVALID_CONVERSION);
1602: }
1603:
1604: /**
1605: * Converter from a numeric object to Long. Input is checked to be
1606: * within range represented by Long.
1607: */
1608: static Long convertToLong(Object o) throws HsqlException {
1609:
1610: if (o instanceof BigDecimal) {
1611: BigInteger bi = ((BigDecimal) o).toBigInteger();
1612:
1613: if (bi.compareTo(MAX_LONG) > 0
1614: || bi.compareTo(MIN_LONG) < 0) {
1615: throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1616: }
1617:
1618: return ValuePool.getLong(bi.longValue());
1619: }
1620:
1621: if (o instanceof Double || o instanceof Float) {
1622: double d = ((Number) o).doubleValue();
1623:
1624: if (Double.isNaN(d) || d >= (double) Long.MAX_VALUE + 1
1625: || d <= (double) Long.MIN_VALUE - 1) {
1626: throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1627: }
1628:
1629: return ValuePool.getLong((long) d);
1630: }
1631:
1632: throw Trace.error(Trace.INVALID_CONVERSION);
1633: }
1634:
1635: /**
1636: * Converter from a numeric object to Double. Input is checked to be
1637: * within range represented by Double
1638: */
1639: static Double convertToDouble(Object o) throws HsqlException {
1640:
1641: double val;
1642:
1643: if (o instanceof BigDecimal) {
1644: BigDecimal bd = (BigDecimal) o;
1645:
1646: val = bd.doubleValue();
1647:
1648: int signum = bd.signum();
1649: BigDecimal bo = new BigDecimal(val + signum);
1650:
1651: if (bo.compareTo(bd) != signum) {
1652: throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1653: }
1654: } else {
1655: val = ((Number) o).doubleValue();
1656: }
1657:
1658: return ValuePool.getDouble(Double.doubleToLongBits(val));
1659: }
1660:
1661: // fredt@users 20020408 - patch 442993 by fredt - arithmetic expressions
1662:
1663: /**
1664: * Arithmetic expression terms are promoted to a type that can
1665: * represent the resulting values and avoid incorrect results.<p>
1666: * When the result or the expression is converted to the
1667: * type of the target column for storage, an exception is thrown if the
1668: * resulting value cannot be stored in the column<p>
1669: * Returns a SQL type "wide" enough to represent the result of the
1670: * expression.<br>
1671: * A type is "wider" than the other if it can represent all its
1672: * numeric values.<BR>
1673: * Types narrower than INTEGER (int) are promoted to
1674: * INTEGER. The order is as follows<p>
1675: *
1676: * INTEGER, BIGINT, DOUBLE, DECIMAL<p>
1677: *
1678: * TINYINT and SMALLINT in any combination return INTEGER<br>
1679: * INTEGER and INTEGER return BIGINT<br>
1680: * BIGINT and INTEGER return NUMERIC/DECIMAL<br>
1681: * BIGINT and BIGINT return NUMERIC/DECIMAL<br>
1682: * DOUBLE and INTEGER return DOUBLE<br>
1683: * DOUBLE and BIGINT return DOUBLE<br>
1684: * NUMERIC/DECIMAL and any type returns NUMERIC/DECIMAL<br>
1685: *
1686: * @author fredt@users
1687: * @param type1 java.sql.Types value for the first numeric type
1688: * @param type2 java.sql.Types value for the second numeric type
1689: * @return either type1 or type2 on the basis of the above order
1690: */
1691: static int getCombinedNumberType(int type1, int type2, int expType) {
1692:
1693: int typeWidth1 = getNumTypeWidth(type1);
1694: int typeWidth2 = getNumTypeWidth(type2);
1695:
1696: if (typeWidth1 == 16 || typeWidth2 == 16) {
1697: return Types.DOUBLE;
1698: }
1699:
1700: switch (expType) {
1701:
1702: case Expression.EQUAL:
1703: case Expression.BIGGER:
1704: case Expression.BIGGER_EQUAL:
1705: case Expression.SMALLER_EQUAL:
1706: case Expression.SMALLER:
1707: case Expression.NOT_EQUAL:
1708: case Expression.ALTERNATIVE:
1709: case Expression.DIVIDE:
1710: return (typeWidth1 > typeWidth2) ? type1 : type2;
1711:
1712: default:
1713: int sum = typeWidth1 + typeWidth2;
1714:
1715: if (sum <= 4) {
1716: return Types.INTEGER;
1717: }
1718:
1719: if (sum <= 8) {
1720: return Types.BIGINT;
1721: }
1722:
1723: return Types.NUMERIC;
1724: }
1725: }
1726:
1727: /**
1728: * @param type java.sql.Types int for a numeric type
1729: * @return relative width
1730: */
1731: static int getNumTypeWidth(int type) {
1732:
1733: switch (type) {
1734:
1735: case Types.TINYINT:
1736: return 1;
1737:
1738: case Types.SMALLINT:
1739: return 2;
1740:
1741: case Types.INTEGER:
1742: return 4;
1743:
1744: case Types.BIGINT:
1745: return 8;
1746:
1747: case Types.REAL:
1748: case Types.FLOAT:
1749: case Types.DOUBLE:
1750: return 16;
1751:
1752: case Types.NUMERIC:
1753: case Types.DECIMAL:
1754: return 32;
1755:
1756: default:
1757: return 32;
1758: }
1759: }
1760:
1761: /**
1762: * returns -1, 0 , +1
1763: */
1764: static int compareToTypeRange(Object o, int targettype) {
1765:
1766: if (!(o instanceof Number)) {
1767: return 0;
1768: }
1769:
1770: if (o instanceof Integer || o instanceof Long) {
1771: long temp = ((Number) o).longValue();
1772: int min;
1773: int max;
1774:
1775: switch (targettype) {
1776:
1777: case Types.TINYINT:
1778: min = Byte.MIN_VALUE;
1779: max = Byte.MAX_VALUE;
1780: break;
1781:
1782: case Types.SMALLINT:
1783: min = Short.MIN_VALUE;
1784: max = Short.MAX_VALUE;
1785: break;
1786:
1787: case Types.INTEGER:
1788: min = Integer.MIN_VALUE;
1789: max = Integer.MAX_VALUE;
1790: break;
1791:
1792: case Types.BIGINT:
1793: case Types.DECIMAL:
1794: case Types.NUMERIC:
1795: default:
1796: return 0;
1797: }
1798:
1799: if (max < temp) {
1800: return 1;
1801: }
1802:
1803: if (temp < min) {
1804: return -1;
1805: }
1806:
1807: return 0;
1808: } else {
1809: try {
1810: o = convertToLong(o);
1811:
1812: return compareToTypeRange(o, targettype);
1813: } catch (HsqlException e) {
1814: if (e.getErrorCode() == -Trace.NUMERIC_VALUE_OUT_OF_RANGE) {
1815: if (o instanceof BigDecimal) {
1816: return ((BigDecimal) o).signum();
1817: } else if (o instanceof Double) {
1818: return ((Double) o).doubleValue() > 0 ? 1 : -1;
1819: }
1820: }
1821: }
1822: }
1823:
1824: return 0;
1825: }
1826:
1827: /**
1828: * Converts the specified hexadecimal digit <CODE>String</CODE>
1829: * to an equivalent array of bytes.
1830: *
1831: * @param hexString a <CODE>String</CODE> of hexadecimal digits
1832: * @throws HsqlException if the specified string contains non-hexadecimal digits.
1833: * @return a byte array equivalent to the specified string of hexadecimal digits
1834: */
1835: public static byte[] hexToByteArray(String hexString)
1836: throws HsqlException {
1837:
1838: try {
1839: return StringConverter.hexToByte(hexString);
1840: } catch (IOException e) {
1841: throw Trace.error(Trace.INVALID_CHARACTER_ENCODING);
1842: }
1843: }
1844:
1845: /**
1846: * Compares a <CODE>byte[]</CODE> with another specified
1847: * <CODE>byte[]</CODE> for order. Returns a negative integer, zero,
1848: * or a positive integer as the first object is less than, equal to, or
1849: * greater than the specified second <CODE>byte[]</CODE>.<p>
1850: *
1851: * @param o1 the first byte[] to be compared
1852: * @param o2 the second byte[] to be compared
1853: * @return a negative integer, zero, or a positive integer as this object
1854: * is less than, equal to, or greater than the specified object.
1855: */
1856: static int compareTo(byte[] o1, byte[] o2) {
1857:
1858: int len = o1.length;
1859: int lenb = o2.length;
1860:
1861: for (int i = 0;; i++) {
1862: int a = 0;
1863: int b = 0;
1864:
1865: if (i < len) {
1866: a = ((int) o1[i]) & 0xff;
1867: } else if (i >= lenb) {
1868: return 0;
1869: }
1870:
1871: if (i < lenb) {
1872: b = ((int) o2[i]) & 0xff;
1873: }
1874:
1875: if (a > b) {
1876: return 1;
1877: }
1878:
1879: if (b > a) {
1880: return -1;
1881: }
1882: }
1883: }
1884: }
|