KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > sql > Table


1 package com.quadcap.sql;
2
3 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.io.ByteArrayOutputStream JavaDoc;
42 import java.io.BufferedInputStream JavaDoc;
43 import java.io.BufferedOutputStream JavaDoc;
44 import java.io.Externalizable JavaDoc;
45 import java.io.IOException JavaDoc;
46 import java.io.InputStream JavaDoc;
47 import java.io.ObjectInput JavaDoc;
48 import java.io.ObjectOutput JavaDoc;
49 import java.io.OutputStream JavaDoc;
50
51 import java.util.BitSet JavaDoc;
52 import java.util.Hashtable JavaDoc;
53 import java.util.Vector JavaDoc;
54
55 import java.sql.ResultSet JavaDoc;
56 import java.sql.ResultSetMetaData JavaDoc;
57 import java.sql.SQLException JavaDoc;
58
59 import com.quadcap.sql.io.ObjectInputStream;
60 import com.quadcap.sql.io.ObjectOutputStream;
61
62 import com.quadcap.sql.index.Btree;
63
64 import com.quadcap.sql.file.BlockFile;
65 import com.quadcap.sql.file.ByteUtil;
66 import com.quadcap.sql.file.Datafile;
67 import com.quadcap.sql.file.Page;
68 import com.quadcap.sql.file.PageManager;
69 import com.quadcap.sql.file.RandomAccess;
70 import com.quadcap.sql.file.RandomAccessOutputStream;
71 import com.quadcap.sql.file.SubPageManager;
72
73 import com.quadcap.sql.types.Type;
74 import com.quadcap.sql.types.TypeBlob;
75 import com.quadcap.sql.types.TypeClob;
76 import com.quadcap.sql.types.Value;
77
78 import com.quadcap.util.ConfigNumber;
79 import com.quadcap.util.Debug;
80 import com.quadcap.util.Util;
81
82
83 /**
84  * A single SQL base table.
85  *
86  * @author Stan Bailes
87  */

88 public class Table extends TupleImpl implements Relation, Externalizable JavaDoc {
89     // bit 0: table insert
90

91     int modifiers = 0;
92     Constraint[] constraints = new Constraint[0];
93     transient boolean underConstruction = false;
94
95     // init: 0, if blobs: 1, else 2;
96
transient int hasBlobs = 0;
97
98     /**
99      * Table modifiers, bit fields. If temporary, either global or local
100      * must be specified.
101      */

102     public static final int TEMPORARY = 1;
103     public static final int LOCAL = 2;
104     public static final int GLOBAL = 4;
105     public static final int STATEMENT_TEMP = 8;
106
107     /**
108      * For in-memory mode, the table identity
109      */

110     long tableIdentity = 1;
111
112     /**
113      * Default constructor (required for deserialization)
114      */

115     public Table() {}
116     
117     /**
118      * Explicit constructor
119      */

120     public Table(String JavaDoc tableName, int modifiers) {
121     super(tableName);
122     this.modifiers = modifiers;
123     }
124
125     /**
126      * Get/Set the value of the 'is under construction' flag. This is used to
127      * determine when ADD CONSTRAINT really has work to do ;-)
128      */

129     public boolean isUnderConstruction() { return underConstruction; }
130
131     /**
132      * Set the value of the 'is under construction' flag.
133      */

134     public void setUnderConstruction(boolean v) { underConstruction = v; }
135
136     /**
137      * Return the modifier bits for this table
138      */

139     public int getModifiers() { return modifiers; }
140
141     /**
142      * Are any of this table's columns BLOB (or CLOB) types?
143      */

144     public boolean hasBlobs() throws SQLException JavaDoc {
145         if (hasBlobs == 0) {
146             hasBlobs = 2;
147             for (int i = 1; hasBlobs == 2 && i <= getColumnCount(); i++) {
148                 Column c = getColumn(i);
149                 Type t = c.getType();
150                 if (t instanceof TypeBlob || t instanceof TypeClob) {
151                     hasBlobs = 1;
152                 }
153             }
154         }
155         return hasBlobs == 1;
156     }
157
158     /**
159      * Read me from a stream
160      */

161     public void readExternal(ObjectInput JavaDoc in)
162     throws IOException JavaDoc, ClassNotFoundException JavaDoc
163     {
164     super.readExternal(in);
165         constraints = new Constraint[in.readInt()];
166         for (int i = 0; i < constraints.length; i++) {
167             constraints[i] = (Constraint)in.readObject();
168             try {
169                 constraints[i].setTable(this);
170             } catch (SQLException JavaDoc ex) {
171                 Debug.print(ex);
172             }
173         }
174     }
175
176     /**
177      * Write me to a stream
178      */

179     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
180     super.writeExternal(out);
181         out.writeInt(constraints.length);
182         for (int i = 0; i < constraints.length; i++) {
183             out.writeObject(constraints[i]);
184         }
185     }
186
187     /**
188      * Add a column to the table; called during initial table construction
189      * only.
190      */

