| 1 65 66 67 package org.hsqldb; 68 69 import java.io.IOException ; 70 71 import org.hsqldb.HsqlNameManager.HsqlName; 72 import org.hsqldb.index.RowIterator; 73 import org.hsqldb.lib.ArrayUtil; 74 import org.hsqldb.lib.HashMappedList; 75 import org.hsqldb.lib.HashSet; 76 import org.hsqldb.lib.HsqlArrayList; 77 import org.hsqldb.lib.Iterator; 78 import org.hsqldb.lib.StringUtil; 79 import org.hsqldb.persist.CachedObject; 80 import org.hsqldb.persist.DataFileCache; 81 import org.hsqldb.persist.PersistentStore; 82 import org.hsqldb.rowio.RowInputInterface; 83 import org.hsqldb.store.ValuePool; 84 85 109 119 public class Table extends BaseTable { 120 121 public static final int SYSTEM_TABLE = 0; 123 public static final int SYSTEM_SUBQUERY = 1; 124 public static final int TEMP_TABLE = 2; 125 public static final int MEMORY_TABLE = 3; 126 public static final int CACHED_TABLE = 4; 127 public static final int TEMP_TEXT_TABLE = 5; 128 public static final int TEXT_TABLE = 6; 129 public static final int VIEW = 7; 130 131 static final int SYSTEM_VIEW = 8; 133 134 public HashMappedList columnList; private int[] primaryKeyCols; private int[] primaryKeyTypes; private int[] primaryKeyColsSequence; int[] bestRowIdentifierCols; boolean bestRowIdentifierStrict; int[] bestIndexForColumn; Index bestIndex; int identityColumn; NumberSequence identitySequence; NumberSequence rowIdSequence; 148 Constraint[] constraintList; HsqlArrayList[] triggerLists; private int[] colTypes; private int[] colSizes; private int[] colScales; private boolean[] colNullable; private Expression[] colDefaults; private int[] defaultColumnMap; private boolean hasDefaultValues; boolean sqlEnforceSize; 160 protected int columnCount; public Database database; 163 protected DataFileCache cache; 164 protected HsqlName tableName; private int tableType; 166 protected boolean isReadOnly; 167 protected boolean isTemp; 168 protected boolean isCached; 169 protected boolean isText; 170 protected boolean isMemory; 171 private boolean isView; 172 protected boolean isLogged; 173 protected int indexType; protected boolean onCommitPreserve; 176 PersistentStore rowStore; 178 Index[] indexList; 180 189 Table(Database db, HsqlName name, int type) throws HsqlException { 190 191 database = db; 192 sqlEnforceSize = db.sqlEnforceStrictSize; 193 identitySequence = new NumberSequence(null, 0, 1, Types.BIGINT); 194 rowIdSequence = new NumberSequence(null, 0, 1, Types.BIGINT); 195 196 switch (type) { 197 198 case SYSTEM_SUBQUERY : 199 isTemp = true; 200 isMemory = true; 201 case SYSTEM_TABLE : 202 isMemory = true; 203 break; 204 205 case CACHED_TABLE : 206 if (DatabaseURL.isFileBasedDatabaseType(db.getType())) { 207 cache = db.logger.getCache(); 208 isCached = true; 209 isLogged = !database.isFilesReadOnly(); 210 indexType = Index.DISK_INDEX; 211 rowStore = new RowStore(); 212 213 break; 214 } 215 216 type = MEMORY_TABLE; 217 case MEMORY_TABLE : 218 isMemory = true; 219 isLogged = !database.isFilesReadOnly(); 220 break; 221 222 case TEMP_TABLE : 223 isMemory = true; 224 isTemp = true; 225 break; 226 227 case TEMP_TEXT_TABLE : 228 if (!DatabaseURL.isFileBasedDatabaseType(db.getType())) { 229 throw Trace.error(Trace.DATABASE_IS_MEMORY_ONLY); 230 } 231 232 isTemp = true; 233 isText = true; 234 isReadOnly = true; 235 indexType = Index.POINTER_INDEX; 236 rowStore = new RowStore(); 237 break; 238 239 case TEXT_TABLE : 240 if (!DatabaseURL.isFileBasedDatabaseType(db.getType())) { 241 throw Trace.error(Trace.DATABASE_IS_MEMORY_ONLY); 242 } 243 244 isText = true; 245 indexType = Index.POINTER_INDEX; 246 rowStore = new RowStore(); 247 break; 248 249 case VIEW : 250 case SYSTEM_VIEW : 251 isView = true; 252 break; 253 } 254 255 tableType = type; 257 tableName = name; 258 primaryKeyCols = null; 259 primaryKeyTypes = null; 260 identityColumn = -1; 261 columnList = new HashMappedList(); 262 indexList = new Index[0]; 263 constraintList = new Constraint[0]; 264 triggerLists = new HsqlArrayList[TriggerDef.NUM_TRIGS]; 265 266 if (db.isFilesReadOnly() && isFileBased()) { 270 this.isReadOnly = true; 271 } 272 273 } 275 276 boolean equals(Session session, String name) { 277 278 284 return (tableName.name.equals(name)); 285 } 286 287 boolean equals(String name) { 288 return (tableName.name.equals(name)); 289 } 290 291 boolean equals(HsqlName name) { 292 return (tableName.equals(name)); 293 } 294 295 public final boolean isText() { 296 return isText; 297 } 298 299 public final boolean isTemp() { 300 return isTemp; 301 } 302 303 public final boolean isReadOnly() { 304 return isReadOnly; 305 } 306 307 final boolean isView() { 308 return isView; 309 } 310 311 final int getIndexType() { 312 return indexType; 313 } 314 315 public final int getTableType() { 316 return tableType; 317 } 318 319 public final boolean isDataReadOnly() { 320 return isReadOnly; 321 } 322 323 326 void checkDataReadOnly() throws HsqlException { 327 328 if (isReadOnly) { 329 throw Trace.error(Trace.DATA_IS_READONLY); 330 } 331 } 332 333 void setDataReadOnly(boolean value) throws HsqlException { 336 337 if (!value && database.isFilesReadOnly() && isFileBased()) { 340 throw Trace.error(Trace.DATA_IS_READONLY); 341 } 342 343 isReadOnly = value; 344 } 345 346 349 boolean isFileBased() { 350 return isCached || isText; 351 } 352 353 356 protected void setDataSource(Session s, String source, boolean isDesc, 357 boolean newFile) throws HsqlException { 358 throw (Trace.error(Trace.TABLE_NOT_FOUND)); 359 } 360 361 364 protected String getDataSource() { 365 return null; 366 } 367 368 371 protected boolean isDescDataSource() { 372 return false; 373 } 374 375 378 public void setHeader(String header) throws HsqlException { 379 throw Trace.error(Trace.TEXT_TABLE_HEADER); 380 } 381 382 385 public String getHeader() { 386 return null; 387 } 388 389 392 void addConstraint(Constraint c) { 393 394 constraintList = 395 (Constraint[]) ArrayUtil.toAdjustedArray(constraintList, c, 396 constraintList.length, 1); 397 } 398 399 402 void addPKConstraint(Constraint c) { 403 constraintList = 404 (Constraint[]) ArrayUtil.toAdjustedArray(constraintList, c, 0, 1); 405 } 406 407 410 Constraint[] getConstraints() { 411 return constraintList; 412 } 413 414 417 Constraint getPrimaryConstraint() { 418 return primaryKeyCols.length == 0 ? null 419 : constraintList[0]; 420 } 421 422 424 425 429 Index getUniqueConstraintIndexForColumns(int[] col) { 430 431 if (ArrayUtil.areEqual(getPrimaryIndex().getColumns(), col, 432 col.length, true)) { 433 return getPrimaryIndex(); 434 } 435 436 for (int i = 0, size = constraintList.length; i < size; i++) { 437 Constraint c = constraintList[i]; 438 439 if (c.getType() != Constraint.UNIQUE) { 440 continue; 441 } 442 443 if (ArrayUtil.areEqual(c.getMainColumns(), col, col.length, 444 true)) { 445 return c.getMainIndex(); 446 } 447 } 448 449 return null; 450 } 451 452 455 Constraint getConstraintForColumns(Table tablemain, int[] colmain, 456 int[] colref) { 457 458 for (int i = 0, size = constraintList.length; i < size; i++) { 459 Constraint c = constraintList[i]; 460 461 if (c.isEquivalent(tablemain, colmain, this, colref)) { 462 return c; 463 } 464 } 465 466 return null; 467 } 468 469 472 Constraint getUniqueConstraintForColumns(int[] cols) { 473 474 for (int i = 0, size = constraintList.length; i < size; i++) { 475 Constraint c = constraintList[i]; 476 477 if (c.isEquivalent(cols, Constraint.UNIQUE)) { 478 return c; 479 } 480 } 481 482 return null; 483 } 484 485 491 Constraint getUniqueOrPKConstraintForIndex(Index index) { 492 493 for (int i = 0, size = constraintList.length; i < size; i++) { 494 Constraint c = constraintList[i]; 495 496 if (c.getMainIndex() == index 497 && (c.getType() == Constraint.UNIQUE 498 || c.getType() == Constraint.PRIMARY_KEY)) { 499 return c; 500 } 501 } 502 503 return null; 504 } 505 506 513 int getNextConstraintIndex(int from, int type) { 514 515 for (int i = from, size = constraintList.length; i < size; i++) { 516 Constraint c = constraintList[i]; 517 518 if (c.getType() == type) { 519 return i; 520 } 521 } 522 523 return -1; 524 } 525 526 528 532 void addColumn(Column column) throws HsqlException { 533 534 if (findColumn(column.columnName.name) >= 0) { 535 throw Trace.error(Trace.COLUMN_ALREADY_EXISTS); 536 } 537 538 if (column.isIdentity()) { 539 Trace.check( 540 column.getType() == Types.INTEGER 541 || column.getType() == Types.BIGINT, Trace.WRONG_DATA_TYPE, 542 column.columnName.name); 543 Trace.check(identityColumn == -1, Trace.SECOND_PRIMARY_KEY, 544 column.columnName.name); 545 546 identityColumn = columnCount; 547 } 548 549 if (primaryKeyCols != null) { 550 Trace.doAssert(false, "Table.addColumn"); 551 } 552 553 columnList.add(column.columnName.name, column); 554 555 columnCount++; 556 } 557 558 561 void addColumns(Result.ResultMetaData metadata, 562 int count) throws HsqlException { 563 564 for (int i = 0; i < count; i++) { 565 Column column = new Column( 566 database.nameManager.newHsqlName( 567 metadata.colLabels[i], metadata.isLabelQuoted[i]), true, 568 metadata.colTypes[i], metadata.colSizes[i], 569 metadata.colScales[i], false, null); 570 571 addColumn(column); 572 } 573 } 574 575 578 void addColumns(Select select) throws HsqlException { 579 580 int colCount = select.iResultLen; 581 582 for (int i = 0; i < colCount; i++) { 583 Expression e = select.exprColumns[i]; 584 Column column = new Column( 585 database.nameManager.newHsqlName( 586 e.getAlias(), e.isAliasQuoted()), true, e.getDataType(), 587 e.getColumnSize(), e.getColumnScale(), false, null); 588 589 addColumn(column); 590 } 591 } 592 593 596 public HsqlName getName() { 597 return tableName; 598 } 599 600 public int getId() { 601 return tableName.hashCode(); 602 } 603 604 609 void rename(Session session, String newname, 610 boolean isquoted) throws HsqlException { 611 612 String oldname = tableName.name; 613 614 tableName.rename(newname, isquoted); 615 616 if (HsqlName.isReservedIndexName(getPrimaryIndex().getName().name)) { 617 getPrimaryIndex().getName().rename("SYS_PK", newname, isquoted); 618 } 619 620 renameTableInCheckConstraints(session, oldname, newname); 621 } 622 623 626 int getInternalColumnCount() { 627 return columnCount; 628 } 629 630 633 protected Table duplicate() throws HsqlException { 634 635 Table t = (new Table(database, tableName, tableType)); 636 637 return t; 638 } 639 640 648 void checkColumnsMatch(int[] col, Table other, 649 int[] othercol) throws HsqlException { 650 651 if (col.length != othercol.length) { 652 throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH); 653 } 654 655 for (int i = 0; i < col.length; i++) { 656 657 if (col[i] >= columnCount || othercol[i] >= other.columnCount) { 659 throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH); 660 } 661 662 if (getColumn(col[i]).getType() 663 != other.getColumn(othercol[i]).getType()) { 664 throw Trace.error(Trace.COLUMN_TYPE_MISMATCH); 665 } 666 } 667 } 668 669 671 679 Table moveDefinition(int[] removeIndex, Column newColumn, int colIndex, 680 int adjust) throws HsqlException { 681 682 Table tn = duplicate(); 683 684 for (int i = 0; i < columnCount + 1; i++) { 687 if (i == colIndex) { 688 if (adjust == 0) { 689 if (newColumn != null) { 690 tn.addColumn(newColumn); 691 692 continue; 693 } 694 } else if (adjust > 0) { 695 tn.addColumn(newColumn); 696 } else if (adjust < 0) { 697 continue; 698 } 699 } 700 701 if (i == columnCount) { 702 break; 703 } 704 705 tn.addColumn(getColumn(i)); 706 } 707 708 int[] primarykey = primaryKeyCols.length == 0 ? null 710 : primaryKeyCols; 711 712 if (primarykey != null) { 713 int[] newpk = ArrayUtil.toAdjustedColumnArray(primarykey, 714 colIndex, adjust); 715 716 if (primarykey.length != newpk.length) { 717 throw Trace.error(Trace.DROP_PRIMARY_KEY); 718 } else { 719 primarykey = newpk; 720 } 721 } 722 723 tn.createPrimaryKey(getIndex(0).getName(), primarykey, false); 724 725 tn.constraintList = constraintList; 726 727 Index idx = null; 728 729 if (removeIndex != null) { 730 idx = getIndex(removeIndex, colIndex); 731 } 732 733 if (idx != null) { 734 if (idx.isConstraint()) { 735 throw Trace.error(Trace.COLUMN_IS_IN_CONSTRAINT); 736 } else { 737 throw Trace.error(Trace.COLUMN_IS_IN_INDEX); 738 } 739 } 740 741 for (int i = 1; i < indexList.length; i++) { 742 if (removeIndex != null && ArrayUtil.find(removeIndex, i) != -1) { 743 continue; 744 } 745 746 tn.createAdjustedIndex(indexList[i], colIndex, adjust); 747 } 748 749 tn.triggerLists = triggerLists; 750 751 return tn; 752 } 753 754 Index getIndex(int[] exclude, int colIndex) { 755 756 for (int i = 1; i < indexList.length; i++) { 757 if (exclude != null && ArrayUtil.find(exclude, i) != -1) { 758 continue; 759 } 760 761 Index idx = indexList[i]; 762 int[] cols = idx.getColumns(); 763 764 if (ArrayUtil.find(cols, colIndex) != -1) { 765 return idx; 766 } 767 } 768 769 return null; 770 } 771 772 private void copyIndexes(Table tn, int removeIndex, int colIndex, 773 int adjust) throws HsqlException { 774 775 for (int i = 1; i < getIndexCount(); i++) { 776 Index idx = indexList[i]; 777 778 if (removeIndex == i) { 779 continue; 780 } 781 782 Index newidx = tn.createAdjustedIndex(idx, colIndex, adjust); 783 784 if (newidx == null) { 785 786 throw Trace.error(Trace.COLUMN_IS_IN_INDEX); 788 } 789 } 790 } 791 792 795 Table moveDefinitionPK(int[] pkCols, 796 boolean withIdentity) throws HsqlException { 797 798 if ((hasPrimaryKey() && pkCols != null) 800 || (!hasPrimaryKey() && pkCols == null)) { 801 throw Trace.error(Trace.DROP_PRIMARY_KEY); 802 } 803 804 Table tn = duplicate(); 805 806 for (int i = 0; i < columnCount; i++) { 807 tn.addColumn(getColumn(i).duplicate(withIdentity)); 808 } 809 810 tn.createPrimaryKey(getIndex(0).getName(), pkCols, true); 811 812 tn.constraintList = constraintList; 813 814 for (int i = 1; i < getIndexCount(); i++) { 815 Index idx = getIndex(i); 816 817 tn.createAdjustedIndex(idx, -1, 0); 818 } 819 820 tn.triggerLists = triggerLists; 821 822 return tn; 823 } 824 825 829 void updateConstraintsTables(Session session, Table old, int colindex, 830 int adjust) throws HsqlException { 831 832 for (int i = 0, size = constraintList.length; i < size; i++) { 833 Constraint c = constraintList[i]; 834 835 c.replaceTable(old, this, colindex, adjust); 836 837 if (c.constType == Constraint.CHECK) { 838 recompileCheckConstraint(session, c); 839 } 840 } 841 } 842 843 private void recompileCheckConstraints(Session session) 844 throws HsqlException { 845 846 for (int i = 0, size = constraintList.length; i < size; i++) { 847 Constraint c = constraintList[i]; 848 849 if (c.constType == Constraint.CHECK) { 850 recompileCheckConstraint(session, c); 851 } 852 } 853 } 854 855 858 private void recompileCheckConstraint(Session session, 859 Constraint c) throws HsqlException { 860 861 String ddl = c.core.check.getDDL(); 862 Tokenizer tokenizer = new Tokenizer(ddl); 863 Parser parser = new Parser(session, database, tokenizer); 864 Expression condition = parser.parseExpression(); 865 866 c.core.check = condition; 867 868 condition.setLikeOptimised(); 870 871 Select s = Expression.getCheckSelect(session, this, condition); 872 873 c.core.checkFilter = s.tFilter[0]; 874 875 c.core.checkFilter.setAsCheckFilter(); 876 877 c.core.mainTable = this; 878 } 879 880 883 void checkColumnInCheckConstraint(String colname) throws HsqlException { 884 885 for (int i = 0, size = constraintList.length; i < size; i++) { 886 Constraint c = constraintList[i]; 887 888 if (c.constType == Constraint.CHECK) { 889 if (c.hasColumn(this, colname)) { 890 throw Trace.error(Trace.COLUMN_IS_REFERENCED, 891 c.getName()); 892 } 893 } 894 } 895 } 896 897 902 void checkColumnInFKConstraint(int colIndex) throws HsqlException { 903 904 for (int i = 0, size = constraintList.length; i < size; i++) { 905 Constraint c = constraintList[i]; 906 907 if (c.hasColumn(colIndex) 908 && (c.getType() == Constraint.MAIN 909 || c.getType() == Constraint.FOREIGN_KEY)) { 910 throw Trace.error(Trace.COLUMN_IS_REFERENCED, 911 c.getName().name); 912 } 913 } 914 } 915 916 921 void checkColumnInFKConstraint(int colIndex, 922 int actionType) throws HsqlException { 923 924 for (int i = 0, size = constraintList.length; i < size; i++) { 925 Constraint c = constraintList[i]; 926 927 if (c.hasColumn(colIndex)) { 928 if (c.getType() == Constraint.FOREIGN_KEY 929 && (actionType == c.getUpdateAction() 930 || actionType == c.getDeleteAction())) { 931 throw Trace.error(Trace.COLUMN_IS_REFERENCED, 932 c.getName().name); 933 } 934 } 935 } 936 } 937 938 941 private void renameColumnInCheckConstraints(String oldname, 942 |