0001: /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
0002: * All rights reserved.
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * Redistributions of source code must retain the above copyright notice, this
0008: * list of conditions and the following disclaimer.
0009: *
0010: * Redistributions in binary form must reproduce the above copyright notice,
0011: * this list of conditions and the following disclaimer in the documentation
0012: * and/or other materials provided with the distribution.
0013: *
0014: * Neither the name of the Hypersonic SQL Group nor the names of its
0015: * contributors may be used to endorse or promote products derived from this
0016: * software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
0022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029: *
0030: * This software consists of voluntary contributions made by many individuals
0031: * on behalf of the Hypersonic SQL Group.
0032: *
0033: *
0034: * For work added by the HSQL Development Group:
0035: *
0036: * Copyright (c) 2001-2005, The HSQL Development Group
0037: * All rights reserved.
0038: *
0039: * Redistribution and use in source and binary forms, with or without
0040: * modification, are permitted provided that the following conditions are met:
0041: *
0042: * Redistributions of source code must retain the above copyright notice, this
0043: * list of conditions and the following disclaimer.
0044: *
0045: * Redistributions in binary form must reproduce the above copyright notice,
0046: * this list of conditions and the following disclaimer in the documentation
0047: * and/or other materials provided with the distribution.
0048: *
0049: * Neither the name of the HSQL Development Group nor the names of its
0050: * contributors may be used to endorse or promote products derived from this
0051: * software without specific prior written permission.
0052: *
0053: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0054: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0055: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0056: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
0057: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0058: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0059: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0060: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0061: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0062: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0063: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0064: */
0065:
0066: package org.hsqldb;
0067:
0068: import java.sql.Connection;
0069: import java.sql.Date;
0070: import java.sql.Time;
0071: import java.sql.Timestamp;
0072: import java.text.FieldPosition;
0073: import java.text.SimpleDateFormat;
0074: import java.util.Calendar;
0075: import java.util.Locale;
0076: import java.util.Random;
0077:
0078: import org.hsqldb.lib.HashMap;
0079: import org.hsqldb.lib.IntValueHashMap;
0080: import org.hsqldb.persist.HsqlDatabaseProperties;
0081: import org.hsqldb.store.ValuePool;
0082:
0083: // fredt@users 20020210 - patch 513005 by sqlbob@users (RMP) - ABS function
0084: // fredt@users 20020305 - patch 1.7.0 - change to 2D string arrays
0085: // sqlbob@users 20020420- patch 1.7.0 - added HEXTORAW and RAWTOHEX.
0086: // boucherb@user 20020918 - doc 1.7.2 - added JavaDoc and code comments
0087: // fredt@user 20021021 - doc 1.7.2 - modified JavaDoc
0088: // boucherb@users 20030201 - patch 1.7.2 - direct calls for org.hsqldb.Library
0089: // fredt@users - patch 1.8.0 - new functions added
0090:
0091: /**
0092: * fredt - todo - since the introduction of SQL built-in functions and
0093: * evaluation of several session-dependent methods outside this class,
0094: * several methods here are dummies. These methods are still reported in
0095: * system tables incorrectly as corresponding to the SQL function names.
0096: */
0097:
0098: /**
0099: * Provides the HSQLDB implementation of standard Open Group SQL CLI
0100: * <em>Extended Scalar Functions</em> and other public HSQLDB SQL functions.<p>
0101: *
0102: * All methods here that have a Connection parameter are dummies and should
0103: * not be called from user supplied Java procedure or trigger code. Use real
0104: * SQL functions should be called instead in these instances.
0105: *
0106: * Extensively rewritten and extended in successive versions of HSQLDB.
0107: *
0108: * @author Thomas Mueller (Hypersonic SQL Group)
0109: * @version 1.8.0
0110: * @since Hypersonic SQL
0111: */
0112: public class Library {
0113:
0114: static final SimpleDateFormat tocharFormat = new SimpleDateFormat();
0115: static final SimpleDateFormat daynameFormat = new SimpleDateFormat(
0116: "EEEE", Locale.ENGLISH);
0117: static final SimpleDateFormat monthnameFormat = new SimpleDateFormat(
0118: "MMMM", Locale.ENGLISH);
0119: static final StringBuffer daynameBuffer = new StringBuffer();
0120: static final StringBuffer monthnameBuffer = new StringBuffer();
0121: static final FieldPosition monthPosition = new FieldPosition(
0122: SimpleDateFormat.MONTH_FIELD);
0123: static final FieldPosition dayPosition = new FieldPosition(
0124: SimpleDateFormat.DAY_OF_WEEK_FIELD);
0125: public static final String[][] sNumeric = {
0126: { "ABS", "org.hsqldb.Library.abs" },
0127: { "ACOS", "java.lang.Math.acos" },
0128: { "ASIN", "java.lang.Math.asin" },
0129: { "ATAN", "java.lang.Math.atan" },
0130: { "ATAN2", "java.lang.Math.atan2" },
0131: { "CEILING", "java.lang.Math.ceil" },
0132: { "COS", "java.lang.Math.cos" },
0133: { "COT", "org.hsqldb.Library.cot" },
0134: { "DEGREES", "java.lang.Math.toDegrees" },
0135: { "EXP", "java.lang.Math.exp" },
0136: { "FLOOR", "java.lang.Math.floor" },
0137: { "LOG", "java.lang.Math.log" },
0138: { "LOG10", "org.hsqldb.Library.log10" },
0139: { "MOD", "org.hsqldb.Library.mod" },
0140: { "PI", "org.hsqldb.Library.pi" },
0141: { "POWER", "java.lang.Math.pow" },
0142: { "RADIANS", "java.lang.Math.toRadians" },
0143: { "RAND", "java.lang.Math.random" },
0144: { "ROUND", "org.hsqldb.Library.round" },
0145: { "SIGN", "org.hsqldb.Library.sign" },
0146: { "SIN", "java.lang.Math.sin" },
0147: { "SQRT", "java.lang.Math.sqrt" },
0148: { "TAN", "java.lang.Math.tan" },
0149: { "TRUNCATE", "org.hsqldb.Library.truncate" },
0150: { "BITAND", "org.hsqldb.Library.bitand" },
0151: { "BITOR", "org.hsqldb.Library.bitor" },
0152: { "BITXOR", "org.hsqldb.Library.bitxor" },
0153: { "ROUNDMAGIC", "org.hsqldb.Library.roundMagic" } };
0154:
0155: // fredt@users 20010701 - patch 418023 by deforest@users
0156: // the definition for SUBSTR was added
0157: public static final String[][] sString = {
0158: { "ASCII", "org.hsqldb.Library.ascii" },
0159: { "BIT_LENGTH", "org.hsqldb.Library.bitLength" },
0160: { "CHAR", "org.hsqldb.Library.character" },
0161: { "CHAR_LENGTH", "org.hsqldb.Library.length" },
0162: { "CHARACTER_LENGTH", "org.hsqldb.Library.length" },
0163: { "CONCAT", "org.hsqldb.Library.concat" },
0164: { "DIFFERENCE", "org.hsqldb.Library.difference" },
0165: { "HEXTORAW", "org.hsqldb.Library.hexToRaw" },
0166: { "INSERT", "org.hsqldb.Library.insert" },
0167: { "LCASE", "org.hsqldb.Library.lcase" },
0168: { "LEFT", "org.hsqldb.Library.left" },
0169: { "LENGTH", "org.hsqldb.Library.length" },
0170: { "LOCATE", "org.hsqldb.Library.locate" },
0171: { "LTRIM", "org.hsqldb.Library.ltrim" },
0172: { "OCTET_LENGTH", "org.hsqldb.Library.octetLength" },
0173: { "RAWTOHEX", "org.hsqldb.Library.rawToHex" },
0174: { "REPEAT", "org.hsqldb.Library.repeat" },
0175: { "REPLACE", "org.hsqldb.Library.replace" },
0176: { "RIGHT", "org.hsqldb.Library.right" },
0177: { "RTRIM", "org.hsqldb.Library.rtrim" },
0178: { "SOUNDEX", "org.hsqldb.Library.soundex" },
0179: { "SPACE", "org.hsqldb.Library.space" },
0180: { "SUBSTR", "org.hsqldb.Library.substring" },
0181: { "SUBSTRING", "org.hsqldb.Library.substring" },
0182: { "UCASE", "org.hsqldb.Library.ucase" },
0183: { "LOWER", "org.hsqldb.Library.lcase" },
0184: { "UPPER", "org.hsqldb.Library.ucase" } };
0185: public static final String[][] sTimeDate = {
0186: { "CURDATE", "org.hsqldb.Library.curdate" },
0187: { "CURTIME", "org.hsqldb.Library.curtime" },
0188: { "DATEDIFF", "org.hsqldb.Library.datediff" },
0189: { "DAYNAME", "org.hsqldb.Library.dayname" },
0190: { "DAY", "org.hsqldb.Library.dayofmonth" },
0191: { "DAYOFMONTH", "org.hsqldb.Library.dayofmonth" },
0192: { "DAYOFWEEK", "org.hsqldb.Library.dayofweek" },
0193: { "DAYOFYEAR", "org.hsqldb.Library.dayofyear" },
0194: { "HOUR", "org.hsqldb.Library.hour" },
0195: { "MINUTE", "org.hsqldb.Library.minute" },
0196: { "MONTH", "org.hsqldb.Library.month" },
0197: { "MONTHNAME", "org.hsqldb.Library.monthname" },
0198: { "NOW", "org.hsqldb.Library.now" },
0199: { "QUARTER", "org.hsqldb.Library.quarter" },
0200: { "SECOND", "org.hsqldb.Library.second" },
0201: { "WEEK", "org.hsqldb.Library.week" },
0202: { "YEAR", "org.hsqldb.Library.year" },
0203: { "TO_CHAR", "org.hsqldb.Library.to_char" } };
0204: public static final String[][] sSystem = {
0205: { "DATABASE", "org.hsqldb.Library.database" },
0206: { "USER", "org.hsqldb.Library.user" },
0207: { "IDENTITY", "org.hsqldb.Library.identity" } };
0208:
0209: private Library() {
0210: }
0211:
0212: static HashMap getAliasMap() {
0213:
0214: HashMap h = new HashMap(83, 1);
0215:
0216: register(h, sNumeric);
0217: register(h, sString);
0218: register(h, sTimeDate);
0219: register(h, sSystem);
0220:
0221: return h;
0222: }
0223:
0224: private static void register(HashMap h, String[][] s) {
0225:
0226: for (int i = 0; i < s.length; i++) {
0227: h.put(s[i][0], s[i][1]);
0228: }
0229: }
0230:
0231: private static final Random rRandom = new Random();
0232:
0233: // NUMERIC FUNCTIONS
0234: // fredt@users 20020220 - patch 489184 by xclayl@users - thread safety
0235:
0236: /**
0237: * Returns the next pseudorandom, uniformly distributed <code>double</code> value
0238: * between 0.0 and 1.0 from a single, system-wide random number generator's
0239: * sequence, optionally re-seeding (and thus resetting) the generator sequence.
0240: *
0241: * If the seed value is <code>null</code>, then the underlying random number
0242: * generator retrieves the next value in its current sequence, else the seed
0243: * alters the state of the generator object so as to be in exactly the same state
0244: * as if it had just been created with the seed value.
0245: * @param seed an optional parameter with which to reseed the underlying
0246: * pseudorandom number generator
0247: * @return the next pseudorandom, uniformly distributed <code>double</code> value between
0248: * 0.0 and 1.0
0249: */
0250: public static double rand(Integer seed) {
0251:
0252: // boucherb@users 20020918
0253: // CHECKME: perhaps rRandom should be a member of Session,
0254: // since otherwise connections are *not* guranteed to get the
0255: // same pseudorandom sequence, given the same set of calls to this
0256: // SQL function. This makes comparitive analysis difficult.
0257: // In fact, rRandom will be shared across multiple in-process
0258: // database instances, so it is not even guaranteed that the
0259: // sole connection to one instance will get the same sequence given
0260: // the same set of calls to this SQL function.
0261: synchronized (rRandom) {
0262: if (seed != null) {
0263: rRandom.setSeed(seed.intValue());
0264: }
0265:
0266: return rRandom.nextDouble();
0267: }
0268: }
0269:
0270: /**
0271: * Returns the absolute value of the given <code>double</code> value.
0272: * @param d the number for which to determine the absolute value
0273: * @return the absolute value of <code>d</code>, as a <code>double</code>
0274: */
0275: public static double abs(double d) {
0276: return Math.abs(d);
0277: }
0278:
0279: // this magic number works for 100000000000000; but not for 0.1 and 0.01
0280: private static final double LOG10_FACTOR = 0.43429448190325183;
0281:
0282: /**
0283: * Returns the base 10 logarithm of the given <code>double</code> value.
0284: * @param x the value for which to calculate the base 10 logarithm
0285: * @return the base 10 logarithm of <code>x</code>, as a <code>double</code>
0286: */
0287: public static double log10(double x) {
0288: return roundMagic(Math.log(x) * LOG10_FACTOR);
0289: }
0290:
0291: /**
0292: * Retrieves a <em>magically</em> rounded </code>double</code> value produced
0293: * from the given <code>double</code> value. This method provides special
0294: * handling for numbers close to zero and performs rounding only for
0295: * numbers within a specific range, returning precisely the given value
0296: * if it does not lie in this range. <p>
0297: *
0298: * Special handling includes: <p>
0299: *
0300: * <UL>
0301: * <LI> input in the interval -0.0000000000001..0.0000000000001 returns 0.0
0302: * <LI> input outside the interval -1000000000000..1000000000000 returns
0303: * input unchanged
0304: * <LI> input is converted to String form
0305: * <LI> input with a <code>String</code> form length greater than 16 returns
0306: * input unchaged
0307: * <LI> <code>String</code> form with last four characters of '...000x' where
0308: * x != '.' is converted to '...0000'
0309: * <LI> <code>String</code> form with last four characters of '...9999' is
0310: * converted to '...999999'
0311: * <LI> the <code>java.lang.Double.doubleValue</code> of the <code>String</code>
0312: * form is returned
0313: * </UL>
0314: * @param d the double value for which to retrieve the <em>magically</em>
0315: * rounded value
0316: * @return the <em>magically</em> rounded value produced
0317: */
0318: public static double roundMagic(double d) {
0319:
0320: // this function rounds numbers in a good way but slow:
0321: // - special handling for numbers around 0
0322: // - only numbers <= +/-1000000000000
0323: // - convert to a string
0324: // - check the last 4 characters:
0325: // '000x' becomes '0000'
0326: // '999x' becomes '999999' (this is rounded automatically)
0327: if ((d < 0.0000000000001) && (d > -0.0000000000001)) {
0328: return 0.0;
0329: }
0330:
0331: if ((d > 1000000000000.) || (d < -1000000000000.)) {
0332: return d;
0333: }
0334:
0335: StringBuffer s = new StringBuffer();
0336:
0337: s.append(d);
0338:
0339: int len = s.length();
0340:
0341: if (len < 16) {
0342: return d;
0343: }
0344:
0345: char cx = s.charAt(len - 1);
0346: char c1 = s.charAt(len - 2);
0347: char c2 = s.charAt(len - 3);
0348: char c3 = s.charAt(len - 4);
0349:
0350: if ((c1 == '0') && (c2 == '0') && (c3 == '0') && (cx != '.')) {
0351: s.setCharAt(len - 1, '0');
0352: } else if ((c1 == '9') && (c2 == '9') && (c3 == '9')
0353: && (cx != '.')) {
0354: s.setCharAt(len - 1, '9');
0355: s.append('9');
0356: s.append('9');
0357: }
0358:
0359: return Double.valueOf(s.toString()).doubleValue();
0360: }
0361:
0362: /**
0363: * Returns the cotangent of the given <code>double</code> value
0364: * expressed in radians.
0365: * @param d the angle, expressed in radians
0366: * @return the cotangent
0367: */
0368: public static double cot(double d) {
0369: return 1. / Math.tan(d);
0370: }
0371:
0372: /**
0373: * Returns the remainder (modulus) of the first given integer divided
0374: * by the second. <p>
0375: *
0376: * @param i1 the numerator
0377: * @param i2 the divisor
0378: * @return <code>i1</code> % <code>i2</code>, as an <code>int</code>
0379: */
0380: public static int mod(int i1, int i2) {
0381: return i1 % i2;
0382: }
0383:
0384: /**
0385: * Returns the constant value, pi.
0386: * @return pi as a <code>double</code> value
0387: */
0388: public static double pi() {
0389: return Math.PI;
0390: }
0391:
0392: /**
0393: * Returns the given <code>double</code> value, rounded to the given
0394: * <code>int</code> places right of the decimal point. If
0395: * the supplied rounding place value is negative, rounding is performed
0396: * to the left of the decimal point, using its magnitude (absolute value).
0397: * @param d the value to be rounded
0398: * @param p the rounding place value
0399: * @return <code>d</code> rounded
0400: */
0401: public static double round(double d, int p) {
0402:
0403: double f = Math.pow(10., p);
0404:
0405: return Math.round(d * f) / f;
0406: }
0407:
0408: /**
0409: * Returns an indicator of the sign of the given <code>double</code>
0410: * value. If the value is less than zero, -1 is returned. If the value
0411: * equals zero, 0 is returned. If the value is greater than zero, 1 is
0412: * returned.
0413: * @param d the value
0414: * @return the sign of <code>d</code>
0415: */
0416: public static int sign(double d) {
0417:
0418: return (d < 0) ? -1 : ((d > 0) ? 1 : 0);
0419: }
0420:
0421: /**
0422: * Returns the given <code>double</code> value, truncated to
0423: * the given <code>int</code> places right of the decimal point.
0424: * If the given place value is negative, the given <code>double</code>
0425: * value is truncated to the left of the decimal point, using the
0426: * magnitude (aboslute value) of the place value.
0427: * @param d the value to truncate
0428: * @param p the places left or right of the decimal point at which to
0429: * truncate
0430: * @return <code>d</code>, truncated
0431: */
0432: public static double truncate(double d, int p) {
0433:
0434: double f = Math.pow(10., p);
0435: double g = d * f;
0436:
0437: return ((d < 0) ? Math.ceil(g) : Math.floor(g)) / f;
0438: }
0439:
0440: /**
0441: * Returns the bit-wise logical <em>and</em> of the given
0442: * integer values.
0443: * @param i the first value
0444: * @param j the second value
0445: * @return the bit-wise logical <em>and</em> of
0446: * <code>i</code> and <code>j</code>
0447: */
0448: public static int bitand(int i, int j) {
0449: return i & j;
0450: }
0451:
0452: /**
0453: * Returns the bit-wise logical <em>or</em> of the given
0454: * integer values.
0455: *
0456: * @param i the first value
0457: * @param j the second value
0458: * @return the bit-wise logical <em>or</em> of
0459: * <code>i</code> and <code>j</code>
0460: */
0461: public static int bitor(int i, int j) {
0462: return i | j;
0463: }
0464:
0465: /**
0466: * Returns the bit-wise logical <em>xor</em> of the given
0467: * integer values.
0468: *
0469: * @param i the first value
0470: * @param j the second value
0471: * @return the bit-wise logical <em>xor</em> of
0472: * <code>i</code> and <code>j</code>
0473: *
0474: * @since 1.8.0
0475: */
0476: public static int bitxor(int i, int j) {
0477: return i ^ j;
0478: }
0479:
0480: // STRING FUNCTIONS
0481:
0482: /**
0483: * Returns the Unicode code value of the leftmost character of
0484: * <code>s</code> as an <code>int</code>. This is the same as the
0485: * ASCII value if the string contains only ASCII characters.
0486: * @param s the <code>String</code> to evaluate
0487: * @return the integer Unicode value of the
0488: * leftmost character
0489: */
0490: public static Integer ascii(String s) {
0491:
0492: if ((s == null) || (s.length() == 0)) {
0493: return null;
0494: }
0495:
0496: return ValuePool.getInt(s.charAt(0));
0497: }
0498:
0499: /**
0500: * Returns the character string corresponding to the given ASCII
0501: * (or Unicode) value.
0502: *
0503: * <b>Note:</b> <p>
0504: *
0505: * In some SQL CLI
0506: * implementations, a <code>null</code> is returned if the range is outside 0..255.
0507: * In HSQLDB, the corresponding Unicode character is returned
0508: * unchecked.
0509: * @param code the character code for which to return a String
0510: * representation
0511: * @return the String representation of the character
0512: */
0513: public static String character(int code) {
0514: return String.valueOf((char) code);
0515: }
0516:
0517: /**
0518: * Returns a <code>String</code> object that is the result of an
0519: * concatenation of the given <code>String</code> objects. <p>
0520: *
0521: * <b>When only one string is NULL, the result is different from that
0522: * returned by an (string1 || string2) expression:
0523: *
0524: * <UL>
0525: * <LI> if both <code>String</code> objects are <code>null</code>, return
0526: * <code>null</code>
0527: * <LI> if only one string is <code>null</code>, return the other
0528: * <LI> if both <code>String</code> objects are non-null, return as a
0529: * <code>String</code> object the character sequence obtained by listing,
0530: * in left to right order, the characters of the first string followed by
0531: * the characters of the second
0532: * </UL>
0533: * @param s1 the first <code>String</code>
0534: * @param s2 the second <code>String</code>
0535: * @return <code>s1</code> concatentated with <code>s2</code>
0536: */
0537: public static String concat(String s1, String s2) {
0538:
0539: if (s1 == null) {
0540: if (s2 == null) {
0541: return null;
0542: }
0543:
0544: return s2;
0545: }
0546:
0547: if (s2 == null) {
0548: return s1;
0549: }
0550:
0551: return s1.concat(s2);
0552: }
0553:
0554: /**
0555: * Returns a count of the characters that do not match when comparing
0556: * the 4 digit numeric SOUNDEX character sequences for the
0557: * given <code>String</code> objects. If either <code>String</code> object is
0558: * <code>null</code>, zero is returned.
0559: * @param s1 the first <code>String</code>
0560: * @param s2 the second <code>String</code>
0561: * @return the number of differences between the <code>SOUNDEX</code> of
0562: * <code>s1</code> and the <code>SOUNDEX</code> of <code>s2</code>
0563: */
0564:
0565: // fredt@users 20020305 - patch 460907 by fredt - soundex
0566: public static int difference(String s1, String s2) {
0567:
0568: // todo: check if this is the standard algorithm
0569: if ((s1 == null) || (s2 == null)) {
0570: return 0;
0571: }
0572:
0573: s1 = soundex(s1);
0574: s2 = soundex(s2);
0575:
0576: int e = 0;
0577:
0578: for (int i = 0; i < 4; i++) {
0579: if (s1.charAt(i) != s2.charAt(i)) {
0580: e++;
0581: }
0582: }
0583:
0584: return e;
0585: }
0586:
0587: /**
0588: * Converts a <code>String</code> of hexidecimal digit characters to a raw
0589: * binary value, represented as a <code>String</code>.<p>
0590: *
0591: * The given <code>String</code> object must consist of a sequence of
0592: * 4 digit hexidecimal character substrings.<p> If its length is not
0593: * evenly divisible by 4, <code>null</code> is returned. If any of
0594: * its 4 character subsequences cannot be parsed as a
0595: * 4 digit, base 16 value, then a NumberFormatException is thrown.
0596: *
0597: * This conversion has the effect of reducing the character count 4:1.
0598: *
0599: * @param s a <code>String</code> of hexidecimal digit characters
0600: * @return an equivalent raw binary value, represented as a
0601: * <code>String</code>
0602: */
0603: public static String hexToRaw(String s) {
0604:
0605: if (s == null) {
0606: return null;
0607: }
0608:
0609: char raw;
0610: StringBuffer to = new StringBuffer();
0611: int len = s.length();
0612:
0613: if (len % 4 != 0) {
0614: return null;
0615: }
0616:
0617: for (int i = 0; i < len; i += 4) {
0618: raw = (char) Integer.parseInt(s.substring(i, i + 4), 16);
0619:
0620: to.append(raw);
0621: }
0622:
0623: return (to.toString());
0624: }
0625:
0626: /**
0627: * Returns a character sequence which is the result of writing the
0628: * first <code>length</code> number of characters from the second
0629: * given <code>String</code> over the first string. The start position
0630: * in the first string where the characters are overwritten is given by
0631: * <code>start</code>.<p>
0632: *
0633: * <b>Note:</b> In order of precedence, boundry conditions are handled as
0634: * follows:<p>
0635: *
0636: * <UL>
0637: * <LI>if either supplied <code>String</code> is null, then the other is
0638: * returned; the check starts with the first given <code>String</code>.
0639: * <LI>if <code>start</code> is less than one, <code>s1</code> is returned
0640: * <LI>if <code>length</code> is less than or equal to zero,
0641: * <code>s1</code> is returned
0642: * <LI>if the length of <code>s2</code> is zero, <code>s1</code> is returned
0643: * <LI>if <code>start</code> is greater than the length of <code>s1</code>,
0644: * <code>s1</code> is returned
0645: * <LI>if <code>length</code> is such that, taken together with
0646: * <code>start</code>, the indicated interval extends
0647: * beyond the end of <code>s1</code>, then the insertion is performed
0648: * precisely as if upon a copy of <code>s1</code> extended in length
0649: * to just include the indicated interval
0650: * </UL>
0651: * @param s1 the <code>String</code> into which to insert <code>s2</code>
0652: * @param start the position, with origin one, at which to start the insertion
0653: * @param length the number of characters in <code>s1</code> to replace
0654: * @param s2 the <code>String</code> to insert into <code>s1</code>
0655: * @return <code>s2</code> inserted into <code>s1</code>, as indicated
0656: * by <code>start</code> and <code>length</code> and adjusted for
0657: * boundry conditions
0658: */
0659: public static String insert(String s1, int start, int length,
0660: String s2) {
0661:
0662: if (s1 == null) {
0663: return s2;
0664: }
0665:
0666: if (s2 == null) {
0667: return s1;
0668: }
0669:
0670: int len1 = s1.length();
0671: int len2 = s2.length();
0672:
0673: start--;
0674:
0675: if (start < 0 || length <= 0 || len2 == 0 || start > len1) {
0676: return s1;
0677: }
0678:
0679: if (start + length > len1) {
0680: length = len1 - start;
0681: }
0682:
0683: return s1.substring(0, start) + s2
0684: + s1.substring(start + length);
0685: }
0686:
0687: /**
0688: * Returns a copy of the given <code>String</code>, with all upper case
0689: * characters converted to lower case. This uses the default Java String
0690: * conversion.
0691: * @param s the <code>String</code> from which to produce a lower case
0692: * version
0693: * @return a lower case version of <code>s</code>
0694: */
0695: public static String lcase(String s) {
0696: return (s == null) ? null : s.toLowerCase();
0697: }
0698:
0699: /**
0700: * Returns the leftmost <code>count</code> characters from the given
0701: * <code>String</code>. <p>
0702: *
0703: * <b>Note:</b> boundry conditions are handled in the following order of
0704: * precedence:
0705: *
0706: * <UL>
0707: * <LI> if <code>s</code> is <code>null</code>, then <code>null</code>
0708: * is returned
0709: * <LI> if <code>count</code> is less than 1, then a zero-length
0710: * <code>String</code> is returned
0711: * <LI> if <code>count</code> is greater than the length of <code>s</code>,
0712: * then a copy of <code>s</code> is returned
0713: * </UL>
0714: * @param s the <code>String</code> from which to retrieve the leftmost
0715: * characters
0716: * @param count the count of leftmost characters to retrieve
0717: * @return the leftmost <code>count</code> characters of <code>s</code>
0718: */
0719: public static String left(String s, int count) {
0720:
0721: if (s == null) {
0722: return null;
0723: }
0724:
0725: return s.substring(0, ((count < 0) ? 0
0726: : (count < s.length()) ? count : s.length()));
0727: }
0728:
0729: // fredt@users - 20020819 - patch 595854 by thomasm@users
0730:
0731: /**
0732: * Returns the number of characters in the given <code>String</code>.
0733: * This includes trailing blanks.
0734: *
0735: * @param s the <code>String</code> for which to determine length
0736: * @return the length of <code>s</code>, including trailing blanks
0737: */
0738: public static Integer length(String s) {
0739: return s == null ? null : ValuePool.getInt(s.length());
0740: }
0741:
0742: /**
0743: * Returns the number of bytes in the given <code>String</code>.
0744: * This includes trailing blanks.
0745: *
0746: * @param s the <code>String</code> for which to determine the octet length
0747: * @return the octet length of <code>s</code>, including trailing blanks
0748: * @since 1.7.2
0749: */
0750: public static Integer octetLength(String s) {
0751: return s == null ? null : ValuePool.getInt(s.length() * 2);
0752: }
0753:
0754: /**
0755: * Returns the number of bits in the given <code>String</code>.
0756: * This includes trailing blanks.
0757: *
0758: * @param s the <code>String</code> for which to determine the bit length
0759: * @return the bit length of <code>s</code>, including trailing blanks
0760: * @since 1.7.2
0761: */
0762: public static Integer bitLength(String s) {
0763: return s == null ? null : ValuePool.getInt(s.length() * 16);
0764: }
0765:
0766: /**
0767: * Returns the starting position of the first occurrence of
0768: * the given <code>search</code> <code>String</code> object within
0769: * the given <code>String</code> object, <code>s</code>.
0770: *
0771: * The search for the first occurrence of <code>search</code> begins with
0772: * the first character position in <code>s</code>, unless the optional
0773: * argument, <code>start</code>, is specified (non-null). If
0774: * <code>start</code> is specified, the search begins with the character
0775: * position indicated by the value of <code>start</code>, where the
0776: * first character position in <code>s</code> is indicated by the value 1.
0777: * If <code>search</code> is not found within <code>s</code>, the
0778: * value 0 is returned.
0779: * @param search the <code>String</code> occurence to find in <code>s</code>
0780: * @param s the <code>String</code> within which to find the first
0781: * occurence of <code>search</code>
0782: * @param start the optional character position from which to start
0783: * looking in <code>s</code>
0784: * @return the one-based starting position of the first occurrence of
0785: * <code>search</code> within <code>s</code>, or 0 if not found
0786: */
0787: public static int locate(String search, String s, Integer start) {
0788:
0789: if (s == null || search == null) {
0790: return 0;
0791: }
0792:
0793: int i = (start == null) ? 0 : start.intValue() - 1;
0794:
0795: return s.indexOf(search, (i < 0) ? 0 : i) + 1;
0796: }
0797:
0798: /**
0799: * As locate but from start position l. <p>
0800: *
0801: * @param search the <code>String</code> occurence to find in <code>s</code>
0802: * @param s the <code>String</code> within which to find the first
0803: * occurence of <code>search</code>
0804: * @return the one-based starting position of the first occurrence of
0805: * <code>search</code> within <code>s</code>, or 0 if not found
0806: */
0807: public static int position(String search, String s) {
0808: return locate(search, s, null);
0809: }
0810:
0811: /**
0812: * Returns the characters of the given <code>String</code>, with the
0813: * leading spaces removed. Characters such as TAB are not removed.
0814: *
0815: * @param s the <code>String</code> from which to remove the leading blanks
0816: * @return the characters of the given <code>String</code>, with the leading
0817: * spaces removed
0818: */
0819: public static String ltrim(String s) {
0820:
0821: if (s == null) {
0822: return s;
0823: }
0824:
0825: int len = s.length(), i = 0;
0826:
0827: while (i < len && s.charAt(i) <= ' ') {
0828: i++;
0829: }
0830:
0831: return (i == 0) ? s : s.substring(i);
0832: }
0833:
0834: /**
0835: * Converts a raw binary value, as represented by the given
0836: * <code>String</code>, to the equivalent <code>String</code>
0837: * of hexidecimal digit characters. <p>
0838: *
0839: * This conversion has the effect of expanding the character count 1:4.
0840: *
0841: * @param s the raw binary value, as a <code>String</code>
0842: * @return an equivalent <code>String</code> of hexidecimal digit characters
0843: */
0844: public static String rawToHex(String s) {
0845:
0846: if (s == null) {
0847: return null;
0848: }
0849:
0850: char[] from = s.toCharArray();
0851: String hex;
0852: StringBuffer to = new StringBuffer(4 * s.length());
0853:
0854: for (int i = 0; i < from.length; i++) {
0855: hex = Integer.toHexString(from[i] & 0xffff);
0856:
0857: for (int j = hex.length(); j < 4; j++) {
0858: to.append('0');
0859: }
0860:
0861: to.append(hex);
0862: }
0863:
0864: return (to.toString());
0865: }
0866:
0867: /**
0868: * Returns a <code>String</code> composed of the given <code>String</code>,
0869: * repeated <code>count</code> times.
0870: *
0871: * @param s the <code>String</code> to repeat
0872: * @param count the number of repetitions
0873: * @return the given <code>String</code>, repeated <code>count</code> times
0874: */
0875: public static String repeat(String s, Integer count) {
0876:
0877: if (s == null || count == null || count.intValue() < 0) {
0878: return null;
0879: }
0880:
0881: int i = count.intValue();
0882: StringBuffer b = new StringBuffer(s.length() * i);
0883:
0884: while (i-- > 0) {
0885: b.append(s);
0886: }
0887:
0888: return b.toString();
0889: }
0890:
0891: // fredt@users - 20020903 - patch 1.7.1 - bug fix to allow multiple replaces
0892:
0893: /**
0894: * Replaces all occurrences of <code>replace</code> in <code>s</code>
0895: * with the <code>String</code> object: <code>with</code>
0896: * @param s the target for replacement
0897: * @param replace the substring(s), if any, in <code>s</code> to replace
0898: * @param with the value to substitute for <code>replace</code>
0899: * @return <code>s</code>, with all occurences of <code>replace</code>
0900: * replaced by <code>with</code>
0901: */
0902: public static String replace(String s, String replace, String with) {
0903:
0904: if (s == null || replace == null) {
0905: return s;
0906: }
0907:
0908: if (with == null) {
0909: with = "";
0910: }
0911:
0912: StringBuffer b = new StringBuffer();
0913: int start = 0;
0914: int lenreplace = replace.length();
0915:
0916: while (true) {
0917: int i = s.indexOf(replace, start);
0918:
0919: if (i == -1) {
0920: b.append(s.substring(start));
0921:
0922: break;
0923: }
0924:
0925: b.append(s.substring(start, i));
0926: b.append(with);
0927:
0928: start = i + lenreplace;
0929: }
0930:
0931: return b.toString();
0932: }
0933:
0934: /**
0935: * Returns the rightmost <code>count</code> characters of the given
0936: * <code>String</code>, <code>s</code>. <p>
0937: *
0938: * <b>Note:</b> boundry conditions are handled in the following order of
0939: * precedence: <p>
0940: *
0941: * <UL>
0942: * <LI> if <code>s</code> is <code>null</code>, <code>null</code> is returned
0943: * <LI> if <code>count</code> is less than one, a zero-length
0944: * <code>String</code> is returned
0945: * <LI> if <code>count</code> is greater than the length of <code>s</code>,
0946: * a copy of <code>s</code> is returned
0947: * </UL>
0948: * @param s the <code>String</code> from which to retrieve the rightmost
0949: * <code>count</code> characters
0950: * @param count the number of rightmost characters to retrieve
0951: * @return the rightmost <code>count</code> characters of <code>s</code>
0952: */
0953: public static String right(String s, int count) {
0954:
0955: if (s == null) {
0956: return null;
0957: }
0958:
0959: count = s.length() - count;
0960:
0961: return s.substring((count < 0) ? 0
0962: : (count < s.length()) ? count : s.length());
0963: }
0964:
0965: // fredt@users 20020530 - patch 1.7.0 fredt - trim only the space character
0966:
0967: /**
0968: * Returns the characters of the given <code>String</code>, with trailing
0969: * spaces removed.
0970: * @param s the <code>String</code> from which to remove the trailing blanks
0971: * @return the characters of the given <code>String</code>, with the
0972: * trailing spaces removed
0973: */
0974: public static String rtrim(String s) {
0975:
0976: if (s == null) {
0977: return s;
0978: }
0979:
0980: int endindex = s.length() - 1;
0981: int i = endindex;
0982:
0983: for (; i >= 0 && s.charAt(i) == ' '; i--) {
0984: }
0985:
0986: return i == endindex ? s : s.substring(0, i + 1);
0987: }
0988:
0989: /**
0990: * Returns the character sequence <code>s</code>, with the leading,
0991: * trailing or both the leading and trailing occurences of the first
0992: * character of the character sequence <code>trimstr</code> removed. <p>
0993: *
0994: * This method is in support of the standard SQL String function TRIM.
0995: * Ordinarily, the functionality of this method is accessed from SQL using
0996: * the following syntax: <p>
0997: *
0998: * <pre class="SqlCodeExample">
0999: * <trim function> ::= TRIM <left paren> <trim operands> <right paren>
1000: * <trim operands> ::= [ [ <trim specification> ] [ <trim character> ] FROM ] <trim source>
1001: * <trim source> ::= <character value expression>
1002: * <trim specification> ::= LEADING | TRAILING | BOTH
1003: * <trim character> ::= <character value expression>
1004: * </pre>
1005: *
1006: * @param s the string to trim
1007: * @param trimstr the character whose occurences will be removed
1008: * @param leading if true, remove leading occurences
1009: * @param trailing if true, remove trailing occurences
1010: * @return s, with the leading, trailing or both the leading and trailing
1011: * occurences of the first character of <code>trimstr</code> removed
1012: * @since 1.7.2
1013: */
1014: public static String trim(String s, String trimstr,
1015: boolean leading, boolean trailing) {
1016:
1017: if (s == null) {
1018: return s;
1019: }
1020:
1021: int trim = trimstr.charAt(0);
1022: int endindex = s.length();
1023:
1024: if (trailing) {
1025: for (--endindex; endindex >= 0
1026: && s.charAt(endindex) == trim; endindex--) {
1027: }
1028:
1029: endindex++;
1030: }
1031:
1032: if (endindex == 0) {
1033: return "";
1034: }
1035:
1036: int startindex = 0;
1037:
1038: if (leading) {
1039: while (startindex < endindex
1040: && s.charAt(startindex) == trim) {
1041: startindex++;
1042: }
1043: }
1044:
1045: if (startindex == 0 && endindex == s.length()) {
1046: return s;
1047: } else {
1048: return s.substring(startindex, endindex);
1049: }
1050: }
1051:
1052: // fredt@users 20011010 - patch 460907 by fredt - soundex
1053:
1054: /**
1055: * Returns a four character code representing the sound of the given
1056: * <code>String</code>. Non-ASCCI characters in the
1057: * input <code>String</code> are ignored. <p>
1058: *
1059: * This method was
1060: * rewritten for HSQLDB by fredt@users to comply with the description at
1061: * <a href="http://www.nara.gov/genealogy/coding.html">
1062: * http://www.nara.gov/genealogy/coding.html</a>.<p>
1063: * @param s the <code>String</code> for which to calculate the 4 character
1064: * <code>SOUNDEX</code> value
1065: * @return the 4 character <code>SOUNDEX</code> value for the given
1066: * <code>String</code>
1067: */
1068: public static String soundex(String s) {
1069:
1070: if (s == null) {
1071: return s;
1072: }
1073:
1074: s = s.toUpperCase(Locale.ENGLISH);
1075:
1076: int len = s.length();
1077: char[] b = new char[] { '0', '0', '0', '0' };
1078: char lastdigit = '0';
1079:
1080: for (int i = 0, j = 0; i < len && j < 4; i++) {
1081: char c = s.charAt(i);
1082: char newdigit;
1083:
1084: if ("AEIOUY".indexOf(c) != -1) {
1085: newdigit = '7';
1086: } else if (c == 'H' || c == 'W') {
1087: newdigit = '8';
1088: } else if ("BFPV".indexOf(c) != -1) {
1089: newdigit = '1';
1090: } else if ("CGJKQSXZ".indexOf(c) != -1) {
1091: newdigit = '2';
1092: } else if (c == 'D' || c == 'T') {
1093: newdigit = '3';
1094: } else if (c == 'L') {
1095: newdigit = '4';
1096: } else if (c == 'M' || c == 'N') {
1097: newdigit = '5';
1098: } else if (c == 'R') {
1099: newdigit = '6';
1100: } else {
1101: continue;
1102: }
1103:
1104: if (j == 0) {
1105: b[j++] = c;
1106: lastdigit = newdigit;
1107: } else if (newdigit <= '6') {
1108: if (newdigit != lastdigit) {
1109: b[j++] = newdigit;
1110: lastdigit = newdigit;
1111: }
1112: } else if (newdigit == '7') {
1113: lastdigit = newdigit;
1114: }
1115: }
1116:
1117: return new String(b, 0, 4);
1118: }
1119:
1120: /**
1121: * Returns a <code>String</code> consisting of <code>count</code> spaces, or
1122: * <code>null</code> if <code>count</code> is less than zero. <p>
1123: *
1124: * @param count the number of spaces to produce
1125: * @return a <code>String</code> of <code>count</code> spaces
1126: */
1127: public static String space(int count) {
1128:
1129: if (count < 0) {
1130: return null;
1131: }
1132:
1133: char[] c = new char[count];
1134:
1135: while (count > 0) {
1136: c[--count] = ' ';
1137: }
1138:
1139: return new String(c);
1140: }
1141:
1142: /**
1143: * Returns the characters from the given <code>String</code>, starting at
1144: * the indicated one-based <code>start</code> position and extending the
1145: * (optional) indicated <code>length</code>. If <code>length</code> is not
1146: * specified (is <code>null</code>), the remainder of <code>s</code> is
1147: * implied.
1148: *
1149: * The rules for boundary conditions on s, start and length are,
1150: * in order of precedence: <p>
1151: *
1152: * 1.) if s is null, return null
1153: *
1154: * 2.) If length is less than 1, return null.
1155: *
1156: * 3.) If start is 0, it is treated as 1.
1157: *
1158: * 4.) If start is positive, count from the beginning of s to find
1159: * the first character postion.
1160: *
1161: * 5.) If start is negative, count backwards from the end of s
1162: * to find the first character.
1163: *
1164: * 6.) If, after applying 2.) or 3.), the start position lies outside s,
1165: * then return null
1166: *
1167: * 7.) if length is ommited or is greated than the number of characters
1168: * from the start position to the end of s, return the remaineder of s,
1169: * starting with the start position.
1170: *
1171: * @param s the <code>String</code> from which to produce the indicated
1172: * substring
1173: * @param start the starting position of the desired substring
1174: * @param length the length of the desired substring
1175: * @return the indicted substring of <code>s</code>.
1176: */
1177:
1178: // fredt@users 20020210 - patch 500767 by adjbirch@users - modified
1179: // boucherb@users 20050205 - patch to correct bug 1107477
1180: public static String substring(final String s, int start,
1181: final Integer length) {
1182:
1183: if (s == null) {
1184: return null;
1185: }
1186:
1187: int sl = s.length();
1188: int ol = (length == null) ? sl : length.intValue();
1189:
1190: if (ol < 1) {
1191: return null;
1192: }
1193:
1194: if (start < 0) {
1195: start = sl + start;
1196: } else if (start > 0) {
1197: start--;
1198: }
1199:
1200: if (start < 0 || start >= sl) {
1201: return null;
1202: } else if (start > sl - ol) {
1203: ol = sl - start;
1204: }
1205:
1206: return s.substring(start, start + ol);
1207: }
1208:
1209: /**
1210: * Returns a copy of the given <code>String</code>, with all lower case
1211: * characters converted to upper case using the default Java method.
1212: * @param s the <code>String</code> from which to produce an upper case
1213: * version
1214: * @return an upper case version of <code>s</code>
1215: */
1216: public static String ucase(String s) {
1217: return (s == null) ? null : s.toUpperCase();
1218: }
1219:
1220: // TIME AND DATE
1221:
1222: /**
1223: * Returns the current date as a date value. <p>
1224: *
1225: * Dummy mehtod.<p>
1226: *
1227: * @return a date value representing the current date
1228: */
1229: public static Date curdate(Connection c) {
1230: return null;
1231: }
1232:
1233: /**
1234: * Returns the current local time as a time value. <p>
1235: *
1236: * Dummy mehtod.<p>
1237: *
1238: * @return a time value representing the current local time
1239: */
1240: public static Time curtime(Connection c) {
1241: return null;
1242: }
1243:
1244: /**
1245: * Returns a character string containing the name of the day
1246: * (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday )
1247: * for the day portion of the given <code>java.sql.Date</code>.
1248: * @param d the date value from which to extract the day name
1249: * @return the name of the day corresponding to the given
1250: * <code>java.sql.Date</code>
1251: */
1252: public static String dayname(Date d) {
1253:
1254: if (d == null) {
1255: return null;
1256: }
1257:
1258: synchronized (daynameBuffer) {
1259: daynameBuffer.setLength(0);
1260:
1261: return daynameFormat.format(d, daynameBuffer, dayPosition)
1262: .toString();
1263: }
1264: }
1265:
1266: /**
1267: * Returns the day of the month from the given date value, as an integer
1268: * value in the range of 1-31.
1269: *
1270: * @param d the date value from which to extract the day of month
1271: * @return the day of the month from the given date value
1272: */
1273: public static Integer dayofmonth(Date d) {
1274:
1275: if (d == null) {
1276: return null;
1277: }
1278:
1279: return ValuePool.getInt(HsqlDateTime.getDateTimePart(d,
1280: Calendar.DAY_OF_MONTH));
1281: }
1282:
1283: /**
1284: * Returns the day of the week from the given date value, as an integer
1285: * value in the range 1-7, where 1 represents Sunday.
1286: *
1287: * @param d the date value from which to extract the day of week
1288: * @return the day of the week from the given date value
1289: */
1290: public static Integer dayofweek(Date d) {
1291:
1292: if (d == null) {
1293: return null;
1294: }
1295:
1296: return ValuePool.getInt(HsqlDateTime.getDateTimePart(d,
1297: Calendar.DAY_OF_WEEK));
1298: }
1299:
1300: /**
1301: * Returns the day of the year from the given date value, as an integer
1302: * value in the range 1-366.
1303: *
1304: * @param d the date value from which to extract the day of year
1305: * @return the day of the year from the given date value
1306: */
1307: public static Integer dayofyear(Date d) {
1308:
1309: if (d == null) {
1310: return null;
1311: }
1312:
1313: return ValuePool.getInt(HsqlDateTime.getDateTimePart(d,
1314: Calendar.DAY_OF_YEAR));
1315: }
1316:
1317: /**
1318: * Returns the hour from the given time value, as an integer value in
1319: * the range of 0-23.
1320: *
1321: * @param t the time value from which to extract the hour of day
1322: * @return the hour of day from the given time value
1323: */
1324:
1325: // fredt@users 20020210 - patch 513005 by sqlbob@users (RMP) - hour
1326: public static Integer hour(Time t) {
1327:
1328: if (t == null) {
1329: return null;
1330: }
1331:
1332: return ValuePool.getInt(HsqlDateTime.getDateTimePart(t,
1333: Calendar.HOUR_OF_DAY));
1334: }
1335:
1336: /**
1337: * Returns the minute from the given time value, as integer value in
1338: * the range of 0-59.
1339: *
1340: * @param t the time value from which to extract the minute value
1341: * @return the minute value from the given time value
1342: */
1343: public static Integer minute(Time t) {
1344:
1345: if (t == null) {
1346: return null;
1347: }
1348:
1349: return ValuePool.getInt(HsqlDateTime.getDateTimePart(t,
1350: Calendar.MINUTE));
1351: }
1352:
1353: /**
1354: * Returns the month from the given date value, as an integer value in the
1355: * range of 1-12. <p>
1356: *
1357: * The sql_month database property is now obsolete.
1358: * The function always returns the SQL (1-12) value for month.
1359: *
1360: * @param d the date value from which to extract the month value
1361: * @return the month value from the given date value
1362: */
1363: public static Integer month(Date d) {
1364:
1365: if (d == null) {
1366: return null;
1367: }
1368:
1369: return ValuePool.getInt(HsqlDateTime.getDateTimePart(d,
1370: Calendar.MONTH) + 1);
1371: }
1372:
1373: /**
1374: * Returns a character string containing the name of month
1375: * (January, February, March, April, May, June, July, August,
1376: * September, October, November, December) for the month portion of
1377: * the given date value.
1378: *
1379: * @param d the date value from which to extract the month name
1380: * @return a String representing the month name from the given date value
1381: */
1382: public static String monthname(Date d) {
1383:
1384: if (d == null) {
1385: return null;
1386: }
1387:
1388: synchronized (monthnameBuffer) {
1389: monthnameBuffer.setLength(0);
1390:
1391: return monthnameFormat.format(d, monthnameBuffer,
1392: monthPosition).toString();
1393: }
1394: }
1395:
1396: /**
1397: * Returns the current date and time as a timestamp value. <p>
1398: *
1399: * Dummy mehtod.<p>
1400: *
1401: * @return a timestamp value representing the current date and time
1402: */
1403: public static Timestamp now(Connection c) {
1404: return null;
1405: }
1406:
1407: /**
1408: * Returns the quarter of the year in the given date value, as an integer
1409: * value in the range of 1-4. <p>
1410: *
1411: * @param d the date value from which to extract the quarter of the year
1412: * @return an integer representing the quater of the year from the given
1413: * date value
1414: */
1415: public static Integer quarter(Date d) {
1416:
1417: if (d == null) {
1418: return null;
1419: }
1420:
1421: return ValuePool.getInt((HsqlDateTime.getDateTimePart(d,
1422: Calendar.MONTH) / 3) + 1);
1423: }
1424:
1425: /**
1426: * Returns the second of the given time value, as an integer value in
1427: * the range of 0-59.
1428: *
1429: * @param d the date value from which to extract the second of the hour
1430: * @return an integer representing the second of the hour from the
1431: * given time value
1432: */
1433: public static Integer second(Time d) {
1434:
1435: if (d == null) {
1436: return null;
1437: }
1438:
1439: return ValuePool.getInt(HsqlDateTime.getDateTimePart(d,
1440: Calendar.SECOND));
1441: }
1442:
1443: /**
1444: * Returns the week of the year from the given date value, as an integer
1445: * value in the range of 1-53. <p>
1446: *
1447: * @param d the date value from which to extract the week of the year
1448: * @return an integer representing the week of the year from the given
1449: * date value
1450: */
1451: public static Integer week(Date d) {
1452:
1453: if (d == null) {
1454: return null;
1455: }
1456:
1457: return ValuePool.getInt(HsqlDateTime.getDateTimePart(d,
1458: Calendar.WEEK_OF_YEAR));
1459: }
1460:
1461: /**
1462: * Returns the year from the given date value, as an integer value in
1463: * the range of 1-9999. <p>
1464: *
1465: * @param d the date value from which to extract the year
1466: * @return an integer value representing the year from the given
1467: * date value
1468: */
1469: public static Integer year(Date d) {
1470:
1471: if (d == null) {
1472: return null;
1473: }
1474:
1475: return ValuePool.getInt(HsqlDateTime.getDateTimePart(d,
1476: Calendar.YEAR));
1477: }
1478:
1479: /**
1480: * @since 1.8.0
1481: */
1482: public static String to_char(java.util.Date d, String format) {
1483:
1484: if (d == null || format == null) {
1485: return null;
1486: }
1487:
1488: synchronized (tocharFormat) {
1489: tocharFormat.applyPattern(HsqlDateTime
1490: .toJavaDatePattern(format));
1491:
1492: return tocharFormat.format(d);
1493: }
1494: }
1495:
1496: // date calculations.
1497:
1498: /**
1499: * Returns the number of units elapsed between two dates.<p>
1500: * The datapart parameter indicates the part to be used for computing the
1501: * difference. Supported types include: 'year', 'yy', 'month', 'mm'
1502: * 'day', 'dd', 'hour', 'hh', 'minute', 'mi', 'second', 'ss', 'millisecond',
1503: * 'ms'.
1504: *
1505: * Contributed by Michael Landon<p>
1506: *
1507: * @param datepart Specifies the unit in which the interval is to be measured.
1508: * @param d1 The starting datetime value for the interval. This value is
1509: * subtracted from d2 to return the number of
1510: * date-parts between the two arguments.
1511: * @param d2 The ending datetime for the interval. d1 is subtracted
1512: * from this value to return the number of date-parts
1513: * between the two arguments.
1514: *
1515: * since 1.7.3
1516: */
1517: public static Long datediff(String datepart, Timestamp d1,
1518: Timestamp d2) throws HsqlException {
1519:
1520: // make sure we've got valid data
1521: if (d1 == null || d2 == null) {
1522: return null;
1523: }
1524:
1525: if ("yy".equalsIgnoreCase(datepart)
1526: || "year".equalsIgnoreCase(datepart)) {
1527: return ValuePool.getLong(getElapsed(Calendar.YEAR, d1, d2));
1528: } else if ("mm".equalsIgnoreCase(datepart)
1529: || "month".equalsIgnoreCase(datepart)) {
1530: return ValuePool
1531: .getLong(getElapsed(Calendar.MONTH, d1, d2));
1532: } else if ("dd".equalsIgnoreCase(datepart)
1533: || "day".equalsIgnoreCase(datepart)) {
1534: return ValuePool.getLong(getElapsed(Calendar.DATE, d1, d2));
1535: } else if ("hh".equalsIgnoreCase(datepart)
1536: || "hour".equalsIgnoreCase(datepart)) {
1537: return ValuePool.getLong(getElapsed(Calendar.HOUR, d1, d2));
1538: } else if ("mi".equalsIgnoreCase(datepart)
1539: || "minute".equalsIgnoreCase(datepart)) {
1540: return ValuePool
1541: .getLong(getElapsed(Calendar.MINUTE, d1, d2));
1542: } else if ("ss".equalsIgnoreCase(datepart)
1543: || "second".equalsIgnoreCase(datepart)) {
1544: return ValuePool
1545: .getLong(getElapsed(Calendar.SECOND, d1, d2));
1546: } else if ("ms".equalsIgnoreCase(datepart)
1547: || "millisecond".equalsIgnoreCase(datepart)) {
1548: return ValuePool.getLong(getElapsed(Calendar.MILLISECOND,
1549: d1, d2));
1550: } else {
1551: throw Trace.error(Trace.INVALID_CONVERSION);
1552: }
1553: }
1554:
1555: /**
1556: * Private method used to do actual calculation units elapsed between
1557: * two given dates. <p>
1558: *
1559: * @param field Calendar field to use to calculate elapsed time
1560: * @param d1 The starting date for the interval. This value is
1561: * subtracted from d2 to return the number of
1562: * date-parts between the two arguments.
1563: * @param d2 The ending date for the interval. d1 is subtracted
1564: * from this value to return the number of date-parts
1565: * between the two arguments.
1566: */
1567: private static long getElapsed(int field, java.util.Date d1,
1568: java.util.Date d2) {
1569:
1570: // can we do this very simply?
1571: if (field == Calendar.MILLISECOND) {
1572: return d2.getTime() - d1.getTime();
1573: }
1574:
1575: // ok, let's work a little harder:
1576: Calendar g1 = Calendar.getInstance(), g2 = Calendar
1577: .getInstance();
1578:
1579: g1.setTime(d1);
1580: g2.setTime(d2);
1581: g1.set(Calendar.MILLISECOND, 0);
1582: g2.set(Calendar.MILLISECOND, 0);
1583:
1584: if (field == Calendar.SECOND) {
1585: return (g2.getTime().getTime() - g1.getTime().getTime()) / 1000;
1586: }
1587:
1588: g1.set(Calendar.SECOND, 0);
1589: g2.set(Calendar.SECOND, 0);
1590:
1591: if (field == Calendar.MINUTE) {
1592: return (g2.getTime().getTime() - g1.getTime().getTime())
1593: / (1000 * 60);
1594: }
1595:
1596: g1.set(Calendar.MINUTE, 0);
1597: g2.set(Calendar.MINUTE, 0);
1598:
1599: if (field == Calendar.HOUR) {
1600: return (g2.getTime().getTime() - g1.getTime().getTime())
1601: / (1000 * 60 * 60);
1602: } // end if-else
1603:
1604: // if we got here, then we really need to work:
1605: long elapsed = 0;
1606: short sign = 1;
1607:
1608: if (g2.before(g1)) {
1609: sign = -1;
1610:
1611: Calendar tmp = g1;
1612:
1613: g1 = g2;
1614: g2 = tmp;
1615: } // end if
1616:
1617: g1.set(Calendar.HOUR_OF_DAY, 0);
1618: g2.set(Calendar.HOUR_OF_DAY, 0);
1619:
1620: if (field == Calendar.MONTH || field == Calendar.YEAR) {
1621: g1.set(Calendar.DATE, 1);
1622: g2.set(Calendar.DATE, 1);
1623: }
1624:
1625: if (field == Calendar.YEAR) {
1626: g1.set(Calendar.MONTH, 1);
1627: g2.set(Calendar.MONTH, 1);
1628: } // end if-else
1629:
1630: // then calculate elapsed units
1631: while (g1.before(g2)) {
1632: g1.add(field, 1);
1633:
1634: elapsed++;
1635: }
1636:
1637: return sign * elapsed;
1638: } // end getElapsed
1639:
1640: // SYSTEM
1641: /*
1642: * All system functions that return Session dependent information are
1643: * dummies here.
1644: */
1645:
1646: /**
1647: * Returns the name of the database corresponding to this connection.
1648: *
1649: * @param conn the connection for which to retrieve the database name
1650: * @return the name of the database for the given connection
1651: * @throws HsqlException if a database access error occurs
1652: */
1653: public static String database(Connection conn) throws HsqlException {
1654: return null;
1655: }
1656:
1657: /**
1658: * Returns the user's authorization name (the user's name as known to this
1659: * database).
1660: *
1661: * @param conn the connection for which to retrieve the user name
1662: * @return the user's name as known to the database
1663: * @throws HsqlException if a database access error occurs
1664: */
1665: public static String user(Connection conn) throws HsqlException {
1666: return null;
1667: }
1668:
1669: /**
1670: * Retrieves the last auto-generated integer indentity value
1671: * used by this connection. <p>
1672: *
1673: * Dummy mehtod.<p>
1674: *
1675: * @return the connection's the last generated integer identity value
1676: * @throws HsqlException if a database access error occurs
1677: */
1678: public static int identity() throws HsqlException {
1679: return 0;
1680: }
1681:
1682: // JDBC SYSTEM
1683:
1684: /**
1685: * Retrieves the autocommit status of this connection. <p>
1686: *
1687: * @param conn the <code>Connection</code> object for which to retrieve
1688: * the current autocommit status
1689: * @return a boolean value representing the connection's autocommit status
1690: * @since 1.7.0
1691: */
1692: public static boolean getAutoCommit(Connection conn) {
1693: return false;
1694: }
1695:
1696: /**
1697: * Retrieves the full version number of this database product. <p>
1698: *
1699: * @return database version number as a <code>String</code> object
1700: * @since 1.8.0.4
1701: */
1702: public static String getDatabaseFullProductVersion() {
1703: return HsqlDatabaseProperties.THIS_FULL_VERSION;
1704: }
1705:
1706: /**
1707: * Retrieves the name of this database product. <p>
1708: *
1709: * @return database product name as a <code>String</code> object
1710: * @since 1.7.2
1711: */
1712: public static String getDatabaseProductName() {
1713: return HsqlDatabaseProperties.PRODUCT_NAME;
1714: }
1715:
1716: /**
1717: * Retrieves the version number of this database product. <p>
1718: *
1719: * @return database version number as a <code>String</code> object
1720: * @since 1.7.2
1721: */
1722: public static String getDatabaseProductVersion() {
1723: return HsqlDatabaseProperties.THIS_VERSION;
1724: }
1725:
1726: /**
1727: * Retrieves the major version number of this database. <p>
1728: *
1729: * @return the database's major version as an <code>int</code> value
1730: * @since 1.7.2
1731: */
1732: public static int getDatabaseMajorVersion() {
1733: return HsqlDatabaseProperties.MAJOR;
1734: }
1735:
1736: /**
1737: * Retrieves the major version number of this database. <p>
1738: *
1739: * @return the database's major version as an <code>int</code> value
1740: * @since 1.7.2
1741: */
1742: public static int getDatabaseMinorVersion() {
1743: return HsqlDatabaseProperties.MINOR;
1744: }
1745:
1746: /**
1747: * Retrieves whether this connection is in read-only mode. <p>
1748: *
1749: * Dummy mehtod.<p>
1750: *
1751: * @param conn the <code>Connection</code> object for which to retrieve
1752: * the current read-only status
1753: * @return <code>true</code> if connection is read-only and
1754: * <code>false</code> otherwise
1755: * @since 1.7.2
1756: */
1757: public static boolean isReadOnlyConnection(Connection conn) {
1758: return false;
1759: }
1760:
1761: /**
1762: * Dummy method. Retrieves whether this database is in read-only mode. <p>
1763: *
1764: * @param c the <code>Connection</code> object for which to retrieve
1765: * the current database read-only status
1766: * @return <code>true</code> if so; <code>false</code> otherwise
1767: * @since 1.7.2
1768: */
1769: public static boolean isReadOnlyDatabase(Connection c) {
1770: return false;
1771: }
1772:
1773: /**
1774: * Retrieves whether the files of this database are in read-only mode. <p>
1775: *
1776: * Dummy mehtod.<p>
1777: *
1778: * @param c the <code>Connection</code> object for which to retrieve
1779: * the current database files read-only status
1780: * @return <code>true</code> if so; <code>false</code> otherwise
1781: * @since 1.7.2
1782: */
1783: public static boolean isReadOnlyDatabaseFiles(Connection c) {
1784: return false;
1785: }
1786:
1787: static final int abs = 0;
1788: static final int ascii = 1;
1789: static final int bitand = 2;
1790: static final int bitLength = 3;
1791: static final int bitor = 4;
1792: static final int bitxor = 5;
1793: static final int character = 6;
1794: static final int concat = 7;
1795: static final int cot = 8;
1796: static final int curdate = 9;
1797: static final int curtime = 10;
1798: static final int database = 11;
1799: static final int datediff = 12;
1800: static final int day = 13;
1801: static final int dayname = 14;
1802: static final int dayofmonth = 15;
1803: static final int dayofweek = 16;
1804: static final int dayofyear = 17;
1805: static final int difference = 18;
1806: static final int getAutoCommit = 19;
1807: static final int getDatabaseFullProductVersion = 20;
1808: static final int getDatabaseMajorVersion = 21;
1809: static final int getDatabaseMinorVersion = 22;
1810: static final int getDatabaseProductName = 23;
1811: static final int getDatabaseProductVersion = 24;
1812: static final int hexToRaw = 25;
1813: static final int hour = 26;
1814: static final int identity = 27;
1815: static final int insert = 28;
1816: static final int isReadOnlyConnection = 29;
1817: static final int isReadOnlyDatabase = 30;
1818: static final int isReadOnlyDatabaseFiles = 31;
1819: static final int lcase = 32;
1820: static final int left = 33;
1821: static final int length = 34;
1822: static final int locate = 35;
1823: static final int log10 = 36;
1824: static final int ltrim = 37;
1825: static final int minute = 38;
1826: static final int mod = 39;
1827: static final int month = 40;
1828: static final int monthname = 41;
1829: static final int now = 42;
1830: static final int octetLength = 43;
1831: static final int pi = 44;
1832: static final int position = 45;
1833: static final int quarter = 46;
1834: static final int rand = 47;
1835: static final int rawToHex = 48;
1836: static final int repeat = 49;
1837: static final int replace = 50;
1838: static final int right = 51;
1839: static final int round = 52;
1840: static final int roundMagic = 53;
1841: static final int rtrim = 54;
1842: static final int second = 55;
1843: static final int sign = 56;
1844: static final int soundex = 57;
1845: static final int space = 58;
1846: static final int substring = 59;
1847: static final int to_char = 60;
1848: static final int trim = 61;
1849: static final int truncate = 62;
1850: static final int ucase = 63;
1851: static final int user = 64;
1852: static final int week = 65;
1853: static final int year = 66;
1854:
1855: /** @todo see bitxor and datediff numbering */
1856:
1857: //
1858: private static final IntValueHashMap functionMap = new IntValueHashMap(
1859: 67);
1860: static final Double piValue = new Double(Library.pi());
1861:
1862: static {
1863: functionMap.put("abs", abs);
1864: functionMap.put("ascii", ascii);
1865: functionMap.put("bitand", bitand);
1866: functionMap.put("bitlength", bitLength);
1867: functionMap.put("bitor", bitor);
1868: functionMap.put("bitxor", bitor);
1869: functionMap.put("character", character);
1870: functionMap.put("concat", concat);
1871: functionMap.put("cot", cot);
1872: functionMap.put("curdate", curdate);
1873: functionMap.put("curtime", curtime);
1874: functionMap.put("database", database);
1875: functionMap.put("datediff", datediff);
1876: functionMap.put("dayname", dayname);
1877: functionMap.put("day", day);
1878: functionMap.put("dayofmonth", dayofmonth);
1879: functionMap.put("dayofweek", dayofweek);
1880: functionMap.put("dayofyear", dayofyear);
1881: functionMap.put("difference", difference);
1882: functionMap.put("getAutoCommit", getAutoCommit);
1883: functionMap.put("getDatabaseFullProductVersion",
1884: getDatabaseFullProductVersion);
1885: functionMap.put("getDatabaseMajorVersion",
1886: getDatabaseMajorVersion);
1887: functionMap.put("getDatabaseMinorVersion",
1888: getDatabaseMinorVersion);
1889: functionMap.put("getDatabaseProductName",
1890: getDatabaseProductName);
1891: functionMap.put("getDatabaseProductVersion",
1892: getDatabaseProductVersion);
1893: functionMap.put("hexToRaw", hexToRaw);
1894: functionMap.put("hour", hour);
1895: functionMap.put("identity", identity);
1896: functionMap.put("insert", insert);
1897: functionMap.put("isReadOnlyConnection", isReadOnlyConnection);
1898: functionMap.put("isReadOnlyDatabase", isReadOnlyDatabase);
1899: functionMap.put("isReadOnlyDatabaseFiles",
1900: isReadOnlyDatabaseFiles);
1901: functionMap.put("lcase", lcase);
1902: functionMap.put("left", left);
1903: functionMap.put("length", length);
1904: functionMap.put("locate", locate);
1905: functionMap.put("log10", log10);
1906: functionMap.put("ltrim", ltrim);
1907: functionMap.put("minute", minute);
1908: functionMap.put("mod", mod);
1909: functionMap.put("month", month);
1910: functionMap.put("monthname", monthname);
1911: functionMap.put("now", now);
1912: functionMap.put("octetLength", octetLength);
1913: functionMap.put("pi", pi);
1914: functionMap.put("position", position);
1915: functionMap.put("quarter", quarter);
1916: functionMap.put("rand", rand);
1917: functionMap.put("rawToHex", rawToHex);
1918: functionMap.put("repeat", repeat);
1919: functionMap.put("replace", replace);
1920: functionMap.put("right", right);
1921: functionMap.put("round", round);
1922: functionMap.put("roundMagic", roundMagic);
1923: functionMap.put("rtrim", rtrim);
1924: functionMap.put("second", second);
1925: functionMap.put("sign", sign);
1926: functionMap.put("soundex", soundex);
1927: functionMap.put("space", space);
1928: functionMap.put("substring", substring);
1929: functionMap.put("to_char", to_char);
1930: functionMap.put("trim", trim);
1931: functionMap.put("truncate", truncate);
1932: functionMap.put("ucase", ucase);
1933: functionMap.put("user", user);
1934: functionMap.put("week", week);
1935: functionMap.put("year", year);
1936: }
1937:
1938: static Object invoke(int fID, Object[] params) throws HsqlException {
1939:
1940: try {
1941: switch (fID) {
1942:
1943: case abs: {
1944: return new Double(Library.abs(((Number) params[0])
1945: .doubleValue()));
1946: }
1947: case ascii: {
1948: return ascii((String) params[0]);
1949: }
1950: case bitand: {
1951: return ValuePool.getInt(bitand(((Number) params[0])
1952: .intValue(), ((Number) params[1]).intValue()));
1953: }
1954: case bitLength: {
1955: return bitLength((String) params[0]);
1956: }
1957: case bitor: {
1958: return ValuePool.getInt(bitor(((Number) params[0])
1959: .intValue(), ((Number) params[1]).intValue()));
1960: }
1961: case bitxor: {
1962: return ValuePool.getInt(bitxor(((Number) params[0])
1963: .intValue(), ((Number) params[1]).intValue()));
1964: }
1965: case character: {
1966: return character(((Number) params[0]).intValue());
1967: }
1968: case concat: {
1969: return concat((String) params[0], (String) params[1]);
1970: }
1971: case cot: {
1972: return new Double(cot(((Number) params[0])
1973: .doubleValue()));
1974: }
1975: case curdate: {
1976: return null;
1977: }
1978: case curtime: {
1979: return null;
1980: }
1981: case database: {
1982: return null;
1983: }
1984: case datediff: {
1985: return datediff((String) params[0],
1986: (Timestamp) params[1], (Timestamp) params[2]);
1987: }
1988: case dayname: {
1989: return dayname((Date) params[0]);
1990: }
1991: case dayofmonth:
1992: case day: {
1993: return dayofmonth((Date) params[0]);
1994: }
1995: case dayofweek: {
1996: return dayofweek((Date) params[0]);
1997: }
1998: case dayofyear: {
1999: return dayofyear((Date) params[0]);
2000: }
2001: case difference: {
2002: return ValuePool.getInt(difference((String) params[0],
2003: (String) params[1]));
2004: }
2005: case getAutoCommit: {
2006: return null;
2007: }
2008: case getDatabaseFullProductVersion: {
2009: return getDatabaseFullProductVersion();
2010: }
2011: case getDatabaseMajorVersion: {
2012: return ValuePool.getInt(getDatabaseMajorVersion());
2013: }
2014: case getDatabaseMinorVersion: {
2015: return ValuePool.getInt(getDatabaseMinorVersion());
2016: }
2017: case getDatabaseProductName: {
2018: return getDatabaseProductName();
2019: }
2020: case getDatabaseProductVersion: {
2021: return getDatabaseProductVersion();
2022: }
2023: case hexToRaw: {
2024: return hexToRaw((String) params[0]);
2025: }
2026: case hour: {
2027: return hour((Time) params[0]);
2028: }
2029: case identity: {
2030: return null;
2031: }
2032: case insert: {
2033: return insert((String) params[0], ((Number) params[1])
2034: .intValue(), ((Number) params[2]).intValue(),
2035: (String) params[3]);
2036: }
2037: case isReadOnlyConnection: {
2038: return null;
2039: }
2040: case isReadOnlyDatabase: {
2041: return null;
2042: }
2043: case lcase: {
2044: return lcase((String) params[0]);
2045: }
2046: case left: {
2047: return left((String) params[0], ((Number) params[1])
2048: .intValue());
2049: }
2050: case length: {
2051: return length((String) params[0]);
2052: }
2053: case locate: {
2054: return ValuePool.getInt(locate((String) params[0],
2055: (String) params[1], (Integer) params[2]));
2056: }
2057: case log10: {
2058: return new Double(log10(((Number) params[0])
2059: .doubleValue()));
2060: }
2061: case ltrim: {
2062: return ltrim((String) params[0]);
2063: }
2064: case minute: {
2065: return minute((Time) params[0]);
2066: }
2067: case mod: {
2068: return ValuePool.getInt(mod(((Number) params[0])
2069: .intValue(), ((Number) params[1]).intValue()));
2070: }
2071: case month: {
2072: return month((Date) params[0]);
2073: }
2074: case monthname: {
2075: return ValuePool.getString(monthname((Date) params[0]));
2076: }
2077: case now: {
2078: return null;
2079: }
2080: case octetLength: {
2081: return octetLength((String) params[0]);
2082: }
2083: case position: {
2084: return ValuePool.getInt(position((String) params[0],
2085: (String) params[1]));
2086: }
2087: case pi: {
2088: return piValue;
2089: }
2090: case quarter: {
2091: return quarter((Date) params[0]);
2092: }
2093: case rand: {
2094: return new Double(rand((Integer) params[0]));
2095: }
2096: case rawToHex: {
2097: return rawToHex((String) params[0]);
2098: }
2099: case repeat: {
2100: return repeat((String) params[0], (Integer) params[1]);
2101: }
2102: case replace: {
2103: return replace((String) params[0], (String) params[1],
2104: (String) params[2]);
2105: }
2106: case right: {
2107: return right((String) params[0], ((Number) params[1])
2108: .intValue());
2109: }
2110: case round: {
2111: return new Double(
2112: round(((Number) params[0]).doubleValue(),
2113: ((Number) params[1]).intValue()));
2114: }
2115: case roundMagic: {
2116: return new Double(roundMagic(((Number) params[0])
2117: .doubleValue()));
2118: }
2119: case rtrim: {
2120: return rtrim((String) params[0]);
2121: }
2122: case second: {
2123: return second((Time) params[0]);
2124: }
2125: case sign: {
2126: return ValuePool.getInt(sign(((Number) params[0])
2127: .doubleValue()));
2128: }
2129: case soundex: {
2130: return soundex((String) params[0]);
2131: }
2132: case space: {
2133: return space(((Number) params[0]).intValue());
2134: }
2135: case substring: {
2136: return substring((String) params[0],
2137: ((Number) params[1]).intValue(),
2138: (Integer) params[2]);
2139: }
2140: case trim: {
2141: return trim((String) params[0], (String) params[1],
2142: ((Boolean) params[2]).booleanValue(),
2143: ((Boolean) params[3]).booleanValue());
2144: }
2145: case truncate: {
2146: return new Double(
2147: truncate(((Number) params[0]).doubleValue(),
2148: ((Number) params[1]).intValue()));
2149: }
2150: case ucase: {
2151: return ucase((String) params[0]);
2152: }
2153: case user: {
2154: return null;
2155: }
2156: case week: {
2157: return week((Date) params[0]);
2158: }
2159: case year: {
2160: return year((Date) params[0]);
2161: }
2162: case to_char: {
2163: return to_char((java.util.Date) params[0],
2164: (String) params[1]);
2165: }
2166: case isReadOnlyDatabaseFiles: {
2167: return null;
2168: }
2169: default: {
2170:
2171: // coding error
2172: Trace.doAssert(false);
2173:
2174: return null;
2175: }
2176: }
2177: } catch (Exception e) {
2178: throw Trace.error(Trace.FUNCTION_CALL_ERROR, e.toString());
2179: }
2180: }
2181:
2182: static final String prefix = "org.hsqldb.Library.";
2183: static final int prefixLength = prefix.length();
2184:
2185: static int functionID(String fname) {
2186:
2187: return fname.startsWith(prefix) ? functionMap.get(fname
2188: .substring(prefixLength), -1) : -1;
2189: }
2190: }
|