191     public void addColumn(Column col) throws SQLException JavaDoc {
192     super.addColumn(col);
193     Vector JavaDoc v = col.getConstraints();
194     if (v != null) {
195         for (int i = 0; i < v.size(); i++) {
196         Constraint c = (Constraint)v.elementAt(i);
197         c.setColumn(col);
198         }
199     }
200     }
201
202     /**
203      * Return the specified table constraint (zero-based)
204      */

205     final public Constraint getConstraint(int num) {
206     return constraints[num];
207     }
208
209     /**
210      * Return the number of table constraints
211      */

212     final public int getNumConstraints() {
213         return constraints.length;
214     }
215
216     /**
217      * Get the constraint with the specified name
218      *
219      * XXX Maybe we should profile this sucker. A hashtable?
220      */

221     public Constraint getConstraint(String JavaDoc name) {
222         for (int i = 0; i < constraints.length; i++) {
223             Constraint c = constraints[i];
224         if (c.getName().equals(name)) {
225         return c;
226         }
227     }
228         return null;
229     }
230
231     /**
232      * Return the table's primary key constraint, if it is defined,
233      * otherwise return null.
234      */

235     public UniqueConstraint getPrimaryKey() {
236         UniqueConstraint uc = null;
237         for (int i = 0; i < constraints.length; i++) {
238             Constraint c = constraints[i];
239             if (c instanceof PrimaryKeyConstraint) {
240                 return (PrimaryKeyConstraint)c;
241             } else if (uc == null && c instanceof UniqueConstraint) {
242                 uc = (UniqueConstraint)c;
243             }
244         }
245         return uc;
246     }
247
248     /**
249      * Generate a unique, semi-meaningful, name for this constratint,
250      * in case the user didn't specify one.
251      */

252     public void nameConstraint(Constraint c) {
253     String JavaDoc name = c.getName();
254     if (name == null) {
255         name = c.getClass().getName();
256         int idx = name.lastIndexOf('.');
257         if (idx > 0) name = name.substring(idx+1);
258         name += "_";
259         name += Integer.toString(constraints.length);
260         c.setName(name);
261     }
262     }
263
264     /**
265      * Add a table constraint
266      */

267     public void addConstraint(Constraint c) throws SQLException JavaDoc {
268         Constraint[] nc = new Constraint[constraints.length + 1];
269         boolean added = false;
270         for (int i = 0; i < constraints.length; i++) {
271             Constraint ci = constraints[i];
272             if (added) {
273                 nc[i+1] = ci;
274             } else {
275                 if (c.getPriority() >= ci.getPriority()) {
276                     nc[i] = ci;
277                 } else {
278                     nc[i] = c;
279                     nc[i+1] = ci;
280                     added = true;
281                 }
282             }
283         }
284         if (!added) nc[constraints.length] = c;
285         nameConstraint(c);
286         constraints = nc;
287     c.setTable(this);
288     final int notnull = ResultSetMetaData.columnNoNulls;
289     if (c instanceof NotNullConstraint ||
290         c instanceof PrimaryKeyConstraint) {
291         int[] cols = c.getColumns();
292         for (int i = 0; i < cols.length; i++) {
293         getColumn(cols[i]).setNullable(notnull);
294         }
295     }
296     }
297
298     /**
299      * Delete the specified table constraint.
300      */

301     public void deleteConstraint(String JavaDoc name)
302     throws SQLException JavaDoc, IOException JavaDoc
303     {
304     int off = 0;
305     for (int i = 0; i < constraints.length; i++) {
306         if (constraints[i].getName().equals(name)) {
307                 off++;
308             } else if (off > 0) {
309                 constraints[i-off] = constraints[i];
310             }
311         }
312         if (off > 0) {
313             Constraint[] nc = new Constraint[constraints.length - off];
314             System.arraycopy(constraints, 0, nc, 0, nc.length);
315             constraints = nc;
316         } else {
317         throw new SQLException JavaDoc("No constraint: " + name + " for table " +
318                                    getName(), "42000");
319     }
320     }
321
322     /**
323      * Delete a column from this table, and reset any column-constraint
324      * mappings
325      */

