1 package com.quadcap.sql; 2 3 40 41 import java.io.Externalizable ; 42 import java.io.IOException ; 43 import java.io.ObjectInput ; 44 import java.io.ObjectOutput ; 45 46 import java.util.Calendar ; 47 import java.util.Hashtable ; 48 import java.util.Random ; 49 50 import java.math.BigDecimal ; 51 52 import java.security.MessageDigest ; 53 54 import java.text.SimpleDateFormat ; 55 56 import java.sql.Date ; 57 import java.sql.SQLException ; 58 import java.sql.Time ; 59 import java.sql.Timestamp ; 60 61 import com.quadcap.sql.types.*; 62 63 import com.quadcap.util.text.Soundex; 64 65 import com.quadcap.util.Debug; 66 67 72 public class FunctionExpression extends Expression implements Externalizable { 73 String name; 74 String uname; 75 VectorExpression args; 76 boolean not = false; 77 Value value = null; 78 79 static final SimpleDateFormat dayNameFmt = new SimpleDateFormat ("EEE"); 81 static final SimpleDateFormat monthNameFmt = new SimpleDateFormat ("MMM"); 82 83 static final int TSI_FRAC_SECOND = -1; 84 static final int TSI_SECOND = Calendar.SECOND; 85 static final int TSI_MINUTE = Calendar.MINUTE; 86 static final int TSI_HOUR = Calendar.HOUR; 87 static final int TSI_DAY = Calendar.DAY_OF_YEAR; 88 static final int TSI_WEEK = Calendar.WEEK_OF_YEAR; 89 static final int TSI_MONTH = Calendar.MONTH; 90 static final int TSI_QUARTER = -2; 91 static final int TSI_YEAR = Calendar.YEAR; 92 93 static final Hashtable functions = new Hashtable (); 95 96 static final int fnABS = 1; 156 static final int fnASCII = 2; 157 static final int fnACOS = 3; 158 static final int fnASIN = 4; 159 static final int fnATAN = 5; 160 static final int fnATAN2 = 6; 161 static final int fnBIT_LENGTH = 7; 162 static final int fnCASE = 8; 163 static final int fnCAST = 9; 164 static final int fnCEILING = 10; 165 static final int fnCHAR = 11; 166 static final int fnCHAR_LENGTH = 12; 167 static final int fnCOALESCE = 13; 168 static final int fnCOS = 14; 169 static final int fnCOT = 15; 170 static final int fnCONCAT = 16; 171 static final int fnCURDATE = 17; 172 static final int fnCURTIME = 18; 173 static final int fnDATABASE = 19; 174 static final int fnDAYNAME = 20; 175 static final int fnDAYOFMONTH = 21; 176 static final int fnDAYOFWEEK = 22; 177 static final int fnDAYOFYEAR = 23; 178 static final int fnDEGREES = 24; 179 static final int fnDIFFERENCE = 25; 180 static final int fnEXP = 26; 181 static final int fnFLOOR = 27; 182 static final int fnHOUR = 28; 183 static final int fnIFNULL = 29; 184 static final int fnINSERT = 30; 185 static final int fnLEFT = 31; 186 static final int fnLENGTH = 32; 187 static final int fnLOCATE = 33; 188 static final int fnLOG = 34; 189 static final int fnLOG10 = 35; 190 static final int fnLOWER = 36; 191 static final int fnLTRIM = 37; 192 static final int fnMINUTE = 38; 193 static final int fnMOD = 39; 194 static final int fnMONTH = 40; 195 static final int fnMONTHNAME = 41; 196 static final int fnNOW = 42; 197 static final int fnNULLIF = 43; 198 static final int fnOCTET_LENGTH = 44; 199 static final int fnPI = 45; 200 static final int fnPOWER = 46; 201 static final int fnQUARTER = 47; 202 static final int fnRADIANS = 48; 203 static final int fnRAND = 49; 204 static final int fnREPEAT = 50; 205 static final int fnREPLACE = 51; 206 static final int fnRIGHT = 52; 207 static final int fnROUND = 53; 208 static final int fnRTRIM = 54; 209 static final int fnSECOND = 55; 210 static final int fnSIGN = 56; 211 static final int fnSIN = 57; 212 static final int fnSOUNDEX = 58; 213 static final int fnSPACE = 59; 214 static final int fnSQRT = 60; 215 static final int fnSUBSTRING = 61; 216 static final int fnTAN = 62; 217 static final int fnTIMESTAMPADD = 63; 218 static final int fnTIMESTAMPDIFF = 64; 219 static final int fnTRUNCATE = 65; 220 static final int fnUPPER = 66; 221 static final int fnUSER = 67; 222 static final int fnWEEK = 68; 223 static final int fnYEAR = 69; 224 static final int fnDIGEST = 70; 225 static final int fnLAST_INSERT_ID = 71; 226 227 static { 228 functions.put("ABS", new Integer (fnABS)); 229 functions.put("ASCII", new Integer (fnASCII)); 230 functions.put("ACOS", new Integer (fnACOS)); 231 functions.put("ASIN", new Integer (fnASIN)); 232 functions.put("ATAN", new Integer (fnATAN)); 233 functions.put("ATAN2", new Integer (fnATAN2)); 234 functions.put("BIT_LENGTH", new Integer (fnBIT_LENGTH)); 235 functions.put("CASE", new Integer (fnCASE)); 236 functions.put("CAST", new Integer (fnCAST)); 237 functions.put("CEILING", new Integer (fnCEILING)); 238 functions.put("CHAR", new Integer (fnCHAR)); 239 functions.put("CHAR_LENGTH", new Integer (fnCHAR_LENGTH)); 240 functions.put("CHARACTER_LENGTH", new Integer (fnCHAR_LENGTH)); 241 functions.put("COALESCE", new Integer (fnCOALESCE)); 242 functions.put("COS", new Integer (fnCOS)); 243 functions.put("COT", new Integer (fnCOT)); 244 functions.put("CONCAT", new Integer (fnCONCAT)); 245 functions.put("CURDATE", new Integer (fnCURDATE)); 246 functions.put("CURTIME", new Integer (fnCURTIME)); 247 functions.put("DATABASE", new Integer (fnDATABASE)); 248 functions.put("DAYNAME", new Integer (fnDAYNAME)); 249 functions.put("DAYOFMONTH", new Integer (fnDAYOFMONTH)); 250 functions.put("DAYOFWEEK", new Integer (fnDAYOFWEEK)); 251 functions.put("DAYOFYEAR", new Integer (fnDAYOFYEAR)); 252 functions.put("DEGREES", new Integer (fnDEGREES)); 253 functions.put("DIFFERENCE", new Integer (fnDIFFERENCE)); 254 functions.put("EXP", new Integer (fnEXP)); 255 functions.put("FLOOR", new Integer (fnFLOOR)); 256 functions.put("HOUR", new Integer (fnHOUR)); 257 functions.put("IFNULL", new Integer (fnIFNULL)); 258 functions.put("INSERT", new Integer (fnINSERT)); 259 functions.put("LEFT", new Integer (fnLEFT)); 260 functions.put("LENGTH", new Integer (fnLENGTH)); 261 functions.put("LOCATE", new Integer (fnLOCATE)); 262 functions.put("LOG", new Integer (fnLOG)); 263 functions.put("LOG10", new Integer (fnLOG10)); 264 functions.put("LOWER", new Integer (fnLOWER)); 265 functions.put("LCASE", new Integer (fnLOWER)); 266 functions.put("LTRIM", new Integer (fnLTRIM)); 267 functions.put("MINUTE", new Integer (fnMINUTE)); 268 functions.put("MOD", new Integer (fnMOD)); 269 functions.put("MONTH", new Integer (fnMONTH)); 270 functions.put("MONTHNAME", new Integer (fnMONTHNAME)); 271 functions.put("NOW", new Integer (fnNOW)); 272 functions.put("NULLIF", new Integer (fnNULLIF)); 273 functions.put("OCTET_LENGTH", new Integer (fnOCTET_LENGTH)); 274 functions.put("PI", new Integer (fnPI)); 275 functions.put("POWER", new Integer (fnPOWER)); 276 functions.put("QUARTER", new Integer (fnQUARTER)); 277 functions.put("RADIANS", new Integer (fnRADIANS)); 278 functions.put("RAND", new Integer (fnRAND)); 279 functions.put("REPEAT", new Integer (fnREPEAT)); 280 functions.put("REPLACE", new Integer (fnREPLACE)); 281 functions.put("RIGHT", new Integer (fnRIGHT)); 282 functions.put("ROUND", new Integer (fnROUND)); 283 functions.put("RTRIM", new Integer (fnRTRIM)); 284 functions.put("SECOND", new Integer (fnSECOND)); 285 functions.put("SIGN", new Integer (fnSIGN)); 286 functions.put("SIN", new Integer (fnSIN)); 287 functions.put("SOUNDEX", new Integer (fnSOUNDEX)); 288 functions.put("SPACE", new Integer (fnSPACE)); 289 functions.put("SQRT", new Integer (fnSQRT)); 290 functions.put("SUBSTRING", new Integer (fnSUBSTRING)); 291 functions.put("TAN", new Integer (fnTAN)); 292 functions.put("TIMESTAMPADD", new Integer (fnTIMESTAMPADD)); 293 functions.put("TIMESTAMPDIFF", new Integer (fnTIMESTAMPDIFF)); 294 functions.put("TRUNCATE", new Integer (fnTRUNCATE)); 295 functions.put("UPPER", new Integer (fnUPPER)); 296 functions.put("UCASE", new Integer (fnUPPER)); 297 functions.put("USER", new Integer (fnUSER)); 298 functions.put("WEEK", new Integer (fnWEEK)); 299 functions.put("YEAR", new Integer (fnYEAR)); 300 functions.put("DIGEST", new Integer (fnDIGEST)); 301 functions.put("LAST_INSERT_ID", new Integer (fnLAST_INSERT_ID)); 302 } 303 304 382 455 457 static final Number toNumber(Value v) throws SQLException , ValueException { 458 Object obj = v.asJavaObject(); 459 if (obj instanceof Number ) { 460 return (Number )obj; 461 } else { 462 throw new ValueException("Not a number: " + v); 463 } 464 } 465 466 static final Value stringLength(Value v, int div, int mul) 467 throws ValueException, SQLException 468 { 469 if (Value.isNull(v)) { 470 return v; 471 } else { 472 int len; 473 if (v instanceof ValueOctets) { 474 len = ((ValueOctets)v).getLength() * mul; 475 } else if (v instanceof ValueString) { 476 len = ((ValueString)v).stringValue().length() * 16; 477 } else if (v instanceof ValueBlob) { 478 len = (int)(((ValueBlob)v).length() * 8 * mul); 479 } else { 480 throw new ValueException("BIT_LENGTH(" + v + 481 "), wrong type"); 482 } 483 return new ValueInteger((len + div-1) / div); 484 } 485 } 486 487 static final String stringValue(Value v) throws ValueException { 488 if (!(v instanceof ValueString)) { 489 v = v.convert(TypeVarChar.typeVarChar); 490 } 491 return ((ValueString)v).stringValue(); 492 } 493 494 static final ValueString getString(Row values, int i) 495 throws ValueException, SQLException 496 { 497 Value v = values.item(i); 498 ValueString vs = null; 499 if (v instanceof ValueString) { 500 vs = (ValueString)v; 501 } else { 502 vs = (ValueString)(v.convert(TypeVarChar.typeVarChar)); 503 } 504 return vs; 505 } 506 507 static final Number getNumber(Row values, int i) 508 throws ValueException, SQLException 509 { 510 return toNumber(values.item(i)); 511 } 512 513 static final Timestamp getTimestamp(Value v, String fn) 514 throws ValueException, SQLException 515 { 516 if (!(v instanceof ValueTimestamp)) { 517 throw new ValueException("fn called with " + 518 "non-TIMESTAMP argument: " + 519 v.getType().getTypeName()); 520 } 521 Timestamp t = (Timestamp )((ValueTimestamp)v).asJavaObject(); 522 return t; 523 } 524 525 static final int getMonths(Timestamp t) { 526 Calendar c = Calendar.getInstance(); 527 c.setTime(t); 528 return c.get(Calendar.YEAR) * 12 + c.get(Calendar.MONTH); 529 } 530 531 535 public Value getTimeComponent(Value v, int field, int offset, boolean time) 536 throws ValueException, SQLException 537 { 538 Value ret = null; 539 if (Value.isNull(v)) { 540 ret = v; 541 } else if (v instanceof ValueInterval) { 542 ret = ((ValueInterval)v).getTimeComponent(field); 543 } else { 544 Calendar c = Calendar.getInstance(); 545 boolean ok = v instanceof ValueTimestamp; 546 if (!ok) { 547 if (time) ok = v instanceof ValueTime; 548 else ok = v instanceof ValueDate; 549 } 550 if (!ok) { 551 throw new ValueException(uname + "() called with " + 552 "non-" + (time ? "TIME" : "DATE") + 553 " argument: " + 554 v.getType().getTypeName() + 555 "(" + v.getClass().getName() + ")"); 556 } 557 Date d = new Date (((ValueDateTime)v).getTime()); 558 c.setTime(d); 559 ret = new ValueInteger(c.get(field) + offset); 560 } 561 return ret; 562 563 } 564 565 public FunctionExpression() {} 566 567 public FunctionExpression(String name, VectorExpression args) { 568 this.name = name; 569 this.uname = name.toUpperCase(); 570 this.args = args; 571 } 572 573 public void invert() { 574 not = !not; 575 } 576 577 public int rank() { return 0; } 578 579 582 585 586 587 public Value getValue(Session session, Cursor cursor) throws SQLException { 588 Integer fi = (Integer )functions.get(uname); 589 Row values = args.getValues(session, cursor); 590 Value v = values.size() > 0 ? values.item(1) : null; 591 Value ret = null; 592 if (fi != null) switch (fi.intValue()) { 593 case fnABS: 594 607 ret = v; 608 if (!Value.isNull(ret) && 609 Value.boolOp(Op.LT, ret, ValueInteger.ZERO)) { 610 ret = ret.unop(Op.MINUS); 611 } 612 break; 613 614 case fnASCII: 615 626 if (Value.isNull(v)) { 627 ret = v; 628 } else { 629 ret = new ValueInteger(stringValue(v).charAt(0) & 0xff); 630 } 631 break; 632 633 case fnACOS: 634 645 if (Value.isNull(v)) { 646 ret = v; 647 } else { 648 ret = new ValueDouble(Math.acos(toNumber(v).doubleValue())); 649 } 650 break; 651 652 case fnASIN: 653 664 if (Value.isNull(v)) { 665 ret = v; 666 } else { 667 ret = new ValueDouble(Math.asin(toNumber(v).doubleValue())); 668 } 669 break; 670 671 case fnATAN: 672 683 if (Value.isNull(v)) { 684 ret = v; 685 } else { 686 ret = new ValueDouble(Math.atan(toNumber(v).doubleValue())); 687 } 688 break; 689 690 case fnATAN2: 691 705 if (Value.isNull(v)) { 706 ret = v; 707 } else { 708 double y = toNumber(v).doubleValue(); 709 double x = toNumber(values.item(2)).doubleValue(); 710 ret = new ValueDouble(Math.atan2(y, x)); 711 } 712 break; 713 714 case fnBIT_LENGTH: 715 726 ret = stringLength(v, 1, 1); 727 break; 728 729 case fnCASE: 730 749 ret = null; 750 for (int i = 1; ret == null && i < values.size(); i += 2) { 751 Value when = values.item(i); 752 if (Value.isTrue(when)) { 753 ret = values.item(i+1); 754 } 755 } 756 if (ret == null && ((values.size() % 2) == 1)) { 757 ret = values.item(values.size()); 758 } 759 if (ret == null) { 760 ret = ValueNull.valueNull; 761 } 762 break; 763 764 case fnCAST: 765 802 if (Value.isNull(v)) { 803 ret = v; 804 } else { 805 ValueType vt = (ValueType)values.item(2); 806 Type type = vt.getType(); 807 if (type == null) { 808 throw new ValueException("Can't convert value to type: " + 809 type); 810 } 811 ret = type.convert(v); 812 } 813 break; 814 815 case fnCEILING: 816 827 if (Value.isNull(v)) { 828 ret = v; 829 } else { 830 ret = new ValueDouble(Math.ceil(toNumber(v).doubleValue())); 831 } 832 break; 833 834 case fnCHAR: 835 847 if (Value.isNull(v)) { 848 ret = v; 849 } else { 850 int n = toNumber(v).intValue(); 851 if (n < 0 || n > 255) { 852 throw new ValueException("CHAR(" + n + 853 "), not an ASCII value"); 854 } 855 char[] cv = new char[1]; 856 cv[0] = (char)n; 857 ret = new ValueString(new String (cv)); 858 } 859 break; 860 861 case fnCHAR_LENGTH: 862 878 ret = stringLength(v, 16, 2); 879 break; 880 881 case fnCOS: 882 893 if (Value.isNull(v)) { 894 ret = v; 895 } else { 896 ret = new ValueDouble(Math.cos(toNumber(v).doubleValue())); 897 } 898 break; 899 900 case fnCOALESCE: 901 913 ret = ValueNull.valueNull; 914 for (int i = 1; i <= values.size(); i++) { 915 Value vt = values.item(i); 916 if (!Value.isNull(vt)) { 917 ret = v; 918 break; 919 } 920 } 921 break; 922 923 case fnCOT: 924 935 if (Value.isNull(v)) { 936 ret = v; 937 } else { 938 double x = toNumber(v).doubleValue(); 939 ret = new ValueDouble(Math.cos(x) / Math.sin(x)); 940 } 941 break; 942 943 case fnCONCAT: 944 955 if (Value.isNull(v) || Value.isNull(values.item(2))) { 956 ret = ValueNull.valueNull; 957 } else { 958 ValueString s1 = getString(values, 1); 959 ValueString s2 = getString(values, 2); 960 ret = new ValueString(s1.stringValue() + s2.stringValue()); 961 } 962 break; 963 964 case fnCURDATE: 965 976 ret = new ValueDate(System.currentTimeMillis()); 977 break; 978 979 case fnCURTIME: 980 991 ret = new ValueTime(System.currentTimeMillis()); 992 break; 993 994 case fnDATABASE: 995 1006 ret = new ValueString(session.getDatabase().getURL()); 1007 break; 1008 1009 case fnDAYNAME: 1010 1021 if (Value.isNull(v)) { 1022 ret = v; 1023 } else { 1024 if (!(v instanceof ValueDate || 1025 v instanceof ValueTimestamp)) { 1026 throw new ValueException("DAYNAME() called with " + 1027 "non-date argument"); 1028 } 1029 Date d = new Date (((ValueDateTime)v).getTime()); 1030 synchronized (dayNameFmt) { 1031 ret = new ValueString(dayNameFmt.format(d)); 1032 } 1033 } 1034 break; 1035 1036 case fnDAYOFMONTH: 1037 1048 ret = getTimeComponent(v, Calendar.DAY_OF_MONTH, 0, false); 1049 break; 1050 1051 case fnDAYOFWEEK: 1052 1064 ret = getTimeComponent(v, Calendar.DAY_OF_WEEK, 0, false); 1065 break; 1066 1067 case fnDAYOFYEAR: 1068 1079 ret = getTimeComponent(v, Calendar.DAY_OF_YEAR, 0, false); 1080 break; 1081 1082 case fnDEGREES: 1083 1093 if (Value.isNull(v)) { 1094 ret = v; 1095 } else { 1096 ret = new ValueDouble( 1097 Math.toDegrees(toNumber(v).doubleValue())); 1098 } 1099 break; 1100 1101 case fnDIFFERENCE: 1102 1116 if (Value.isNull(v)) { 1117 ret = v; 1118 } else { 1119 String s1 = getString(values, 1).stringValue(); 1120 String s2 = getString(values, 2).stringValue(); 1121 ret = new ValueInteger(Soundex.difference(s1, s2)); 1122 } 1123 break; 1124 1125 case fnEXP: 1126 1137 if (Value.isNull(v)) { 1138 ret = v; 1139 } else { 1140 ret = new ValueDouble(Math.exp(toNumber(v).doubleValue())); 1141 } 1142 break; 1143 1144 case fnFLOOR: 1145 1156 if (Value.isNull(v)) { 1157 ret = v; 1158 } else { 1159 ret = new ValueDouble(Math.floor(toNumber(v).doubleValue())); 1160 } 1161 break; 1162 1163 case fnHOUR: 1164 1176 ret = getTimeComponent(v, Calendar.HOUR_OF_DAY, 0, true); 1177 break; 1178 1179 case fnIFNULL: 1180 1194 if (Value.isNull(v)) { 1195 ret = values.item(2); 1196 } else { 1197 ret = v; 1198 } 1199 break; 1200 1201 case fnINSERT: 1202 1218 { 1219 try { 1220 String s1 = getString(values, 1).stringValue(); 1221 int start = getNumber(values, 2).intValue(); 1222 int len = getNumber(values, 3).intValue(); 1223 String s2 = getString(values, 4).stringValue(); 1224 StringBuffer sb = new StringBuffer (s1.substring(0, start)); 1225 sb.append(s2); 1226 sb.append(s1.substring(start+len)); 1227 ret = new ValueString(sb.toString()); 1228 } catch (ValueException e) { 1229 if (Value.isNull(v) || 1230 Value.isNull(values.item(2)) || 1231 Value.isNull(values.item(3)) || 1232 Value.isNull(values.item(4))) { 1233 ret = ValueNull.valueNull; 1234 } else { 1235 throw e; 1236 } 1237 } 1238 break; 1239 } 1240 1241 case fnLEFT: 1242 1255 if (Value.isNull(v) || Value.isNull(values.item(2))) { 1256 ret = ValueNull.valueNull; 1257 } else { 1258 String s = getString(values, 1).stringValue(); 1259 int count = getNumber(values, 2).intValue(); 1260 ret = new ValueString(s.substring(0, count)); 1261 } 1262 break; 1263 1264 case fnLENGTH: 1265 1278 if (Value.isNull(v)) { 1279 ret = v; 1280 } else { 1281 String s = getString(values, 1).stringValue(); 1282 int len = s.length() - 1; 1283 while (len >= 0 && Character.isSpace(s.charAt(len))) len--; 1284 ret = new ValueInteger(len+1); 1285 } 1286 break; 1287 1288 case fnLOCATE: 1289 1307 if (Value.isNull(v) || Value.isNull(values.item(2)) || 1308 (values.size() > 2 && Value.isNull(values.item(3)))) { 1309 ret = ValueNull.valueNull; 1310 } else { 1311 String s1 = getString(values, 1).stringValue(); 1312 String s2 = getString(values, 2).stringValue(); 1313 int pos = 0; 1314 if (values.size() > 2) { 1315 pos = getNumber(values, 3).intValue() - 1; 1316 } 1317 int idx = s2.indexOf(s1, pos) + 1; 1318 ret = new ValueInteger(idx); 1319 } 1320 break; 1321 1322 case fnLOG: 1323 1334 if (Value.isNull(v)) { 1335 ret = v; 1336 } else { 1337 ret = new ValueDouble(Math.log(toNumber(v).doubleValue())); 1338 } 1339 break; 1340 1341 case fnLOG10: 1342 1353 if (Value.isNull(v)) { 1354 ret = v; 1355 } else { 1356 ret = new ValueDouble(Math.log(toNumber(v).doubleValue()) / 1357 Math.log(10.0)); 1358 } 1359 break; 1360 1361 case fnLOWER: 1362 1376 if (Value.isNull(v)) { 1377 ret = v; 1378 } else { 1379 String s = getString(values, 1).stringValue(); 1380 ret = new ValueString(s.toLowerCase()); 1381 } 1382 break; 1383 1384 case fnLTRIM: 1385 1396 if (Value.isNull(v)) { 1397 ret = v; 1398 } else { 1399 String s = getString(values, 1).stringValue(); 1400 int i = 0; 1401 while (i < s.length() && Character.isWhitespace(s.charAt(i))) { 1402 i++; 1403 } 1404 if (i > 0) s = s.substring(i); 1405 ret = new ValueString(s); 1406 } 1407 break; 1408 1409 case fnMINUTE: 1410 1422 ret = getTimeComponent(v, Calendar.MINUTE, 0, true); 1423 break; 1424 1425 case fnMOD: 1426 1437 if (Value.isNull(v)) { 1438 ret = v; 1439 } else { 1440 long x = toNumber(v).longValue(); 1441 long y = toNumber(values.item(2)).longValue(); 1442 long m = x % y; 1443 if (m < Integer.MAX_VALUE && m > Integer.MIN_VALUE) { 1444 ret = new ValueInteger((int)m); 1445 } else { 1446 ret = new ValueLong(m); 1447 } 1448 } 1449 break; 1450 1451 case fnMONTH: 1452 1463 ret = getTimeComponent(v, Calendar.MONTH, 1, false); 1464 break; 1465 1466 case fnMONTHNAME: 1467 1478 if (Value.isNull(v)) { 1479 ret = v; 1480 } else { 1481 if (!(v instanceof ValueDate || 1482 v instanceof ValueTimestamp)) { 1483 throw new ValueException("MONTHNAME() called with " + 1484 "non-date argument"); 1485 } 1486 Date d = new Date (((ValueDateTime)v).getTime()); 1487 synchronized (monthNameFmt) { 1488 ret = new ValueString(monthNameFmt.format(d)); 1489 } 1490 } 1491 break; 1492 1493 case fnNOW: 1494 1505 ret = new ValueTimestamp(System.currentTimeMillis()); 1506 break; 1507 1508 case fnNULLIF: 1509 1523 if (Value.boolOp(Op.EQ, v, values.item(2))) { 1524 ret = ValueNull.valueNull; 1525 } else { 1526 ret = v; 1527 } 1528 break; 1529 1530 case fnOCTET_LENGTH: 1531 1542 ret = stringLength(v, 8, 1); 1543 break; 1544 1545 case fnPI: 1546 1557 ret = new ValueDouble(Math.PI); 1558 break; 1559 1560 case fnPOWER: 1561 1572 if (Value.isNull(v) || Value.isNull(values.item(2))) { 1573 ret = ValueNull.valueNull; 1574 } else { 1575 double x = toNumber(v).doubleValue(); 1576 double y = toNumber(values.item(2)).doubleValue(); 1577 double res = Math.pow(x, y); 1578 if ((int)res == res) { 1579 ret = new ValueInteger((int)res); 1580 } else if ((long)res == res) { 1581 ret = new ValueLong((long)res); 1582 } else { 1583 ret = new ValueDouble(res); 1584 } 1585 } 1586 break; 1587 1588 case fnQUARTER: 1589 1601 ret = getTimeComponent(v, Calendar.MONTH, 0, false); 1602 ret = new ValueInteger(((((ValueInteger)ret).intValue()-1)/3)*4+1); 1603 break; 1604 1605 case fnRADIANS: 1606 1616 if (Value.isNull(v)) { 1617 ret = v; 1618 } else { 1619 ret = new ValueDouble( 1620 Math.toRadians(toNumber(v).doubleValue()) 1621 ); 1622 } 1623 break; 1624 1625 case fnRAND: 1626 1640 if (values.size() > 0) { 1641 if (Value.isNull(v)) { 1642 ret = ValueNull.valueNull; 1643 } else { 1644 Random r = session.getRandom(); 1645 r.setSeed(toNumber(v).longValue()); 1646 ret = new ValueDouble(r.nextDouble()); 1647 } 1648 } else { 1649 ret = new ValueDouble(session.getRandom().nextDouble()); 1650 } 1651 break; 1652 1653 case fnREPEAT: 1654 1665 if (Value.isNull(v) || Value.isNull(values.item(2))) { 1666 ret = ValueNull.valueNull; 1667 } else { 1668 String s = getString(values, 1).stringValue(); 1669 int cnt = getNumber(values, 2).intValue(); 1670 StringBuffer sb = new StringBuffer (); 1671 while (cnt-- > 0) { 1672 sb.append(s); 1673 } 1674 ret = new ValueString(sb.toString()); 1675 } 1676 break; 1677 1678 case fnREPLACE: 1679 1691 if (Value.isNull(v) || Value.isNull(values.item(2)) || 1692 Value.isNull(values.item(3))) { 1693 ret = ValueNull.valueNull; 1694 } else { 1695 String s1 = getString(values, 1).stringValue(); 1696 String s2 = getString(values, 2).stringValue(); 1697 String s3 = getString(values, 3).stringValue(); 1698 StringBuffer sb = new StringBuffer (); 1699 int start = 0; 1700 while (start < s1.length()) { 1701 int pos = s1.indexOf(s2, start); 1702 if (pos < 0) { 1703 sb.append(s1.substring(start)); 1704 start = s1.length(); 1705 } else { 1706 sb.append(s1.substring(start, pos)); 1707 sb.append(s3); 1708 start = pos + s2.length(); 1709 } 1710 } 1711 return new ValueString(sb.toString()); 1712 } 1713 break; 1714 1715 case fnRIGHT: 1716 1729 if (Value.isNull(v) || Value.isNull(values.item(2))) { 1730 ret = ValueNull.valueNull; 1731 } else { 1732 String s = getString(values, 1).stringValue(); 1733 int count = getNumber(values, 2).intValue(); 1734 ret = new ValueString(s.substring(s.length() - count)); 1735 } 1736 break; 1737 1738 case fnROUND: 1739 1751 if (Value.isNull(v) || Value.isNull(values.item(2))) { 1752 ret = ValueNull.valueNull; 1753 } else { 1754 ValueScaledInteger si = 1755 (ValueScaledInteger)v.convert(TypeDecimal.typeDecimal); 1756 BigDecimal d = (BigDecimal )si.asJavaObject(); 1757 int scale = getNumber(values, 2).intValue(); 1758 d = d.setScale(scale, BigDecimal.ROUND_HALF_DOWN); 1759 ret = new ValueScaledInteger(d); 1760 } 1761 break; 1762 1763 case fnRTRIM: 1764 1775 if (Value.isNull(v)) { 1776 ret = v; 1777 } else { 1778 String s = getString(values, 1).stringValue(); 1779 int i = s.length() - 1; 1780 while (i > 0 && Character.isWhitespace(s.charAt(i))) { 1781 i--; 1782 } 1783 if (i < s.length() - 1) s = s.substring(0, i + 1); 1784 ret = new ValueString(s); 1785 } 1786 break; 1787 1788 case fnSECOND: 1789 1801 ret = getTimeComponent(v, Calendar.SECOND, 0, true); 1802 break; 1803 1804 case fnSIGN: 1805 1816 if (Value.isNull(v)) { 1817 ret = v; 1818 } else { 1819 double d = toNumber(v).doubleValue(); 1820 int sign = 0; 1821 if (d != 0) { 1822 if (d > 0) sign = 1; 1823 else sign = -1; 1824 } 1825 ret = new ValueInteger(sign); 1826 } 1827 break; 1828 1829 case fnSIN: 1830 1841 if (Value.isNull(v)) { 1842 ret = v; 1843 } else { 1844 ret = new ValueDouble(Math.sin(toNumber(v).doubleValue())); 1845 } 1846 break; 1847 1848 case fnSOUNDEX: 1849 1860 { 1861 String s = getString(values, 1).stringValue(); 1862 ret = new ValueString(Soundex.soundex(s)); 1863 break; 1864 } 1865 1866 case fnSPACE: 1867 1878 if (Value.isNull(v)) { 1879 ret = ValueNull.valueNull; 1880 } else { 1881 int count = toNumber(v).intValue(); 1882 StringBuffer sb = new StringBuffer (); 1883 while (count-- > 0) sb.append(' '); 1884 ret = new ValueString(sb.toString()); 1885 } 1886 break; 1887 1888 case fnSQRT: 1889 1899 if (Value.isNull(v)) { 1900 ret = v; 1901 } else { 1902 ret = new ValueDouble(Math.sqrt(toNumber(v).doubleValue())); 1903 } 1904 break; 1905 1906 case fnSUBSTRING: 1907 1923 if (Value.isNull(v) || Value.isNull(values.item(2)) || 1924 (values.size() > 2 && Value.isNull(values.item(3)))) { 1925 ret = ValueNull.valueNull; 1926 } else { 1927 String s = getString(values, 1).stringValue(); 1928 int len = s.length(); 1929 int end = len; 1930 int start = getNumber(values, 2).intValue() - 1; 1931 if (values.size() > 2) { 1932 end = start + getNumber(values, 3).intValue(); 1933 } 1934 if (end < start) { 1935 throw new SQLException ("SUBSTRING error, string = '" + 1936 s + "', length = " + s.length() + 1937 ", start = " + start + 1938 ", end = " + end); 1939 } 1940 if (start >= len || end < 0) { 1941 s = ""; 1942 } else { 1943 if (start < 0) start = 0; 1944 if (end > len) end = len; 1945 s = s.substring(start, end); 1946 } 1947 ret = new ValueString(s); 1948 } 1949 break; 1950 1951 case fnTAN: 1952 1963 if (Value.isNull(v)) { 1964 ret = v; 1965 } else { 1966 ret = new ValueDouble(Math.tan(toNumber(v).doubleValue())); 1967 } 1968 break; 1969 1970 case fnTIMESTAMPADD: 1971 1999 if (Value.isNull(v) || Value.isNull(values.item(2)) || 2000 Value.isNull(values.item(3))) { 2001 ret = ValueNull.valueNull; 2002 } else { 2003 int itype = toNumber(v).intValue(); 2004 int count = toNumber(values.item(2)).intValue(); 2005 Timestamp t = getTimestamp(values.item(3), "TIMESTAMPADD"); 2006 Calendar c = Calendar.getInstance(); 2007 c.setTime(t); 2008 if (itype >= 0) { 2009 c.add(itype, count); 2010 t.setTime(c.getTime().getTime()); 2011 } else switch (itype) { 2012 case TSI_FRAC_SECOND: 2013 t.setNanos(t.getNanos() + count); 2014 break; 2015 case TSI_QUARTER: 2016 c.add(Calendar.MONTH, count*3); 2017 t.setTime(c.getTime().getTime()); 2018 break; 2019 } 2020 return new ValueTimestamp(t); 2021 2022 } 2023 break; 2024 2025 case fnTIMESTAMPDIFF: 2026 2054 if (Value.isNull(v) || Value.isNull(values.item(2)) || 2055 Value.isNull(values.item(3))) { 2056 ret = ValueNull.valueNull; 2057 } else { 2058 int itype = toNumber(v).intValue(); 2059 Timestamp t1 = getTimestamp(values.item(2), "TIMESTAMPDIFF"); 2060 Timestamp t2 = getTimestamp(values.item(3), "TIMESTAMPDIFF"); 2061 long secdiff = t2.getTime() / 1000 - t1.getTime() / 1000; 2062 long nanodiff = t2.getNanos() - t1.getNanos(); 2063 int monthdiff = getMonths(t2) - getMonths(t1); 2064 long diff; 2065 switch (itype) { 2066 case TSI_FRAC_SECOND: 2067 diff = secdiff * 1000000000L + nanodiff; 2068 break; 2069 case TSI_SECOND: 2070 diff = secdiff; 2071 break; 2072 case TSI_MINUTE: 2073 diff = secdiff / 60; 2074 break; 2075 case TSI_HOUR: 2076 diff = secdiff / 3600; 2077 break; 2078 case TSI_DAY: 2079 diff = secdiff / (3600*24); 2080 break; 2081 case TSI_WEEK: 2082 diff = secdiff / (3600*24*7); 2083 break; 2084 case TSI_MONTH: 2085 diff = monthdiff; 2086 break; 2087 case TSI_QUARTER: 2088 diff = monthdiff / 3; 2089 break; 2090 case TSI_YEAR: 2091 diff = monthdiff / 12; 2092 break; 2093 default: 2094 throw new SQLException ("Bad argument to TIMESTAMPDIFF"); 2095 } 2096 ret = new ValueLong(diff); 2097 } 2098 break; 2099 2100 case fnTRUNCATE: 2101 2113 if (Value.isNull(v) || Value.isNull(values.item(2))) { 2114 ret = ValueNull.valueNull; 2115 } else { 2116 ValueScaledInteger si = 2117 (ValueScaledInteger)v.convert(TypeDecimal.typeDecimal); 2118 BigDecimal d = (BigDecimal )si.asJavaObject(); 2119 int scale = getNumber(values, 2).intValue(); 2120 d = d.setScale(scale, BigDecimal.ROUND_DOWN); 2121 ret = new ValueScaledInteger(d); 2122 } 2123 break; 2124 2125 case fnUPPER: 2126 2139 if (Value.isNull(v)) { 2140 ret = v; 2141 } else { 2142 String s = getString(values, 1).stringValue(); 2143 ret = new ValueString(s.toUpperCase()); 2144 } 2145 break; 2146 2147 case fnUSER: 2148 2159 ret = new ValueString(session.getConnection().getAuth()); 2160 break; 2161 2162 case fnWEEK: 2163 2174 ret = getTimeComponent(v, Calendar.WEEK_OF_YEAR, 0, false); 2175 break; 2176 2177 case fnYEAR: 2178 2189 ret = getTimeComponent(v, Calendar.YEAR, 0, false); 2190 break; 2191 2192 case fnDIGEST: 2193 2205 if (!Value.isNull(v)) { 2206 String algorithm = "SHA"; 2207 if (values.size() > 1) { 2208 algorithm = getString(values, 1).stringValue(); 2209 } 2210 try { 2211 MessageDigest md = MessageDigest.getInstance(algorithm); 2212 byte[] b = md.digest(Value.bytes(v)); 2213 ret = new ValueOctets(b); 2214 } catch (Exception e) { 2215 throw new ValueException(e.toString()); 2216 } 2217 } 2218 break; 2219 2220 case fnLAST_INSERT_ID: 2221 2233 ret = new ValueLong(session.getLastInsertId()); 2234 break; 2235 2236 default: 2237 throw new SQLException ("scalar function not implemented: " + name); 2238 } 2239 if (ret == null) { 2240 throw new SQLException ("undefined function: " + name); 2241 } 2242 return ret; 2243 } 2244 2245 public Type getType(Session session, Cursor cursor) throws SQLException { 2246 Integer fi = (Integer )functions.get(uname); 2247 Expression e1 = args.size() > 0 ? args.get(0) : null; 2248 Type t = e1 != null ? e1.getType(session, cursor) : TypeAny.any; 2249 if (fi != null) switch (fi.intValue()) { 2250 case fnABS: 2251 break; 2252 2253 case fnASCII: 2254 case fnBIT_LENGTH: 2255 case fnCEILING: 2256 case fnCHAR_LENGTH: 2257 case fnDAYOFMONTH: 2258 case fnDAYOFWEEK: 2259 case fnDAYOFYEAR: 2260 case fnDIFFERENCE: 2261 case fnHOUR: 2262 case fnLENGTH: 2263 case fnLOCATE: 2264 case fnMINUTE: 2265 case fnMONTH: 2266 case fnOCTET_LENGTH: 2267 case fnQUARTER: 2268 case fnSECOND: 2269 case fnSIGN: 2270 case fnWEEK: 2271 case fnYEAR: 2272 t = TypeInt.typeInt; 2273 break; 2274 2275 case fnACOS: 2276 case fnASIN: 2277 case fnATAN: 2278 case fnATAN2: 2279 case fnCOS: 2280 case fnCOT: 2281 case fnDEGREES: 2282 case fnEXP: 2283 case fnFLOOR: 2284 case fnLOG: 2285 case fnLOG10: 2286 case fnPI: 2287 case fnPOWER: 2288 case fnRADIANS: 2289 case fnRAND: 2290 case fnSIN: 2291 case fnSQRT: 2292 case fnTAN: 2293 t = TypeReal.typeDouble; 2294 break; 2295 2296 case fnCASE: 2297 t = null; 2298 if ((args.size() % 2) == 1) { 2299 t = args.get(args.size() - 1).getType(session, cursor); 2300 } 2301 for (int i = 1; i < args.size(); i += 2) { 2302 Expression e = args.get(i); 2303 Type et = e.getType(session, cursor); 2304 if (t == null) { 2305 t = et; 2306 } else if (t.getJDBCType() != et.getJDBCType()) { 2307 t = TypeAny.any; 2308 } 2309 } 2310 break; 2311 2312 case fnCAST: 2313 t = args.get(1).getType(session, cursor); 2314 break; 2315 2316 case fnCHAR: 2317 case fnCONCAT: 2318 case fnDATABASE: 2319 case fnDAYNAME: 2320 case fnINSERT: 2321 case fnLEFT: 2322 case fnLOWER: 2323 case fnLTRIM: 2324 case fnMONTHNAME: 2325 case fnREPEAT: 2326 case fnREPLACE: 2327 case fnRIGHT: 2328 case fnRTRIM: 2329 case fnSOUNDEX: 2330 case fnSPACE: 2331 case fnSUBSTRING: 2332 case fnUPPER: 2333 case fnUSER: 2334 t = TypeVarChar.typeVarChar; 2335 break; 2336 2337 case fnCOALESCE: 2338 t = TypeAny.any; 2339 break; 2340 2341 case fnCURDATE: 2342 t = TypeDate.typeDate; 2343 break; 2344 2345 case fnCURTIME: 2346 t = TypeTime.typeTime; 2347 break; 2348 2349 case fnIFNULL: 2350 case fnNULLIF: 2351 break; 2353 2354 case fnMOD: 2355 case fnTIMESTAMPDIFF: 2356 case fnLAST_INSERT_ID: 2357 t = TypeBigInt.typeBigInt; 2358 break; 2359 2360 case fnNOW: 2361 case fnTIMESTAMPADD: 2362 t = TypeTimestamp.typeTimestamp; 2363 break; 2364 2365 case fnROUND: 2366 case fnTRUNCATE: 2367 t = TypeDecimal.typeDecimal; 2368 break; 2369 2370 case fnDIGEST: 2371 t = TypeVarBinary.typeVarBinary; 2372 break; 2373 2374 default: 2375 throw new SQLException ("scalar function not implemented: " + name); 2376 } 2377 return t; 2378 } 2379 2380 public void visitSubExpressions(ExpressionVisitor ev) { 2381 args.visitSubExpressions(ev); 2382 } 2383 2384 public String toString() { 2385 StringBuffer sb = new StringBuffer (name); 2386 sb.append('('); 2387 sb.append(args.toString()); 2388 sb.append(')'); 2389 return sb.toString(); 2390 } 2391 2392 public void readExternal(ObjectInput in) 2393 throws IOException , ClassNotFoundException 2394 { 2395 name = (String )in.readObject(); 2396 uname = name.toUpperCase(); 2397 args = (VectorExpression)in.readObject(); 2398 not = in.read() == 1; 2399 } 2400 2401 public void writeExternal(ObjectOutput out) throws IOException { 2402 out.writeObject(name); 2403 out.writeObject(args); 2404 out.write(not ? 1 : 0); 2405 } 2406} 2407 | Popular Tags |