|
What this is
Other links
The source code
/* Copyrights and Licenses
*
* This product includes Hypersonic SQL.
* Originally developed by Thomas Mueller and the Hypersonic SQL Group.
*
* Copyright (c) 1995-2000 by the Hypersonic SQL Group. All rights reserved.
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* - All advertising materials mentioning features or use of this software must display the
* following acknowledgment: "This product includes Hypersonic SQL."
* - Products derived from this software may not be called "Hypersonic SQL" nor may
* "Hypersonic SQL" appear in their names without prior written permission of the
* Hypersonic SQL Group.
* - Redistributions of any form whatsoever must retain the following acknowledgment: "This
* product includes Hypersonic SQL."
* This software is provided "as is" and any expressed or implied warranties, including, but
* not limited to, the implied warranties of merchantability and fitness for a particular purpose are
* disclaimed. In no event shall the Hypersonic SQL Group or its contributors be liable for any
* direct, indirect, incidental, special, exemplary, or consequential damages (including, but
* not limited to, procurement of substitute goods or services; loss of use, data, or profits;
* or business interruption). However caused any on any theory of liability, whether in contract,
* strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this
* software, even if advised of the possibility of such damage.
* This software consists of voluntary contributions made by many individuals on behalf of the
* Hypersonic SQL Group.
*
*
* For work added by the HSQL Development Group:
*
* Copyright (c) 2001-2004, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer, including earlier
* license statements (above) and comply with all above license conditions.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution, including earlier
* license statements (above) and comply with all above license conditions.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.Time;
import java.sql.Timestamp;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.Collator;
import org.hsqldb.lib.StringConverter;
import org.hsqldb.lib.HsqlByteArrayOutputStream;
import org.hsqldb.lib.HsqlByteArrayInputStream;
import org.hsqldb.store.ValuePool;
import org.hsqldb.HsqlNameManager.HsqlName;
// fredt@users 20020130 - patch 491987 by jimbag@users
// fredt@users 20020320 - doc 1.7.0 - update
// fredt@users 20020401 - patch 442993 by fredt - arithmetic expressions
// to allow mixed type arithmetic expressions beginning with a narrower type
// changes applied to several lines of code and not marked separately
// consists of changes to arithmatic functions to allow promotion of
// java.lang.Number values and new functions to choose type for promotion
// fredt@users 20020401 - patch 455757 by galena@users (Michiel de Roo)
// interpretation of TINYINT as Byte instead of Short
// fredt@users 20020130 - patch 505356 by daniel_fiser@users
// use of the current locale for string comparison (instead of posix)
// turned off by default but can be applied accross the database by defining
// sql.compare_in_locale=true in database.properties file
// changes marked separately
// fredt@users 20020130 - patch 491987 by jimbag@users
// support for sql standard char and varchar. size is maintained as
// defined in the DDL and trimming and padding takes place accordingly
// modified by fredt - trimming and padding are turned off by default but
// can be applied accross the database by defining sql.enforce_size=true in
// database.properties file
// fredt@users 20020215 - patch 1.7.0 by fredt - quoted identifiers
// applied to different parts to support the sql standard for
// naming of columns and tables (use of quoted identifiers as names)
// fredt@users 20020328 - patch 1.7.0 by fredt - change REAL to Double
// fredt@users 20020402 - patch 1.7.0 by fredt - type conversions
// frequently used type conversions are done without creating temporary
// Strings to reduce execution time and garbage collection
// fredt@users 20021013 - patch 1.7.1 by fredt - type conversions
// scripting of Double.Nan and infinity values
// fredt@users 20020825 - patch 1.7.1 - ByteArray.java converted to static
// methods
// BINARY objest are now represented internally as byte[] and use the static
// methods in this class to compare or convert the byte[] objects
// fredt@users 20021110 - patch 1.7.2 - ByteArray.java removed and methods
// moved here
/**
* Implementation of SQL table columns as defined in DDL statements with
* static methods to process their values.
*
* @version 1.7.0
*/
public class Column {
// --------------------------------------------------
// DDL name, size, scale, null, identity and default values
// most variables are final but not declared so because of a bug in
// JDK 1.1.8 compiler
public HsqlName columnName;
private int colType;
private int colSize;
private int colScale;
private boolean isNullable;
private boolean isIdentity;
private boolean isPrimaryKey;
private Expression defaultExpression;
long identityStart;
long identityIncrement;
static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
static final BigInteger MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE);
static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE);
static final BigInteger MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE);
static final BigDecimal BIG_DECIMAL_0 = new BigDecimal(0);
static final BigDecimal BIG_DECIMAL_1 = new BigDecimal(1);
/**
* Creates a column defined in DDL statement.
*
* @param name
* @param nullable
* @param type
* @param size
* @param scale
* @param identity
* @param startvalue
* @param increment
* @param primarykey
* @param defstring
*/
Column(HsqlName name, boolean nullable, int type, int size, int scale,
boolean identity, long startvalue, long increment,
boolean primarykey,
Expression defexpression) throws HsqlException {
columnName = name;
isNullable = nullable;
colType = type;
colSize = size;
colScale = scale;
isIdentity = identity;
identityStart = startvalue;
identityIncrement = increment;
isPrimaryKey = primarykey;
defaultExpression = defexpression;
if (isIdentity) {
if (type == Types.INTEGER) {
if (identityStart > Integer.MAX_VALUE
|| identityIncrement > Integer.MAX_VALUE) {
throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE,
name.statementName);
}
}
}
}
/**
* Is this the identity column in the table.
*
* @return boolean
*/
boolean isIdentity() {
return isIdentity;
}
/**
* Is column nullable.
*
* @return boolean
*/
boolean isNullable() {
return isNullable;
}
/**
* Set nullable.
*
*/
void setNullable(boolean value) {
isNullable = value;
}
/**
* Is this single column primary key of the table.
*
* @return boolean
*/
public boolean isPrimaryKey() {
return isPrimaryKey;
}
/**
* Set primary key.
*
*/
void setPrimaryKey(boolean value) {
isPrimaryKey = value;
}
/**
* Returns default value in the session context.
*/
Object getDefaultValue(Session session) throws HsqlException {
return defaultExpression == null ? null
: defaultExpression.getValue(session,
colType);
}
/**
* Returns DDL for default value.
*/
String getDefaultDDL() {
String ddl = null;
try {
ddl = defaultExpression == null ? null
: defaultExpression.getDDL();
} catch (HsqlException e) {}
return ddl;
}
/**
* Returns default expression for the column.
*/
Expression getDefaultExpression() {
return defaultExpression;
}
void setDefaultExpression(Expression expr) {
defaultExpression = expr;
}
/**
* Type of the column.
*
* @return java.sql.Types int value for the column
*/
int getType() {
return colType;
}
int getDIType() {
return colType == Types.VARCHAR_IGNORECASE ? Types.VARCHAR
: colType;
}
int getDITypeSub() {
if (colType == Types.VARCHAR_IGNORECASE) {
return Types.TYPE_SUB_IGNORECASE;
}
return Types.TYPE_SUB_DEFAULT;
}
/**
* Size of the column in DDL (0 if not defined).
*
* @return DDL size of column
*/
int getSize() {
return colSize;
}
/**
* Scale of the column in DDL (0 if not defined).
*
* @return DDL scale of column
*/
int getScale() {
return colScale;
}
/**
* Add two object of a given type
*
* @param a
* @param b
* @param type
* @return result
* @throws HsqlException
*/
static Object add(Object a, Object b, int type) throws HsqlException {
if (a == null || b == null) {
return null;
}
switch (type) {
case Types.NULL :
return null;
case Types.REAL :
case Types.FLOAT :
case Types.DOUBLE : {
double ad = ((Number) a).doubleValue();
double bd = ((Number) b).doubleValue();
return ValuePool.getDouble(Double.doubleToLongBits(ad + bd));
// return new Double(ad + bd);
}
case Types.VARCHAR :
case Types.CHAR :
case Types.LONGVARCHAR :
case Types.VARCHAR_IGNORECASE :
return (String) a + (String) b;
case Types.NUMERIC :
case Types.DECIMAL : {
BigDecimal abd = (BigDecimal) a;
BigDecimal bbd = (BigDecimal) b;
return abd.add(bbd);
}
case Types.TINYINT :
case Types.SMALLINT :
case Types.INTEGER : {
int ai = ((Number) a).intValue();
int bi = ((Number) b).intValue();
return ValuePool.getInt(ai + bi);
}
case Types.BIGINT : {
long longa = ((Number) a).longValue();
long longb = ((Number) b).longValue();
return ValuePool.getLong(longa + longb);
}
default :
throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
Types.getTypeString(type));
}
}
/**
* Concat two objects by turning them into strings first.
*
* @param a
* @param b
* @return result
* @throws HsqlException
*/
static Object concat(Object a, Object b) throws HsqlException {
if (a == null || b == null) {
return null;
}
return convertObject(a) + convertObject(b);
}
/**
* Negate a numeric object.
*
* @param a
* @param type
* @return result
* @throws HsqlException
*/
static Object negate(Object a, int type) throws HsqlException {
if (a == null) {
return null;
}
switch (type) {
case Types.NULL :
return null;
case Types.REAL :
case Types.FLOAT :
case Types.DOUBLE : {
double ad = -((Number) a).doubleValue();
return ValuePool.getDouble(Double.doubleToLongBits(ad));
}
case Types.NUMERIC :
case Types.DECIMAL :
return ((BigDecimal) a).negate();
case Types.TINYINT :
case Types.SMALLINT :
case Types.INTEGER :
return ValuePool.getInt(-((Number) a).intValue());
case Types.BIGINT :
return ValuePool.getLong(-((Number) a).longValue());
default :
throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
Types.getTypeString(type));
}
}
/**
* Multiply two numeric objects.
*
* @param a
* @param b
* @param type
* @return result
* @throws HsqlException
*/
static Object multiply(Object a, Object b,
int type) throws HsqlException {
if (a == null || b == null) {
return null;
}
// fredt@users - type conversion - may need to apply to other arithmetic operations too
if (!(a instanceof Number && b instanceof Number)) {
a = Column.convertObject(b, type);
b = Column.convertObject(b, type);
}
switch (type) {
case Types.NULL :
return null;
case Types.REAL :
case Types.FLOAT :
case Types.DOUBLE : {
double ad = ((Number) a).doubleValue();
double bd = ((Number) b).doubleValue();
return ValuePool.getDouble(Double.doubleToLongBits(ad * bd));
}
case Types.NUMERIC :
case Types.DECIMAL : {
BigDecimal abd = (BigDecimal) a;
BigDecimal bbd = (BigDecimal) b;
return abd.multiply(bbd);
}
case Types.TINYINT :
case Types.SMALLINT :
case Types.INTEGER : {
int ai = ((Number) a).intValue();
int bi = ((Number) b).intValue();
return ValuePool.getInt(ai * bi);
}
case Types.BIGINT : {
long longa = ((Number) a).longValue();
long longb = ((Number) b).longValue();
return ValuePool.getLong(longa * longb);
}
default :
throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
Types.getTypeString(type));
}
}
/**
* Divide numeric object a by object b.
*
* @param a
* @param b
* @param type
* @return result
* @throws HsqlException
*/
static Object divide(Object a, Object b, int type) throws HsqlException {
if (a == null || b == null) {
return null;
}
switch (type) {
case Types.NULL :
return null;
case Types.REAL :
case Types.FLOAT :
case Types.DOUBLE : {
double ad = ((Number) a).doubleValue();
double bd = ((Number) b).doubleValue();
return ValuePool.getDouble(Double.doubleToLongBits(ad / bd));
}
case Types.NUMERIC :
case Types.DECIMAL : {
BigDecimal abd = (BigDecimal) a;
BigDecimal bbd = (BigDecimal) b;
int scale = abd.scale() > bbd.scale() ? abd.scale()
: bbd.scale();
return (bbd.signum() == 0) ? null
: abd.divide(bbd, scale,
BigDecimal.ROUND_HALF_DOWN);
}
case Types.TINYINT :
case Types.SMALLINT :
case Types.INTEGER : {
int ai = ((Number) a).intValue();
int bi = ((Number) b).intValue();
Trace.check(bi != 0, Trace.DIVISION_BY_ZERO);
return ValuePool.getInt(ai / bi);
}
case Types.BIGINT : {
long longa = ((Number) a).longValue();
long longb = ((Number) b).longValue();
return (longb == 0) ? null
: ValuePool.getLong(longa / longb);
}
default :
throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
Types.getTypeString(type));
}
}
/**
* Subtract numeric object b from object a.
*
* @param a
* @param b
* @param type
* @return result
* @throws HsqlException
*/
static Object subtract(Object a, Object b,
int type) throws HsqlException {
if (a == null || b == null) {
return null;
}
switch (type) {
case Types.NULL :
return null;
case Types.REAL :
case Types.FLOAT :
case Types.DOUBLE : {
double ad = ((Number) a).doubleValue();
double bd = ((Number) b).doubleValue();
return ValuePool.getDouble(Double.doubleToLongBits(ad - bd));
}
case Types.NUMERIC :
case Types.DECIMAL : {
BigDecimal abd = (BigDecimal) a;
BigDecimal bbd = (BigDecimal) b;
return abd.subtract(bbd);
}
case Types.TINYINT :
case Types.SMALLINT :
case Types.INTEGER : {
int ai = ((Number) a).intValue();
int bi = ((Number) b).intValue();
return ValuePool.getInt(ai - bi);
}
case Types.BIGINT : {
long longa = ((Number) a).longValue();
long longb = ((Number) b).longValue();
return ValuePool.getLong(longa - longb);
}
default :
throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
Types.getTypeString(type));
}
}
// fredt@users 20020130 - patch 505356 by daniel_fiser@users
// modified for performance and made optional
private static Collator i18nCollator = Collator.getInstance();
static boolean sql_compare_in_locale = false;
static void setCompareInLocal(boolean value) {
sql_compare_in_locale = value;
}
/**
* Compare a with b and return int value as result.
*
* @param a instance of Java wrapper, depending on type, but always same for a & b (can be null)
* @param b instance of Java wrapper, depending on type, but always same for a & b (can be null)
* @param type one of the java.sql.Types
* @return result 1 if a>b, 0 if a=b, -1 if b>a
* @throws HsqlException
*/
static int compare(Object a, Object b, int type) throws HsqlException {
int i = 0;
if (a == b) {
return 0;
}
// Current null handling here: null==null and smaller any value
// Note, standard SQL null handling is handled by Expression.test() calling testNull() instead of this!
// Attention, this is also used for grouping ('null' is one group)
if (a == null) {
if (b == null) {
return 0;
}
return -1;
}
if (b == null) {
return 1;
}
switch (type) {
case Types.NULL :
return 0;
case Types.VARCHAR :
case Types.LONGVARCHAR :
if (sql_compare_in_locale) {
i = i18nCollator.compare((String) a, (String) b);
} else {
i = ((String) a).compareTo((String) b);
}
break;
// fredt@users 20020130 - patch 418022 by deforest@users
// use of rtrim() to mimic SQL92 behaviour
case Types.CHAR :
if (sql_compare_in_locale) {
i = i18nCollator.compare(Library.rtrim((String) a),
Library.rtrim((String) b));
} else {
i = (Library.rtrim((String) a)).compareTo(
Library.rtrim((String) b));
}
break;
// boucherb@users 2003-09-25
// TODO: Maybe use //#ifdef tag or reflective static method attribute
// instantiation to take advantage of String.compareToIgnoreCase when
// available (JDK 1.2 and greater) during ANT build. That or perhaps
// consider using either local character-wise comparison or first converting
// to lower case and then to upper case. Sun states that the JDK 1.2 introduced
// String.compareToIngnorCase() comparison involves calling
// Character.toLowerCase(Character.toUpperCase()) on compared characters,
// to correctly handle some caveats concering using only the one operation or
// the other outside the ascii character range.
case Types.VARCHAR_IGNORECASE :
if (sql_compare_in_locale) {
i = i18nCollator.compare(((String) a).toUpperCase(),
((String) b).toUpperCase());
} else {
i = ((String) a).toUpperCase().compareTo(
((String) b).toUpperCase());
}
break;
case Types.TINYINT :
case Types.SMALLINT :
case Types.INTEGER : {
int ai = ((Number) a).intValue();
int bi = ((Number) b).intValue();
return (ai > bi) ? 1
: (bi > ai ? -1
: 0);
}
case Types.BIGINT : {
long longa = ((Number) a).longValue();
long longb = ((Number) b).longValue();
return (longa > longb) ? 1
: (longb > longa ? -1
: 0);
}
case Types.REAL :
case Types.FLOAT :
case Types.DOUBLE : {
double ad = ((Number) a).doubleValue();
double bd = ((Number) b).doubleValue();
return (ad > bd) ? 1
: (bd > ad ? -1
: 0);
}
case Types.NUMERIC :
case Types.DECIMAL :
i = ((BigDecimal) a).compareTo((BigDecimal) b);
break;
case Types.DATE :
if (((java.sql.Date) a).after((java.sql.Date) b)) {
return 1;
} else if (((java.sql.Date) a).before((java.sql.Date) b)) {
return -1;
} else {
return 0;
}
case Types.TIME :
return HsqlDateTime.compare((Time) a, (Time) b);
case Types.TIMESTAMP :
if (((Timestamp) a).after((Timestamp) b)) {
return 1;
} else if (((Timestamp) a).before((Timestamp) b)) {
return -1;
} else {
return 0;
}
case Types.BOOLEAN : {
boolean boola = ((Boolean) a).booleanValue();
boolean boolb = ((Boolean) b).booleanValue();
return (boola == boolb) ? 0
: (boolb ? -1
: 1);
}
case Types.BINARY :
case Types.VARBINARY :
case Types.LONGVARBINARY :
if (a instanceof Binary && b instanceof Binary) {
i = compareTo(((Binary) a).getBytes(),
((Binary) b).getBytes());
} else {
throw Trace.error(Trace.INVALID_CONVERSION,
Types.getTypeString(type));
}
break;
case Types.OTHER :
return 0;
default :
throw Trace.error(Trace.INVALID_CONVERSION,
Types.getTypeString(type));
}
return (i == 0) ? 0
: (i < 0 ? -1
: 1);
}
/**
* Return a java string representation of a java object.
*
* @param o
* @return result (null value for null object)
*/
static String convertObject(Object o) {
if (o == null) {
return null;
}
return o.toString();
}
/**
* Convert an object into a Java object that represents its SQL type.
|
Copyright 1998-2008 Alvin Alexander
All Rights Reserved.
devdaily.com is based in louisville, kentucky, and this web site is hosted by godaddy.com