326     public void deleteColumn(int c) throws SQLException JavaDoc, IOException JavaDoc {
327         super.deleteColumn(c);
328         resetColumnConstraints();
329     }
330
331     /**
332      * Reset any constraint-column mapping (typically after a column
333      * has been added or dropped)
334      */

335     public void resetColumnConstraints() throws SQLException JavaDoc {
336         final int num = getNumConstraints();
337         for (int i = 0; i < num; i++) {
338         Constraint con = getConstraint(i);
339             con.resetColumns();
340     }
341     }
342  
343     /**
344       * Convenience method to write a new row to the database
345       */

346     public static final long putRow(Session session, Tuple t, Row row)
347     throws SQLException JavaDoc, IOException JavaDoc
348     {
349         return session.getDatabase().putRow(session, session.getFile(), t, row);
350     }
351     
352 // /**
353
// * Update the specified row
354
// */
355
// public final void writeRow(Session session, long rowId, Row row)
356
// throws SQLException, IOException
357
// {
358
// //#ifdef TRACE
359
// if (Trace.bit(11)) {
360
// Debug.println("Table[" + getName() + "].putRow(" + row + ")");
361
// }
362
// //#endif
363
// byte[] buf = LazyRow.writeRow(session, this, row);
364
// session.getFile().updateBytes(rowId, buf);
365
// }
366

367 // /**
368
// * Write (an already serialized) row to the database
369
// */
370
// public final static void writeRow(BlockFile file, long rowId, byte[] buf)
371
// throws SQLException, IOException
372
// {
373
// final RandomAccess ra = file.getStream(rowId);
374
// ra.resize(buf.length);
375
// ra.write(0, buf, 0, buf.length);
376
// }
377

378     static final String JavaDoc strip(String JavaDoc s) {
379         int idx = s.lastIndexOf(".");
380         if (idx >= 0) s = s.substring(idx+1);
381         return s;
382     }
383
384     Row getRow(Database db, long rowId) throws IOException JavaDoc, SQLException JavaDoc {
385         LazyRow row = new LazyRow(getColumnCount());
386         db.getRow(rowId, row, false);
387         return row;
388     }
389
390     /**
391      * Return a cursor on this table
392      */

