KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > common > sql > CreateRequest


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2005 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Julie Marguerite.
22  * Contributor(s): Mathieu Peltier, Emmanuel Cecchet.
23  */

24
25 package org.objectweb.cjdbc.common.sql;
26
27 import java.io.IOException JavaDoc;
28 import java.io.Serializable JavaDoc;
29 import java.sql.SQLException JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.StringTokenizer JavaDoc;
32
33 import org.objectweb.cjdbc.common.sql.schema.DatabaseColumn;
34 import org.objectweb.cjdbc.common.sql.schema.DatabaseSchema;
35 import org.objectweb.cjdbc.common.sql.schema.DatabaseTable;
36 import org.objectweb.cjdbc.common.sql.schema.TableColumn;
37 import org.objectweb.cjdbc.common.stream.CJDBCInputStream;
38
39 /**
40  * A <code>CreateRequest</code> is a SQL request of the following syntax:
41  *
42  * <pre>
43  * CREATE [TEMPORARY] TABLE table-name [(column-name column-type [,column-name colum-type]* [,table-constraint-definition]*)]
44  * </pre>
45  *
46  * @author <a HREF="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
47  * @author <a HREF="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
48  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
49  * @version 1.0
50  */

51 public class CreateRequest extends AbstractWriteRequest implements Serializable JavaDoc
52 {
53   private static final long serialVersionUID = 2953585153643414325L;
54
55   /** The table to create. */
56   private transient DatabaseTable table = null;
57
58   /**
59    * List of tables used to fill the created table in case of create query
60    * containing a select.
61    */

62   private transient ArrayList JavaDoc fromTables = null;
63
64   /**
65    * alterDatabaseSchema is true if this create request alters the current
66    * database schema (using create table, create schema, create view) and false
67    * otherwise (create database, create index, create function, create method,
68    * create role, create trigger, create type).
69    * <p>
70    * To force a refresh in case we don't understand the query, we default to
71    * true.
72    */

73   private boolean alterDatabaseSchema = true;
74
75   /**
76    * alterDefinitions is true if this create request alters the current database
77    * definitions (using create function, create method, create trigger, create
78    * type) and false otherwise (create database, create table, create schema,
79    * create view, create index, create role).
80    * <p>
81    * To force a refresh in case we don't understand the query, we default to
82    * true.
83    */

84   private boolean alterDefinitions = true;
85
86   /**
87    * Creates a new <code>CreateRequest</code> instance. The caller must give
88    * an SQL request, without any leading or trailing spaces and beginning with
89    * 'create table ' (it will not be checked).
90    * <p>
91    * If the syntax is incorrect an exception is thrown.
92    *
93    * @param sqlQuery the SQL request
94    * @param escapeProcessing should the driver to escape processing before
95    * sending to the database?
96    * @param timeout an <code>int</code> value
97    * @param lineSeparator the line separator used in the query
98    * @param schema a <code>DatabaseSchema</code> value
99    * @param granularity parsing granularity as defined in
100    * <code>ParsingGranularities</code>
101    * @param isCaseSensitive true if parsing is case sensitive
102    * @exception SQLException if an error occurs
103    */

104   public CreateRequest(String JavaDoc sqlQuery, boolean escapeProcessing, int timeout,
105       String JavaDoc lineSeparator, DatabaseSchema schema, int granularity,
106       boolean isCaseSensitive) throws SQLException JavaDoc
107   {
108     this(sqlQuery, escapeProcessing, timeout, lineSeparator);
109     parse(schema, granularity, isCaseSensitive);
110   }
111
112   /**
113    * Creates a new <code>CreateRequest</code> instance. The caller must give
114    * an SQL request, without any leading or trailing spaces and beginning with
115    * 'create table ' (it will not be checked).
116    * <p>
117    * The request is not parsed but it can be done later by a call to
118    * {@link #parse(DatabaseSchema, int, boolean)}.
119    *
120    * @param sqlQuery the SQL request
121    * @param escapeProcessing should the driver to escape processing before
122    * sending to the database ?
123    * @param timeout an <code>int</code> value
124    * @param lineSeparator the line separator used in the query
125    * @see #parse
126    */

127   public CreateRequest(String JavaDoc sqlQuery, boolean escapeProcessing, int timeout,
128       String JavaDoc lineSeparator)
129   {
130     super(sqlQuery, escapeProcessing, timeout, lineSeparator,
131         RequestType.CREATE);
132   }
133
134   /**
135    * @see AbstractWriteRequest
136    */

137   public CreateRequest(CJDBCInputStream in) throws IOException JavaDoc
138   {
139     super(in, RequestType.CREATE);
140   }
141
142   /**
143    * @see org.objectweb.cjdbc.common.sql.AbstractRequest#parse(org.objectweb.cjdbc.common.sql.schema.DatabaseSchema,
144    * int, boolean)
145    */

146   public void parse(DatabaseSchema schema, int granularity,
147       boolean isCaseSensitive) throws SQLException JavaDoc
148   {
149     if (granularity == ParsingGranularities.NO_PARSING)
150     {
151       isParsed = true;
152       return;
153     }
154
155     String JavaDoc originalSQL = this.trimCarriageReturnAndTabs();
156     String JavaDoc sql = originalSQL.toLowerCase();
157
158     // Strip create
159
sql = sql.substring("create".length()).trim();
160
161     // Check what kind of create we are facing
162
if (sql.startsWith("database") || sql.startsWith("index")
163         || sql.startsWith("unique") || sql.startsWith("role"))
164     { // CREATE DATABASE, CREATE [UNIQUE] INDEX, CREATE ROLE does not alter
165
// anything
166
alterDatabaseSchema = false;
167       alterDefinitions = false;
168       return;
169     }
170     if (sql.startsWith("function") || sql.startsWith("method")
171         || sql.startsWith("procedure") || sql.startsWith("trigger")
172         || sql.startsWith("type"))
173     { // CREATE FUNCTION, CREATE METHOD, CREATE PROCEDURE, CREATE TRIGGER and
174
// CREATE TYPE only alters definitions
175
alterDatabaseSchema = false;
176       alterDefinitions = true;
177       return;
178     }
179     if (sql.startsWith("schema") || sql.startsWith("view"))
180     {
181       alterDatabaseSchema = true;
182       alterDefinitions = false;
183       return;
184     }
185
186     // Let's try to check if we have a 'create [temporary] table '
187
int tableIdx = sql.indexOf("table");
188     if (tableIdx < 0)
189       throw new SQLException JavaDoc("Unsupported CREATE statement: '" + sqlQuery + "'");
190
191     //
192
// Starting from here, everything is just to handle CREATE TABLE statements
193
//
194

195     // Strip up to 'table'
196
sql = sql.substring(tableIdx + 5).trim();
197
198     // Does the query contain a select?
199
int selectIdx = sql.indexOf("select");
200     if (selectIdx != -1 && sql.charAt(selectIdx + 6) != ' ')
201       selectIdx = -1;
202
203     if (isCaseSensitive) // Reverse to the original case
204
sql = originalSQL.substring(originalSQL.length() - sql.length());
205
206     if (selectIdx != -1)
207     {
208       // Get the table on which CREATE occurs
209
int nextSpaceIdx = sql.indexOf(" ");
210       tableName = sql.substring(0, nextSpaceIdx).trim();
211       table = new DatabaseTable(tableName);
212       // Parse the select
213
sql = sql.substring(selectIdx).trim();
214       SelectRequest select = new SelectRequest(sql, false, 60,
215           getLineSeparator());
216       select.parse(schema, granularity, isCaseSensitive);
217       fromTables = select.getFrom();
218       if (granularity > ParsingGranularities.TABLE)
219       { // Update the columns and add them to the table
220
columns = select.getSelect();
221         int size = columns.size();
222         for (int i = 0; i < size; i++)
223         {
224           TableColumn tc = (TableColumn) columns.get(i);
225           table.addColumn(new DatabaseColumn(tc.getColumnName(), false));
226         }
227       }
228     }
229     else
230     {
231       // Get the table on which CREATE occurs
232
// Look for the parenthesis
233
int openParenthesisIdx = sql.indexOf("(");
234       int closeParenthesisIdx = sql.lastIndexOf(")");
235       if ((openParenthesisIdx == -1) && (closeParenthesisIdx == -1))
236       {
237         // no parenthesis found
238
table = new DatabaseTable(sql.trim());
239         if (granularity > ParsingGranularities.TABLE)
240           columns = new ArrayList JavaDoc();
241         return;
242       }
243       else if ((openParenthesisIdx == -1) || (closeParenthesisIdx == -1)
244           || (openParenthesisIdx > closeParenthesisIdx))
245       {
246         throw new SQLException JavaDoc("Syntax error in this CREATE statement: '"
247             + sqlQuery + "'");
248       }
249       else
250       {
251         tableName = sql.substring(0, openParenthesisIdx).trim();
252       }
253       table = new DatabaseTable(tableName);
254
255       // Get the column names
256
if (granularity > ParsingGranularities.TABLE)
257       {
258         columns = new ArrayList JavaDoc();
259         sql = sql.substring(openParenthesisIdx + 1, closeParenthesisIdx).trim();
260         StringTokenizer JavaDoc columnTokens = new StringTokenizer JavaDoc(sql, ",");
261         String JavaDoc word;
262         String JavaDoc lowercaseWord;
263         StringTokenizer JavaDoc wordTokens = null;
264         String JavaDoc token;
265         DatabaseColumn col = null;
266
267         while (columnTokens.hasMoreTokens())
268         {
269           token = columnTokens.nextToken().trim();
270
271           // work around to prevent bug: if the request contains for example:
272
// INDEX foo (col1,col2)
273
// we have to merge the 2 tokens: 'INDEX foo (col1' and 'col2)'
274
if ((token.indexOf("(") != -1) && (token.indexOf(")") == -1))
275           {
276             if (columnTokens.hasMoreTokens())
277               token = token + "," + columnTokens.nextToken().trim();
278             else
279             {
280               tableName = null;
281               columns = null;
282               throw new SQLException JavaDoc("Syntax error in this CREATE statement: '"
283                   + sqlQuery + "'");
284             }
285           }
286
287           // First word of the line: either a column name or
288
// a table constraint definition
289
wordTokens = new StringTokenizer JavaDoc(token, " ");
290           word = wordTokens.nextToken().trim();
291           lowercaseWord = word.toLowerCase();
292
293           // If it's a constraint, index or check keyword do not do anything
294
// else parse the line
295
if (!lowercaseWord.equals("constraint")
296               && !lowercaseWord.equals("index")
297               && !lowercaseWord.equals("check"))
298           {
299             String JavaDoc columnName;
300             boolean isUnique = false;
301             // Check for primary key or unique constraint
302
if (lowercaseWord.equals("primary")
303                 || lowercaseWord.startsWith("unique"))
304             {
305
306               // Get the name of the column
307
openParenthesisIdx = token.indexOf("(");
308               closeParenthesisIdx = token.indexOf(")");
309               if ((openParenthesisIdx == -1) || (closeParenthesisIdx == -1)
310                   || (openParenthesisIdx > closeParenthesisIdx))
311               {
312                 tableName = null;
313                 columns = null;
314                 throw new SQLException JavaDoc(
315                     "Syntax error in this CREATE statement: '" + sqlQuery + "'");
316               }
317
318               columnName = token.substring(openParenthesisIdx + 1,
319                   closeParenthesisIdx).trim();
320
321               int comma;
322               while ((comma = columnName.indexOf(',')) != -1)
323               {
324                 String JavaDoc col1 = columnName.substring(0, comma).trim();
325                 col = table.getColumn(col1);
326                 if (col == null)
327                 {
328                   tableName = null;
329                   columns = null;
330                   throw new SQLException JavaDoc(
331                       "Syntax error in this CREATE statement: '" + sqlQuery
332                           + "'");
333                 }
334                 else
335                   col.setIsUnique(true);
336                 columnName = columnName.substring(comma + 1);
337               }
338
339               // Set this column to unique
340
col = table.getColumn(columnName);
341
342               // Test first if dbTable contains this column. This can fail with
343
// some invalid request, for example:
344
// CREATE TABLE categories(id INT4, name TEXT, PRIMARY KEY((id))
345
if (col == null)
346               {
347                 tableName = null;
348                 columns = null;
349                 throw new SQLException JavaDoc(
350                     "Syntax error in this CREATE statement: '" + sqlQuery + "'");
351               }
352               else
353                 col.setIsUnique(true);
354             }
355             else
356             {
357               // It's a column name
358
columnName = word;
359
360               if (!wordTokens.hasMoreTokens())
361               {
362                 // at least type declaration is required
363
tableName = null;
364                 columns = null;
365                 throw new SQLException JavaDoc(
366                     "Syntax error in this CREATE statement: '" + sqlQuery + "'");
367               }
368
369               // Check for primary key or unique constraints
370
do
371               {
372                 word = wordTokens.nextToken().trim().toLowerCase();
373                 if (word.equals("primary") || word.startsWith("unique"))
374                 {
375                   // Create the column as unique
376
isUnique = true;
377                   break;
378                 }
379               }
380               while (wordTokens.hasMoreTokens());
381
382               // Add the column to the parsed columns list and
383
// to the create DatabaseTable
384
columns.add(new TableColumn(tableName, columnName));
385               table.addColumn(new DatabaseColumn(columnName, isUnique));
386             }
387           }
388         }
389       }
390     }
391     isParsed = true;
392   }
393
394   /**
395    * Returns true if this create request alters the current database schema
396    * (using create table, create schema, create view) and false otherwise
397    * (create database, create index, create function, create method, create
398    * procedure, create role, create trigger, create type).
399    *
400    * @return Returns true if this query alters the database schema.
401    */

402   public boolean altersDatabaseSchema()
403   {
404     return alterDatabaseSchema;
405   }
406
407   /**
408    * Returns true if this create request alters the current database definitions
409    * (using create function, create method, create procedure, create trigger,
410    * create type) and false otherwise (create database, create table, create
411    * schema, create view, create index, create role).
412    *
413    * @return Returns true if this query alters database definitions.
414    */

415   public boolean altersDefinitions()
416   {
417     return alterDefinitions;
418   }
419
420   /**
421    * @see AbstractRequest#cloneParsing(AbstractRequest)
422    */

423   public void cloneParsing(AbstractRequest request)
424   {
425     if (!request.isParsed())
426       return;
427     CreateRequest createRequest = (CreateRequest) request;
428     cloneTableNameAndColumns((AbstractWriteRequest) request);
429     table = createRequest.getDatabaseTable();
430     fromTables = createRequest.getFromTables();
431     isParsed = true;
432   }
433
434   /**
435    * Gets the database table created by this statement (in case of a CREATE
436    * TABLE statement).
437    *
438    * @return a <code>DatabaseTable</code> value
439    */

440   public DatabaseTable getDatabaseTable()
441   {
442     return table;
443   }
444
445   /**
446    * Returns the list of tables used to fill the created table in case of create
447    * query containing a select.
448    *
449    * @return and <code>ArrayList</code>
450    */

451   public ArrayList JavaDoc getFromTables()
452   {
453     return fromTables;
454   }
455
456   /**
457    * @see org.objectweb.cjdbc.common.sql.AbstractRequest#needsMacroProcessing()
458    */

459   public boolean needsMacroProcessing()
460   {
461     return false;
462   }
463
464   /**
465    * @see org.objectweb.cjdbc.common.sql.AbstractRequest#returnsResultSet()
466    */

467   public boolean returnsResultSet()
468   {
469     return false;
470   }
471
472   /**
473    * Displays some debugging information about this request.
474    */

475   public void debug()
476   {
477     super.debug();
478     if (tableName != null)
479       System.out.println("Created table: " + tableName);
480     else
481       System.out.println("No information about created table");
482
483     if (columns != null)
484     {
485       System.out.println("Created columns:");
486       for (int i = 0; i < columns.size(); i++)
487         System.out.println(" "
488             + ((TableColumn) columns.get(i)).getColumnName());
489     }
490     else
491       System.out.println("No information about created columns");
492
493     System.out.println();
494   }
495
496 }
Popular Tags