KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > interpret > CreateTable


1 /**
2  * com.mckoi.database.interpret.CreateTable 14 Sep 2001
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database.interpret;
26
27 import com.mckoi.database.*;
28 import com.mckoi.util.IntegerVector;
29 import java.util.Vector JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.List JavaDoc;
32
33 /**
34  * A parsed state container for the 'create' statement.
35  *
36  * @author Tobias Downer
37  */

38
39 public class CreateTable extends Statement {
40
41   /**
42    * Set to true if this create statement is for a temporary table.
43    */

44   boolean temporary = false;
45
46   /**
47    * Only create if table doesn't exist.
48    */

49   boolean only_if_not_exists = false;
50
51   /**
52    * The name of the table to create.
53    */

54   String JavaDoc table_name;
55
56   /**
57    * List of column declarations (ColumnDef)
58    */

59   ArrayList JavaDoc columns;
60
61   /**
62    * List of table constraints (ConstraintDef)
63    */

64   ArrayList JavaDoc constraints;
65
66 // /**
67
// * The expression that must be evaluated to true for this row to be
68
// * added to the table.
69
// */
70
// Expression check_exp;
71

72   /**
73    * The TableName object.
74    */

75   private TableName tname;
76
77
78 // /**
79
// * Adds a new ColumnDef object to this create statement. A ColumnDef
80
// * object describes a column for the new table we are creating. The column's
81
// * must be added in the order they are to be in the created table.
82
// */
83
// void addColumnDef(ColumnDef column) {
84
// columns.addElement(column);
85
// }
86

87   /**
88    * Adds a new ConstraintDef object to this create statement. A ConstraintDef
89    * object describes any constraints for the new table we are creating.
90    */

91   void addConstraintDef(ConstraintDef constraint) {
92     constraints.add(constraint);
93   }
94
95 // /**
96
// * Handles the create statement 'CHECK' expression for compatibility.
97
// */
98
// void addCheckConstraint(Expression check_expression) {
99
// ConstraintDef constraint = new ConstraintDef();
100
// constraint.setCheck(check_expression);
101
// constraints.addElement(constraint);
102
// }
103

104   /**
105    * Creates a DataTableDef that describes the table that was defined by
106    * this create statement. This is used by the 'alter' statement.
107    */

108   DataTableDef createDataTableDef() throws DatabaseException {
109     // Make all this information into a DataTableDef object...
110
DataTableDef table_def = new DataTableDef();
111     table_def.setTableName(tname);
112     table_def.setTableClass("com.mckoi.database.VariableSizeDataTableFile");
113
114     // Add the columns.
115
// NOTE: Any duplicate column names will be found here...
116
for (int i = 0; i < columns.size(); ++i) {
117       DataTableColumnDef cd = (DataTableColumnDef) columns.get(i);
118       table_def.addColumn(cd);
119     }
120
121     return table_def;
122   }
123
124
125   /**
126    * Adds a schema constraint to the rules for the schema represented by the
127    * manager.
128    */

129   static void addSchemaConstraint(DatabaseConnection manager,
130                                   TableName table, ConstraintDef constraint)
131                                                   throws DatabaseException {
132     if (constraint.type == ConstraintDef.PRIMARY_KEY) {
133       manager.addPrimaryKeyConstraint(table,
134           constraint.getColumnList(), constraint.deferred, constraint.name);
135     }
136     else if (constraint.type == ConstraintDef.FOREIGN_KEY) {
137       // Currently we forbid referencing a table in another schema
138
TableName ref_table =
139                           TableName.resolve(constraint.reference_table_name);
140       String JavaDoc update_rule = constraint.getUpdateRule().toUpperCase();
141       String JavaDoc delete_rule = constraint.getDeleteRule().toUpperCase();
142       if (table.getSchema().equals(ref_table.getSchema())) {
143         manager.addForeignKeyConstraint(
144              table, constraint.getColumnList(),
145              ref_table, constraint.getColumnList2(),
146              delete_rule, update_rule, constraint.deferred, constraint.name);
147       }
148       else {
149         throw new DatabaseException("Foreign key reference error: " +
150                 "Not permitted to reference a table outside of the schema: " +
151                 table + " -> " + ref_table);
152       }
153     }
154     else if (constraint.type == ConstraintDef.UNIQUE) {
155       manager.addUniqueConstraint(table, constraint.getColumnList(),
156                                   constraint.deferred, constraint.name);
157     }
158     else if (constraint.type == ConstraintDef.CHECK) {
159       manager.addCheckConstraint(table, constraint.original_check_expression,
160                                  constraint.deferred, constraint.name);
161     }
162     else {
163       throw new DatabaseException("Unrecognized constraint type.");
164     }
165   }
166
167   /**
168    * Returns a com.mckoi.database.interpret.ColumnDef object a a
169    * com.mckoi.database.DataTableColumnDef object.
170    */

171   static DataTableColumnDef convertColumnDef(ColumnDef cdef) {
172     TType type = cdef.type;
173
174     DataTableColumnDef dtcdef = new DataTableColumnDef();
175     dtcdef.setName(cdef.name);
176     dtcdef.setNotNull(cdef.isNotNull());
177     dtcdef.setFromTType(type);
178
179     if (cdef.index_str != null) {
180       dtcdef.setIndexScheme(cdef.index_str);
181     }
182     if (cdef.default_expression != null) {
183       dtcdef.setDefaultExpression(cdef.original_default_expression);
184     }
185
186     dtcdef.initTTypeInfo();
187     return dtcdef;
188   }
189
190   /**
191    * Sets up all constraints specified in this create statement.
192    */

193   void setupAllConstraints() throws DatabaseException {
194     for (int i = 0; i < constraints.size(); ++i) {
195       ConstraintDef constraint = (ConstraintDef) constraints.get(i);
196
197       // Add this to the schema manager tables
198
addSchemaConstraint(database, tname, constraint);
199     }
200   }
201
202
203
204
205   // ---------- Implemented from Statement ----------
206

207   public void prepare() throws DatabaseException {
208
209     // Get the state from the model
210
temporary = cmd.getBoolean("temporary");
211     only_if_not_exists = cmd.getBoolean("only_if_not_exists");
212     table_name = (String JavaDoc) cmd.getObject("table_name");
213     ArrayList JavaDoc column_list = (ArrayList JavaDoc) cmd.getObject("column_list");
214     constraints = (ArrayList JavaDoc) cmd.getObject("constraint_list");
215
216     // Convert column_list to list of com.mckoi.database.DataTableColumnDef
217
int size = column_list.size();
218     columns = new ArrayList JavaDoc(size);
219     for (int i = 0; i < size; ++i) {
220       ColumnDef cdef = (ColumnDef) column_list.get(i);
221       columns.add(convertColumnDef(cdef));
222     }
223
224     // ----
225

226     String JavaDoc schema_name = database.getCurrentSchema();
227     tname = TableName.resolve(schema_name, table_name);
228
229     String JavaDoc name_strip = tname.getName();
230
231     if (name_strip.indexOf('.') != -1) {
232       throw new DatabaseException("Table name can not contain '.' character.");
233     }
234
235     final boolean ignores_case = database.isInCaseInsensitiveMode();
236
237     // Implement the checker class for this statement.
238
ColumnChecker checker = new ColumnChecker() {
239
240       String JavaDoc resolveColumnName(String JavaDoc col_name) throws DatabaseException {
241         // We need to do case sensitive and case insensitive resolution,
242
String JavaDoc found_col = null;
243         for (int n = 0; n < columns.size(); ++n) {
244           DataTableColumnDef col = (DataTableColumnDef) columns.get(n);
245           if (!ignores_case) {
246             if (col.getName().equals(col_name)) {
247               return col_name;
248             }
249           }
250           else {
251             if (col.getName().equalsIgnoreCase(col_name)) {
252               if (found_col != null) {
253                 throw new DatabaseException("Ambiguous column name '" +
254                                             col_name + "'");
255               }
256               found_col = col.getName();
257             }
258           }
259         }
260         return found_col;
261       }
262
263     };
264
265     ArrayList JavaDoc unique_column_list = new ArrayList JavaDoc();
266     ArrayList JavaDoc primary_key_column_list = new ArrayList JavaDoc();
267
268     // Check the expressions that represent the default values for the columns.
269
// Also check each column name
270
for (int i = 0; i < columns.size(); ++i) {
271       DataTableColumnDef cdef = (DataTableColumnDef) columns.get(i);
272       ColumnDef model_cdef = (ColumnDef) column_list.get(i);
273       checker.checkExpression(cdef.getDefaultExpression(database.getSystem()));
274       String JavaDoc col_name = cdef.getName();
275       // If column name starts with [table_name]. then strip it off
276
cdef.setName(checker.stripTableName(name_strip, col_name));
277       // If unique then add to unique columns
278
if (model_cdef.isUnique()) {
279         unique_column_list.add(col_name);
280       }
281       // If primary key then add to primary key columns
282
if (model_cdef.isPrimaryKey()) {
283         primary_key_column_list.add(col_name);
284       }
285     }
286
287     // Add the unique and primary key constraints.
288
if (unique_column_list.size() > 0) {
289       ConstraintDef constraint = new ConstraintDef();
290       constraint.setUnique(unique_column_list);
291       addConstraintDef(constraint);
292     }
293     if (primary_key_column_list.size() > 0) {
294       ConstraintDef constraint = new ConstraintDef();
295       constraint.setPrimaryKey(primary_key_column_list);
296       addConstraintDef(constraint);
297     }
298
299     // Strip the column names and set the expression in all the constraints.
300
for (int i = 0; i < constraints.size(); ++i) {
301       ConstraintDef constraint = (ConstraintDef) constraints.get(i);
302       checker.stripColumnList(name_strip, constraint.column_list);
303       // Check the referencing table for foreign keys
304
if (constraint.type == ConstraintDef.FOREIGN_KEY) {
305         checker.stripColumnList(constraint.reference_table_name,
306                                 constraint.column_list2);
307         TableName ref_tname =
308                  resolveTableName(constraint.reference_table_name, database);
309         if (database.isInCaseInsensitiveMode()) {
310           ref_tname = database.tryResolveCase(ref_tname);
311         }
312         constraint.reference_table_name = ref_tname.toString();
313
314         DataTableDef ref_table_def;
315         if (database.tableExists(ref_tname)) {
316           // Get the DataTableDef for the table we are referencing
317
ref_table_def = database.getDataTableDef(ref_tname);
318         }
319         else if (ref_tname.equals(tname)) {
320           // We are referencing the table we are creating
321
ref_table_def = createDataTableDef();
322         }
323         else {
324           throw new DatabaseException(
325                 "Referenced table '" + ref_tname + "' in constraint '" +
326                 constraint.name + "' does not exist.");
327         }
328         // Resolve columns against the given table def
329
ref_table_def.resolveColumnsInArray(database, constraint.column_list2);
330
331       }
332       checker.checkExpression(constraint.check_expression);
333       checker.checkColumnList(constraint.column_list);
334     }
335
336   }
337
338   public Table evaluate() throws DatabaseException {
339
340     DatabaseQueryContext context = new DatabaseQueryContext(database);
341
342     // Does the schema exist?
343
boolean ignore_case = database.isInCaseInsensitiveMode();
344     SchemaDef schema =
345             database.resolveSchemaCase(tname.getSchema(), ignore_case);
346     if (schema == null) {
347       throw new DatabaseException("Schema '" + tname.getSchema() +
348                                   "' doesn't exist.");
349     }
350     else {
351       tname = new TableName(schema.getName(), tname.getName());
352     }
353
354     // Does the user have privs to create this tables?
355
if (!database.getDatabase().canUserCreateTableObject(context,
356                                                          user, tname)) {
357       throw new UserAccessException(
358          "User not permitted to create table: " + table_name);
359     }
360
361
362     
363     // PENDING: Creation of temporary tables...
364

365
366
367
368     // Does the table already exist?
369
if (!database.tableExists(tname)) {
370
371       // Create the data table definition and tell the database to create
372
// it.
373
DataTableDef table_def = createDataTableDef();
374       database.createTable(table_def);
375
376       // The initial grants for a table is to give the user who created it
377
// full access.
378
database.getGrantManager().addGrant(
379            Privileges.TABLE_ALL_PRIVS, GrantManager.TABLE, tname.toString(),
380            user.getUserName(), true, Database.INTERNAL_SECURE_USERNAME);
381
382       // Set the constraints in the schema.
383
setupAllConstraints();
384
385       // Return '0' if we created the table. (0 rows affected)
386
return FunctionTable.resultTable(context, 0);
387     }
388
389     // Report error unless 'if not exists' command is in the statement.
390
if (only_if_not_exists == false) {
391       throw new DatabaseException("Table '" + tname + "' already exists.");
392     }
393
394     // Return '0' (0 rows affected). This happens when we don't create a
395
// table (because it exists) and the 'IF NOT EXISTS' clause is present.
396
return FunctionTable.resultTable(context, 0);
397
398   }
399
400 }
401
Popular Tags