393     public Cursor getCursor(Session session, Expression where,
394                 String JavaDoc asName, Cursor outer)
395     throws SQLException JavaDoc
396     {
397     try {
398         session.getTableReadLock(getName());
399             Hashtable JavaDoc t = getNames(where);
400         IndexConstraint con = getIndexForNames(session, t);
401         String JavaDoc qualName = asName;
402         if (qualName == null) qualName = getName();
403         Cursor c = new IndexCursor(this, session, con, where,
404                                        qualName, outer);
405             return c;
406     } catch (IOException JavaDoc e) {
407         throw DbException.wrapThrowable(e);
408     }
409     }
410
411     public Cursor getCursor(Session session, Expression where,
412                 String JavaDoc asName)
413     throws SQLException JavaDoc
414     {
415     return getCursor(session, where, asName, null);
416     }
417
418     public IndexCursor getCursor(Session session, IndexConstraint notMe)
419         throws SQLException JavaDoc
420     {
421     try {
422         session.getTableReadLock(getName());
423         IndexConstraint con = getAnyIndexBut(session, notMe);
424         if (con == null) return null;
425         return new IndexCursor(this, session, con, null, getName(), null);
426     } catch (IOException JavaDoc e) {
427         throw DbException.wrapThrowable(e);
428     }
429     }
430
431     class GetNames implements ExpressionVisitor {
432     Hashtable JavaDoc t = new Hashtable JavaDoc();
433     public void visit(Expression ex) {
434             String JavaDoc name = ex.getName();
435             if (name != null) {
436                 t.put(name, name);
437             } else {
438                 ex.visitSubExpressions(this);
439             }
440         }
441     }
442
443     Hashtable JavaDoc getNames(Expression ex) {
444     GetNames get = new GetNames();
445     if (ex != null) get.visit(ex);
446     return get.t;
447     }
448
449     final IndexConstraint getAnyIndex(Session session)
450         throws IOException JavaDoc, SQLException JavaDoc
451     {
452         return getIndexConstraint(session, null, null);
453     }
454
455     final IndexConstraint getIndexForNames(Session session, Hashtable JavaDoc names)
456     throws IOException JavaDoc, SQLException JavaDoc
457     {
458     return getIndexConstraint(session, names, null);
459     }
460
461     final IndexConstraint getAnyIndexBut(Session session, IndexConstraint notMe)
462     throws IOException JavaDoc, SQLException JavaDoc
463     {
464     return getIndexConstraint(session, null, notMe);
465     }
466
467     IndexConstraint getIndexConstraint(Session session, Hashtable JavaDoc names,
468                                        IndexConstraint notMe)
469     throws IOException JavaDoc, SQLException JavaDoc
470     {
471     // try to find, in this order:
472
// a unique constraint matching an item in the where clause
473
UniqueConstraint wcon = null;
474     // any index constraint matching an item in the where clause
475
IndexConstraint icon = null;
476     // any unique constraint
477
UniqueConstraint ucon = null;
478     // any index
479
IndexConstraint acon = null;
480
481         String JavaDoc sc = "";
482         String JavaDoc nm = getName();
483         int idx = nextUnquotedPeriod(nm);
484         if (idx >= 0) {
485             sc = nm.substring(0, idx);
486             nm = nm.substring(idx+1);
487         }
488
489         for (int ci = 0; ci < constraints.length; ci++) {
490             Constraint con = constraints[ci];
491         if (con == notMe) continue;
492         if (con instanceof IndexConstraint) {
493         acon = (IndexConstraint)con;
494         Vector JavaDoc cnames = con.getColumnNames();
495                 if (cnames == null) {
496                     // bad news, skip out the back
497
//#ifdef DEBUG
498
throw new SQLException JavaDoc("Index constraint has no columns: "+
499                                            con);
500                     //#else
501
//- continue;
502
//#endif
503
}
504         boolean matched = false;
505         if (names != null) {
506                     matched = true;
507                     for (int i = 0; matched && i < cnames.size(); i++) {
508                         String JavaDoc cnam = cnames.get(i).toString();
509                         if (names.get(cnam) == null &&
510                             names.get(nm + "." + cnam) == null &&
511                             names.get(sc + "." + nm + "." + cnam) == null) {
512                             matched = false;
513                         }
514                     }
515                 }
516         if (matched) {
517             if (acon instanceof UniqueConstraint) {
518             wcon = (UniqueConstraint)acon;
519             } else {
520                         icon = acon;
521                     }
522         } else {
523             if (acon instanceof UniqueConstraint) {
524             ucon = (UniqueConstraint)acon;
525             }
526         }
527         }
528     }
529         
530     if (wcon != null) return wcon;
531     if (icon != null) return icon;
532     if (ucon != null) return ucon;
533     if (acon != null) return acon;
534
535     // Don't throw an exception when trying to create first index.
536
if (notMe == null) {
537         throw new SQLException JavaDoc("No index", "42000");
538     } else {
539         return null;
540     }
541     }
542
543     UniqueConstraint getIndexForColumns(int[] cols) throws SQLException JavaDoc {
544     BitSet JavaDoc match = new BitSet JavaDoc();
545     for (int i = 0; i < cols.length; i++) {
546         match.set(cols[i]);
547     }
548     for (int i = 0; i < constraints.length; i++) {
549         Constraint con = constraints[i];
550         if (con instanceof UniqueConstraint) {
551         int[] tcols = con.getColumns();
552         BitSet JavaDoc tmatch = new BitSet JavaDoc();
553         for (int j = 0; j < tcols.length; j++) {
554             tmatch.set(tcols[j]);
555         }
556         if (match.equals(tmatch)) return (UniqueConstraint)con;
557         }
558     }
559     return null;
560     }
561
562     /**
563      * My SQL type
564      */

565     public String JavaDoc getType() {
566     if ((modifiers & TEMPORARY) != 0) {
567         if ((modifiers & GLOBAL) != 0) {
568         return "GLOBAL TEMPORARY";
569         }
570         if ((modifiers & LOCAL) != 0) {
571         return "LOCAL TEMPORARY";
572         }
573     }
574     return "TABLE";
575     }
576
577     /** (haiku-comment)
578      * I am a table
579      * and therefore updateable
580      * @return true not false
581      */

582     public boolean isUpdatable() { return true; }
583
584     //#ifdef DEBUG
585
/**
586      * String representation for debugging
587      */

588     public String JavaDoc toString() {
589         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(super.toString());
590         sb.append("Constraints:\n");
591         for (int i = 0; i < constraints.length; i++) {
592             Constraint c = constraints[i];
593             sb.append(" ");
594             sb.append(String.valueOf(c));
595             sb.append("\n");
596         }
597         return sb.toString();
598     }
599     //#endif
600

601     public void insertRow(Session session, Row row)
602         throws SQLException JavaDoc, IOException JavaDoc
603     {
604         TableOps.insertRow(session, this, row);
605     }
606     
607 }
608
609
Popular Tags