0001: /* =============================================================
0002: * SmallSQL : a free Java DBMS library for the Java(tm) platform
0003: * =============================================================
0004: *
0005: * (C) Copyright 2004-2007, by Volker Berlin.
0006: *
0007: * Project Info: http://www.smallsql.de/
0008: *
0009: * This library is free software; you can redistribute it and/or modify it
0010: * under the terms of the GNU Lesser General Public License as published by
0011: * the Free Software Foundation; either version 2.1 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * This library is distributed in the hope that it will be useful, but
0015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
0016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
0017: * License for more details.
0018: *
0019: * You should have received a copy of the GNU Lesser General Public
0020: * License along with this library; if not, write to the Free Software
0021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0022: * USA.
0023: *
0024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
0025: * in the United States and other countries.]
0026: *
0027: * ---------------
0028: * ExpressionArithmethic.java
0029: * ---------------
0030: * Author: Volker Berlin
0031: *
0032: */
0033: package smallsql.database;
0034:
0035: import java.sql.*;
0036: import smallsql.database.language.Language;
0037:
0038: public class ExpressionArithmetic extends Expression {
0039:
0040: private Expression left;
0041: private Expression right;
0042: private Expression right2;
0043: private Expression[] inList;
0044: final private int operation;
0045:
0046: /**
0047: * Constructor for NOT, NEGATIVE, BIT_NOT, ISNULL and ISNOTNULL
0048: */
0049: ExpressionArithmetic(Expression left, int operation) {
0050: super (FUNCTION);
0051: this .left = left;
0052: this .operation = operation;
0053: super .setParams(new Expression[] { left });
0054: }
0055:
0056: ExpressionArithmetic(Expression left, Expression right,
0057: int operation) {
0058: super (FUNCTION);
0059: this .left = left;
0060: this .right = right;
0061: this .operation = operation;
0062: super .setParams(new Expression[] { left, right });
0063: }
0064:
0065: /**
0066: * Constructor for BETWEEN
0067: */
0068: ExpressionArithmetic(Expression left, Expression right,
0069: Expression right2, int operation) {
0070: super (FUNCTION);
0071: this .left = left;
0072: this .right = right;
0073: this .right2 = right2;
0074: this .operation = operation;
0075: super .setParams(new Expression[] { left, right, right2 });
0076: }
0077:
0078: /**
0079: * Constructor for IN
0080: */
0081: ExpressionArithmetic(Expression left, Expressions inList,
0082: int operation) {
0083: super (FUNCTION);
0084: this .left = left;
0085: this .operation = operation;
0086: Expression[] params;
0087: if (inList != null) {
0088: this .inList = inList.toArray();
0089: params = new Expression[this .inList.length + 1];
0090: params[0] = left;
0091: System.arraycopy(this .inList, 0, params, 1,
0092: this .inList.length);
0093: } else {
0094: //Occur with ExpressionInSelect, in this case the method isInList() is overridden
0095: params = new Expression[] { left };
0096: }
0097: super .setParams(params);
0098: }
0099:
0100: /**
0101: * Get the arithmetic operation of this expression.
0102: * @return
0103: */
0104: int getOperation() {
0105: return operation;
0106: }
0107:
0108: private Expression convertExpressionIfNeeded(Expression expr,
0109: Expression other) {
0110: if (expr == null || other == null) {
0111: return expr;
0112: }
0113: switch (expr.getDataType()) {
0114: case SQLTokenizer.CHAR:
0115: case SQLTokenizer.NCHAR:
0116: case SQLTokenizer.BINARY:
0117: switch (other.getDataType()) {
0118: case SQLTokenizer.VARCHAR:
0119: case SQLTokenizer.NVARCHAR:
0120: case SQLTokenizer.CLOB:
0121: case SQLTokenizer.NCLOB:
0122: case SQLTokenizer.LONGNVARCHAR:
0123: case SQLTokenizer.LONGVARCHAR:
0124: case SQLTokenizer.VARBINARY:
0125: ExpressionFunctionRTrim trim = new ExpressionFunctionRTrim();
0126: trim.setParams(new Expression[] { expr });
0127: return trim;
0128: case SQLTokenizer.CHAR:
0129: case SQLTokenizer.NCHAR:
0130: case SQLTokenizer.BINARY:
0131: if (other.getPrecision() > expr.getPrecision()) {
0132: return new ExpressionFunctionConvert(
0133: new ColumnExpression(other), expr, null);
0134: }
0135: break;
0136: }
0137: break;
0138: }
0139: return expr;
0140: }
0141:
0142: final void setParamAt(Expression param, int idx) {
0143: switch (idx) {
0144: case 0:
0145: left = param;
0146: break;
0147: case 1:
0148: if (right != null) {
0149: right = param;
0150: }
0151: break;
0152: case 2:
0153: if (right != null) {
0154: right2 = param;
0155: }
0156: break;
0157: }
0158: if (inList != null && idx > 0 && idx <= inList.length) {
0159: inList[idx - 1] = param;
0160: }
0161: super .setParamAt(param, idx);
0162: }
0163:
0164: /**
0165: * Is used in GroupResult.
0166: */
0167: public boolean equals(Object expr) {
0168: if (!super .equals(expr))
0169: return false;
0170: if (!(expr instanceof ExpressionArithmetic))
0171: return false;
0172: if (((ExpressionArithmetic) expr).operation != operation)
0173: return false;
0174: return true;
0175: }
0176:
0177: int getInt() throws java.lang.Exception {
0178: if (isNull())
0179: return 0;
0180: int dataType = getDataType();
0181: switch (dataType) {
0182: case SQLTokenizer.BIT:
0183: case SQLTokenizer.BOOLEAN:
0184: return getBoolean() ? 1 : 0;
0185: case SQLTokenizer.TINYINT:
0186: case SQLTokenizer.SMALLINT:
0187: case SQLTokenizer.INT:
0188: return getIntImpl();
0189: case SQLTokenizer.BIGINT:
0190: return (int) getLongImpl();
0191: case SQLTokenizer.REAL:
0192: return (int) getFloatImpl();
0193: case SQLTokenizer.FLOAT:
0194: case SQLTokenizer.DOUBLE:
0195: case SQLTokenizer.MONEY:
0196: case SQLTokenizer.SMALLMONEY:
0197: case SQLTokenizer.NUMERIC:
0198: case SQLTokenizer.DECIMAL:
0199: // FIXME: bug! if get returns a number outside of
0200: // integer interval, it's not rounded to max/min,
0201: // instead it returns a wrong value
0202: return (int) getDoubleImpl();
0203: }
0204: throw createUnspportedConversion(SQLTokenizer.INT);
0205: }
0206:
0207: private int getIntImpl() throws java.lang.Exception {
0208: switch (operation) {
0209: case ADD:
0210: return left.getInt() + right.getInt();
0211: case SUB:
0212: return left.getInt() - right.getInt();
0213: case MUL:
0214: return left.getInt() * right.getInt();
0215: case DIV:
0216: return left.getInt() / right.getInt();
0217: case NEGATIVE:
0218: return -left.getInt();
0219: case MOD:
0220: return left.getInt() % right.getInt();
0221: case BIT_NOT:
0222: return ~left.getInt();
0223: }
0224: throw createUnspportedConversion(SQLTokenizer.INT);
0225: }
0226:
0227: long getLong() throws java.lang.Exception {
0228: if (isNull())
0229: return 0;
0230: int dataType = getDataType();
0231: switch (dataType) {
0232: case SQLTokenizer.BIT:
0233: case SQLTokenizer.BOOLEAN:
0234: return getBoolean() ? 1 : 0;
0235: case SQLTokenizer.TINYINT:
0236: case SQLTokenizer.SMALLINT:
0237: case SQLTokenizer.INT:
0238: return getIntImpl();
0239: case SQLTokenizer.BIGINT:
0240: return getLongImpl();
0241: case SQLTokenizer.REAL:
0242: return (long) getFloatImpl();
0243: case SQLTokenizer.FLOAT:
0244: case SQLTokenizer.DOUBLE:
0245: case SQLTokenizer.MONEY:
0246: case SQLTokenizer.SMALLMONEY:
0247: case SQLTokenizer.NUMERIC:
0248: case SQLTokenizer.DECIMAL:
0249: return (long) getDoubleImpl();
0250: }
0251: throw createUnspportedConversion(SQLTokenizer.LONG);
0252: }
0253:
0254: private long getLongImpl() throws java.lang.Exception {
0255: if (isNull())
0256: return 0;
0257: switch (operation) {
0258: case ADD:
0259: return left.getLong() + right.getLong();
0260: case SUB:
0261: return left.getLong() - right.getLong();
0262: case MUL:
0263: return left.getLong() * right.getLong();
0264: case DIV:
0265: return left.getLong() / right.getLong();
0266: case NEGATIVE:
0267: return -left.getLong();
0268: case MOD:
0269: return left.getLong() % right.getLong();
0270: case BIT_NOT:
0271: return ~right.getInt();
0272: }
0273: throw createUnspportedConversion(SQLTokenizer.LONG);
0274: }
0275:
0276: double getDouble() throws java.lang.Exception {
0277: if (isNull())
0278: return 0;
0279: int dataType = getDataType();
0280: switch (dataType) {
0281: case SQLTokenizer.BIT:
0282: case SQLTokenizer.BOOLEAN:
0283: return getBoolean() ? 1 : 0;
0284: case SQLTokenizer.TINYINT:
0285: case SQLTokenizer.SMALLINT:
0286: case SQLTokenizer.INT:
0287: return getIntImpl();
0288: case SQLTokenizer.BIGINT:
0289: return getLongImpl();
0290: case SQLTokenizer.REAL:
0291: return getFloatImpl();
0292: case SQLTokenizer.FLOAT:
0293: case SQLTokenizer.DOUBLE:
0294: case SQLTokenizer.MONEY:
0295: case SQLTokenizer.SMALLMONEY:
0296: case SQLTokenizer.NUMERIC:
0297: case SQLTokenizer.DECIMAL:
0298: return getDoubleImpl();
0299: }
0300: throw createUnspportedConversion(SQLTokenizer.DOUBLE);
0301: }
0302:
0303: private double getDoubleImpl() throws java.lang.Exception {
0304: if (operation == NEGATIVE)
0305: return getDoubleImpl(0, left.getDouble());
0306: return getDoubleImpl(left.getDouble(), right.getDouble());
0307: }
0308:
0309: private double getDoubleImpl(double lVal, double rVal)
0310: throws java.lang.Exception {
0311: switch (operation) {
0312: case ADD:
0313: return lVal + rVal;
0314: case SUB:
0315: return lVal - rVal;
0316: case MUL:
0317: return lVal * rVal;
0318: case DIV:
0319: return lVal / rVal;
0320: case NEGATIVE:
0321: return -rVal;
0322: case MOD:
0323: return lVal % rVal;
0324: }
0325: throw createUnspportedConversion(SQLTokenizer.DOUBLE);
0326: }
0327:
0328: float getFloat() throws java.lang.Exception {
0329: if (isNull())
0330: return 0;
0331: int dataType = getDataType();
0332: switch (dataType) {
0333: case SQLTokenizer.BIT:
0334: case SQLTokenizer.BOOLEAN:
0335: return getBoolean() ? 1 : 0;
0336: case SQLTokenizer.TINYINT:
0337: case SQLTokenizer.SMALLINT:
0338: case SQLTokenizer.INT:
0339: return getIntImpl();
0340: case SQLTokenizer.BIGINT:
0341: return getLongImpl();
0342: case SQLTokenizer.REAL:
0343: return getFloatImpl();
0344: case SQLTokenizer.FLOAT:
0345: case SQLTokenizer.DOUBLE:
0346: case SQLTokenizer.MONEY:
0347: case SQLTokenizer.SMALLMONEY:
0348: case SQLTokenizer.NUMERIC:
0349: case SQLTokenizer.DECIMAL:
0350: return (float) getDoubleImpl();
0351: }
0352: throw createUnspportedConversion(SQLTokenizer.DOUBLE);
0353: }
0354:
0355: private float getFloatImpl() throws java.lang.Exception {
0356: switch (operation) {
0357: case ADD:
0358: return left.getFloat() + right.getFloat();
0359: case SUB:
0360: return left.getFloat() - right.getFloat();
0361: case MUL:
0362: return left.getFloat() * right.getFloat();
0363: case DIV:
0364: return left.getFloat() / right.getFloat();
0365: case NEGATIVE:
0366: return -left.getFloat();
0367: case MOD:
0368: return left.getFloat() % right.getFloat();
0369: }
0370: throw createUnspportedConversion(SQLTokenizer.REAL);
0371: }
0372:
0373: long getMoney() throws java.lang.Exception {
0374: if (isNull())
0375: return 0;
0376: int dataType = getDataType();
0377: switch (dataType) {
0378: case SQLTokenizer.BIT:
0379: case SQLTokenizer.BOOLEAN:
0380: return getBoolean() ? 10000 : 0;
0381: case SQLTokenizer.TINYINT:
0382: case SQLTokenizer.SMALLINT:
0383: case SQLTokenizer.INT:
0384: return getIntImpl() * 10000;
0385: case SQLTokenizer.BIGINT:
0386: return getLongImpl() * 10000;
0387: case SQLTokenizer.REAL:
0388: return Utils.doubleToMoney(getFloatImpl());
0389: case SQLTokenizer.FLOAT:
0390: case SQLTokenizer.DOUBLE:
0391: case SQLTokenizer.NUMERIC:
0392: case SQLTokenizer.DECIMAL:
0393: return Utils.doubleToMoney(getDoubleImpl());
0394: case SQLTokenizer.MONEY:
0395: case SQLTokenizer.SMALLMONEY:
0396: return getMoneyImpl();
0397: }
0398: throw createUnspportedConversion(SQLTokenizer.DOUBLE);
0399: }
0400:
0401: private long getMoneyImpl() throws java.lang.Exception {
0402: switch (operation) {
0403: case ADD:
0404: return left.getMoney() + right.getMoney();
0405: case SUB:
0406: return left.getMoney() - right.getMoney();
0407: case MUL:
0408: return left.getMoney() * right.getMoney() / 10000;
0409: case DIV:
0410: return left.getMoney() * 10000 / right.getMoney();
0411: case NEGATIVE:
0412: return -left.getMoney();
0413: }
0414: throw createUnspportedConversion(SQLTokenizer.MONEY);
0415: }
0416:
0417: MutableNumeric getNumeric() throws java.lang.Exception {
0418: if (isNull())
0419: return null;
0420: int dataType = getDataType();
0421: switch (dataType) {
0422: case SQLTokenizer.BIT:
0423: case SQLTokenizer.BOOLEAN:
0424: return new MutableNumeric(getBoolean() ? 1 : 0);
0425: case SQLTokenizer.TINYINT:
0426: case SQLTokenizer.SMALLINT:
0427: case SQLTokenizer.INT:
0428: return new MutableNumeric(getIntImpl());
0429: case SQLTokenizer.BIGINT:
0430: return new MutableNumeric(getLongImpl());
0431: case SQLTokenizer.REAL:
0432: return new MutableNumeric(getFloatImpl());
0433: case SQLTokenizer.FLOAT:
0434: case SQLTokenizer.DOUBLE:
0435: return new MutableNumeric(getDoubleImpl());
0436: case SQLTokenizer.NUMERIC:
0437: case SQLTokenizer.DECIMAL:
0438: return getNumericImpl();
0439: case SQLTokenizer.MONEY:
0440: case SQLTokenizer.SMALLMONEY:
0441: return new MutableNumeric(getMoneyImpl(), 4);
0442: }
0443: throw createUnspportedConversion(SQLTokenizer.DOUBLE);
0444: }
0445:
0446: private MutableNumeric getNumericImpl() throws java.lang.Exception {
0447: switch (operation) {
0448: case ADD: {
0449: MutableNumeric num = left.getNumeric();
0450: num.add(right.getNumeric());
0451: return num;
0452: }
0453: case SUB: {
0454: MutableNumeric num = left.getNumeric();
0455: num.sub(right.getNumeric());
0456: return num;
0457: }
0458: case MUL:
0459: if (getDataType(right.getDataType(), SQLTokenizer.INT) == SQLTokenizer.INT) {
0460: MutableNumeric num = left.getNumeric();
0461: num.mul(right.getInt());
0462: return num;
0463: } else if (getDataType(left.getDataType(), SQLTokenizer.INT) == SQLTokenizer.INT) {
0464: MutableNumeric num = right.getNumeric();
0465: num.mul(left.getInt());
0466: return num;
0467: } else {
0468: MutableNumeric num = left.getNumeric();
0469: num.mul(right.getNumeric());
0470: return num;
0471: }
0472: case DIV: {
0473: MutableNumeric num = left.getNumeric();
0474: if (getDataType(right.getDataType(), SQLTokenizer.INT) == SQLTokenizer.INT)
0475: num.div(right.getInt());
0476: else
0477: num.div(right.getNumeric());
0478: return num;
0479: }
0480: case NEGATIVE: {
0481: MutableNumeric num = left.getNumeric();
0482: num.setSignum(-num.getSignum());
0483: return num;
0484: }
0485: case MOD: {
0486: if (getDataType(getDataType(), SQLTokenizer.INT) == SQLTokenizer.INT)
0487: return new MutableNumeric(getInt());
0488: MutableNumeric num = left.getNumeric();
0489: num.mod(right.getNumeric());
0490: return num;
0491: }
0492: default:
0493: throw createUnspportedConversion(SQLTokenizer.NUMERIC);
0494: }
0495: }
0496:
0497: Object getObject() throws java.lang.Exception {
0498: if (isNull())
0499: return null;
0500: int dataType = getDataType();
0501: switch (dataType) {
0502: case SQLTokenizer.BIT:
0503: case SQLTokenizer.BOOLEAN:
0504: return getBoolean() ? Boolean.TRUE : Boolean.FALSE;
0505: case SQLTokenizer.BINARY:
0506: case SQLTokenizer.VARBINARY:
0507: return getBytes();
0508: case SQLTokenizer.TINYINT:
0509: case SQLTokenizer.SMALLINT:
0510: case SQLTokenizer.INT:
0511: return new Integer(getInt());
0512: case SQLTokenizer.BIGINT:
0513: return new Long(getLong());
0514: case SQLTokenizer.REAL:
0515: return new Float(getFloat());
0516: case SQLTokenizer.FLOAT:
0517: case SQLTokenizer.DOUBLE:
0518: return new Double(getDouble());
0519: case SQLTokenizer.MONEY:
0520: case SQLTokenizer.SMALLMONEY:
0521: return Money.createFromUnscaledValue(getMoney());
0522: case SQLTokenizer.NUMERIC:
0523: case SQLTokenizer.DECIMAL:
0524: return getNumeric();
0525: case SQLTokenizer.CHAR:
0526: case SQLTokenizer.NCHAR:
0527: case SQLTokenizer.VARCHAR:
0528: case SQLTokenizer.NVARCHAR:
0529: case SQLTokenizer.LONGNVARCHAR:
0530: case SQLTokenizer.LONGVARCHAR:
0531: return getString(left.getString(), right.getString());
0532: case SQLTokenizer.JAVA_OBJECT:
0533: Object lObj = left.getObject();
0534: //FIXME NullPointerException bei NEGATIVE
0535: Object rObj = right.getObject();
0536: if (lObj instanceof Number && rObj instanceof Number)
0537: return new Double(getDoubleImpl(((Number) lObj)
0538: .doubleValue(), ((Number) rObj).doubleValue()));
0539: else
0540: return getString(lObj.toString(), rObj.toString());
0541: case SQLTokenizer.LONGVARBINARY:
0542: return getBytes();
0543: case SQLTokenizer.DATE:
0544: case SQLTokenizer.TIME:
0545: case SQLTokenizer.TIMESTAMP:
0546: case SQLTokenizer.SMALLDATETIME:
0547: return new DateTime(getLong(), dataType);
0548: case SQLTokenizer.UNIQUEIDENTIFIER:
0549: return getBytes();
0550: default:
0551: throw createUnspportedDataType();
0552: }
0553: }
0554:
0555: boolean getBoolean() throws java.lang.Exception {
0556: switch (operation) {
0557: case OR:
0558: return left.getBoolean() || right.getBoolean();
0559: case AND:
0560: return left.getBoolean() && right.getBoolean();
0561: case NOT:
0562: return !left.getBoolean();
0563: case LIKE:
0564: return Utils.like(left.getString(), right.getString());
0565: case ISNULL:
0566: return left.isNull();
0567: case ISNOTNULL:
0568: return !left.isNull();
0569: case IN:
0570: if (right == null)
0571: return isInList();
0572: break;
0573: }
0574: final boolean leftIsNull = left.isNull();
0575: int dataType;
0576: if (operation == NEGATIVE || operation == BIT_NOT) {
0577: if (leftIsNull)
0578: return false;
0579: dataType = left.getDataType();
0580: } else {
0581: final boolean rightIsNull = right.isNull();
0582: if (operation == EQUALS_NULL && leftIsNull && rightIsNull)
0583: return true;
0584: if (leftIsNull || rightIsNull)
0585: return false;
0586: dataType = getDataType(left, right);
0587: }
0588: switch (dataType) {
0589: case SQLTokenizer.BOOLEAN:
0590: switch (operation) {
0591: case IN:
0592: case EQUALS_NULL:
0593: case EQUALS:
0594: return left.getBoolean() == right.getBoolean();
0595: case UNEQUALS:
0596: return left.getBoolean() != right.getBoolean();
0597: }
0598: //break; interpret it as BIT
0599: case SQLTokenizer.TINYINT:
0600: case SQLTokenizer.SMALLINT:
0601: case SQLTokenizer.INT:
0602: case SQLTokenizer.BIT:
0603: switch (operation) {
0604: case IN:
0605: case EQUALS_NULL:
0606: case EQUALS:
0607: return left.getInt() == right.getInt();
0608: case GREATER:
0609: return left.getInt() > right.getInt();
0610: case GRE_EQU:
0611: return left.getInt() >= right.getInt();
0612: case LESSER:
0613: return left.getInt() < right.getInt();
0614: case LES_EQU:
0615: return left.getInt() <= right.getInt();
0616: case UNEQUALS:
0617: return left.getInt() != right.getInt();
0618: case BETWEEN:
0619: int _left = left.getInt();
0620: return _left >= right.getInt()
0621: && right2.getInt() >= _left;
0622: default:
0623: return getInt() != 0;
0624: }
0625: case SQLTokenizer.BIGINT:
0626: case SQLTokenizer.TIMESTAMP:
0627: case SQLTokenizer.TIME:
0628: case SQLTokenizer.DATE:
0629: case SQLTokenizer.SMALLDATETIME:
0630: switch (operation) {
0631: case IN:
0632: case EQUALS_NULL:
0633: case EQUALS:
0634: return left.getLong() == right.getLong();
0635: case GREATER:
0636: return left.getLong() > right.getLong();
0637: case GRE_EQU:
0638: return left.getLong() >= right.getLong();
0639: case LESSER:
0640: return left.getLong() < right.getLong();
0641: case LES_EQU:
0642: return left.getLong() <= right.getLong();
0643: case UNEQUALS:
0644: return left.getLong() != right.getLong();
0645: case BETWEEN:
0646: long _left = left.getLong();
0647: return _left >= right.getLong()
0648: && right2.getLong() >= _left;
0649: default:
0650: return getLong() != 0;
0651: }
0652: case SQLTokenizer.REAL:
0653: switch (operation) {
0654: case IN:
0655: case EQUALS_NULL:
0656: case EQUALS:
0657: return left.getFloat() == right.getFloat();
0658: case GREATER:
0659: return left.getFloat() > right.getFloat();
0660: case GRE_EQU:
0661: return left.getFloat() >= right.getFloat();
0662: case LESSER:
0663: return left.getFloat() < right.getFloat();
0664: case LES_EQU:
0665: return left.getFloat() <= right.getFloat();
0666: case UNEQUALS:
0667: return left.getFloat() != right.getFloat();
0668: case BETWEEN:
0669: float _left = left.getFloat();
0670: return _left >= right.getFloat()
0671: && right2.getFloat() >= _left;
0672: default:
0673: return getFloat() != 0;
0674: }
0675: case SQLTokenizer.FLOAT:
0676: case SQLTokenizer.DOUBLE:
0677: switch (operation) {
0678: case IN:
0679: case EQUALS_NULL:
0680: case EQUALS:
0681: return left.getDouble() == right.getDouble();
0682: case GREATER:
0683: return left.getDouble() > right.getDouble();
0684: case GRE_EQU:
0685: return left.getDouble() >= right.getDouble();
0686: case LESSER:
0687: return left.getDouble() < right.getDouble();
0688: case LES_EQU:
0689: return left.getDouble() <= right.getDouble();
0690: case UNEQUALS:
0691: return left.getDouble() != right.getDouble();
0692: case BETWEEN:
0693: double _left = left.getDouble();
0694: return _left >= right.getDouble()
0695: && right2.getDouble() >= _left;
0696: default:
0697: return getDouble() != 0;
0698: }
0699: case SQLTokenizer.MONEY:
0700: case SQLTokenizer.SMALLMONEY:
0701: switch (operation) {
0702: case IN:
0703: case EQUALS_NULL:
0704: case EQUALS:
0705: return left.getMoney() == right.getMoney();
0706: case GREATER:
0707: return left.getMoney() > right.getMoney();
0708: case GRE_EQU:
0709: return left.getMoney() >= right.getMoney();
0710: case LESSER:
0711: return left.getMoney() < right.getMoney();
0712: case LES_EQU:
0713: return left.getMoney() <= right.getMoney();
0714: case UNEQUALS:
0715: return left.getMoney() != right.getMoney();
0716: case BETWEEN:
0717: long _left = left.getMoney();
0718: return _left >= right.getMoney()
0719: && right2.getMoney() >= _left;
0720: default:
0721: return getMoney() != 0;
0722: }
0723: case SQLTokenizer.DECIMAL:
0724: case SQLTokenizer.NUMERIC: {
0725: if (operation == NEGATIVE)
0726: return left.getNumeric().getSignum() != 0;
0727: int comp = left.getNumeric().compareTo(right.getNumeric());
0728: switch (operation) {
0729: case IN:
0730: case EQUALS_NULL:
0731: case EQUALS:
0732: return comp == 0;
0733: case GREATER:
0734: return comp > 0;
0735: case GRE_EQU:
0736: return comp >= 0;
0737: case LESSER:
0738: return comp < 0;
0739: case LES_EQU:
0740: return comp <= 0;
0741: case UNEQUALS:
0742: return comp != 0;
0743: case BETWEEN:
0744: return comp >= 0
0745: && 0 >= left.getNumeric().compareTo(
0746: right2.getNumeric());
0747: default:
0748: return getNumeric().getSignum() != 0;
0749: }
0750: }
0751: case SQLTokenizer.VARCHAR:
0752: case SQLTokenizer.NVARCHAR:
0753: case SQLTokenizer.CHAR:
0754: case SQLTokenizer.NCHAR:
0755: case SQLTokenizer.LONGVARCHAR:
0756: case SQLTokenizer.LONGNVARCHAR:
0757: case SQLTokenizer.CLOB: {
0758: final String leftStr = left.getString();
0759: final String rightStr = right.getString();
0760: int comp = String.CASE_INSENSITIVE_ORDER.compare(leftStr,
0761: rightStr);
0762: switch (operation) {
0763: case IN:
0764: case EQUALS_NULL:
0765: case EQUALS:
0766: return comp == 0;
0767: case GREATER:
0768: return comp > 0;
0769: case GRE_EQU:
0770: return comp >= 0;
0771: case LESSER:
0772: return comp < 0;
0773: case LES_EQU:
0774: return comp <= 0;
0775: case UNEQUALS:
0776: return comp != 0;
0777: case BETWEEN:
0778: return comp >= 0
0779: && 0 >= String.CASE_INSENSITIVE_ORDER.compare(
0780: leftStr, right2.getString());
0781: case ADD:
0782: return Utils.string2boolean(leftStr + rightStr);
0783: }
0784: break;
0785: }
0786: case SQLTokenizer.BINARY:
0787: case SQLTokenizer.VARBINARY:
0788: case SQLTokenizer.LONGVARBINARY:
0789: case SQLTokenizer.BLOB:
0790: case SQLTokenizer.UNIQUEIDENTIFIER: {
0791: byte[] leftBytes = left.getBytes();
0792: byte[] rightBytes = right.getBytes();
0793: int comp = Utils.compareBytes(leftBytes, rightBytes);
0794: switch (operation) {
0795: case IN:
0796: case EQUALS_NULL:
0797: case EQUALS:
0798: return comp == 0;
0799: case GREATER:
0800: return comp > 0;
0801: case GRE_EQU:
0802: return comp >= 0;
0803: case LESSER:
0804: return comp < 0;
0805: case LES_EQU:
0806: return comp <= 0;
0807: case UNEQUALS:
0808: return comp != 0;
0809: case BETWEEN:
0810: return comp >= 0
0811: && 0 >= Utils.compareBytes(leftBytes, right2
0812: .getBytes());
0813: }
0814: break;
0815: }
0816: }
0817: throw createUnspportedDataType();
0818: }
0819:
0820: String getString() throws java.lang.Exception {
0821: if (isNull())
0822: return null;
0823: return getObject().toString();
0824: }
0825:
0826: final private String getString(String lVal, String rVal)
0827: throws java.lang.Exception {
0828: switch (operation) {
0829: case ADD:
0830: return lVal + rVal;
0831: }
0832: throw createUnspportedConversion(SQLTokenizer.VARCHAR);
0833: }
0834:
0835: int getDataType() {
0836: switch (operation) {
0837: case NEGATIVE:
0838: case BIT_NOT:
0839: return left.getDataType();
0840: case EQUALS:
0841: case EQUALS_NULL:
0842: case GREATER:
0843: case GRE_EQU:
0844: case LESSER:
0845: case LES_EQU:
0846: case UNEQUALS:
0847: case BETWEEN:
0848: case OR:
0849: case AND:
0850: case NOT:
0851: case LIKE:
0852: case ISNULL:
0853: case ISNOTNULL:
0854: return SQLTokenizer.BOOLEAN;
0855: default:
0856: return getDataType(left, right);
0857: }
0858: }
0859:
0860: int getScale() {
0861: int dataType = getDataType();
0862: switch (dataType) {
0863: case SQLTokenizer.DECIMAL:
0864: case SQLTokenizer.NUMERIC:
0865: switch (operation) {
0866: case ADD:
0867: case SUB:
0868: return Math.max(left.getScale(), right.getScale());
0869: case MUL:
0870: return left.getScale() + right.getScale();
0871: case DIV:
0872: return Math.max(left.getScale() + 5,
0873: right.getScale() + 4);
0874: case NEGATIVE:
0875: return left.getScale();
0876: case MOD:
0877: return 0;
0878: }
0879: }
0880: return getScale(dataType);
0881: }
0882:
0883: boolean isNull() throws Exception {
0884: switch (operation) {
0885: case OR:
0886: case AND:
0887: case NOT:
0888: case LIKE:
0889: case ISNULL:
0890: case ISNOTNULL:
0891: case IN:
0892: return false; //Boolean operations return ever a result ???, but at least ISNULL and ISNOTNULL
0893: case NEGATIVE:
0894: case BIT_NOT:
0895: return left.isNull();
0896: default:
0897: return left.isNull() || right.isNull();
0898: }
0899: }
0900:
0901: byte[] getBytes() throws java.lang.Exception {
0902: throw createUnspportedConversion(SQLTokenizer.BINARY);
0903: }
0904:
0905: boolean isInList() throws Exception {
0906: if (left.isNull())
0907: return false;
0908: try {
0909: for (int i = 0; i < inList.length; i++) {
0910: right = inList[i];
0911: if (getBoolean())
0912: return true;
0913: }
0914: } finally {
0915: right = null;
0916: }
0917: return false;
0918: }
0919:
0920: SQLException createUnspportedDataType() {
0921: Object[] params = {
0922: SQLTokenizer.getKeyWord(getDataType(left, right)),
0923: getKeywordFromOperation(operation) };
0924: return SmallSQLException.create(
0925: Language.UNSUPPORTED_DATATYPE_OPER, params);
0926: }
0927:
0928: SQLException createUnspportedConversion(int dataType) {
0929: int type = left == null ? right.getDataType() : getDataType(
0930: left, right);
0931: Object[] params = new Object[] {
0932: SQLTokenizer.getKeyWord(dataType),
0933: SQLTokenizer.getKeyWord(type),
0934: getKeywordFromOperation(operation) };
0935: return SmallSQLException.create(
0936: Language.UNSUPPORTED_CONVERSION_OPER, params);
0937: }
0938:
0939: void optimize() throws SQLException {
0940: super .optimize();
0941: Expression[] params = getParams();
0942: if (params.length == 1) {
0943: return;
0944: }
0945: setParamAt(convertExpressionIfNeeded(params[0], params[1]), 0);
0946:
0947: for (int p = 1; p < params.length; p++) {
0948: setParamAt(convertExpressionIfNeeded(params[p], left), p);
0949: }
0950: }
0951:
0952: /**
0953: * This method only for creating an error message. Thats there is no optimizing.
0954: * @param value
0955: * @return
0956: */
0957: private static String getKeywordFromOperation(int operation) {
0958: int token = 0;
0959: for (int i = 1; i < 1000; i++) {
0960: if (getOperationFromToken(i) == operation) {
0961: token = i;
0962: break;
0963: }
0964: }
0965: if (operation == NEGATIVE)
0966: token = SQLTokenizer.MINUS;
0967: if (operation == ISNOTNULL)
0968: token = SQLTokenizer.IS;
0969: String keyword = SQLTokenizer.getKeyWord(token);
0970: if (keyword == null)
0971: keyword = "" + (char) token;
0972: return keyword;
0973: }
0974:
0975: static int getOperationFromToken(int value) {
0976: switch (value) {
0977: case SQLTokenizer.PLUS:
0978: return ADD;
0979: case SQLTokenizer.MINUS:
0980: return SUB;
0981: case SQLTokenizer.ASTERISK:
0982: return MUL;
0983: case SQLTokenizer.SLACH:
0984: return DIV;
0985: case SQLTokenizer.PERCENT:
0986: return MOD;
0987: case SQLTokenizer.EQUALS:
0988: return EQUALS;
0989: case SQLTokenizer.GREATER:
0990: return GREATER;
0991: case SQLTokenizer.GREATER_EQU:
0992: return GRE_EQU;
0993: case SQLTokenizer.LESSER:
0994: return LESSER;
0995: case SQLTokenizer.LESSER_EQU:
0996: return LES_EQU;
0997: case SQLTokenizer.UNEQUALS:
0998: return UNEQUALS;
0999: case SQLTokenizer.BETWEEN:
1000: return BETWEEN;
1001: case SQLTokenizer.LIKE:
1002: return LIKE;
1003: case SQLTokenizer.IN:
1004: return IN;
1005: case SQLTokenizer.IS:
1006: return ISNULL;
1007: case SQLTokenizer.OR:
1008: return OR;
1009: case SQLTokenizer.AND:
1010: return AND;
1011: case SQLTokenizer.NOT:
1012: return NOT;
1013: case SQLTokenizer.BIT_OR:
1014: return BIT_OR;
1015: case SQLTokenizer.BIT_AND:
1016: return BIT_AND;
1017: case SQLTokenizer.BIT_XOR:
1018: return BIT_XOR;
1019: case SQLTokenizer.TILDE:
1020: return BIT_NOT;
1021: default:
1022: return 0;
1023: }
1024: }
1025:
1026: /**
1027: * Returns the higher level data type from 2 expressions.
1028: */
1029: static int getDataType(Expression left, Expression right) {
1030: int typeLeft = left.getDataType();
1031: int typeRight = right.getDataType();
1032: return getDataType(typeLeft, typeRight);
1033: }
1034:
1035: /**
1036: * Return the best data type for a complex number operation. This method return only
1037: * SQLTokenizer.INT,
1038: * SQLTokenizer.BIGINT,
1039: * SQLTokenizer.MONEY,
1040: * SQLTokenizer.DECIMAL or
1041: * SQLTokenizer.DOUBLE.
1042: * @param paramDataType
1043: */
1044: static int getBestNumberDataType(int paramDataType) {
1045: int dataTypeIdx = Utils.indexOf(paramDataType, DatatypeRange);
1046: if (dataTypeIdx >= NVARCHAR_IDX)
1047: return SQLTokenizer.DOUBLE;
1048: if (dataTypeIdx >= INT_IDX)
1049: return SQLTokenizer.INT;
1050: if (dataTypeIdx >= BIGINT_IDX)
1051: return SQLTokenizer.BIGINT;
1052: if (dataTypeIdx >= MONEY_IDX)
1053: return SQLTokenizer.MONEY;
1054: if (dataTypeIdx >= DECIMAL_IDX)
1055: return SQLTokenizer.DECIMAL;
1056: return SQLTokenizer.DOUBLE;
1057: }
1058:
1059: /**
1060: * Returns the higher level data type from 2 data types.
1061: */
1062: static int getDataType(int typeLeft, int typeRight) {
1063: if (typeLeft == typeRight)
1064: return typeLeft;
1065:
1066: int dataTypeIdx = Math
1067: .min(Utils.indexOf(typeLeft, DatatypeRange), Utils
1068: .indexOf(typeRight, DatatypeRange));
1069: if (dataTypeIdx < 0)
1070: throw new Error("getDataType(): " + typeLeft + ", "
1071: + typeRight);
1072: return DatatypeRange[dataTypeIdx];
1073: }
1074:
1075: // value decade is the operation order
1076: static final int OR = 11; // OR
1077: static final int AND = 21; // AND
1078: static final int NOT = 31; // NOT
1079: static final int BIT_OR = 41; // |
1080: static final int BIT_AND = 42; // &
1081: static final int BIT_XOR = 43; // ^
1082: static final int EQUALS = 51; // =
1083: static final int EQUALS_NULL = 52; // like Equals but (null = null) --> true
1084: static final int GREATER = 53; // >
1085: static final int GRE_EQU = 54; // >=
1086: static final int LESSER = 55; // <
1087: static final int LES_EQU = 56; // <=
1088: static final int UNEQUALS = 57; // <>
1089: static final int IN = 61; // IN
1090: static final int BETWEEN = 62; // BETWEEN
1091: static final int LIKE = 63; // LIKE
1092: static final int ISNULL = 64; // IS NULL
1093: static final int ISNOTNULL = ISNULL + 1; // IS NOT NULL
1094: static final int ADD = 71; // +
1095: static final int SUB = 72; // -
1096: static final int MUL = 81; // *
1097: static final int DIV = 82; // /
1098: static final int MOD = 83; // %
1099: static final int BIT_NOT = 91; // ~
1100: static final int NEGATIVE = 101; // -
1101:
1102: private static final int[] DatatypeRange = {
1103: SQLTokenizer.TIMESTAMP, SQLTokenizer.SMALLDATETIME,
1104: SQLTokenizer.DATE, SQLTokenizer.TIME, SQLTokenizer.DOUBLE,
1105: SQLTokenizer.FLOAT, SQLTokenizer.REAL,
1106: SQLTokenizer.DECIMAL, SQLTokenizer.NUMERIC,
1107: SQLTokenizer.MONEY, SQLTokenizer.SMALLMONEY,
1108: SQLTokenizer.BIGINT, SQLTokenizer.INT,
1109: SQLTokenizer.SMALLINT, SQLTokenizer.TINYINT,
1110: SQLTokenizer.BIT, SQLTokenizer.BOOLEAN,
1111: SQLTokenizer.LONGNVARCHAR, SQLTokenizer.UNIQUEIDENTIFIER,
1112: SQLTokenizer.NVARCHAR, SQLTokenizer.NCHAR,
1113: SQLTokenizer.VARCHAR, SQLTokenizer.CHAR,
1114: SQLTokenizer.LONGVARCHAR, SQLTokenizer.CLOB,
1115: SQLTokenizer.VARBINARY, SQLTokenizer.BINARY,
1116: SQLTokenizer.LONGVARBINARY, SQLTokenizer.BLOB,
1117: SQLTokenizer.NULL };
1118:
1119: private static int NVARCHAR_IDX = Utils.indexOf(
1120: SQLTokenizer.NVARCHAR, DatatypeRange);
1121: private static int INT_IDX = Utils.indexOf(SQLTokenizer.INT,
1122: DatatypeRange);
1123: private static int BIGINT_IDX = Utils.indexOf(SQLTokenizer.BIGINT,
1124: DatatypeRange);
1125: private static int MONEY_IDX = Utils.indexOf(SQLTokenizer.MONEY,
1126: DatatypeRange);
1127: private static int DECIMAL_IDX = Utils.indexOf(
1128: SQLTokenizer.DECIMAL, DatatypeRange);
1129: }
|