001: /*
002: * This class provides string manipulation methods.
003: *
004: * $Author: davis $
005: * $Date: 2004/12/18 21:23:31 $
006: * $Revision: 1.1 $
007: *
008: * This library is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Lesser General Public
010: * License as published by the Free Software Foundation; either
011: * version 2.1 of the License, or (at your option) any later version.
012: *
013: * This library is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public
019: * License along with this library; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021: *
022: * Revision History:
023: *
024: * Written by Davis Swan in February, 2004.
025: */
026: package com.sqlmagic.tinysql;
027:
028: import java.text.*;
029: import java.util.*;
030: import java.lang.*;
031: import java.sql.Types;
032:
033: public class UtilString {
034: /*
035: * Is this a quoted string?
036: */
037: public static boolean isQuotedString(String inputString) {
038: String trimString;
039: int trimLength;
040: if (inputString == (String) null)
041: return false;
042: trimString = inputString.trim();
043: trimLength = trimString.length();
044: if (trimString.length() == 0)
045: return false;
046: if ((trimString.charAt(0) == '\'' & trimString
047: .charAt(trimLength - 1) == '\'')
048: | (trimString.charAt(0) == '"' & trimString
049: .charAt(trimLength - 1) == '"')) {
050: return true;
051: }
052: return false;
053: }
054:
055: /*
056: * Remove enclosing quotes from a string.
057: */
058: public static String removeQuotes(String inputString) {
059: String trimString;
060: int trimLength;
061: if (inputString == (String) null)
062: return inputString;
063: trimString = inputString.trim();
064: trimLength = trimString.length();
065: if (trimString.length() == 0)
066: return inputString;
067: if ((trimString.charAt(0) == '\'' & trimString
068: .charAt(trimLength - 1) == '\'')
069: | (trimString.charAt(0) == '"' & trimString
070: .charAt(trimLength - 1) == '"')) {
071: return trimString.substring(1, trimString.length() - 1);
072: }
073: return inputString;
074: }
075:
076: /*
077: * Convert a string to a double or return a default value.
078: */
079: public static double doubleValue(String inputString) {
080: return doubleValue(inputString, Double.MIN_VALUE);
081: }
082:
083: public static double doubleValue(String inputString,
084: double defaultValue) {
085: try {
086: return Double.parseDouble(inputString);
087: } catch (Exception e) {
088: return defaultValue;
089: }
090: }
091:
092: /*
093: * Convert a date string in the format YYYYMMDD to the standard
094: * date output YYYY-MM-DD
095: */
096: public static String toStandardDate(String inputDateString)
097: throws tinySQLException {
098: String dateString, stdDateString;
099: int month;
100: if (inputDateString == (String) null)
101: throw new tinySQLException("Cannot format NULL date");
102: if (inputDateString.length() < 8)
103: throw new tinySQLException("Date " + inputDateString
104: + " not in YYYYMMDD format");
105: /*
106: * Convert the input to YYYYMMDD - this is required because
107: * versions of tinySQL before 2.26d incorrectly stored dates in several
108: * different character string representations.
109: */
110: dateString = dateValue(inputDateString);
111: stdDateString = dateString.substring(0, 4) + "-"
112: + dateString.substring(4, 6) + "-"
113: + dateString.substring(6, 8);
114: return stdDateString;
115: }
116:
117: /*
118: * Convert a date string in the format DD-MON-YY, DD-MON-YYYY, or YYYYMMDD
119: * to the output YYYYMMDD after checking the validity of all subfields.
120: * A tinySQLException is thrown if there are problems.
121: */
122: public static String dateValue(String inputString)
123: throws tinySQLException {
124: String months = "-JAN-FEB-MAR-APR-MAY-JUN-JUL-AUG-SEP-OCT-NOV-DEC-";
125: int[] daysInMonth = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31,
126: 30, 31 };
127: String dateString, dayField, monthName, monthField, yearField;
128: String[] ftFields;
129: FieldTokenizer ft;
130: int year, month, day, monthAt;
131: dateString = inputString.toUpperCase().trim();
132: if (dateString.length() < 8)
133: throw new tinySQLException(dateString
134: + " is less than 8 characters.");
135: /*
136: * Check for YYYY-MM-DD format - convert to YYYYMMDD if found.
137: */
138: if (dateString.length() == 10 & dateString.charAt(4) == '-'
139: & dateString.charAt(7) == '-') {
140: dateString = dateString.substring(0, 4)
141: + dateString.substring(5, 7)
142: + dateString.substring(8, 10);
143: }
144: /*
145: * First check for an 8 character field properly formatted.
146: */
147: if (dateString.length() == 8 & isInteger(dateString)) {
148: try {
149: year = Integer.parseInt(dateString.substring(0, 4));
150: if (year < 0 | year > 2100)
151: throw new tinySQLException(dateString
152: + " year not " + "recognized.");
153: month = Integer.parseInt(dateString.substring(4, 6));
154: if (month < 1 | month > 12)
155: throw new tinySQLException(dateString
156: + " month not " + "recognized.");
157: day = Integer.parseInt(dateString.substring(6, 8));
158: if (day < 1 | day > daysInMonth[month - 1])
159: throw new tinySQLException(dateString + " day not "
160: + "recognized.");
161: return dateString;
162: } catch (Exception dateEx) {
163: throw new tinySQLException(dateEx.getMessage());
164: }
165: }
166: /*
167: * Check for dd-MON-YY formats - strip off TO_DATE if it exists.
168: */
169: if (dateString.startsWith("TO_DATE")) {
170: dateString = dateString.substring(8,
171: dateString.length() - 1);
172: dateString = removeQuotes(dateString);
173: }
174: ft = new FieldTokenizer(dateString, '-', false);
175: ftFields = ft.getFields();
176: if (ftFields.length < 3) {
177: throw new tinySQLException(dateString
178: + " is not a date with " + "format DD-MON-YY!");
179: } else {
180: try {
181: day = Integer.parseInt(ftFields[0]);
182: monthName = ftFields[1];
183: monthAt = months.indexOf("-" + monthName + "-");
184: if (monthAt == -1)
185: throw new tinySQLException(dateString
186: + " month not " + "recognized.");
187: month = (monthAt + 4) / 4;
188: if (day < 1 | day > daysInMonth[month - 1])
189: throw new tinySQLException(dateString + " day not "
190: + "between 1 and " + daysInMonth[month - 1]);
191: year = Integer.parseInt(ftFields[2]);
192: if (year < 0 | year > 2100)
193: throw new tinySQLException(dateString
194: + " year not " + "recognized.");
195: /*
196: * Assume that years < 50 are in the 21st century, otherwise
197: * the 20th.
198: */
199: if (year < 50)
200: year = 2000 + year;
201: else
202: year = 1900 + year;
203: dayField = Integer.toString(day);
204: if (dayField.length() < 2)
205: dayField = "0" + dayField;
206: monthField = Integer.toString(month);
207: if (monthField.length() < 2)
208: monthField = "0" + monthField;
209: yearField = Integer.toString(year);
210: return yearField + monthField + dayField;
211: } catch (Exception dayEx) {
212: throw new tinySQLException(dateString + " exception "
213: + dayEx.getMessage());
214: }
215: }
216: }
217:
218: /*
219: * The following method replaces all occurrences of oldString with newString
220: * in the inputString. This function can be replaced with the native
221: * String method replaceAll in JDK 1.4 and above but is provide to support
222: * earlier versions of the JRE.
223: */
224: public static String replaceAll(String inputString,
225: String oldString, String newString) {
226: StringBuffer outputString = new StringBuffer(100);
227: int startIndex = 0, nextIndex;
228: while (inputString.substring(startIndex).indexOf(oldString) > -1) {
229: nextIndex = startIndex
230: + inputString.substring(startIndex).indexOf(
231: oldString);
232: if (nextIndex > startIndex) {
233: outputString.append(inputString.substring(startIndex,
234: nextIndex));
235: }
236: outputString.append(newString);
237: startIndex = nextIndex + oldString.length();
238: }
239: if (startIndex <= inputString.length() - 1) {
240: outputString.append(inputString.substring(startIndex));
241: }
242: return outputString.toString();
243: }
244:
245: /*
246: * Check to see if the input string is an integer.
247: */
248: public static boolean isInteger(String inputString) {
249: int testInt;
250: try {
251: testInt = Integer.parseInt(inputString);
252: return true;
253: } catch (Exception e) {
254: return false;
255: }
256: }
257:
258: /*
259: * Convert a string to an int or return a default value.
260: */
261: public static int intValue(String inputString, int defaultValue) {
262: try {
263: return Integer.parseInt(inputString);
264: } catch (Exception e) {
265: return defaultValue;
266: }
267: }
268:
269: /*
270: * Convert a date in the format MM/DD/YYYY to YYYYMMDD
271: */
272: public static String toYMD(String inputDate) {
273: String day, month;
274: FieldTokenizer ft;
275: String[] ftFields;
276: ft = new FieldTokenizer(inputDate, '/', false);
277: ftFields = ft.getFields();
278: if (ftFields.length == 1) {
279: return inputDate;
280: } else if (ftFields.length == 3) {
281: month = ftFields[0];
282: if (month.length() == 1)
283: month = "0" + month;
284: day = ftFields[1];
285: if (day.length() == 1)
286: day = "0" + day;
287: return ftFields[2] + month + day;
288: }
289: return inputDate;
290: }
291:
292: /*
293: * This method formats an action Hashtable for display.
294: */
295: public static String actionToString(Hashtable displayAction) {
296: StringBuffer displayBuffer = new StringBuffer();
297: String displayType, tableName;
298: tinySQLWhere displayWhere;
299: tsColumn createColumn, displayColumn;
300: boolean groupBy = false, orderBy = false;
301: int i;
302: Vector displayTables, displayColumns, columnDefs, displayValues, displayContext;
303: Hashtable tables;
304: displayType = (String) displayAction.get("TYPE");
305: displayBuffer.append(displayType + " ");
306: displayWhere = (tinySQLWhere) null;
307: displayContext = (Vector) null;
308: displayColumns = (Vector) null;
309: if (displayType.equals("SELECT")) {
310: tables = (Hashtable) displayAction.get("TABLES");
311: displayTables = (Vector) tables.get("TABLE_SELECT_ORDER");
312: displayColumns = (Vector) displayAction.get("COLUMNS");
313: displayWhere = (tinySQLWhere) displayAction.get("WHERE");
314: for (i = 0; i < displayColumns.size(); i++) {
315: displayColumn = (tsColumn) displayColumns.elementAt(i);
316: if (displayColumn.getContext("GROUP")) {
317: groupBy = true;
318: continue;
319: } else if (displayColumn.getContext("ORDER")) {
320: orderBy = true;
321: continue;
322: }
323: if (i > 0)
324: displayBuffer.append(",");
325: displayBuffer.append((String) displayColumn.name);
326: }
327: displayBuffer.append(" FROM ");
328: for (i = 0; i < displayTables.size(); i++) {
329: if (i > 0)
330: displayBuffer.append(",");
331: displayBuffer.append((String) displayTables
332: .elementAt(i));
333: }
334: } else if (displayType.equals("DROP_TABLE")) {
335: tableName = (String) displayAction.get("TABLE");
336: displayBuffer.append(tableName);
337: } else if (displayType.equals("CREATE_TABLE")) {
338: tableName = (String) displayAction.get("TABLE");
339: displayBuffer.append(tableName + " (");
340: columnDefs = (Vector) displayAction.get("COLUMN_DEF");
341: for (i = 0; i < columnDefs.size(); i++) {
342: if (i > 0)
343: displayBuffer.append(",");
344: createColumn = (tsColumn) columnDefs.elementAt(i);
345: displayBuffer.append(createColumn.name + " "
346: + createColumn.type + "( " + createColumn.size
347: + "," + createColumn.decimalPlaces + ")");
348: }
349: displayBuffer.append(")");
350: } else if (displayType.equals("INSERT")) {
351: tableName = (String) displayAction.get("TABLE");
352: displayBuffer.append("INTO " + tableName + "(");
353: displayColumns = (Vector) displayAction.get("COLUMNS");
354: for (i = 0; i < displayColumns.size(); i++) {
355: if (i > 0)
356: displayBuffer.append(",");
357: displayBuffer.append((String) displayColumns
358: .elementAt(i));
359: }
360: displayBuffer.append(") VALUES (");
361: displayValues = (Vector) displayAction.get("VALUES");
362: for (i = 0; i < displayValues.size(); i++) {
363: if (i > 0)
364: displayBuffer.append(",");
365: displayBuffer.append((String) displayValues
366: .elementAt(i));
367: }
368: displayBuffer.append(")");
369: } else if (displayType.equals("UPDATE")) {
370: tableName = (String) displayAction.get("TABLE");
371: displayBuffer.append(tableName + " SET ");
372: displayColumns = (Vector) displayAction.get("COLUMNS");
373: displayValues = (Vector) displayAction.get("VALUES");
374: displayWhere = (tinySQLWhere) displayAction.get("WHERE");
375: for (i = 0; i < displayColumns.size(); i++) {
376: if (i > 0)
377: displayBuffer.append(",");
378: displayBuffer.append((String) displayColumns
379: .elementAt(i)
380: + "=" + (String) displayValues.elementAt(i));
381: }
382: } else if (displayType.equals("DELETE")) {
383: tableName = (String) displayAction.get("TABLE");
384: displayBuffer.append(" FROM " + tableName);
385: displayWhere = (tinySQLWhere) displayAction.get("WHERE");
386: }
387: if (displayWhere != (tinySQLWhere) null) {
388: displayBuffer.append(displayWhere.toString());
389: }
390: if (groupBy) {
391: displayBuffer.append(" GROUP BY ");
392: for (i = 0; i < displayColumns.size(); i++) {
393: displayColumn = (tsColumn) displayColumns.elementAt(i);
394: if (!displayColumn.getContext("GROUP"))
395: continue;
396: if (!displayBuffer.toString().endsWith(" GROUP BY "))
397: displayBuffer.append(",");
398: displayBuffer.append(displayColumn.name);
399: }
400: }
401: if (orderBy) {
402: displayBuffer.append(" ORDER BY ");
403: for (i = 0; i < displayColumns.size(); i++) {
404: displayColumn = (tsColumn) displayColumns.elementAt(i);
405: if (!displayColumn.getContext("ORDER"))
406: continue;
407: if (!displayBuffer.toString().endsWith(" ORDER BY "))
408: displayBuffer.append(",");
409: displayBuffer.append(displayColumn.name);
410: }
411: }
412: return displayBuffer.toString();
413: }
414:
415: /*
416: * Find the input table alias in the list provided and return the table name.
417: */
418: public static String findTableForAlias(String inputAlias,
419: Vector tableList) throws tinySQLException {
420: int i, aliasAt;
421: String tableAndAlias;
422: tableAndAlias = findTableAlias(inputAlias, tableList);
423: aliasAt = tableAndAlias.indexOf("->");
424: return tableAndAlias.substring(0, aliasAt);
425: }
426:
427: /*
428: * Find the input table alias in the list provided and return the table name
429: * and alias in the form tableName=tableAlias.
430: */
431: public static String findTableAlias(String inputAlias,
432: Vector tableList) throws tinySQLException {
433: int i, aliasAt;
434: String tableAndAlias, tableName, tableAlias;
435: for (i = 0; i < tableList.size(); i++) {
436: tableAndAlias = (String) tableList.elementAt(i);
437: aliasAt = tableAndAlias.indexOf("->");
438: tableName = tableAndAlias.substring(0, aliasAt);
439: tableAlias = tableAndAlias.substring(aliasAt + 2);
440: if (inputAlias.equals(tableAlias)) {
441: return tableAndAlias;
442: }
443: }
444: throw new tinySQLException("Unable to identify table alias "
445: + inputAlias);
446: }
447:
448: /*
449: * Determine a type for the input string.
450: */
451: public static int getValueType(String inputValue) {
452: double doubleValue;
453: long intValue;
454: if (inputValue.startsWith("\"") | inputValue.startsWith("'"))
455: return Types.CHAR;
456: try {
457: /*
458: * If the parse methods don't generate an exception this is a
459: * valid number
460: */
461: if (inputValue.trim().indexOf(".") > -1) {
462: doubleValue = Double.parseDouble(inputValue.trim());
463: return Types.FLOAT;
464: } else {
465: intValue = Long.parseLong(inputValue.trim());
466: return Types.INTEGER;
467: }
468: } catch (Exception e) {
469: return Types.CHAR;
470: }
471: }
472: }
|