1 | /* ============================================================= |
2 | * SmallSQL : a free Java DBMS library for the Java(tm) platform |
3 | * ============================================================= |
4 | * |
5 | * (C) Copyright 2004-2006, by Volker Berlin. |
6 | * |
7 | * Project Info: http://www.smallsql.de/ |
8 | * |
9 | * This library is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU Lesser General Public License as published by |
11 | * the Free Software Foundation; either version 2.1 of the License, or |
12 | * (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
17 | * License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Lesser General Public |
20 | * License along with this library; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
22 | * USA. |
23 | * |
24 | * [Java is a trademark or registered trademark of Sun Microsystems, Inc. |
25 | * in the United States and other countries.] |
26 | * |
27 | * --------------- |
28 | * ExpressionArithmethic.java |
29 | * --------------- |
30 | * Author: Volker Berlin |
31 | * |
32 | */ |
33 | package smallsql.database; |
34 | |
35 | import java.sql.*; |
36 | |
37 | |
38 | public class ExpressionArithmetic extends Expression { |
39 | |
40 | private Expression left; |
41 | private Expression right; |
42 | private Expression right2; |
43 | private Expression[] inList; |
44 | final private int operation; |
45 | |
46 | /** |
47 | * Constructor for NOT, NEGATIVE, BIT_NOT, ISNULL and ISNOTNULL |
48 | */ |
49 | ExpressionArithmetic( Expression right, int operation){ |
50 | super(FUNCTION); |
51 | this.right = right; |
52 | this.operation = operation; |
53 | super.setParams( new Expression[]{ right }); |
54 | } |
55 | |
56 | ExpressionArithmetic( Expression left, Expression right, int operation){ |
57 | super(FUNCTION); |
58 | this.left = left; |
59 | this.right = right; |
60 | this.operation = operation; |
61 | super.setParams( new Expression[]{ left, right }); |
62 | } |
63 | |
64 | /** |
65 | * Constructor for BETWEEN |
66 | */ |
67 | ExpressionArithmetic( Expression left, Expression right, Expression right2, int operation){ |
68 | super(FUNCTION); |
69 | this.left = left; |
70 | this.right = right; |
71 | this.right2 = right2; |
72 | this.operation = operation; |
73 | super.setParams( new Expression[]{ left, right, right2 }); |
74 | } |
75 | |
76 | /** |
77 | * Constructor for IN |
78 | */ |
79 | ExpressionArithmetic( Expression left, Expressions inList, int operation){ |
80 | super(FUNCTION); |
81 | this.left = left; |
82 | this.operation = operation; |
83 | Expression[] params; |
84 | if(inList != null){ |
85 | this.inList = inList.toArray(); |
86 | params = new Expression[this.inList.length+1]; |
87 | params[0] = left; |
88 | System.arraycopy(this.inList, 0, params, 1, this.inList.length); |
89 | }else{ |
90 | params = new Expression[]{ left }; |
91 | } |
92 | super.setParams( params ); |
93 | } |
94 | |
95 | |
96 | final void setParamAt( Expression param, int idx){ |
97 | switch(idx){ |
98 | case 0: |
99 | left = param; |
100 | break; |
101 | case 1: |
102 | right = param; |
103 | break; |
104 | case 2: |
105 | right2 = param; |
106 | break; |
107 | } |
108 | if(inList != null && idx>0 && idx<=inList.length){ |
109 | inList[idx+1] = param; |
110 | } |
111 | super.setParamAt( param, idx ); |
112 | } |
113 | |
114 | |
115 | /** |
116 | * Is used in GroupResult. |
117 | */ |
118 | public boolean equals(Object expr){ |
119 | if(!super.equals(expr)) return false; |
120 | if(!(expr instanceof ExpressionArithmetic)) return false; |
121 | if( ((ExpressionArithmetic)expr).operation != operation) return false; |
122 | return true; |
123 | } |
124 | |
125 | |
126 | |
127 | int getInt() throws java.lang.Exception { |
128 | if(isNull()) return 0; |
129 | int dataType = getDataType(); |
130 | switch(dataType){ |
131 | case SQLTokenizer.BIT: |
132 | case SQLTokenizer.BOOLEAN: |
133 | return getBoolean() ? 1 : 0; |
134 | case SQLTokenizer.TINYINT: |
135 | case SQLTokenizer.SMALLINT: |
136 | case SQLTokenizer.INT: |
137 | return getIntImpl(); |
138 | case SQLTokenizer.BIGINT: |
139 | return (int)getLongImpl(); |
140 | case SQLTokenizer.REAL: |
141 | return (int)getFloatImpl(); |
142 | case SQLTokenizer.FLOAT: |
143 | case SQLTokenizer.DOUBLE: |
144 | case SQLTokenizer.MONEY: |
145 | case SQLTokenizer.SMALLMONEY: |
146 | case SQLTokenizer.NUMERIC: |
147 | case SQLTokenizer.DECIMAL: |
148 | return (int)getDoubleImpl(); |
149 | } |
150 | throw createUnspportedConversion( SQLTokenizer.INT); |
151 | } |
152 | |
153 | |
154 | private int getIntImpl() throws java.lang.Exception { |
155 | switch(operation){ |
156 | case ADD: return left.getInt() + right.getInt(); |
157 | case SUB: return left.getInt() - right.getInt(); |
158 | case MUL: return left.getInt() * right.getInt(); |
159 | case DIV: return left.getInt() / right.getInt(); |
160 | case NEGATIVE: return - right.getInt(); |
161 | case MOD: return left.getInt() % right.getInt(); |
162 | case BIT_NOT: return ~ right.getInt(); |
163 | } |
164 | throw createUnspportedConversion( SQLTokenizer.INT); |
165 | } |
166 | |
167 | |
168 | long getLong() throws java.lang.Exception { |
169 | if(isNull()) return 0; |
170 | int dataType = getDataType(); |
171 | switch(dataType){ |
172 | case SQLTokenizer.BIT: |
173 | case SQLTokenizer.BOOLEAN: |
174 | return getBoolean() ? 1 : 0; |
175 | case SQLTokenizer.TINYINT: |
176 | case SQLTokenizer.SMALLINT: |
177 | case SQLTokenizer.INT: |
178 | return getIntImpl(); |
179 | case SQLTokenizer.BIGINT: |
180 | return getLongImpl(); |
181 | case SQLTokenizer.REAL: |
182 | return (long)getFloatImpl(); |
183 | case SQLTokenizer.FLOAT: |
184 | case SQLTokenizer.DOUBLE: |
185 | case SQLTokenizer.MONEY: |
186 | case SQLTokenizer.SMALLMONEY: |
187 | case SQLTokenizer.NUMERIC: |
188 | case SQLTokenizer.DECIMAL: |
189 | return (long)getDoubleImpl(); |
190 | } |
191 | throw createUnspportedConversion( SQLTokenizer.LONG); |
192 | } |
193 | |
194 | |
195 | private long getLongImpl() throws java.lang.Exception { |
196 | if(isNull()) return 0; |
197 | switch(operation){ |
198 | case ADD: return left.getLong() + right.getLong(); |
199 | case SUB: return left.getLong() - right.getLong(); |
200 | case MUL: return left.getLong() * right.getLong(); |
201 | case DIV: return left.getLong() / right.getLong(); |
202 | case NEGATIVE: return - right.getLong(); |
203 | case MOD: return left.getLong() % right.getLong(); |
204 | case BIT_NOT: return ~ right.getInt(); |
205 | } |
206 | throw createUnspportedConversion( SQLTokenizer.LONG); |
207 | } |
208 | |
209 | |
210 | double getDouble() throws java.lang.Exception { |
211 | if(isNull()) return 0; |
212 | int dataType = getDataType(); |
213 | switch(dataType){ |
214 | case SQLTokenizer.BIT: |
215 | case SQLTokenizer.BOOLEAN: |
216 | return getBoolean() ? 1 : 0; |
217 | case SQLTokenizer.TINYINT: |
218 | case SQLTokenizer.SMALLINT: |
219 | case SQLTokenizer.INT: |
220 | return getIntImpl(); |
221 | case SQLTokenizer.BIGINT: |
222 | return getLongImpl(); |
223 | case SQLTokenizer.REAL: |
224 | return getFloatImpl(); |
225 | case SQLTokenizer.FLOAT: |
226 | case SQLTokenizer.DOUBLE: |
227 | case SQLTokenizer.MONEY: |
228 | case SQLTokenizer.SMALLMONEY: |
229 | case SQLTokenizer.NUMERIC: |
230 | case SQLTokenizer.DECIMAL: |
231 | return getDoubleImpl(); |
232 | } |
233 | throw createUnspportedConversion( SQLTokenizer.DOUBLE); |
234 | } |
235 | |
236 | |
237 | private double getDoubleImpl() throws java.lang.Exception{ |
238 | if(operation == NEGATIVE) |
239 | return getDoubleImpl(0, right.getDouble()); |
240 | return getDoubleImpl(left.getDouble(), right.getDouble()); |
241 | } |
242 | |
243 | |
244 | private double getDoubleImpl( double lVal, double rVal) throws java.lang.Exception{ |
245 | switch(operation){ |
246 | case ADD: return lVal + rVal; |
247 | case SUB: return lVal - rVal; |
248 | case MUL: return lVal * rVal; |
249 | case DIV: return lVal / rVal; |
250 | case NEGATIVE: return - rVal; |
251 | case MOD: return lVal % rVal; |
252 | } |
253 | throw createUnspportedConversion( SQLTokenizer.DOUBLE); |
254 | } |
255 | |
256 | |
257 | float getFloat() throws java.lang.Exception { |
258 | if(isNull()) return 0; |
259 | int dataType = getDataType(); |
260 | switch(dataType){ |
261 | case SQLTokenizer.BIT: |
262 | case SQLTokenizer.BOOLEAN: |
263 | return getBoolean() ? 1 : 0; |
264 | case SQLTokenizer.TINYINT: |
265 | case SQLTokenizer.SMALLINT: |
266 | case SQLTokenizer.INT: |
267 | return getIntImpl(); |
268 | case SQLTokenizer.BIGINT: |
269 | return getLongImpl(); |
270 | case SQLTokenizer.REAL: |
271 | return getFloatImpl(); |
272 | case SQLTokenizer.FLOAT: |
273 | case SQLTokenizer.DOUBLE: |
274 | case SQLTokenizer.MONEY: |
275 | case SQLTokenizer.SMALLMONEY: |
276 | case SQLTokenizer.NUMERIC: |
277 | case SQLTokenizer.DECIMAL: |
278 | return (float)getDoubleImpl(); |
279 | } |
280 | throw createUnspportedConversion( SQLTokenizer.DOUBLE); |
281 | } |
282 | |
283 | |
284 | private float getFloatImpl() throws java.lang.Exception { |
285 | switch(operation){ |
286 | case ADD: return left.getFloat() + right.getFloat(); |
287 | case SUB: return left.getFloat() - right.getFloat(); |
288 | case MUL: return left.getFloat() * right.getFloat(); |
289 | case DIV: return left.getFloat() / right.getFloat(); |
290 | case NEGATIVE: return - right.getFloat(); |
291 | case MOD: return left.getFloat() % right.getFloat(); |
292 | } |
293 | throw createUnspportedConversion( SQLTokenizer.REAL ); |
294 | } |
295 | |
296 | |
297 | long getMoney() throws java.lang.Exception { |
298 | if(isNull()) return 0; |
299 | int dataType = getDataType(); |
300 | switch(dataType){ |
301 | case SQLTokenizer.BIT: |
302 | case SQLTokenizer.BOOLEAN: |
303 | return getBoolean() ? 10000 : 0; |
304 | case SQLTokenizer.TINYINT: |
305 | case SQLTokenizer.SMALLINT: |
306 | case SQLTokenizer.INT: |
307 | return getIntImpl() * 10000; |
308 | case SQLTokenizer.BIGINT: |
309 | return getLongImpl() * 10000; |
310 | case SQLTokenizer.REAL: |
311 | return Utils.doubleToMoney( getFloatImpl() ); |
312 | case SQLTokenizer.FLOAT: |
313 | case SQLTokenizer.DOUBLE: |
314 | case SQLTokenizer.NUMERIC: |
315 | case SQLTokenizer.DECIMAL: |
316 | return Utils.doubleToMoney( getDoubleImpl() ); |
317 | case SQLTokenizer.MONEY: |
318 | case SQLTokenizer.SMALLMONEY: |
319 | return getMoneyImpl(); |
320 | } |
321 | throw createUnspportedConversion( SQLTokenizer.DOUBLE); |
322 | } |
323 | |
324 | |
325 | private long getMoneyImpl() throws java.lang.Exception { |
326 | switch(operation){ |
327 | case ADD: return left.getMoney() + right.getMoney(); |
328 | case SUB: return left.getMoney() - right.getMoney(); |
329 | case MUL: return left.getMoney() * right.getMoney() / 10000; |
330 | case DIV: return left.getMoney() * 10000 / right.getMoney(); |
331 | case NEGATIVE: return - right.getMoney(); |
332 | } |
333 | throw createUnspportedConversion( SQLTokenizer.MONEY ); |
334 | } |
335 | |
336 | |
337 | MutableNumeric getNumeric() throws java.lang.Exception { |
338 | if(isNull()) return null; |
339 | int dataType = getDataType(); |
340 | switch(dataType){ |
341 | case SQLTokenizer.BIT: |
342 | case SQLTokenizer.BOOLEAN: |
343 | return new MutableNumeric(getBoolean() ? 1 : 0); |
344 | case SQLTokenizer.TINYINT: |
345 | case SQLTokenizer.SMALLINT: |
346 | case SQLTokenizer.INT: |
347 | return new MutableNumeric(getIntImpl()); |
348 | case SQLTokenizer.BIGINT: |
349 | return new MutableNumeric(getLongImpl()); |
350 | case SQLTokenizer.REAL: |
351 | return new MutableNumeric(getFloatImpl()); |
352 | case SQLTokenizer.FLOAT: |
353 | case SQLTokenizer.DOUBLE: |
354 | return new MutableNumeric( getDoubleImpl() ); |
355 | case SQLTokenizer.NUMERIC: |
356 | case SQLTokenizer.DECIMAL: |
357 | return getNumericImpl(); |
358 | case SQLTokenizer.MONEY: |
359 | case SQLTokenizer.SMALLMONEY: |
360 | return new MutableNumeric(getMoneyImpl(),4); |
361 | } |
362 | throw createUnspportedConversion( SQLTokenizer.DOUBLE); |
363 | } |
364 | |
365 | |
366 | private MutableNumeric getNumericImpl() throws java.lang.Exception { |
367 | switch(operation){ |
368 | case ADD: |
369 | { |
370 | MutableNumeric num = left.getNumeric(); |
371 | num.add( right.getNumeric() ); |
372 | return num; |
373 | } |
374 | case SUB: |
375 | { |
376 | MutableNumeric num = left.getNumeric(); |
377 | num.sub( right.getNumeric() ); |
378 | return num; |
379 | } |
380 | case MUL: |
381 | if(getDataType(right.getDataType(), SQLTokenizer.INT) == SQLTokenizer.INT){ |
382 | MutableNumeric num = left.getNumeric(); |
383 | num.mul(right.getInt()); |
384 | return num; |
385 | }else |
386 | if(getDataType(left.getDataType(), SQLTokenizer.INT) == SQLTokenizer.INT){ |
387 | MutableNumeric num = right.getNumeric(); |
388 | num.mul(left.getInt()); |
389 | return num; |
390 | }else{ |
391 | MutableNumeric num = left.getNumeric(); |
392 | num.mul( right.getNumeric() ); |
393 | return num; |
394 | } |
395 | case DIV: |
396 | { |
397 | MutableNumeric num = left.getNumeric(); |
398 | if(getDataType(right.getDataType(), SQLTokenizer.INT) == SQLTokenizer.INT) |
399 | num.div( right.getInt() ); |
400 | else |
401 | num.div( right.getNumeric() ); |
402 | return num; |
403 | } |
404 | case NEGATIVE: |
405 | { |
406 | MutableNumeric num = right.getNumeric(); |
407 | num.signum = -num.signum; |
408 | return num; |
409 | } |
410 | case MOD: |
411 | { |
412 | if(getDataType(getDataType(), SQLTokenizer.INT) == SQLTokenizer.INT) |
413 | return new MutableNumeric(getInt()); |
414 | MutableNumeric num = left.getNumeric(); |
415 | num.mod( right.getNumeric() ); |
416 | return num; |
417 | } |
418 | default: throw createUnspportedConversion( SQLTokenizer.NUMERIC ); |
419 | } |
420 | } |
421 | |
422 | |
423 | Object getObject() throws java.lang.Exception { |
424 | if(isNull()) return null; |
425 | int dataType = getDataType(); |
426 | switch(dataType){ |
427 | case SQLTokenizer.BIT: |
428 | case SQLTokenizer.BOOLEAN: |
429 | return getBoolean() ? Boolean.TRUE : Boolean.FALSE; |
430 | case SQLTokenizer.BINARY: |
431 | case SQLTokenizer.VARBINARY: |
432 | return getBytes(); |
433 | case SQLTokenizer.TINYINT: |
434 | case SQLTokenizer.SMALLINT: |
435 | case SQLTokenizer.INT: |
436 | return new Integer( getInt() ); |
437 | case SQLTokenizer.BIGINT: |
438 | return new Long( getLong() ); |
439 | case SQLTokenizer.REAL: |
440 | return new Float( getFloat() ); |
441 | case SQLTokenizer.FLOAT: |
442 | case SQLTokenizer.DOUBLE: |
443 | return new Double( getDouble() ); |
444 | case SQLTokenizer.MONEY: |
445 | case SQLTokenizer.SMALLMONEY: |
446 | return Money.createFromUnscaledValue( getMoney() ); |
447 | case SQLTokenizer.NUMERIC: |
448 | case SQLTokenizer.DECIMAL: |
449 | return getNumeric(); |
450 | case SQLTokenizer.CHAR: |
451 | case SQLTokenizer.NCHAR: |
452 | case SQLTokenizer.VARCHAR: |
453 | case SQLTokenizer.NVARCHAR: |
454 | case SQLTokenizer.LONGNVARCHAR: |
455 | case SQLTokenizer.LONGVARCHAR: |
456 | return getString( left.getString(), right.getString() ); |
457 | case SQLTokenizer.JAVA_OBJECT: |
458 | Object lObj = left.getObject(); |
459 | //FIXME NullPointerException bei NEGATIVE |
460 | Object rObj = right.getObject(); |
461 | if(lObj instanceof Number && rObj instanceof Number) |
462 | return new Double( getDoubleImpl( ((Number)lObj).doubleValue(), ((Number)rObj).doubleValue() ) ); |
463 | else |
464 | return getString( lObj.toString(), rObj.toString() ); |
465 | case SQLTokenizer.LONGVARBINARY: |
466 | return getBytes(); |
467 | case SQLTokenizer.DATE: |
468 | case SQLTokenizer.TIME: |
469 | case SQLTokenizer.TIMESTAMP: |
470 | case SQLTokenizer.SMALLDATETIME: |
471 | return new DateTime( getLong(), dataType ); |
472 | case SQLTokenizer.UNIQUEIDENTIFIER: |
473 | return getBytes(); |
474 | default: throw createUnspportedDataType(); |
475 | } |
476 | } |
477 | |
478 | |
479 | boolean getBoolean() throws java.lang.Exception { |
480 | switch(operation){ |
481 | case OR: return left.getBoolean() || right.getBoolean(); |
482 | case AND: return left.getBoolean() && right.getBoolean(); |
483 | case NOT: return !right.getBoolean(); |
484 | case LIKE: return Utils.like( left.getString(), right.getString()); |
485 | case ISNULL:return right.isNull(); |
486 | case ISNOTNULL: return !right.isNull(); |
487 | case IN: if(right == null) |
488 | return isInList(); |
489 | break; |
490 | } |
491 | final boolean rightIsNull = right.isNull(); |
492 | int dataType; |
493 | if(operation == NEGATIVE || operation == BIT_NOT){ |
494 | if(rightIsNull) return false; |
495 | dataType = right.getDataType(); |
496 | }else{ |
497 | final boolean leftIsNull = left.isNull(); |
498 | if(operation == EQUALS_NULL && leftIsNull && rightIsNull) return true; |
499 | if(leftIsNull || rightIsNull) return false; |
500 | dataType = getDataType(left, right); |
501 | } |
502 | switch(dataType){ |
503 | case SQLTokenizer.BOOLEAN: |
504 | switch(operation){ |
505 | case IN: |
506 | case EQUALS_NULL: |
507 | case EQUALS: return left.getBoolean() == right.getBoolean(); |
508 | case UNEQUALS: return left.getBoolean() != right.getBoolean(); |
509 | } |
510 | //break; interpret it as BIT |
511 | case SQLTokenizer.TINYINT: |
512 | case SQLTokenizer.SMALLINT: |
513 | case SQLTokenizer.INT: |
514 | case SQLTokenizer.BIT: |
515 | switch(operation){ |
516 | case IN: |
517 | case EQUALS_NULL: |
518 | case EQUALS: return left.getInt() == right.getInt(); |
519 | case GREATER: return left.getInt() > right.getInt(); |
520 | case GRE_EQU: return left.getInt() >= right.getInt(); |
521 | case LESSER: return left.getInt() < right.getInt(); |
522 | case LES_EQU: return left.getInt() <= right.getInt(); |
523 | case UNEQUALS: return left.getInt() != right.getInt(); |
524 | case BETWEEN: |
525 | int _left = left.getInt(); |
526 | return _left >= right.getInt() && right2.getInt() >= _left; |
527 | default: |
528 | return getInt() != 0; |
529 | } |
530 | case SQLTokenizer.BIGINT: |
531 | case SQLTokenizer.TIMESTAMP: |
532 | case SQLTokenizer.TIME: |
533 | case SQLTokenizer.DATE: |
534 | case SQLTokenizer.SMALLDATETIME: |
535 | switch(operation){ |
536 | case IN: |
537 | case EQUALS_NULL: |
538 | case EQUALS: return left.getLong() == right.getLong(); |
539 | case GREATER: return left.getLong() > right.getLong(); |
540 | case GRE_EQU: return left.getLong() >= right.getLong(); |
541 | case LESSER: return left.getLong() < right.getLong(); |
542 | case LES_EQU: return left.getLong() <= right.getLong(); |
543 | case UNEQUALS: return left.getLong() != right.getLong(); |
544 | case BETWEEN: |
545 | long _left = left.getLong(); |
546 | return _left >= right.getLong() && right2.getLong() >= _left; |
547 | default: |
548 | return getLong() != 0; |
549 | } |
550 | case SQLTokenizer.REAL: |
551 | switch(operation){ |
552 | case IN: |
553 | case EQUALS_NULL: |
554 | case EQUALS: return left.getFloat() == right.getFloat(); |
555 | case GREATER: return left.getFloat() > right.getFloat(); |
556 | case GRE_EQU: return left.getFloat() >= right.getFloat(); |
557 | case LESSER: return left.getFloat() < right.getFloat(); |
558 | case LES_EQU: return left.getFloat() <= right.getFloat(); |
559 | case UNEQUALS: return left.getFloat() != right.getFloat(); |
560 | case BETWEEN: |
561 | float _left = left.getFloat(); |
562 | return _left >= right.getFloat() && right2.getFloat() >= _left; |
563 | default: |
564 | return getFloat() != 0; |
565 | } |
566 | case SQLTokenizer.FLOAT: |
567 | case SQLTokenizer.DOUBLE: |
568 | switch(operation){ |
569 | case IN: |
570 | case EQUALS_NULL: |
571 | case EQUALS: return left.getDouble() == right.getDouble(); |
572 | case GREATER: return left.getDouble() > right.getDouble(); |
573 | case GRE_EQU: return left.getDouble() >= right.getDouble(); |
574 | case LESSER: return left.getDouble() < right.getDouble(); |
575 | case LES_EQU: return left.getDouble() <= right.getDouble(); |
576 | case UNEQUALS: return left.getDouble() != right.getDouble(); |
577 | case BETWEEN: |
578 | double _left = left.getDouble(); |
579 | return _left >= right.getDouble() && right2.getDouble() >= _left; |
580 | default: |
581 | return getDouble() != 0; |
582 | } |
583 | case SQLTokenizer.MONEY: |
584 | case SQLTokenizer.SMALLMONEY: |
585 | switch(operation){ |
586 | case IN: |
587 | case EQUALS_NULL: |
588 | case EQUALS: return left.getMoney() == right.getMoney(); |
589 | case GREATER: return left.getMoney() > right.getMoney(); |
590 | case GRE_EQU: return left.getMoney() >= right.getMoney(); |
591 | case LESSER: return left.getMoney() < right.getMoney(); |
592 | case LES_EQU: return left.getMoney() <= right.getMoney(); |
593 | case UNEQUALS: return left.getMoney() != right.getMoney(); |
594 | case BETWEEN: |
595 | long _left = left.getMoney(); |
596 | return _left >= right.getMoney() && right2.getMoney() >= _left; |
597 | default: |
598 | return getMoney() != 0; |
599 | } |
600 | case SQLTokenizer.DECIMAL: |
601 | case SQLTokenizer.NUMERIC:{ |
602 | if(operation == NEGATIVE) |
603 | return right.getNumeric().signum != 0; |
604 | int comp = left.getNumeric().compareTo( right.getNumeric() ); |
605 | switch(operation){ |
606 | case IN: |
607 | case EQUALS_NULL: |
608 | case EQUALS: return comp == 0; |
609 | case GREATER: return comp > 0; |
610 | case GRE_EQU: return comp >= 0; |
611 | case LESSER: return comp < 0; |
612 | case LES_EQU: return comp <= 0; |
613 | case UNEQUALS: return comp != 0; |
614 | case BETWEEN: |
615 | return comp >= 0 && 0 >= left.getNumeric().compareTo( right2.getNumeric() ); |
616 | default: |
617 | return getNumeric().signum != 0; |
618 | } |
619 | } |
620 | case SQLTokenizer.VARCHAR: |
621 | case SQLTokenizer.NVARCHAR: |
622 | case SQLTokenizer.CHAR: |
623 | case SQLTokenizer.NCHAR: |
624 | case SQLTokenizer.LONGVARCHAR: |
625 | case SQLTokenizer.LONGNVARCHAR: |
626 | case SQLTokenizer.CLOB:{ |
627 | int comp = String.CASE_INSENSITIVE_ORDER.compare( left.getString(), right.getString() ); |
628 | switch(operation){ |
629 | case IN: |
630 | case EQUALS_NULL: |
631 | case EQUALS: return comp == 0; |
632 | case GREATER: return comp > 0; |
633 | case GRE_EQU: return comp >= 0; |
634 | case LESSER: return comp < 0; |
635 | case LES_EQU: return comp <= 0; |
636 | case UNEQUALS: return comp != 0; |
637 | case BETWEEN: |
638 | return comp >= 0 && 0 >= String.CASE_INSENSITIVE_ORDER.compare( left.getString(), right2.getString() ); |
639 | case ADD: return Utils.string2boolean(left.getString() + right.getString()); |
640 | } |
641 | break;} |
642 | case SQLTokenizer.BINARY: |
643 | case SQLTokenizer.VARBINARY: |
644 | case SQLTokenizer.LONGVARBINARY: |
645 | case SQLTokenizer.BLOB: |
646 | case SQLTokenizer.UNIQUEIDENTIFIER:{ |
647 | byte[] leftBytes = left.getBytes(); |
648 | byte[] rightBytes= right.getBytes(); |
649 | int comp = Utils.compareBytes( leftBytes, rightBytes); |
650 | switch(operation){ |
651 | case IN: |
652 | case EQUALS_NULL: |
653 | case EQUALS: return comp == 0; |
654 | case GREATER: return comp > 0; |
655 | case GRE_EQU: return comp >= 0; |
656 | case LESSER: return comp < 0; |
657 | case LES_EQU: return comp <= 0; |
658 | case UNEQUALS: return comp != 0; |
659 | case BETWEEN: |
660 | return comp >= 0 && 0 >= Utils.compareBytes( leftBytes, right2.getBytes() ); |
661 | } |
662 | break;} |
663 | } |
664 | throw createUnspportedDataType(); |
665 | } |
666 | |
667 | |
668 | String getString() throws java.lang.Exception { |
669 | if(isNull()) return null; |
670 | return getObject().toString(); |
671 | } |
672 | |
673 | |
674 | final private String getString( String lVal, String rVal ) throws java.lang.Exception { |
675 | switch(operation){ |
676 | case ADD: return lVal + rVal; |
677 | } |
678 | throw createUnspportedConversion( SQLTokenizer.VARCHAR ); |
679 | } |
680 | |
681 | |
682 | int getDataType() { |
683 | switch(operation){ |
684 | case NEGATIVE: |
685 | case BIT_NOT: |
686 | return right.getDataType(); |
687 | case EQUALS: |
688 | case EQUALS_NULL: |
689 | case GREATER: |
690 | case GRE_EQU: |
691 | case LESSER: |
692 | case LES_EQU: |
693 | case UNEQUALS: |
694 | case BETWEEN: |
695 | case OR: |
696 | case AND: |
697 | case NOT: |
698 | case LIKE: |
699 | case ISNULL: |
700 | case ISNOTNULL: |
701 | return SQLTokenizer.BOOLEAN; |
702 | default: |
703 | return getDataType(left, right); |
704 | } |
705 | } |
706 | |
707 | |
708 | int getScale(){ |
709 | int dataType = getDataType(); |
710 | switch(dataType){ |
711 | case SQLTokenizer.DECIMAL: |
712 | case SQLTokenizer.NUMERIC: |
713 | switch(operation){ |
714 | case ADD: |
715 | case SUB: |
716 | return Math.max(left.getScale(), right.getScale()); |
717 | case MUL: |
718 | return left.getScale() + right.getScale(); |
719 | case DIV: |
720 | return Math.max(left.getScale()+5, right.getScale()+4); |
721 | case NEGATIVE: |
722 | return right.getScale(); |
723 | case MOD: |
724 | return 0; |
725 | } |
726 | } |
727 | return getScale(dataType); |
728 | } |
729 | |
730 | |
731 | boolean isNull() throws Exception{ |
732 | switch(operation){ |
733 | case OR: |
734 | case AND: |
735 | case NOT: |
736 | case LIKE: |
737 | case ISNULL: |
738 | case ISNOTNULL: |
739 | case IN: |
740 | return false; //Boolesche Operationen liefern immer ein Ergebniss ???, midestends aber ISNULL und ISNOTNULL |
741 | case NEGATIVE: |
742 | case BIT_NOT: |
743 | return right.isNull(); |
744 | default: return left.isNull() || right.isNull(); |
745 | } |
746 | } |
747 | |
748 | |
749 | byte[] getBytes() throws java.lang.Exception { |
750 | throw createUnspportedConversion( SQLTokenizer.BINARY ); |
751 | } |
752 | |
753 | |
754 | boolean isInList() throws Exception{ |
755 | if(left.isNull()) return false; |
756 | try{ |
757 | for(int i=0; i<inList.length; i++){ |
758 | right = inList[i]; |
759 | if(getBoolean()) return true; |
760 | } |
761 | }finally{ |
762 | right = null; |
763 | } |
764 | return false; |
765 | } |
766 | |
767 | |
768 | SQLException createUnspportedDataType(){ |
769 | return Utils.createSQLException("Unsupported data type '" + |
770 | SQLTokenizer.getKeyWord(getDataType(left, right)) + |
771 | "' for Operation '" + getKeywordFromOperation(operation)+'\''); |
772 | } |
773 | |
774 | |
775 | SQLException createUnspportedConversion( int dataType ){ |
776 | int type = left == null ? right.getDataType() : getDataType(left, right); |
777 | return Utils.createSQLException("Unsupported conversion to data type '" + |
778 | SQLTokenizer.getKeyWord(dataType) + |
779 | "' from data type '" + |
780 | SQLTokenizer.getKeyWord(type) + |
781 | "' for Operation '" + getKeywordFromOperation(operation)+'\''); |
782 | } |
783 | |
784 | |
785 | /** |
786 | * This method only for creating an error message. Thats there is no optimizing. |
787 | * @param value |
788 | * @return |
789 | */ |
790 | private static String getKeywordFromOperation(int operation){ |
791 | int token = 0; |
792 | for(int i=1; i<1000; i++){ |
793 | if(getOperationFromToken(i) == operation){ |
794 | token = i; |
795 | break; |
796 | } |
797 | } |
798 | if(operation == NEGATIVE) token = SQLTokenizer.MINUS; |
799 | if(operation == ISNOTNULL) token = SQLTokenizer.IS; |
800 | String keyword = SQLTokenizer.getKeyWord(token); |
801 | if(keyword == null) keyword = "" + (char)token; |
802 | return keyword; |
803 | } |
804 | |
805 | |
806 | static int getOperationFromToken( int value ){ |
807 | switch(value){ |
808 | case SQLTokenizer.PLUS: return ADD; |
809 | case SQLTokenizer.MINUS: return SUB; |
810 | case SQLTokenizer.ASTERISK: return MUL; |
811 | case SQLTokenizer.SLACH: return DIV; |
812 | case SQLTokenizer.PERCENT: return MOD; |
813 | case SQLTokenizer.EQUALS: return EQUALS; |
814 | case SQLTokenizer.GREATER: return GREATER; |
815 | case SQLTokenizer.GREATER_EQU: return GRE_EQU; |
816 | case SQLTokenizer.LESSER: return LESSER; |
817 | case SQLTokenizer.LESSER_EQU: return LES_EQU; |
818 | case SQLTokenizer.UNEQUALS: return UNEQUALS; |
819 | case SQLTokenizer.BETWEEN: return BETWEEN; |
820 | case SQLTokenizer.LIKE: return LIKE; |
821 | case SQLTokenizer.IN: return IN; |
822 | case SQLTokenizer.IS: return ISNULL; |
823 | case SQLTokenizer.OR: return OR; |
824 | case SQLTokenizer.AND: return AND; |
825 | case SQLTokenizer.NOT: return NOT; |
826 | case SQLTokenizer.BIT_OR: return BIT_OR; |
827 | case SQLTokenizer.BIT_AND: return BIT_AND; |
828 | case SQLTokenizer.BIT_XOR: return BIT_XOR; |
829 | case SQLTokenizer.TILDE: return BIT_NOT; |
830 | default: return 0; |
831 | } |
832 | } |
833 | |
834 | |
835 | /** |
836 | * Returns the higher level data type from 2 expressions. |
837 | */ |
838 | static int getDataType(Expression left, Expression right){ |
839 | int typeLeft = left.getDataType(); |
840 | int typeRight = right.getDataType(); |
841 | return getDataType( typeLeft, typeRight); |
842 | } |
843 | |
844 | |
845 | /** |
846 | * Return the best data type for a complex number operation. This method return only |
847 | * SQLTokenizer.INT, |
848 | * SQLTokenizer.BIGINT, |
849 | * SQLTokenizer.MONEY, |
850 | * SQLTokenizer.DECIMAL or |
851 | * SQLTokenizer.DOUBLE. |
852 | * @param paramDataType |
853 | */ |
854 | static int getBestNumberDataType(int paramDataType){ |
855 | int dataTypeIdx = Utils.indexOf( paramDataType, DatatypeRange); |
856 | if(dataTypeIdx >= NVARCHAR_IDX) |
857 | return SQLTokenizer.DOUBLE; |
858 | if(dataTypeIdx >= INT_IDX) |
859 | return SQLTokenizer.INT; |
860 | if(dataTypeIdx >= BIGINT_IDX) |
861 | return SQLTokenizer.BIGINT; |
862 | if(dataTypeIdx >= MONEY_IDX) |
863 | return SQLTokenizer.MONEY; |
864 | if(dataTypeIdx >= DECIMAL_IDX) |
865 | return SQLTokenizer.DECIMAL; |
866 | return SQLTokenizer.DOUBLE; |
867 | } |
868 | |
869 | /** |
870 | * Returns the higher level data type from 2 data types. |
871 | */ |
872 | static int getDataType(int typeLeft, int typeRight){ |
873 | if(typeLeft == typeRight) return typeLeft; |
874 | |
875 | int dataTypeIdx = Math.min( Utils.indexOf( typeLeft, DatatypeRange), Utils.indexOf( typeRight, DatatypeRange) ); |
876 | if(dataTypeIdx < 0) throw new Error("getDataType(): "+typeLeft+", "+typeRight); |
877 | return DatatypeRange[ dataTypeIdx ]; |
878 | } |
879 | |
880 | |
881 | // value decade is the operation order |
882 | static final int OR = 11; // OR |
883 | static final int AND = 21; // AND |
884 | static final int NOT = 31; // NOT |
885 | static final int BIT_OR = 41; // | |
886 | static final int BIT_AND = 42; // & |
887 | static final int BIT_XOR = 43; // ^ |
888 | static final int EQUALS = 51; // = |
889 | static final int EQUALS_NULL= 52; // like Equals but (null = null) --> true |
890 | static final int GREATER = 53; // > |
891 | static final int GRE_EQU = 54; // >= |
892 | static final int LESSER = 55; // < |
893 | static final int LES_EQU = 56; // <= |
894 | static final int UNEQUALS = 57; // <> |
895 | static final int IN = 61; // IN |
896 | static final int BETWEEN = 62; // BETWEEN |
897 | static final int LIKE = 63; // LIKE |
898 | static final int ISNULL = 64; // IS NULL |
899 | static final int ISNOTNULL = ISNULL+1; // IS NOT NULL |
900 | static final int ADD = 71; // + |
901 | static final int SUB = 72; // - |
902 | static final int MUL = 81; // * |
903 | static final int DIV = 82; // / |
904 | static final int MOD = 83; // % |
905 | static final int BIT_NOT = 91; // ~ |
906 | static final int NEGATIVE =101; // - |
907 | |
908 | private static final int[] DatatypeRange = { |
909 | SQLTokenizer.TIMESTAMP, |
910 | SQLTokenizer.SMALLDATETIME, |
911 | SQLTokenizer.DATE, |
912 | SQLTokenizer.TIME, |
913 | SQLTokenizer.DOUBLE, |
914 | SQLTokenizer.FLOAT, |
915 | SQLTokenizer.REAL, |
916 | SQLTokenizer.DECIMAL, |
917 | SQLTokenizer.NUMERIC, |
918 | SQLTokenizer.MONEY, |
919 | SQLTokenizer.SMALLMONEY, |
920 | SQLTokenizer.BIGINT, |
921 | SQLTokenizer.INT, |
922 | SQLTokenizer.SMALLINT, |
923 | SQLTokenizer.TINYINT, |
924 | SQLTokenizer.BIT, |
925 | SQLTokenizer.BOOLEAN, |
926 | SQLTokenizer.LONGNVARCHAR, |
927 | SQLTokenizer.UNIQUEIDENTIFIER, |
928 | SQLTokenizer.NVARCHAR, |
929 | SQLTokenizer.NCHAR, |
930 | SQLTokenizer.VARCHAR, |
931 | SQLTokenizer.CHAR, |
932 | SQLTokenizer.LONGVARCHAR, |
933 | SQLTokenizer.CLOB, |
934 | SQLTokenizer.VARBINARY, |
935 | SQLTokenizer.BINARY, |
936 | SQLTokenizer.LONGVARBINARY, |
937 | SQLTokenizer.BLOB, |
938 | SQLTokenizer.NULL}; |
939 | |
940 | |
941 | private static int NVARCHAR_IDX = Utils.indexOf( SQLTokenizer.NVARCHAR, DatatypeRange); |
942 | private static int INT_IDX = Utils.indexOf( SQLTokenizer.INT, DatatypeRange); |
943 | private static int BIGINT_IDX = Utils.indexOf( SQLTokenizer.BIGINT, DatatypeRange); |
944 | private static int MONEY_IDX = Utils.indexOf( SQLTokenizer.MONEY, DatatypeRange); |
945 | private static int DECIMAL_IDX = Utils.indexOf( SQLTokenizer.DECIMAL, DatatypeRange); |
946 | } |