Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

CreateRequest.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2005 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Julie Marguerite.
00022  * Contributor(s): Mathieu Peltier, Emmanuel Cecchet.
00023  */
00024 
00025 package org.objectweb.cjdbc.common.sql;
00026 
00027 import java.io.Serializable;
00028 import java.sql.SQLException;
00029 import java.util.ArrayList;
00030 import java.util.StringTokenizer;
00031 
00032 import org.objectweb.cjdbc.common.sql.schema.DatabaseColumn;
00033 import org.objectweb.cjdbc.common.sql.schema.DatabaseSchema;
00034 import org.objectweb.cjdbc.common.sql.schema.DatabaseTable;
00035 import org.objectweb.cjdbc.common.sql.schema.TableColumn;
00036 
00037 /**
00038  * A <code>CreateRequest</code> is a SQL request of the following syntax:
00039  * 
00040  * <pre>
00041  *  CREATE [TEMPORARY] TABLE table-name [(column-name column-type [,column-name colum-type]* [,table-constraint-definition]*)]
00042  * </pre>
00043  * 
00044  * @author <a href="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
00045  * @author <a href="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
00046  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00047  * @version 1.0
00048  */
00049 public class CreateRequest extends AbstractWriteRequest implements Serializable
00050 {
00051   /** The table to create. */
00052   private transient DatabaseTable table      = null;
00053 
00054   /**
00055    * List of tables used to fill the created table in case of create query
00056    * containing a select.
00057    */
00058   private transient ArrayList     fromTables = null;
00059 
00060   /**
00061    * Creates a new <code>CreateRequest</code> instance. The caller must give
00062    * an SQL request, without any leading or trailing spaces and beginning with
00063    * 'create table ' (it will not be checked).
00064    * <p>
00065    * If the syntax is incorrect an exception is thrown.
00066    * 
00067    * @param sqlQuery the SQL request
00068    * @param escapeProcessing should the driver to escape processing before
00069    *          sending to the database?
00070    * @param timeout an <code>int</code> value
00071    * @param lineSeparator the line separator used in the query
00072    * @param schema a <code>DatabaseSchema</code> value
00073    * @param granularity parsing granularity as defined in
00074    *          <code>ParsingGranularities</code>
00075    * @param isCaseSensitive true if parsing is case sensitive
00076    * @exception SQLException if an error occurs
00077    */
00078   public CreateRequest(String sqlQuery, boolean escapeProcessing, int timeout,
00079       String lineSeparator, DatabaseSchema schema, int granularity,
00080       boolean isCaseSensitive) throws SQLException
00081   {
00082     this(sqlQuery, escapeProcessing, timeout, lineSeparator);
00083     parse(schema, granularity, isCaseSensitive);
00084   }
00085 
00086   /**
00087    * Creates a new <code>CreateRequest</code> instance. The caller must give
00088    * an SQL request, without any leading or trailing spaces and beginning with
00089    * 'create table ' (it will not be checked).
00090    * <p>
00091    * The request is not parsed but it can be done later by a call to
00092    * {@link #parse(DatabaseSchema, int, boolean)}.
00093    * 
00094    * @param sqlQuery the SQL request
00095    * @param escapeProcessing should the driver to escape processing before
00096    *          sending to the database ?
00097    * @param timeout an <code>int</code> value
00098    * @param lineSeparator the line separator used in the query
00099    * @see #parse
00100    */
00101   public CreateRequest(String sqlQuery, boolean escapeProcessing, int timeout,
00102       String lineSeparator)
00103   {
00104     super(sqlQuery, escapeProcessing, timeout, lineSeparator);
00105     cacheable = RequestType.UNCACHEABLE;
00106     isParsed = false;
00107   }
00108 
00109   /**
00110    * @see org.objectweb.cjdbc.common.sql.AbstractRequest#parse(org.objectweb.cjdbc.common.sql.schema.DatabaseSchema,
00111    *      int, boolean)
00112    */
00113   public void parse(DatabaseSchema schema, int granularity,
00114       boolean isCaseSensitive) throws SQLException
00115   {
00116     if (granularity == ParsingGranularities.NO_PARSING)
00117     {
00118       isParsed = true;
00119       return;
00120     }
00121 
00122     String originalSQL = this.trimCarriageReturn();
00123     String sql = originalSQL.toLowerCase();
00124 
00125     // Strip 'create [temporary] table '
00126     int tableIdx = sql.indexOf("table");
00127     sql = sql.substring(tableIdx + 5).trim();
00128 
00129     // Does the query contain a select?
00130     int selectIdx = sql.indexOf("select");
00131     if (selectIdx != -1 && sql.charAt(selectIdx + 6) != ' ')
00132       selectIdx = -1;
00133 
00134     if (isCaseSensitive) // Reverse to the original case
00135       sql = originalSQL.substring(originalSQL.length() - sql.length());
00136 
00137     if (selectIdx != -1)
00138     {
00139       // Get the table on which CREATE occurs
00140       int nextSpaceIdx = sql.indexOf(" ");
00141       tableName = sql.substring(0, nextSpaceIdx).trim();
00142       table = new DatabaseTable(tableName);
00143       // Parse the select
00144       sql = sql.substring(selectIdx).trim();
00145       SelectRequest select = new SelectRequest(sql, false, 60,
00146           getLineSeparator());
00147       select.parse(schema, granularity, isCaseSensitive);
00148       fromTables = select.getFrom();
00149       if (granularity > ParsingGranularities.TABLE)
00150       { // Update the columns and add them to the table
00151         columns = select.getSelect();
00152         int size = columns.size();
00153         for (int i = 0; i < size; i++)
00154         {
00155           TableColumn tc = (TableColumn) columns.get(i);
00156           table.addColumn(new DatabaseColumn(tc.getColumnName(), false));
00157         }
00158       }
00159     }
00160     else
00161     {
00162       // Get the table on which CREATE occurs
00163       // Look for the parenthesis
00164       int openParenthesisIdx = sql.indexOf("(");
00165       int closeParenthesisIdx = sql.lastIndexOf(")");
00166       if ((openParenthesisIdx == -1) && (closeParenthesisIdx == -1))
00167       {
00168         // no parenthesis found
00169         table = new DatabaseTable(sql.trim());
00170         if (granularity > ParsingGranularities.TABLE)
00171           columns = new ArrayList();
00172         return;
00173       }
00174       else if ((openParenthesisIdx == -1) || (closeParenthesisIdx == -1)
00175           || (openParenthesisIdx > closeParenthesisIdx))
00176       {
00177         throw new SQLException("Syntax error in this CREATE statement: '"
00178             + sqlQuery + "'");
00179       }
00180       else
00181       {
00182         tableName = sql.substring(0, openParenthesisIdx).trim();
00183       }
00184       table = new DatabaseTable(tableName);
00185 
00186       // Get the column names
00187       if (granularity > ParsingGranularities.TABLE)
00188       {
00189         columns = new ArrayList();
00190         sql = sql.substring(openParenthesisIdx + 1, closeParenthesisIdx).trim();
00191         StringTokenizer columnTokens = new StringTokenizer(sql, ",");
00192         String word;
00193         String lowercaseWord;
00194         StringTokenizer wordTokens = null;
00195         String token;
00196         DatabaseColumn col = null;
00197 
00198         while (columnTokens.hasMoreTokens())
00199         {
00200           token = columnTokens.nextToken().trim();
00201 
00202           // work around to prevent bug: if the request contains for example:
00203           // INDEX foo (col1,col2)
00204           // we have to merge the 2 tokens: 'INDEX foo (col1' and 'col2)'
00205           if ((token.indexOf("(") != -1) && (token.indexOf(")") == -1))
00206           {
00207             if (columnTokens.hasMoreTokens())
00208               token = token + "," + columnTokens.nextToken().trim();
00209             else
00210             {
00211               tableName = null;
00212               columns = null;
00213               throw new SQLException("Syntax error in this CREATE statement: '"
00214                   + sqlQuery + "'");
00215             }
00216           }
00217 
00218           // First word of the line: either a column name or
00219           // a table constraint definition
00220           wordTokens = new StringTokenizer(token, " ");
00221           word = wordTokens.nextToken().trim();
00222           lowercaseWord = word.toLowerCase();
00223 
00224           // If it's a constraint, index or check keyword do not do anything
00225           // else parse the line
00226           if (!lowercaseWord.equals("constraint")
00227               && !lowercaseWord.equals("index")
00228               && !lowercaseWord.equals("check"))
00229           {
00230             String columnName;
00231             boolean isUnique = false;
00232             // Check for primary key or unique constraint
00233             if (lowercaseWord.equals("primary")
00234                 || lowercaseWord.startsWith("unique"))
00235             {
00236 
00237               // Get the name of the column
00238               openParenthesisIdx = token.indexOf("(");
00239               closeParenthesisIdx = token.indexOf(")");
00240               if ((openParenthesisIdx == -1) || (closeParenthesisIdx == -1)
00241                   || (openParenthesisIdx > closeParenthesisIdx))
00242               {
00243                 tableName = null;
00244                 columns = null;
00245                 throw new SQLException(
00246                     "Syntax error in this CREATE statement: '" + sqlQuery + "'");
00247               }
00248 
00249               columnName = token.substring(openParenthesisIdx + 1,
00250                   closeParenthesisIdx).trim();
00251 
00252               int comma;
00253               while ((comma = columnName.indexOf(',')) != -1)
00254               {
00255                 String col1 = columnName.substring(0, comma).trim();
00256                 col = table.getColumn(col1);
00257                 if (col == null)
00258                 {
00259                   tableName = null;
00260                   columns = null;
00261                   throw new SQLException(
00262                       "Syntax error in this CREATE statement: '" + sqlQuery
00263                           + "'");
00264                 }
00265                 else
00266                   col.setIsUnique(true);
00267                 columnName = columnName.substring(comma + 1);
00268               }
00269 
00270               // Set this column to unique
00271               col = table.getColumn(columnName);
00272 
00273               // Test first if dbTable contains this column. This can fail with
00274               // some invalid request, for example:
00275               // CREATE TABLE categories(id INT4, name TEXT, PRIMARY KEY((id))
00276               if (col == null)
00277               {
00278                 tableName = null;
00279                 columns = null;
00280                 throw new SQLException(
00281                     "Syntax error in this CREATE statement: '" + sqlQuery + "'");
00282               }
00283               else
00284                 col.setIsUnique(true);
00285             }
00286             else
00287             {
00288               // It's a column name
00289               columnName = word;
00290 
00291               if (!wordTokens.hasMoreTokens())
00292               {
00293                 // at least type declaration is required
00294                 tableName = null;
00295                 columns = null;
00296                 throw new SQLException(
00297                     "Syntax error in this CREATE statement: '" + sqlQuery + "'");
00298               }
00299 
00300               // Check for primary key or unique constraints
00301               do
00302               {
00303                 word = wordTokens.nextToken().trim().toLowerCase();
00304                 if (word.equals("primary") || word.startsWith("unique"))
00305                 {
00306                   // Create the column as unique
00307                   isUnique = true;
00308                   break;
00309                 }
00310               }
00311               while (wordTokens.hasMoreTokens());
00312 
00313               // Add the column to the parsed columns list and
00314               // to the create DatabaseTable
00315               columns.add(new TableColumn(tableName, columnName));
00316               table.addColumn(new DatabaseColumn(columnName, isUnique));
00317             }
00318           }
00319         }
00320       }
00321     }
00322     isParsed = true;
00323   }
00324 
00325   /**
00326    * @see AbstractRequest#cloneParsing(AbstractRequest)
00327    */
00328   public void cloneParsing(AbstractRequest request)
00329   {
00330     if (!request.isParsed())
00331       return;
00332     CreateRequest createRequest = (CreateRequest) request;
00333     cloneTableNameAndColumns((AbstractWriteRequest) request);
00334     table = createRequest.getDatabaseTable();
00335     fromTables = createRequest.getFromTables();
00336     isParsed = true;
00337   }
00338 
00339   /**
00340    * @return <code>true</code>
00341    * @see org.objectweb.cjdbc.common.sql.AbstractWriteRequest#isCreate()
00342    */
00343   public boolean isCreate()
00344   {
00345     return true;
00346   }
00347 
00348   /**
00349    * @return <code>false</code>
00350    * @see org.objectweb.cjdbc.common.sql.AbstractWriteRequest#isInsert()
00351    */
00352   public boolean isInsert()
00353   {
00354     return false;
00355   }
00356 
00357   /**
00358    * @return <code>false</code>
00359    * @see org.objectweb.cjdbc.common.sql.AbstractWriteRequest#isUpdate()
00360    */
00361   public boolean isUpdate()
00362   {
00363     return false;
00364   }
00365 
00366   /**
00367    * @return <code>false</code>
00368    * @see org.objectweb.cjdbc.common.sql.AbstractWriteRequest#isDelete()
00369    */
00370   public boolean isDelete()
00371   {
00372     return false;
00373   }
00374 
00375   /**
00376    * @return <code>false</code>
00377    * @see org.objectweb.cjdbc.common.sql.AbstractWriteRequest#isDrop()
00378    */
00379   public boolean isDrop()
00380   {
00381     return false;
00382   }
00383 
00384   /**
00385    * Gets the database table created by this statement.
00386    * 
00387    * @return a <code>DatabaseTable</code> value
00388    */
00389   public DatabaseTable getDatabaseTable()
00390   {
00391     return table;
00392   }
00393 
00394   /**
00395    * Returns the list of tables used to fill the created table in case of create
00396    * query containing a select.
00397    * 
00398    * @return and <code>ArrayList</code>
00399    */
00400   public ArrayList getFromTables()
00401   {
00402     return fromTables;
00403   }
00404 
00405   /**
00406    * Displays some debugging information about this request.
00407    */
00408   public void debug()
00409   {
00410     super.debug();
00411     if (tableName != null)
00412       System.out.println("Created table: " + tableName);
00413     else
00414       System.out.println("No information about created table");
00415 
00416     if (columns != null)
00417     {
00418       System.out.println("Created columns:");
00419       for (int i = 0; i < columns.size(); i++)
00420         System.out.println("  "
00421             + ((TableColumn) columns.get(i)).getColumnName());
00422     }
00423     else
00424       System.out.println("No information about created columns");
00425 
00426     System.out.println();
00427   }
00428 
00429   /**
00430    * @see org.objectweb.cjdbc.common.sql.AbstractWriteRequest#isAlter()
00431    */
00432   public boolean isAlter()
00433   {
00434     return false;
00435   }
00436 }

Generated on Mon Apr 11 22:01:30 2005 for C-JDBC by  doxygen 1.3.9.1