00001
package com.quadcap.sql;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.io.ByteArrayOutputStream;
00042
import java.io.BufferedInputStream;
00043
import java.io.BufferedOutputStream;
00044
import java.io.Externalizable;
00045
import java.io.IOException;
00046
import java.io.InputStream;
00047
import java.io.ObjectInput;
00048
import java.io.ObjectOutput;
00049
import java.io.OutputStream;
00050
00051
import java.util.BitSet;
00052
import java.util.Hashtable;
00053
import java.util.Vector;
00054
00055
import java.sql.ResultSet;
00056
import java.sql.ResultSetMetaData;
00057
import java.sql.SQLException;
00058
00059
import com.quadcap.sql.io.ObjectInputStream;
00060
import com.quadcap.sql.io.ObjectOutputStream;
00061
00062
import com.quadcap.sql.index.Btree;
00063
00064
import com.quadcap.sql.file.BlockFile;
00065
import com.quadcap.sql.file.ByteUtil;
00066
import com.quadcap.sql.file.Datafile;
00067
import com.quadcap.sql.file.Page;
00068
import com.quadcap.sql.file.PageManager;
00069
import com.quadcap.sql.file.RandomAccess;
00070
import com.quadcap.sql.file.RandomAccessOutputStream;
00071
import com.quadcap.sql.file.SubPageManager;
00072
00073
import com.quadcap.sql.types.Type;
00074
import com.quadcap.sql.types.TypeBlob;
00075
import com.quadcap.sql.types.TypeClob;
00076
import com.quadcap.sql.types.Value;
00077
00078
import com.quadcap.util.ConfigNumber;
00079
import com.quadcap.util.Debug;
00080
import com.quadcap.util.Util;
00081
00082
00083
00084
00085
00086
00087
00088 public class Table extends TupleImpl implements
Relation,
Externalizable {
00089
00090
00091 int modifiers = 0;
00092 Constraint[]
constraints =
new Constraint[0];
00093 transient boolean underConstruction =
false;
00094
00095
00096 transient int hasBlobs = 0;
00097
00098
00099
00100
00101
00102 public static final int TEMPORARY = 1;
00103 public static final int LOCAL = 2;
00104 public static final int GLOBAL = 4;
00105 public static final int STATEMENT_TEMP = 8;
00106
00107
00108
00109
00110 long tableIdentity = 1;
00111
00112
00113
00114
00115 public Table() {}
00116
00117
00118
00119
00120 public Table(String tableName,
int modifiers) {
00121 super(tableName);
00122
this.modifiers = modifiers;
00123 }
00124
00125
00126
00127
00128
00129 public boolean isUnderConstruction() {
return underConstruction; }
00130
00131
00132
00133
00134 public void setUnderConstruction(
boolean v) {
underConstruction = v; }
00135
00136
00137
00138
00139 public int getModifiers() {
return modifiers; }
00140
00141
00142
00143
00144 public boolean hasBlobs() throws SQLException {
00145
if (hasBlobs == 0) {
00146 hasBlobs = 2;
00147
for (
int i = 1; hasBlobs == 2 && i <=
getColumnCount(); i++) {
00148
Column c = getColumn(i);
00149
Type t = c.
getType();
00150
if (t instanceof
TypeBlob || t instanceof
TypeClob) {
00151 hasBlobs = 1;
00152 }
00153 }
00154 }
00155
return hasBlobs == 1;
00156 }
00157
00158
00159
00160
00161 public void readExternal(ObjectInput in)
00162
throws IOException, ClassNotFoundException
00163 {
00164 super.readExternal(in);
00165
constraints =
new Constraint[in.readInt()];
00166
for (
int i = 0; i <
constraints.length; i++) {
00167
constraints[i] = (Constraint)in.readObject();
00168
try {
00169
constraints[i].
setTable(
this);
00170 }
catch (SQLException ex) {
00171
Debug.print(ex);
00172 }
00173 }
00174 }
00175
00176
00177
00178
00179 public void writeExternal(ObjectOutput out)
throws IOException {
00180 super.writeExternal(out);
00181 out.writeInt(
constraints.length);
00182
for (
int i = 0; i <
constraints.length; i++) {
00183 out.writeObject(
constraints[i]);
00184 }
00185 }
00186
00187
00188
00189
00190
00191 public void addColumn(
Column col)
throws SQLException {
00192 super.addColumn(col);
00193 Vector v = col.getConstraints();
00194
if (v != null) {
00195
for (
int i = 0; i < v.size(); i++) {
00196
Constraint c = (
Constraint)v.elementAt(i);
00197 c.
setColumn(col);
00198 }
00199 }
00200 }
00201
00202
00203
00204
00205 final public Constraint getConstraint(
int num) {
00206
return constraints[num];
00207 }
00208
00209
00210
00211
00212 final public int getNumConstraints() {
00213
return constraints.length;
00214 }
00215
00216
00217
00218
00219
00220
00221 public Constraint getConstraint(String name) {
00222
for (
int i = 0; i <
constraints.length; i++) {
00223
Constraint c =
constraints[i];
00224
if (c.
getName().equals(name)) {
00225
return c;
00226 }
00227 }
00228
return null;
00229 }
00230
00231
00232
00233
00234
00235 public UniqueConstraint getPrimaryKey() {
00236
UniqueConstraint uc = null;
00237
for (
int i = 0; i <
constraints.length; i++) {
00238
Constraint c =
constraints[i];
00239
if (c instanceof
PrimaryKeyConstraint) {
00240
return (
PrimaryKeyConstraint)c;
00241 }
else if (uc == null && c instanceof
UniqueConstraint) {
00242 uc = (
UniqueConstraint)c;
00243 }
00244 }
00245
return uc;
00246 }
00247
00248
00249
00250
00251
00252 public void nameConstraint(
Constraint c) {
00253 String name = c.
getName();
00254
if (name == null) {
00255 name = c.getClass().
getName();
00256
int idx = name.lastIndexOf(
'.');
00257
if (idx > 0) name = name.substring(idx+1);
00258 name +=
"_";
00259 name += Integer.toString(
constraints.length);
00260 c.
setName(name);
00261 }
00262 }
00263
00264
00265
00266
00267 public void addConstraint(
Constraint c)
throws SQLException {
00268
Constraint[] nc =
new Constraint[
constraints.length + 1];
00269
boolean added =
false;
00270
for (
int i = 0; i <
constraints.length; i++) {
00271 Constraint ci =
constraints[i];
00272
if (added) {
00273 nc[i+1] = ci;
00274 }
else {
00275
if (c.getPriority() >= ci.
getPriority()) {
00276 nc[i] = ci;
00277 }
else {
00278 nc[i] = c;
00279 nc[i+1] = ci;
00280 added =
true;
00281 }
00282 }
00283 }
00284
if (!added) nc[
constraints.length] = c;
00285 nameConstraint(c);
00286
constraints = nc;
00287 c.
setTable(
this);
00288
final int notnull = ResultSetMetaData.columnNoNulls;
00289
if (c instanceof
NotNullConstraint ||
00290 c instanceof
PrimaryKeyConstraint) {
00291
int[] cols = c.getColumns();
00292
for (
int i = 0; i < cols.length; i++) {
00293 getColumn(cols[i]).
setNullable(notnull);
00294 }
00295 }
00296 }
00297
00298
00299
00300
00301 public void deleteConstraint(String name)
00302
throws SQLException, IOException
00303 {
00304
int off = 0;
00305
for (
int i = 0; i <
constraints.length; i++) {
00306
if (
constraints[i].
getName().equals(name)) {
00307 off++;
00308 }
else if (off > 0) {
00309
constraints[i-off] =
constraints[i];
00310 }
00311 }
00312
if (off > 0) {
00313
Constraint[] nc =
new Constraint[
constraints.length - off];
00314 System.arraycopy(
constraints, 0, nc, 0, nc.length);
00315
constraints = nc;
00316 }
else {
00317
throw new SQLException(
"No constraint: " + name +
" for table " +
00318
getName(),
"42000");
00319 }
00320 }
00321
00322
00323
00324
00325
00326 public void deleteColumn(
int c)
throws SQLException, IOException {
00327 super.deleteColumn(c);
00328
resetColumnConstraints();
00329 }
00330
00331
00332
00333
00334
00335 public void resetColumnConstraints() throws SQLException {
00336
final int num =
getNumConstraints();
00337
for (
int i = 0; i < num; i++) {
00338
Constraint con = getConstraint(i);
00339 con.
resetColumns();
00340 }
00341 }
00342
00343
00344
00345
00346 public static final long putRow(
Session session,
Tuple t,
Row row)
00347
throws SQLException, IOException
00348 {
00349
return session.getDatabase().putRow(session, session.getFile(), t, row);
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 static final String
strip(String s) {
00379
int idx = s.lastIndexOf(
".");
00380
if (idx >= 0) s = s.substring(idx+1);
00381
return s;
00382 }
00383
00384 Row getRow(
Database db,
long rowId)
throws IOException, SQLException {
00385
LazyRow row =
new LazyRow(
getColumnCount());
00386 db.getRow(rowId, row,
false);
00387
return row;
00388 }
00389
00390
00391
00392
00393 public Cursor getCursor(
Session session,
Expression where,
00394 String asName,
Cursor outer)
00395
throws SQLException
00396 {
00397
try {
00398 session.getTableReadLock(
getName());
00399 Hashtable t =
getNames(where);
00400
IndexConstraint con =
getIndexForNames(session, t);
00401 String qualName = asName;
00402
if (qualName == null) qualName =
getName();
00403
Cursor c =
new IndexCursor(
this, session, con, where,
00404 qualName, outer);
00405
return c;
00406 }
catch (IOException e) {
00407
throw DbException.wrapThrowable(e);
00408 }
00409 }
00410
00411 public Cursor getCursor(
Session session,
Expression where,
00412 String asName)
00413
throws SQLException
00414 {
00415
return getCursor(session, where, asName, null);
00416 }
00417
00418 public IndexCursor getCursor(
Session session,
IndexConstraint notMe)
00419
throws SQLException
00420 {
00421
try {
00422 session.getTableReadLock(
getName());
00423
IndexConstraint con =
getAnyIndexBut(session, notMe);
00424
if (con == null)
return null;
00425
return new IndexCursor(
this, session, con, null,
getName(), null);
00426 }
catch (IOException e) {
00427
throw DbException.wrapThrowable(e);
00428 }
00429 }
00430
00431 class GetNames implements ExpressionVisitor {
00432 Hashtable
t =
new Hashtable();
00433 public void visit(
Expression ex) {
00434 String name = ex.
getName();
00435
if (name != null) {
00436
t.put(name, name);
00437 }
else {
00438 ex.
visitSubExpressions(
this);
00439 }
00440 }
00441 }
00442
00443 Hashtable
getNames(
Expression ex) {
00444
GetNames get =
new GetNames();
00445
if (ex != null) get.
visit(ex);
00446
return get.
t;
00447 }
00448
00449 final IndexConstraint getAnyIndex(
Session session)
00450
throws IOException, SQLException
00451 {
00452
return getIndexConstraint(session, null, null);
00453 }
00454
00455 final IndexConstraint getIndexForNames(
Session session, Hashtable names)
00456
throws IOException, SQLException
00457 {
00458
return getIndexConstraint(session, names, null);
00459 }
00460
00461 final IndexConstraint getAnyIndexBut(
Session session,
IndexConstraint notMe)
00462
throws IOException, SQLException
00463 {
00464
return getIndexConstraint(session, null, notMe);
00465 }
00466
00467 IndexConstraint getIndexConstraint(
Session session, Hashtable names,
00468
IndexConstraint notMe)
00469
throws IOException, SQLException
00470 {
00471
00472
00473
UniqueConstraint wcon = null;
00474
00475
IndexConstraint icon = null;
00476
00477
UniqueConstraint ucon = null;
00478
00479
IndexConstraint acon = null;
00480
00481 String sc =
"";
00482 String nm =
getName();
00483
int idx = nextUnquotedPeriod(nm);
00484
if (idx >= 0) {
00485 sc = nm.substring(0, idx);
00486 nm = nm.substring(idx+1);
00487 }
00488
00489
for (
int ci = 0; ci <
constraints.length; ci++) {
00490
Constraint con =
constraints[ci];
00491
if (con == notMe)
continue;
00492
if (con instanceof
IndexConstraint) {
00493 acon = (
IndexConstraint)con;
00494 Vector cnames = con.
getColumnNames();
00495
if (cnames == null) {
00496
00497
00498
throw new SQLException(
"Index constraint has no columns: "+
00499 con);
00500
00501
00502
00503 }
00504
boolean matched =
false;
00505
if (names != null) {
00506 matched =
true;
00507
for (
int i = 0; matched && i < cnames.size(); i++) {
00508 String cnam = cnames.get(i).toString();
00509
if (names.get(cnam) == null &&
00510 names.get(nm +
"." + cnam) == null &&
00511 names.get(sc +
"." + nm +
"." + cnam) == null) {
00512 matched =
false;
00513 }
00514 }
00515 }
00516
if (matched) {
00517
if (acon instanceof
UniqueConstraint) {
00518 wcon = (
UniqueConstraint)acon;
00519 }
else {
00520 icon = acon;
00521 }
00522 }
else {
00523
if (acon instanceof
UniqueConstraint) {
00524 ucon = (
UniqueConstraint)acon;
00525 }
00526 }
00527 }
00528 }
00529
00530
if (wcon != null)
return wcon;
00531
if (icon != null)
return icon;
00532
if (ucon != null)
return ucon;
00533
if (acon != null)
return acon;
00534
00535
00536
if (notMe == null) {
00537
throw new SQLException(
"No index",
"42000");
00538 }
else {
00539
return null;
00540 }
00541 }
00542
00543 UniqueConstraint getIndexForColumns(
int[] cols)
throws SQLException {
00544 BitSet match =
new BitSet();
00545
for (
int i = 0; i < cols.length; i++) {
00546 match.set(cols[i]);
00547 }
00548
for (
int i = 0; i <
constraints.length; i++) {
00549
Constraint con =
constraints[i];
00550
if (con instanceof
UniqueConstraint) {
00551
int[] tcols = con.
getColumns();
00552 BitSet tmatch =
new BitSet();
00553
for (
int j = 0; j < tcols.length; j++) {
00554 tmatch.set(tcols[j]);
00555 }
00556
if (match.equals(tmatch))
return (
UniqueConstraint)con;
00557 }
00558 }
00559
return null;
00560 }
00561
00562
00563
00564
00565 public String
getType() {
00566
if ((
modifiers &
TEMPORARY) != 0) {
00567
if ((
modifiers &
GLOBAL) != 0) {
00568
return "GLOBAL TEMPORARY";
00569 }
00570
if ((
modifiers &
LOCAL) != 0) {
00571
return "LOCAL TEMPORARY";
00572 }
00573 }
00574
return "TABLE";
00575 }
00576
00577
00578
00579
00580
00581
00582 public boolean isUpdatable() {
return true; }
00583
00584
00585
00586
00587
00588 public String
toString() {
00589 StringBuffer sb =
new StringBuffer(super.toString());
00590 sb.append(
"Constraints:\n");
00591
for (
int i = 0; i <
constraints.length; i++) {
00592
Constraint c =
constraints[i];
00593 sb.append(
" ");
00594 sb.append(String.valueOf(c));
00595 sb.append(
"\n");
00596 }
00597
return sb.toString();
00598 }
00599
00600
00601 public void insertRow(
Session session,
Row row)
00602
throws SQLException, IOException
00603 {
00604
TableOps.insertRow(session,
this, row);
00605 }
00606
00607 }
00608