00001
package com.quadcap.sql;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.io.Externalizable;
00042
import java.io.IOException;
00043
import java.io.ObjectInput;
00044
import java.io.ObjectOutput;
00045
00046
import java.util.Calendar;
00047
import java.util.Hashtable;
00048
import java.util.Random;
00049
00050
import java.math.BigDecimal;
00051
00052
import java.security.MessageDigest;
00053
00054
import java.text.SimpleDateFormat;
00055
00056
import java.sql.Date;
00057
import java.sql.SQLException;
00058
import java.sql.Time;
00059
import java.sql.Timestamp;
00060
00061
import com.quadcap.sql.types.*;
00062
00063
import com.quadcap.util.text.Soundex;
00064
00065
import com.quadcap.util.Debug;
00066
00067
00068
00069
00070
00071
00072 public class FunctionExpression extends Expression implements
Externalizable {
00073 String
name;
00074 String
uname;
00075 VectorExpression args;
00076 boolean not =
false;
00077 Value value = null;
00078
00079
00080 static final SimpleDateFormat
dayNameFmt =
new SimpleDateFormat(
"EEE");
00081 static final SimpleDateFormat
monthNameFmt =
new SimpleDateFormat(
"MMM");
00082
00083 static final int TSI_FRAC_SECOND = -1;
00084 static final int TSI_SECOND = Calendar.SECOND;
00085 static final int TSI_MINUTE = Calendar.MINUTE;
00086 static final int TSI_HOUR = Calendar.HOUR;
00087 static final int TSI_DAY = Calendar.DAY_OF_YEAR;
00088 static final int TSI_WEEK = Calendar.WEEK_OF_YEAR;
00089 static final int TSI_MONTH = Calendar.MONTH;
00090 static final int TSI_QUARTER = -2;
00091 static final int TSI_YEAR = Calendar.YEAR;
00092
00093
00094 static final Hashtable
functions =
new Hashtable();
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 static final int fnABS = 1;
00156 static final int fnASCII = 2;
00157 static final int fnACOS = 3;
00158 static final int fnASIN = 4;
00159 static final int fnATAN = 5;
00160 static final int fnATAN2 = 6;
00161 static final int fnBIT_LENGTH = 7;
00162 static final int fnCASE = 8;
00163 static final int fnCAST = 9;
00164 static final int fnCEILING = 10;
00165 static final int fnCHAR = 11;
00166 static final int fnCHAR_LENGTH = 12;
00167 static final int fnCOALESCE = 13;
00168 static final int fnCOS = 14;
00169 static final int fnCOT = 15;
00170 static final int fnCONCAT = 16;
00171 static final int fnCURDATE = 17;
00172 static final int fnCURTIME = 18;
00173 static final int fnDATABASE = 19;
00174 static final int fnDAYNAME = 20;
00175 static final int fnDAYOFMONTH = 21;
00176 static final int fnDAYOFWEEK = 22;
00177 static final int fnDAYOFYEAR = 23;
00178 static final int fnDEGREES = 24;
00179 static final int fnDIFFERENCE = 25;
00180 static final int fnEXP = 26;
00181 static final int fnFLOOR = 27;
00182 static final int fnHOUR = 28;
00183 static final int fnIFNULL = 29;
00184 static final int fnINSERT = 30;
00185 static final int fnLEFT = 31;
00186 static final int fnLENGTH = 32;
00187 static final int fnLOCATE = 33;
00188 static final int fnLOG = 34;
00189 static final int fnLOG10 = 35;
00190 static final int fnLOWER = 36;
00191 static final int fnLTRIM = 37;
00192 static final int fnMINUTE = 38;
00193 static final int fnMOD = 39;
00194 static final int fnMONTH = 40;
00195 static final int fnMONTHNAME = 41;
00196 static final int fnNOW = 42;
00197 static final int fnNULLIF = 43;
00198 static final int fnOCTET_LENGTH = 44;
00199 static final int fnPI = 45;
00200 static final int fnPOWER = 46;
00201 static final int fnQUARTER = 47;
00202 static final int fnRADIANS = 48;
00203 static final int fnRAND = 49;
00204 static final int fnREPEAT = 50;
00205 static final int fnREPLACE = 51;
00206 static final int fnRIGHT = 52;
00207 static final int fnROUND = 53;
00208 static final int fnRTRIM = 54;
00209 static final int fnSECOND = 55;
00210 static final int fnSIGN = 56;
00211 static final int fnSIN = 57;
00212 static final int fnSOUNDEX = 58;
00213 static final int fnSPACE = 59;
00214 static final int fnSQRT = 60;
00215 static final int fnSUBSTRING = 61;
00216 static final int fnTAN = 62;
00217 static final int fnTIMESTAMPADD = 63;
00218 static final int fnTIMESTAMPDIFF = 64;
00219 static final int fnTRUNCATE = 65;
00220 static final int fnUPPER = 66;
00221 static final int fnUSER = 67;
00222 static final int fnWEEK = 68;
00223 static final int fnYEAR = 69;
00224 static final int fnDIGEST = 70;
00225 static final int fnLAST_INSERT_ID = 71;
00226
00227
static {
00228
functions.put(
"ABS",
new Integer(
fnABS));
00229
functions.put(
"ASCII",
new Integer(
fnASCII));
00230
functions.put(
"ACOS",
new Integer(
fnACOS));
00231
functions.put(
"ASIN",
new Integer(
fnASIN));
00232
functions.put(
"ATAN",
new Integer(
fnATAN));
00233
functions.put(
"ATAN2",
new Integer(
fnATAN2));
00234
functions.put(
"BIT_LENGTH",
new Integer(
fnBIT_LENGTH));
00235
functions.put(
"CASE",
new Integer(
fnCASE));
00236
functions.put(
"CAST",
new Integer(
fnCAST));
00237
functions.put(
"CEILING",
new Integer(
fnCEILING));
00238
functions.put(
"CHAR",
new Integer(
fnCHAR));
00239
functions.put(
"CHAR_LENGTH",
new Integer(
fnCHAR_LENGTH));
00240
functions.put(
"CHARACTER_LENGTH",
new Integer(fnCHAR_LENGTH));
00241
functions.put(
"COALESCE",
new Integer(
fnCOALESCE));
00242
functions.put(
"COS",
new Integer(
fnCOS));
00243
functions.put(
"COT",
new Integer(
fnCOT));
00244
functions.put(
"CONCAT",
new Integer(
fnCONCAT));
00245
functions.put(
"CURDATE",
new Integer(
fnCURDATE));
00246
functions.put(
"CURTIME",
new Integer(
fnCURTIME));
00247
functions.put(
"DATABASE",
new Integer(
fnDATABASE));
00248
functions.put(
"DAYNAME",
new Integer(
fnDAYNAME));
00249
functions.put(
"DAYOFMONTH",
new Integer(
fnDAYOFMONTH));
00250
functions.put(
"DAYOFWEEK",
new Integer(
fnDAYOFWEEK));
00251
functions.put(
"DAYOFYEAR",
new Integer(
fnDAYOFYEAR));
00252
functions.put(
"DEGREES",
new Integer(
fnDEGREES));
00253
functions.put(
"DIFFERENCE",
new Integer(
fnDIFFERENCE));
00254
functions.put(
"EXP",
new Integer(
fnEXP));
00255
functions.put(
"FLOOR",
new Integer(
fnFLOOR));
00256
functions.put(
"HOUR",
new Integer(
fnHOUR));
00257
functions.put(
"IFNULL",
new Integer(
fnIFNULL));
00258
functions.put(
"INSERT",
new Integer(
fnINSERT));
00259
functions.put(
"LEFT",
new Integer(
fnLEFT));
00260
functions.put(
"LENGTH",
new Integer(
fnLENGTH));
00261
functions.put(
"LOCATE",
new Integer(
fnLOCATE));
00262
functions.put(
"LOG",
new Integer(
fnLOG));
00263
functions.put(
"LOG10",
new Integer(
fnLOG10));
00264
functions.put(
"LOWER",
new Integer(
fnLOWER));
00265
functions.put(
"LCASE",
new Integer(fnLOWER));
00266
functions.put(
"LTRIM",
new Integer(
fnLTRIM));
00267
functions.put(
"MINUTE",
new Integer(
fnMINUTE));
00268
functions.put(
"MOD",
new Integer(
fnMOD));
00269
functions.put(
"MONTH",
new Integer(
fnMONTH));
00270
functions.put(
"MONTHNAME",
new Integer(
fnMONTHNAME));
00271
functions.put(
"NOW",
new Integer(
fnNOW));
00272
functions.put(
"NULLIF",
new Integer(
fnNULLIF));
00273
functions.put(
"OCTET_LENGTH",
new Integer(
fnOCTET_LENGTH));
00274
functions.put(
"PI",
new Integer(
fnPI));
00275
functions.put(
"POWER",
new Integer(
fnPOWER));
00276
functions.put(
"QUARTER",
new Integer(
fnQUARTER));
00277
functions.put(
"RADIANS",
new Integer(
fnRADIANS));
00278
functions.put(
"RAND",
new Integer(
fnRAND));
00279
functions.put(
"REPEAT",
new Integer(
fnREPEAT));
00280
functions.put(
"REPLACE",
new Integer(
fnREPLACE));
00281
functions.put(
"RIGHT",
new Integer(
fnRIGHT));
00282
functions.put(
"ROUND",
new Integer(
fnROUND));
00283
functions.put(
"RTRIM",
new Integer(
fnRTRIM));
00284
functions.put(
"SECOND",
new Integer(
fnSECOND));
00285
functions.put(
"SIGN",
new Integer(
fnSIGN));
00286
functions.put(
"SIN",
new Integer(
fnSIN));
00287
functions.put(
"SOUNDEX",
new Integer(
fnSOUNDEX));
00288
functions.put(
"SPACE",
new Integer(
fnSPACE));
00289
functions.put(
"SQRT",
new Integer(
fnSQRT));
00290
functions.put(
"SUBSTRING",
new Integer(
fnSUBSTRING));
00291
functions.put(
"TAN",
new Integer(
fnTAN));
00292
functions.put(
"TIMESTAMPADD",
new Integer(
fnTIMESTAMPADD));
00293
functions.put(
"TIMESTAMPDIFF",
new Integer(
fnTIMESTAMPDIFF));
00294
functions.put(
"TRUNCATE",
new Integer(
fnTRUNCATE));
00295
functions.put(
"UPPER",
new Integer(
fnUPPER));
00296
functions.put(
"UCASE",
new Integer(fnUPPER));
00297
functions.put(
"USER",
new Integer(
fnUSER));
00298
functions.put(
"WEEK",
new Integer(
fnWEEK));
00299
functions.put(
"YEAR",
new Integer(
fnYEAR));
00300
functions.put(
"DIGEST",
new Integer(
fnDIGEST));
00301
functions.put(
"LAST_INSERT_ID",
new Integer(
fnLAST_INSERT_ID));
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 static final Number toNumber(
Value v)
throws SQLException,
ValueException {
00458 Object obj = v.asJavaObject();
00459
if (obj instanceof
Number) {
00460
return (
Number)obj;
00461 }
else {
00462
throw new ValueException(
"Not a number: " + v);
00463 }
00464 }
00465
00466 static final Value stringLength(
Value v,
int div,
int mul)
00467
throws ValueException, SQLException
00468 {
00469
if (
Value.isNull(v)) {
00470
return v;
00471 }
else {
00472
int len;
00473
if (v instanceof
ValueOctets) {
00474 len = ((
ValueOctets)v).getLength() * mul;
00475 }
else if (v instanceof
ValueString) {
00476 len = ((
ValueString)v).stringValue().length() * 16;
00477 }
else if (v instanceof
ValueBlob) {
00478 len = (
int)(((
ValueBlob)v).length() * 8 * mul);
00479 }
else {
00480
throw new ValueException(
"BIT_LENGTH(" + v +
00481
"), wrong type");
00482 }
00483
return new ValueInteger((len + div-1) / div);
00484 }
00485 }
00486
00487 static final String
stringValue(
Value v)
throws ValueException {
00488
if (!(v instanceof
ValueString)) {
00489 v = v.convert(
TypeVarChar.typeVarChar);
00490 }
00491
return ((
ValueString)v).stringValue();
00492 }
00493
00494 static final ValueString getString(
Row values,
int i)
00495
throws ValueException, SQLException
00496 {
00497
Value v = values.item(i);
00498
ValueString vs = null;
00499
if (v instanceof
ValueString) {
00500 vs = (
ValueString)v;
00501 }
else {
00502 vs = (
ValueString)(v.
convert(
TypeVarChar.typeVarChar));
00503 }
00504
return vs;
00505 }
00506
00507 static final Number getNumber(
Row values,
int i)
00508
throws ValueException, SQLException
00509 {
00510
return toNumber(values.item(i));
00511 }
00512
00513 static final Timestamp
getTimestamp(
Value v, String fn)
00514
throws ValueException, SQLException
00515 {
00516
if (!(v instanceof
ValueTimestamp)) {
00517
throw new ValueException(
"fn called with " +
00518
"non-TIMESTAMP argument: " +
00519 v.getType().getTypeName());
00520 }
00521 Timestamp t = (Timestamp)((
ValueTimestamp)v).asJavaObject();
00522
return t;
00523 }
00524
00525 static final int getMonths(Timestamp t) {
00526 Calendar c = Calendar.getInstance();
00527 c.setTime(t);
00528
return c.get(Calendar.YEAR) * 12 + c.get(Calendar.MONTH);
00529 }
00530
00531
00532
00533
00534
00535 public Value getTimeComponent(
Value v,
int field,
int offset,
boolean time)
00536
throws ValueException, SQLException
00537 {
00538
Value ret = null;
00539
if (
Value.isNull(v)) {
00540 ret = v;
00541 }
else if (v instanceof
ValueInterval) {
00542 ret = ((
ValueInterval)v).getTimeComponent(field);
00543 }
else {
00544 Calendar c = Calendar.getInstance();
00545
boolean ok = v instanceof
ValueTimestamp;
00546
if (!ok) {
00547
if (time) ok = v instanceof
ValueTime;
00548
else ok = v instanceof
ValueDate;
00549 }
00550
if (!ok) {
00551
throw new ValueException(
uname +
"() called with " +
00552
"non-" + (time ?
"TIME" :
"DATE") +
00553
" argument: " +
00554 v.getType().getTypeName() +
00555
"(" + v.getClass().getName() +
")");
00556 }
00557 Date d =
new Date(((
ValueDateTime)v).getTime());
00558 c.setTime(d);
00559 ret =
new ValueInteger(c.get(field) + offset);
00560 }
00561
return ret;
00562
00563 }
00564
00565 public FunctionExpression() {}
00566
00567 public FunctionExpression(String name,
VectorExpression args) {
00568
this.name = name;
00569
this.uname = name.toUpperCase();
00570
this.args = args;
00571 }
00572
00573 public void invert() {
00574
not = !
not;
00575 }
00576
00577 public int rank() {
return 0; }
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587 public Value getValue(
Session session,
Cursor cursor)
throws SQLException {
00588 Integer fi = (Integer)
functions.get(
uname);
00589
Row values =
args.
getValues(session, cursor);
00590
Value v = values.
size() > 0 ? values.
item(1) : null;
00591
Value ret = null;
00592
if (fi != null)
switch (fi.intValue()) {
00593
case fnABS:
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 ret = v;
00608
if (!
Value.isNull(ret) &&
00609
Value.boolOp(
Op.LT, ret,
ValueInteger.ZERO)) {
00610 ret = ret.
unop(
Op.MINUS);
00611 }
00612
break;
00613
00614
case fnASCII:
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
if (
Value.isNull(v)) {
00627 ret = v;
00628 }
else {
00629 ret =
new ValueInteger(stringValue(v).charAt(0) & 0xff);
00630 }
00631
break;
00632
00633
case fnACOS:
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
if (
Value.isNull(v)) {
00646 ret = v;
00647 }
else {
00648 ret =
new ValueDouble(Math.acos(toNumber(v).doubleValue()));
00649 }
00650
break;
00651
00652
case fnASIN:
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
if (
Value.isNull(v)) {
00665 ret = v;
00666 }
else {
00667 ret =
new ValueDouble(Math.asin(toNumber(v).doubleValue()));
00668 }
00669
break;
00670
00671
case fnATAN:
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
if (
Value.isNull(v)) {
00684 ret = v;
00685 }
else {
00686 ret =
new ValueDouble(Math.atan(toNumber(v).doubleValue()));
00687 }
00688
break;
00689
00690
case fnATAN2:
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
if (
Value.isNull(v)) {
00706 ret = v;
00707 }
else {
00708
double y = toNumber(v).doubleValue();
00709
double x = toNumber(values.
item(2)).doubleValue();
00710 ret =
new ValueDouble(Math.atan2(y, x));
00711 }
00712
break;
00713
00714
case fnBIT_LENGTH:
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726 ret = stringLength(v, 1, 1);
00727
break;
00728
00729
case fnCASE:
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749 ret = null;
00750
for (
int i = 1; ret == null && i < values.
size(); i += 2) {
00751
Value when = values.
item(i);
00752
if (
Value.isTrue(when)) {
00753 ret = values.
item(i+1);
00754 }
00755 }
00756
if (ret == null && ((values.
size() % 2) == 1)) {
00757 ret = values.
item(values.
size());
00758 }
00759
if (ret == null) {
00760 ret =
ValueNull.valueNull;
00761 }
00762
break;
00763
00764
case fnCAST:
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
if (
Value.isNull(v)) {
00803 ret = v;
00804 }
else {
00805
ValueType vt = (
ValueType)values.
item(2);
00806
Type type = vt.
getType();
00807
if (type == null) {
00808
throw new ValueException(
"Can't convert value to type: " +
00809 type);
00810 }
00811 ret = type.
convert(v);
00812 }
00813
break;
00814
00815
case fnCEILING:
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
if (
Value.isNull(v)) {
00828 ret = v;
00829 }
else {
00830 ret =
new ValueDouble(Math.ceil(toNumber(v).doubleValue()));
00831 }
00832
break;
00833
00834
case fnCHAR:
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
if (
Value.isNull(v)) {
00848 ret = v;
00849 }
else {
00850
int n = toNumber(v).intValue();
00851
if (n < 0 || n > 255) {
00852
throw new ValueException(
"CHAR(" + n +
00853
"), not an ASCII value");
00854 }
00855
char[] cv =
new char[1];
00856 cv[0] = (
char)n;
00857 ret =
new ValueString(
new String(cv));
00858 }
00859
break;
00860
00861
case fnCHAR_LENGTH:
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878 ret = stringLength(v, 16, 2);
00879
break;
00880
00881
case fnCOS:
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
if (
Value.isNull(v)) {
00894 ret = v;
00895 }
else {
00896 ret =
new ValueDouble(Math.cos(toNumber(v).doubleValue()));
00897 }
00898
break;
00899
00900
case fnCOALESCE:
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913 ret =
ValueNull.valueNull;
00914
for (
int i = 1; i <= values.
size(); i++) {
00915
Value vt = values.
item(i);
00916
if (!
Value.isNull(vt)) {
00917 ret = v;
00918
break;
00919 }
00920 }
00921
break;
00922
00923
case fnCOT:
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
if (
Value.isNull(v)) {
00936 ret = v;
00937 }
else {
00938
double x = toNumber(v).doubleValue();
00939 ret =
new ValueDouble(Math.cos(x) / Math.sin(x));
00940 }
00941
break;
00942
00943
case fnCONCAT:
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
if (
Value.isNull(v) ||
Value.isNull(values.
item(2))) {
00956 ret =
ValueNull.valueNull;
00957 }
else {
00958
ValueString s1 = getString(values, 1);
00959
ValueString s2 = getString(values, 2);
00960 ret =
new ValueString(s1.
stringValue() + s2.
stringValue());
00961 }
00962
break;
00963
00964
case fnCURDATE:
00965
00966
00967 <