001: /*
002: * tinySQLParser
003: *
004: * $Author: davis $
005: * $Date: 2004/12/18 21:28:17 $
006: * $Revision: 1.1 $
007: *
008: * This simple token based parser replaces the CUP generated parser
009: * simplifying extensions and reducing the total amount of code in
010: * tinySQL considerably.
011: *
012: * This library is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU Lesser General Public
014: * License as published by the Free Software Foundation; either
015: * version 2.1 of the License, or (at your option) any later version.
016: *
017: * This library is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
020: * Lesser General Public License for more details.
021: *
022: * You should have received a copy of the GNU Lesser General Public
023: * License along with this library; if not, write to the Free Software
024: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
025: *
026: * Revision History;
027: *
028: * Written by Davis Swan in April, 2004.
029: */
030:
031: package com.sqlmagic.tinysql;
032:
033: import java.io.*;
034: import java.util.*;
035: import java.text.*;
036: import java.sql.Types;
037:
038: public class tinySQLParser {
039: Vector columnList, tableList, actionList, valueList, contextList,
040: columnAliasList, columns;
041: Hashtable tables;
042: tinySQL dbEngine;
043: tinySQLWhere whereClause;
044: String tableName, tableAlias, dataDir;
045: String statementType = (String) null;
046: String lastKeyWord = (String) null, orderType = (String) null;
047: String oldColumnName = (String) null,
048: newColumnName = (String) null;
049: String[] colTypeNames = { "INT", "FLOAT", "CHAR", "DATE" };
050: int[] colTypes = { Types.INTEGER, Types.FLOAT, Types.CHAR,
051: Types.DATE };
052: boolean distinct = false, defaultOrderBy = true;
053:
054: public tinySQLParser(InputStream sqlInput, tinySQL inputEngine)
055: throws tinySQLException {
056: StreamTokenizer st;
057: FieldTokenizer ft;
058: Reader r;
059: String nextToken, upperField, nextField, keyWord = (String) null;
060: StringBuffer cmdBuffer, inputSQLBuffer;
061: int lastIndex, keyIndex;
062: r = new BufferedReader(new InputStreamReader(sqlInput));
063: dbEngine = inputEngine;
064: actionList = new Vector();
065: columnList = new Vector();
066: columns = new Vector();
067: columnAliasList = new Vector();
068: contextList = new Vector();
069: valueList = new Vector();
070: tableName = (String) null;
071: whereClause = (tinySQLWhere) null;
072: /*
073: * The tableList is a list of table names, in the optimal order
074: * in which they should be scanned for the SELECT phrase.
075: * The Hashtable tables contains table objects keyed by table
076: * alias and name.
077: */
078: tableList = new Vector();
079: tables = new Hashtable();
080: tables.put("TABLE_SELECT_ORDER", tableList);
081: try {
082: st = new StreamTokenizer(r);
083: st.eolIsSignificant(false);
084: st.wordChars('\'', '}');
085: st.wordChars('?', '?');
086: st.wordChars('"', '.');
087: st.ordinaryChars('0', '9');
088: st.wordChars('0', '9');
089: cmdBuffer = new StringBuffer();
090: inputSQLBuffer = new StringBuffer();
091: while (st.nextToken() != StreamTokenizer.TT_EOF) {
092: if (st.ttype == StreamTokenizer.TT_WORD)
093: nextToken = st.sval.trim();
094: else
095: continue;
096: if (inputSQLBuffer.length() > 0)
097: inputSQLBuffer.append(" ");
098: inputSQLBuffer.append(nextToken);
099: }
100: ft = new FieldTokenizer(inputSQLBuffer.toString(), ' ',
101: false);
102: while (ft.hasMoreFields()) {
103: nextField = ft.nextField();
104: upperField = nextField.toUpperCase();
105: if (statementType == (String) null) {
106: statementType = upperField;
107: lastIndex = getKeywordIndex(statementType,
108: statementType);
109: if (lastIndex != 0)
110: throwException(9);
111: keyWord = statementType;
112: } else {
113: keyIndex = getKeywordIndex(statementType,
114: upperField);
115: if (keyIndex < 0) {
116: if (cmdBuffer.length() > 0)
117: cmdBuffer.append(" ");
118: cmdBuffer.append(nextField);
119: } else {
120: setPhrase(keyWord, cmdBuffer.toString());
121: cmdBuffer = new StringBuffer();
122: keyWord = upperField;
123: if (tinySQLGlobals.PARSER_DEBUG)
124: System.out.println("Found keyword "
125: + keyWord);
126: }
127: }
128: }
129: if (keyWord != (String) null)
130: setPhrase(keyWord, cmdBuffer.toString());
131: addAction();
132: if (tinySQLGlobals.PARSER_DEBUG)
133: System.out.println("SQL:" + inputSQLBuffer.toString());
134: } catch (Exception ex) {
135: if (tinySQLGlobals.DEBUG)
136: ex.printStackTrace(System.out);
137: throw new tinySQLException(ex.getMessage());
138: }
139: }
140:
141: /*
142: * This method sets up particular phrase elements for the SQL command.
143: * Examples would be a list of selected columns and tables for a SELECT
144: * statement, or a list of column definitions for a CREATE TABLE
145: * statement. These phrase elements will be added to the action list
146: * once the entire statement has been parsed.
147: */
148: public void setPhrase(String inputKeyWord, String inputString)
149: throws tinySQLException {
150: String nextField, upperField, colTypeStr, colTypeSpec, fieldString, syntaxErr, tempString, columnName, columnAlias;
151: StringBuffer colTypeBuffer, concatBuffer;
152: FieldTokenizer ft1, ft2, ft3;
153: tsColumn createColumn;
154: int i, j, k, lenc, colType, countFields;
155: /*
156: * Handle compound keywords.
157: */
158: if (inputString == (String) null) {
159: lastKeyWord = inputKeyWord;
160: return;
161: } else if (inputString.trim().length() == 0) {
162: lastKeyWord = inputKeyWord;
163: return;
164: }
165: if (tinySQLGlobals.PARSER_DEBUG)
166: System.out.println("setPhrase " + inputString);
167: ft1 = new FieldTokenizer(inputString, ',', false);
168: while (ft1.hasMoreFields()) {
169: nextField = ft1.nextField().trim();
170: if (tinySQLGlobals.PARSER_DEBUG)
171: System.out.println(inputKeyWord + " field is "
172: + nextField);
173: upperField = nextField.toUpperCase();
174: if (inputKeyWord.equals("SELECT")) {
175: /*
176: * Check for the keyword DISTINCT
177: */
178: if (nextField.toUpperCase().startsWith("DISTINCT")) {
179: distinct = true;
180: nextField = nextField.substring(9).trim();
181: }
182: /*
183: * Check for and set column alias.
184: */
185: ft2 = new FieldTokenizer(nextField, ' ', false);
186: columnName = ft2.getField(0);
187: columnAlias = (String) null;
188: /*
189: * A column alias can be preceded by the keyword AS which will
190: * be ignored by tinySQL.
191: */
192: if (ft2.countFields() == 2)
193: columnAlias = ft2.getField(1);
194: else if (ft2.countFields() == 3)
195: columnAlias = ft2.getField(2);
196: /*
197: * Check for column concatenation using the | symbol
198: */
199: ft2 = new FieldTokenizer(columnName, '|', false);
200: if (ft2.countFields() > 1) {
201: concatBuffer = new StringBuffer("CONCAT(");
202: while (ft2.hasMoreFields()) {
203: if (concatBuffer.length() > 7)
204: concatBuffer.append(",");
205: concatBuffer.append(ft2.nextField());
206: }
207: columnName = concatBuffer.toString() + ")";
208: }
209: columnList.addElement(columnName);
210: columnAliasList.addElement(columnAlias);
211: contextList.addElement(inputKeyWord);
212: } else if (inputKeyWord.equals("TABLE")) {
213: /*
214: * If the input keyword is TABLE, update the statement type to be a
215: * compound type such as CREATE_TABLE, DROP_TABLE, or ALTER_TABLE.
216: */
217: if (!statementType.equals("INSERT"))
218: statementType = statementType + "_TABLE";
219: if (statementType.equals("CREATE_TABLE")) {
220: /*
221: * Parse out the column definition.
222: */
223: ft2 = new FieldTokenizer(nextField, '(', false);
224: if (ft2.countFields() != 2)
225: throwException(1);
226: tableName = ft2.getField(0);
227: fieldString = ft2.getField(1);
228: ft2 = new FieldTokenizer(fieldString, ',', false);
229: while (ft2.hasMoreFields()) {
230: tempString = ft2.nextField();
231: createColumn = parseColumnDefn(tempString);
232: if (createColumn != (tsColumn) null)
233: columnList.addElement(createColumn);
234: }
235: } else if (statementType.equals("DROP_TABLE")) {
236: /*
237: * Handle dropping of non-existent tables
238: */
239: tableName = upperField;
240: try {
241: validateTable(upperField, true);
242: } catch (Exception dropEx) {
243: throw new tinySQLException("Table " + tableName
244: + " does not exist.");
245: }
246: } else {
247: tableName = upperField;
248: validateTable(upperField, true);
249: }
250: } else if (inputKeyWord.equals("BY")) {
251: /*
252: * Set up Group by and Order by columns.
253: */
254: if (lastKeyWord == (String) null) {
255: throwException(6);
256: } else {
257: ft3 = new FieldTokenizer(upperField, ' ', false);
258: columnList.addElement(ft3.getField(0));
259: if (ft3.countFields() == 2) {
260: /*
261: * ASC or DESC are the only allowable directives after GROUP BY
262: */
263: if (ft3.getField(1).startsWith("ASC")
264: | ft3.getField(1).startsWith("DESC"))
265: orderType = ft3.getField(1);
266: else
267: throwException(7);
268: }
269: if (lastKeyWord.equals("ORDER"))
270: defaultOrderBy = false;
271: contextList.addElement(lastKeyWord);
272: }
273: } else if (inputKeyWord.equals("DROP")) {
274: /*
275: * Parse list of columns to be dropped.
276: */
277: statementType = "ALTER_DROP";
278: ft2 = new FieldTokenizer(upperField, ' ', false);
279: while (ft2.hasMoreFields()) {
280: columnList.addElement(UtilString.removeQuotes(ft2
281: .nextField()));
282: }
283: } else if (inputKeyWord.equals("RENAME")) {
284: /*
285: * Parse old and new column name.
286: */
287: statementType = "ALTER_RENAME";
288: ft2 = new FieldTokenizer(upperField, ' ', false);
289: oldColumnName = ft2.getField(0);
290: newColumnName = ft2.getField(1);
291: if (newColumnName.equals("TO") & ft2.countFields() == 3)
292: newColumnName = ft2.getField(2);
293: if (newColumnName.length() > 11)
294: newColumnName = tinySQLGlobals
295: .getShortName(newColumnName);
296: } else if (inputKeyWord.equals("ADD")) {
297: /*
298: * Parse definition of columns to be added.
299: */
300: statementType = "ALTER_ADD";
301: createColumn = parseColumnDefn(nextField);
302: if (createColumn != (tsColumn) null)
303: columnList.addElement(createColumn);
304: } else if (inputKeyWord.equals("FROM")) {
305: /*
306: * Check for valid table
307: */
308: tableName = upperField;
309: validateTable(tableName);
310: } else if (inputKeyWord.equals("INTO")) {
311: ft2 = new FieldTokenizer(nextField, '(', false);
312: if (ft2.countFields() != 2)
313: throwException(3);
314: tableName = ft2.getField(0).toUpperCase();
315: validateTable(tableName);
316: fieldString = ft2.getField(1).toUpperCase();
317: ft2 = new FieldTokenizer(fieldString, ',', false);
318: while (ft2.hasMoreFields()) {
319: tempString = UtilString.removeQuotes(ft2
320: .nextField());
321: columnList.addElement(tempString);
322: contextList.addElement(inputKeyWord);
323: }
324: } else if (inputKeyWord.equals("VALUES")) {
325: ft2 = new FieldTokenizer(nextField, '(', false);
326: fieldString = ft2.getField(0);
327: ft2 = new FieldTokenizer(fieldString, ',', false);
328: while (ft2.hasMoreFields()) {
329: tempString = UtilString.removeQuotes(ft2
330: .nextField());
331: tempString = UtilString.replaceAll(tempString,
332: "''", "'");
333: valueList.addElement(tempString);
334: }
335: } else if (inputKeyWord.equals("UPDATE")) {
336: tableName = nextField.toUpperCase();
337: validateTable(tableName);
338: } else if (inputKeyWord.equals("SET")) {
339: /*
340: * Parse the update column name/value pairs
341: */
342: ft2 = new FieldTokenizer(nextField, '=', false);
343: if (ft2.countFields() != 2)
344: throwException(4);
345: columnList.addElement(ft2.getField(0));
346: contextList.addElement(inputKeyWord);
347: valueList.addElement(UtilString.removeQuotes(ft2
348: .getField(1)));
349: } else if (inputKeyWord.equals("WHERE")) {
350: whereClause = new tinySQLWhere(nextField, tables);
351: } else if (!inputKeyWord.equals("TABLE")) {
352: throwException(10);
353: }
354: }
355: lastKeyWord = inputKeyWord;
356: }
357:
358: public void validateTable(String tableSpec) throws tinySQLException {
359: validateTable(tableSpec, false);
360: }
361:
362: public void validateTable(String tableSpec, boolean closeTable)
363: throws tinySQLException {
364: /*
365: * Create a table object for each table used in the SELECT statement
366: * and store these objects in the tables Hashtable. Save the original
367: * list of table names to set the default selection order.
368: *
369: * If closeTable is true the table object will be closed after it is
370: * validated (for DROP TABLE and ALTER TABLE commands).
371: */
372: String tableName, tableAlias, tableNameAndAlias, sortName;
373: tinySQLTable addTable, sortTable;
374: boolean tableAdded;
375: FieldTokenizer ftTable;
376: int i, addRowCount, sortRowCount;
377: ftTable = new FieldTokenizer(tableSpec, ' ', false);
378: tableName = ftTable.getField(0);
379: tableAlias = (ftTable.getField(1, tableName)).toUpperCase();
380: tableNameAndAlias = tableName + "->" + tableAlias;
381: addTable = dbEngine.getTable(tableNameAndAlias);
382: addTable.GoTop();
383: addRowCount = addTable.GetRowCount();
384: if (closeTable)
385: addTable.close();
386: if (tinySQLGlobals.PARSER_DEBUG)
387: System.out.println("Add table " + tableNameAndAlias
388: + " to tables");
389: tables.put(tableNameAndAlias, addTable);
390: tableAdded = false;
391: for (i = 0; i < tableList.size(); i++) {
392: sortName = (String) tableList.elementAt(i);
393: sortTable = (tinySQLTable) tables.get(sortName);
394: sortRowCount = sortTable.GetRowCount();
395: /*
396: * Sort the table selections from smallest to largest table to
397: * enhance the query performance.
398: */
399: if (addRowCount > sortRowCount)
400: continue;
401: tableList.insertElementAt(tableNameAndAlias, i);
402: tableAdded = true;
403: break;
404: }
405: if (!tableAdded)
406: tableList.addElement(tableNameAndAlias);
407: if (tinySQLGlobals.PARSER_DEBUG) {
408: System.out.println("Table selection order");
409: for (i = 0; i < tableList.size(); i++) {
410: sortName = (String) tableList.elementAt(i);
411: sortTable = (tinySQLTable) tables.get(sortName);
412: sortRowCount = sortTable.GetRowCount();
413: System.out.println(sortName + " " + sortRowCount);
414: }
415: }
416: }
417:
418: /*
419: * Validate the column specifications by checking against the tables.
420: */
421: public void validateColumns() throws tinySQLException {
422: String columnName, columnAlias, columnContext;
423: tsColumn columnObject;
424: boolean selectStar;
425: tinySQLTable jtbl;
426: int i, j;
427: /*
428: * Check for a column named *
429: */
430: selectStar = false;
431: for (i = 0; i < columnList.size(); i++) {
432: columnName = (String) columnList.elementAt(i);
433: columnContext = (String) contextList.elementAt(i);
434: if (columnName.equals("*")) {
435: if (!columnContext.equals("SELECT"))
436: throw new tinySQLException(
437: "* must be a SELECT column.");
438: selectStar = true;
439: break;
440: }
441: }
442: if (selectStar) {
443: /*
444: * A column * has been found. Delete the existing list of SELECT
445: * columns and replace by using an enumeration variable to cycle through
446: * the columns in the tables Hashtable.
447: */
448: for (i = 0; i < columnList.size(); i++) {
449: columnContext = (String) contextList.elementAt(i);
450: if (columnContext.equals("SELECT")) {
451: columnList.removeElementAt(i);
452: contextList.removeElementAt(i);
453: columnAliasList.removeElementAt(i);
454: }
455: }
456: for (i = 0; i < tableList.size(); i++) {
457: jtbl = (tinySQLTable) tables.get((String) tableList
458: .elementAt(i));
459: /*
460: * Expand to all columns.
461: */
462: for (j = 0; j < jtbl.columnNameKeys.size(); j++) {
463: columnName = (String) jtbl.columnNameKeys
464: .elementAt(j);
465: columnList.addElement(jtbl.table + "->"
466: + jtbl.tableAlias + "." + columnName);
467: columnAliasList.addElement(columnName);
468: contextList.addElement("SELECT");
469: }
470: }
471: }
472: /*
473: * Build a column object for each selected column.
474: */
475: if (tables == (Hashtable) null)
476: System.out
477: .println("*****Column validation - no tables defined.");
478: for (i = 0; i < columnList.size(); i++) {
479: columnName = (String) columnList.elementAt(i);
480: columnContext = (String) contextList.elementAt(i);
481: columnAlias = (String) null;
482: if (i < columnAliasList.size())
483: columnAlias = (String) columnAliasList.elementAt(i);
484: columnObject = new tsColumn(columnName, tables,
485: columnContext);
486: columnObject.alias = UtilString.removeQuotes(columnAlias);
487: columns.addElement(columnObject);
488: }
489: }
490:
491: /*
492: * Parse out the column definition for a CREATE statement.
493: */
494: public tsColumn parseColumnDefn(String columnDefn)
495: throws tinySQLException {
496: tsColumn createColumn;
497: int i;
498: FieldTokenizer ft;
499: String columnName, fieldString, tempString, colTypeStr, colTypeSpec;
500: ft = new FieldTokenizer(columnDefn.toUpperCase(), ' ', false);
501: /*
502: * A column definition must consist of a column name followed by a
503: * column specification.
504: */
505: if (ft.countFields() < 2)
506: throwException(2);
507: columnName = ft.getField(0);
508: /*
509: * Check for quotes around a column name that may contain blanks.
510: */
511: if (columnName.charAt(0) == '"'
512: & columnName.charAt(columnName.length() - 1) == '"')
513: columnName = columnName.substring(1,
514: columnName.length() - 1);
515: if (columnName.length() > 11) {
516: columnName = tinySQLGlobals.getShortName(columnName);
517: }
518: createColumn = new tsColumn(columnName);
519: colTypeStr = "";
520: for (i = 1; i < ft.countFields(); i++)
521: colTypeStr += ft.getField(1);
522: ft = new FieldTokenizer(colTypeStr, '(', false);
523: colTypeStr = ft.getField(0);
524: createColumn.size = 10;
525: createColumn.decimalPlaces = 0;
526: if (colTypeStr.equals("FLOAT")) {
527: createColumn.size = 12;
528: createColumn.decimalPlaces = 2;
529: }
530: colTypeSpec = ft.getField(1);
531: if (!colTypeSpec.equals("NULL")) {
532: /*
533: * Parse out the scale and precision if supplied.
534: */
535: ft = new FieldTokenizer(colTypeSpec, ',', false);
536: createColumn.size = ft.getInt(0, 8);
537: createColumn.decimalPlaces = ft.getInt(1, 0);
538: }
539: createColumn.type = Integer.MIN_VALUE;
540: for (i = 0; i < colTypeNames.length; i++)
541: if (colTypeStr.equals(colTypeNames[i]))
542: createColumn.type = colTypes[i];
543: if (createColumn.type == Integer.MIN_VALUE)
544: throwException(8);
545: if (tinySQLGlobals.PARSER_DEBUG)
546: System.out.println("Column " + createColumn.name
547: + ", type is " + createColumn.type + ",size is "
548: + createColumn.size + ",precision is "
549: + createColumn.decimalPlaces);
550: return createColumn;
551: }
552:
553: /*
554: * This method is used to identify SQL key words, and the order in which they
555: * should appear in the SQL statement.
556: */
557: public int getKeywordIndex(String inputContext, String inputWord) {
558: String[][] sqlSyntax = {
559: { "SELECT", "FROM", "WHERE", "GROUP", "ORDER", "BY" },
560: { "INSERT", "INTO", "VALUES" }, { "DROP", "TABLE" },
561: { "DELETE", "FROM", "WHERE" }, { "CREATE", "TABLE" },
562: { "UPDATE", "SET", "WHERE" },
563: { "ALTER", "TABLE", "DROP", "MODIFY", "ADD", "RENAME" } };
564: int i, j;
565: for (i = 0; i < sqlSyntax.length; i++) {
566: for (j = 0; j < sqlSyntax[i].length; j++) {
567: if (sqlSyntax[i][0].equals(inputContext)
568: & sqlSyntax[i][j].equals(inputWord))
569: return j;
570: }
571: }
572: return Integer.MIN_VALUE;
573: }
574:
575: /*
576: * Add an action Hashtable to the list of actions
577: */
578: public void addAction() throws tinySQLException,
579: CloneNotSupportedException {
580: int i, columnCount;
581: tsColumn checkColumn, orderColumn;
582: Hashtable newAction = new Hashtable();
583: newAction.put("TYPE", statementType);
584: if (statementType.equals("SELECT")) {
585: newAction.put("TABLES", tables);
586: if (whereClause != (tinySQLWhere) null)
587: newAction.put("WHERE", whereClause);
588: /*
589: * Validate the column specifications and expand * if present
590: */
591: validateColumns();
592: /*
593: * If no ORDER BY clause was specified, default to the list of
594: * SELECT columns.
595: */
596: if (defaultOrderBy) {
597: columnCount = columns.size();
598: for (i = 0; i < columnCount; i++) {
599: orderColumn = (tsColumn) (columns.elementAt(i));
600: if (orderColumn.getContext("SELECT")) {
601: orderColumn.addContext("ORDER");
602: }
603: }
604: }
605: newAction.put("COLUMNS", columns);
606: if (orderType != (String) null)
607: newAction.put("ORDER_TYPE", orderType);
608: if (distinct)
609: newAction.put("DISTINCT", "TRUE");
610: } else if (statementType.equals("DROP_TABLE")) {
611: newAction.put("TABLE", tableName);
612: } else if (statementType.equals("CREATE_TABLE")) {
613: newAction.put("TABLE", tableName);
614: newAction.put("COLUMN_DEF", columnList);
615: } else if (statementType.equals("ALTER_RENAME")) {
616: newAction.put("TABLE", tableName);
617: newAction.put("OLD_COLUMN", oldColumnName);
618: newAction.put("NEW_COLUMN", newColumnName);
619: } else if (statementType.equals("ALTER_ADD")) {
620: newAction.put("TABLE", tableName);
621: newAction.put("COLUMN_DEF", columnList);
622: } else if (statementType.equals("ALTER_DROP")) {
623: newAction.put("TABLE", tableName);
624: newAction.put("COLUMNS", columnList);
625: } else if (statementType.equals("DELETE")) {
626: newAction.put("TABLE", tableName);
627: if (whereClause != (tinySQLWhere) null)
628: newAction.put("WHERE", whereClause);
629: } else if (statementType.equals("INSERT")
630: | statementType.equals("UPDATE")) {
631: newAction.put("TABLE", tableName);
632: if (columnList.size() != valueList.size())
633: throwException(5);
634: newAction.put("COLUMNS", columnList);
635: newAction.put("VALUES", valueList);
636: if (whereClause != (tinySQLWhere) null)
637: newAction.put("WHERE", whereClause);
638: }
639: actionList.addElement(newAction);
640: }
641:
642: public void throwException(int exceptionNumber)
643: throws tinySQLException {
644: throwException(exceptionNumber, (String) null);
645: }
646:
647: public void throwException(int exceptionNumber, String parameter)
648: throws tinySQLException {
649: String exMsg = (String) null;
650: if (exceptionNumber == 1)
651: exMsg = "CREATE TABLE must be followed by a table name and a list"
652: + " of column specifications enclosed in brackets.";
653: else if (exceptionNumber == 2)
654: exMsg = "A column specification must consist of a column name"
655: + " followed by a column type specification.";
656: else if (exceptionNumber == 3)
657: exMsg = "INTO should be followed by a table name and "
658: + "a list of columns enclosed in backets.";
659: else if (exceptionNumber == 4)
660: exMsg = "SET must be followed by assignments in the form"
661: + " <columnName>=<value>.";
662: else if (exceptionNumber == 5)
663: exMsg = "INSERT statement number of columns and values provided"
664: + " do not match.";
665: else if (exceptionNumber == 6)
666: exMsg = "BY cannot be the first keyword.";
667: else if (exceptionNumber == 7)
668: exMsg = "ORDER BY can only be followed by the ASC or DESC directives";
669: else if (exceptionNumber == 8)
670: exMsg = "Supported column types are INT,CHAR,FLOAT,DATE";
671: else if (exceptionNumber == 9)
672: exMsg = "Expecting SELECT, INSERT, ALTER, etc. in "
673: + statementType;
674: else if (exceptionNumber == 10)
675: exMsg = "Unrecognized keyword ";
676: throw new tinySQLException(exMsg);
677: }
678:
679: public Vector getActions() {
680: return actionList;
681: }
682: }
|