/* Copyright (c) 2001-2018, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb;
import org.hsqldb.
HsqlNameManager.
HsqlName;
import org.hsqldb.error.
Error;
import org.hsqldb.error.
ErrorCode;
import org.hsqldb.index.
Index;
import org.hsqldb.index.
Index.
IndexUse;
import org.hsqldb.lib.
ArrayUtil;
import org.hsqldb.lib.
HashMappedList;
import org.hsqldb.lib.
HsqlArrayList;
import org.hsqldb.lib.
OrderedHashSet;
import org.hsqldb.lib.
OrderedIntHashSet;
import org.hsqldb.lib.
Set;
import org.hsqldb.lib.
StringUtil;
import org.hsqldb.map.
ValuePool;
import org.hsqldb.navigator.
RangeIterator;
import org.hsqldb.navigator.
RowIterator;
import org.hsqldb.navigator.
RowSetNavigator;
import org.hsqldb.navigator.
RowSetNavigatorDataChange;
import org.hsqldb.persist.
CachedObject;
import org.hsqldb.persist.
DataSpaceManager;
import org.hsqldb.persist.
PersistentStore;
import org.hsqldb.result.
Result;
import org.hsqldb.rights.
Grantee;
import org.hsqldb.types.
BinaryData;
import org.hsqldb.types.
CharacterType;
import org.hsqldb.types.
Collation;
import org.hsqldb.types.
Type;
/**
* Holds the data structures and methods for creation of a named database table.
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 2.4.1
* @since 1.6.1
*/
public class
Table extends
TableBase implements
SchemaObject {
public static final
Table[]
emptyArray = new
Table[]{};
// main properties
protected
HsqlName tableName;
protected long
changeTimestamp;
//
public
HashMappedList columnList; // columns in table
int
identityColumn; // -1 means no such column
NumberSequence identitySequence; // next value of identity column
// -----------------------------------------------------------------------
Constraint[]
constraintList; // constraint for the table
Constraint[]
fkConstraints; //
Constraint[]
fkMainConstraints;
Constraint[]
checkConstraints;
TriggerDef[]
triggerList;
TriggerDef[][]
triggerLists; // array of trigger lists
Expression[]
colDefaults; // expressions of DEFAULT values
private boolean
hasDefaultValues; // shortcut for above
boolean[]
colGenerated; // generated columns
private boolean
hasGeneratedValues; // shortcut for above
boolean[]
colUpdated; // auto update columns
private boolean
hasUpdatedValues; // shortcut for above
boolean[]
colRefFK; // foreign key columns
boolean[]
colMainFK; // columns referenced by foreign key
int
referentialActions; // has set null, set default or cascade
int
cascadingDeletes; // has on delete cascade
boolean
isDropped; // has been dropped
private boolean
hasDomainColumns; // shortcut
private boolean
hasNotNullColumns; // shortcut
protected int[]
defaultColumnMap; // holding 0,1,2,3,...
RangeVariable[]
defaultRanges;
//
public
Table(
Database database,
HsqlName name, int
type) {
this.
database =
database;
this.
tableName =
name;
this.
persistenceId =
database.
persistentStoreCollection.
getNextId();
switch (
type) {
case
CHANGE_SET_TABLE :
persistenceScope =
SCOPE_STATEMENT;
isSessionBased = true;
break;
case
SYSTEM_SUBQUERY :
persistenceScope =
SCOPE_STATEMENT;
isSessionBased = true;
break;
case
INFO_SCHEMA_TABLE :
persistenceScope =
SCOPE_TRANSACTION;
isSessionBased = true;
break;
case
SYSTEM_TABLE :
persistenceScope =
SCOPE_FULL;
isSchemaBased = true;
break;
case
CACHED_TABLE :
if (
database.
logger.
isFileDatabase()) {
persistenceScope =
SCOPE_FULL;
isSchemaBased = true;
isCached = true;
isLogged = !
database.
isFilesReadOnly();
break;
}
type =
MEMORY_TABLE;
// fall through
case
MEMORY_TABLE :
persistenceScope =
SCOPE_FULL;
isSchemaBased = true;
isLogged = !
database.
isFilesReadOnly();
break;
case
TEMP_TABLE :
persistenceScope =
SCOPE_TRANSACTION;
isTemp = true;
isSchemaBased = true;
isSessionBased = true;
break;
case
TEMP_TEXT_TABLE :
persistenceScope =
SCOPE_SESSION;
if (!
database.
logger.
isFileDatabase()) {
throw
Error.
error(
ErrorCode.
DATABASE_IS_MEMORY_ONLY);
}
isSchemaBased = true;
isSessionBased = true;
isTemp = true;
isText = true;
isReadOnly = true;
break;
case
TEXT_TABLE :
persistenceScope =
SCOPE_FULL;
if (!
database.
logger.
isFileDatabase()) {
if (!
database.
logger.
isAllowedFullPath()) {
throw
Error.
error(
ErrorCode.
DATABASE_IS_MEMORY_ONLY);
}
isReadOnly = true;
}
isSchemaBased = true;
isText = true;
break;
case
VIEW_TABLE :
persistenceScope =
SCOPE_STATEMENT;
isSchemaBased = true;
isSessionBased = true;
isView = true;
break;
case
MODULE_TABLE :
case
RESULT_TABLE :
persistenceScope =
SCOPE_SESSION;
isSessionBased = true;
break;
case
TableBase.
FUNCTION_TABLE :
persistenceScope =
SCOPE_STATEMENT;
isSessionBased = true;
break;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "Table");
}
// type may have changed above for CACHED tables
tableType =
type;
identityColumn = -1;
columnList = new
HashMappedList();
indexList =
Index.
emptyArray;
constraintList =
Constraint.
emptyArray;
fkConstraints =
Constraint.
emptyArray;
fkMainConstraints =
Constraint.
emptyArray;
checkConstraints =
Constraint.
emptyArray;
triggerList =
TriggerDef.
emptyArray;
triggerLists = new
TriggerDef[
TriggerDef.
NUM_TRIGS][];
for (int
i = 0;
i <
TriggerDef.
NUM_TRIGS;
i++) {
triggerLists[
i] =
TriggerDef.
emptyArray;
}
if (
database.
isFilesReadOnly() &&
isFileBased()) {
this.
isReadOnly = true;
}
}
/** trigger transition table */
public
Table(
Table table,
HsqlName name) {
persistenceScope =
SCOPE_STATEMENT;
name.
schema =
SqlInvariants.
SYSTEM_SCHEMA_HSQLNAME;
this.
tableName =
name;
this.
database =
table.
database;
this.
tableType =
RESULT_TABLE;
this.
columnList =
table.
columnList;
this.
columnCount =
table.
columnCount;
this.
indexList =
Index.
emptyArray;
this.
constraintList =
Constraint.
emptyArray;
createPrimaryKey();
}
public int
getType() {
return
SchemaObject.
TABLE;
}
/**
* Returns the HsqlName object fo the table
*/
public final
HsqlName getName() {
return
tableName;
}
/**
* Returns the catalog name or null, depending on a database property.
*/
public
HsqlName getCatalogName() {
return
database.
getCatalogName();
}
/**
* Returns the schema name.
*/
public
HsqlName getSchemaName() {
return
tableName.
schema;
}
public
Grantee getOwner() {
return
tableName.
schema.
owner;
}
public
OrderedHashSet getReferences() {
OrderedHashSet set = new
OrderedHashSet();
if (
identitySequence != null &&
identitySequence.
getName() != null) {
set.
add(
identitySequence.
getName());
}
return
set;
}
public
RangeVariable[]
getDefaultRanges() {
if (
defaultRanges == null) {
defaultRanges = new
RangeVariable[]{ new
RangeVariable(this, 0) };
}
return
defaultRanges;
}
public
OrderedHashSet getReferencesForDependents() {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0;
i <
colTypes.length;
i++) {
ColumnSchema column =
getColumn(
i);
OrderedHashSet refs =
column.
getReferences();
if (
refs != null && !
refs.
isEmpty()) {
set.
add(
column.
getName());
}
}
for (int
i = 0;
i <
fkConstraints.length;
i++) {
if (
fkConstraints[
i].
getMainTableName() !=
getName()) {
set.
add(
fkConstraints[
i].
getName());
}
}
for (int
i = 0;
i <
triggerList.length;
i++) {
set.
add(
triggerList[
i].
getName());
}
return
set;
}
public
OrderedHashSet getComponents() {
OrderedHashSet set = new
OrderedHashSet();
set.
addAll(
constraintList);
set.
addAll(
triggerList);
for (int
i = 0;
i <
indexList.length;
i++) {
if (!
indexList[
i].
isConstraint()) {
set.
add(
indexList[
i]);
}
}
return
set;
}
public void
compile(
Session session,
SchemaObject parentObject) {
for (int
i = 0;
i <
columnCount;
i++) {
ColumnSchema column =
getColumn(
i);
column.
compile(
session, this);
}
}
public
String getSQL() {
StringBuffer sb = new
StringBuffer();
sb.
append(
Tokens.
T_CREATE).
append(' ');
if (
isTemp()) {
sb.
append(
Tokens.
T_GLOBAL).
append(' ');
sb.
append(
Tokens.
T_TEMPORARY).
append(' ');
} else if (
isText()) {
sb.
append(
Tokens.
T_TEXT).
append(' ');
} else if (
isCached()) {
sb.
append(
Tokens.
T_CACHED).
append(' ');
} else {
sb.
append(
Tokens.
T_MEMORY).
append(' ');
}
sb.
append(
Tokens.
T_TABLE).
append(' ');
sb.
append(
getName().
getSchemaQualifiedStatementName());
sb.
append('(');
int[]
pk =
getPrimaryKey();
Constraint pkConst =
getPrimaryConstraint();
for (int
j = 0;
j <
columnCount;
j++) {
ColumnSchema column =
getColumn(
j);
String colname =
column.
getName().
statementName;
Type type =
column.
getDataType();
if (
j > 0) {
sb.
append(',');
}
sb.
append(
colname);
sb.
append(' ');
sb.
append(
type.
getTypeDefinition());
if (!
type.
isDistinctType() && !
type.
isDomainType()) {
if (
type.
isCharacterType()) {
Collation collation =
((
CharacterType)
type).
getCollation();
if (
collation.
isObjectCollation()) {
sb.
append(' ').
append(
collation.
getCollateSQL());
}
}
}
String defaultString =
column.
getDefaultSQL();
if (
defaultString != null) {
sb.
append(' ').
append(
Tokens.
T_DEFAULT).
append(' ');
sb.
append(
defaultString);
}
if (
column.
isAutoUpdate()) {
sb.
append(' ').
append(
Tokens.
T_ON).
append(' ');
sb.
append(
Tokens.
T_UPDATE).
append(' ');
sb.
append(
column.
getUpdateExpression().
getSQL());
}
if (
column.
isIdentity()) {
sb.
append(' ').
append(
column.
getIdentitySequence().
getSQLColumnDefinition());
}
if (
column.
isGenerated()) {
sb.
append(' ').
append(
Tokens.
T_GENERATED).
append(' ');
sb.
append(
Tokens.
T_ALWAYS).
append(' ').
append(
Tokens.
T_AS).
append(
Tokens.
T_OPENBRACKET);
sb.
append(
column.
getGeneratingExpression().
getSQL());
sb.
append(
Tokens.
T_CLOSEBRACKET);
}
if (!
column.
isNullable()) {
Constraint c =
getNotNullConstraintForColumn(
j);
if (
c != null && !
c.
getName().
isReservedName()) {
sb.
append(' ').
append(
Tokens.
T_CONSTRAINT).
append(
' ').
append(
c.
getName().
statementName);
}
sb.
append(' ').
append(
Tokens.
T_NOT).
append(' ').
append(
Tokens.
T_NULL);
}
if (
pk.length == 1 &&
j ==
pk[0]
&&
pkConst.
getName().
isReservedName()) {
sb.
append(' ').
append(
Tokens.
T_PRIMARY).
append(' ').
append(
Tokens.
T_KEY);
}
}
Constraint[]
constraintList =
getConstraints();
for (int
j = 0,
vSize =
constraintList.length;
j <
vSize;
j++) {
Constraint c =
constraintList[
j];
if (!
c.
isForward) {
String d =
c.
getSQL();
if (
d.
length() > 0) {
sb.
append(',');
sb.
append(
d);
}
}
}
sb.
append(')');
if (
onCommitPreserve()) {
sb.
append(' ').
append(
Tokens.
T_ON).
append(' ');
sb.
append(
Tokens.
T_COMMIT).
append(' ').
append(
Tokens.
T_PRESERVE);
sb.
append(' ').
append(
Tokens.
T_ROWS);
}
return
sb.
toString();
}
public long
getChangeTimestamp() {
return
changeTimestamp;
}
public final void
setName(
HsqlName name) {
tableName =
name;
}
String[]
getSQL(
OrderedHashSet resolved,
OrderedHashSet unresolved) {
for (int
i = 0;
i <
constraintList.length;
i++) {
Constraint c =
constraintList[
i];
if (
c.
isForward) {
unresolved.
add(
c);
} else if (
c.
getConstraintType() ==
SchemaObject.
ConstraintTypes
.
UNIQUE ||
c.
getConstraintType() ==
SchemaObject
.
ConstraintTypes.
PRIMARY_KEY) {
resolved.
add(
c.
getName());
}
}
HsqlArrayList list = new
HsqlArrayList();
list.
add(
getSQL());
if (!
isTemp && !
isText &&
identitySequence != null
&&
identitySequence.
getName() == null) {
list.
add(
NumberSequence.
getRestartSQL(this));
}
for (int
i = 0;
i <
indexList.length;
i++) {
if (!
indexList[
i].
isConstraint()
&&
indexList[
i].
getColumnCount() > 0) {
list.
add(
indexList[
i].
getSQL());
}
}
String[]
array = new
String[
list.
size()];
list.
toArray(
array);
return
array;
}
public
String getSQLForReadOnly() {
if (
isReadOnly) {
StringBuffer sb = new
StringBuffer(64);
sb.
append(
Tokens.
T_SET).
append(' ').
append(
Tokens.
T_TABLE).
append(
' ');
sb.
append(
getName().
getSchemaQualifiedStatementName());
sb.
append(' ').
append(
Tokens.
T_READ).
append(' ');
sb.
append(
Tokens.
T_ONLY);
return
sb.
toString();
} else {
return null;
}
}
public
String[]
getSQLForTextSource(boolean
withHeader) {
// readonly for TEXT tables only
if (
isText()) {
HsqlArrayList list = new
HsqlArrayList();
if (
isReadOnly) {
list.
add(
getSQLForReadOnly());
}
// data source
String dataSource = ((
TextTable) this).
getDataSourceDDL();
if (
dataSource != null) {
list.
add(
dataSource);
}
// header
String header = ((
TextTable) this).
getDataSourceHeader();
if (
withHeader &&
header != null && !
isReadOnly) {
list.
add(
header);
}
String[]
array = new
String[
list.
size()];
list.
toArray(
array);
return
array;
} else {
return null;
}
}
public
String getSQLForClustered() {
if (!
isCached() && !
isText()) {
return null;
}
Index index =
getClusteredIndex();
if (
index == null) {
return null;
}
String colList =
getColumnListSQL(
index.
getColumns(),
index.
getColumnCount());
StringBuffer sb = new
StringBuffer(64);
sb.
append(
Tokens.
T_SET).
append(' ').
append(
Tokens.
T_TABLE).
append(' ');
sb.
append(
getName().
getSchemaQualifiedStatementName());
sb.
append(' ').
append(
Tokens.
T_CLUSTERED).
append(' ');
sb.
append(
Tokens.
T_ON).
append(' ').
append(
colList);
return
sb.
toString();
}
public
String getSQLForTableSpace() {
if (!
isCached() ||
tableSpace ==
DataSpaceManager.
tableIdDefault) {
return null;
}
StringBuffer sb = new
StringBuffer(64);
sb.
append(
Tokens.
T_SET).
append(' ').
append(
Tokens.
T_TABLE).
append(' ');
sb.
append(
getName().
getSchemaQualifiedStatementName());
sb.
append(' ').
append(
Tokens.
T_SPACE).
append(' ').
append(
tableSpace);
return
sb.
toString();
}
public
String[]
getTriggerSQL() {
HsqlArrayList list = new
HsqlArrayList();
for (int
i = 0;
i <
triggerList.length;
i++) {
if (!
triggerList[
i].
isSystem()) {
list.
add(
triggerList[
i].
getSQL());
}
}
String[]
array = new
String[
list.
size()];
list.
toArray(
array);
return
array;
}
public
String getIndexRootsSQL(long[]
roots) {
StringBuffer sb = new
StringBuffer(128);
sb.
append(
Tokens.
T_SET).
append(' ').
append(
Tokens.
T_TABLE).
append(' ');
sb.
append(
getName().
getSchemaQualifiedStatementName());
sb.
append(' ').
append(
Tokens.
T_INDEX).
append(' ').
append('\'');
sb.
append(
StringUtil.
getList(
roots, " ", ""));
sb.
append(' ');
sb.
append(
StringUtil.
getList(new long[
indexList.length], " ", ""));
sb.
append(' ').
append(
store.
elementCount());
sb.
append('\'');
return
sb.
toString();
}
public
String getColumnListSQL(int[]
col, int
len) {
StringBuffer sb = new
StringBuffer();
sb.
append('(');
for (int
i = 0;
i <
len;
i++) {
sb.
append(
getColumn(
col[
i]).
getName().
statementName);
if (
i <
len - 1) {
sb.
append(',');
}
}
sb.
append(')');
return
sb.
toString();
}
public
String getColumnListWithTypeSQL() {
StringBuffer sb = new
StringBuffer();
sb.
append('(');
for (int
j = 0;
j <
columnCount;
j++) {
ColumnSchema column =
getColumn(
j);
String colname =
column.
getName().
statementName;
Type type =
column.
getDataType();
if (
j > 0) {
sb.
append(',');
}
sb.
append(
colname);
sb.
append(' ');
sb.
append(
type.
getTypeDefinition());
}
sb.
append(')');
return
sb.
toString();
}
public boolean
isConnected() {
return true;
}
/**
* compares two full table rows based on a set of columns
*
* @param a a full row
* @param b a full row
* @param cols array of column indexes to compare
* @param coltypes array of column types for the full row
*
* @return comparison result, -1,0,+1
*/
public static int
compareRows(
Session session,
Object[]
a,
Object[]
b,
int[]
cols,
Type[]
coltypes) {
int
fieldcount =
cols.length;
for (int
j = 0;
j <
fieldcount;
j++) {
int
i =
coltypes[
cols[
j]].
compare(
session,
a[
cols[
j]],
b[
cols[
j]]);
if (
i != 0) {
return
i;
}
}
return 0;
}
/**
* Used to create row id's
*/
public int
getId() {
return
tableName.
hashCode();
}
public
String getTableTypeString() {
switch (
tableType) {
case
TableBase.
MEMORY_TABLE :
return
Tokens.
T_MEMORY;
case
TableBase.
CACHED_TABLE :
return
Tokens.
T_CACHED;
case
TableBase.
TEXT_TABLE :
return
Tokens.
T_TEXT;
case
TableBase.
MODULE_TABLE :
return
Tokens.
T_MODULE;
case
TableBase.
FUNCTION_TABLE :
return
Tokens.
T_FUNCTION;
case
TableBase.
INFO_SCHEMA_TABLE :
case
TableBase.
VIEW_TABLE :
return
Tokens.
T_VIEW;
case
TableBase.
TEMP_TABLE :
return
Tokens.
T_TEMP;
case
TableBase.
SYSTEM_SUBQUERY :
default :
return "SUBQUERY";
}
}
public final boolean
isSchemaBaseTable() {
switch (
tableType) {
case
TableBase.
MEMORY_TABLE :
case
TableBase.
CACHED_TABLE :
case
TableBase.
TEXT_TABLE :
return true;
default :
return false;
}
}
public final boolean
isWithDataSource() {
return
isWithDataSource;
}
public final boolean
isText() {
return
isText;
}
public final boolean
isTemp() {
return
isTemp;
}
public final boolean
isReadOnly() {
return
isReadOnly;
}
public final boolean
isView() {
return
isView;
}
public boolean
isQueryBased() {
return false;
}
public boolean
isCached() {
return
isCached;
}
public boolean
isDataReadOnly() {
return
isReadOnly;
}
public boolean
isDropped() {
return
isDropped;
}
/**
* returns false if the table has to be recreated in order to add / drop
* indexes. Only CACHED tables return false.
*/
final boolean
isIndexingMutable() {
return !
isCached;
}
/**
* Used by INSERT, DELETE, UPDATE operations
*/
public void
checkDataReadOnly() {
if (
isDataReadOnly()) {
throw
Error.
error(
ErrorCode.
DATA_IS_READONLY);
}
}
// ----------------------------------------------------------------------------
// akede@users - 1.7.2 patch Files readonly
public void
setDataReadOnly(boolean
value) {
// Changing the Read-Only mode for the table is only allowed if the
// the database can realize it.
if (!
value) {
if (
database.
isFilesReadOnly() &&
isFileBased()) {
throw
Error.
error(
ErrorCode.
DATA_IS_READONLY);
} else if (
database.
getType() ==
DatabaseType.
DB_MEM &&
isText) {
throw
Error.
error(
ErrorCode.
DATA_IS_READONLY);
}
}
isReadOnly =
value;
}
/**
* Text or Cached Tables are normally file based
*/
public boolean
isFileBased() {
return
isCached ||
isText;
}
/**
* Adds a constraint.
*/
public void
addConstraint(
Constraint c) {
int
index =
c.
getConstraintType()
==
SchemaObject.
ConstraintTypes.
PRIMARY_KEY ? 0
:
constraintList
.length;
constraintList =
(
Constraint[])
ArrayUtil.
toAdjustedArray(
constraintList,
c,
index,
1);
updateConstraintLists();
}
void
updateConstraintLists() {
int
fkCount = 0;
int
mainCount = 0;
int
checkCount = 0;
referentialActions = 0;
cascadingDeletes = 0;
for (int
i = 0;
i <
constraintList.length;
i++) {
switch (
constraintList[
i].
getConstraintType()) {
case
SchemaObject.
ConstraintTypes.
FOREIGN_KEY :
fkCount++;
break;
case
SchemaObject.
ConstraintTypes.
MAIN :
mainCount++;
break;
case
SchemaObject.
ConstraintTypes.
CHECK :
if (
constraintList[
i].
isNotNull()) {
break;
}
checkCount++;
break;
}
}
fkConstraints =
fkCount == 0 ?
Constraint.
emptyArray
: new
Constraint[
fkCount];
fkCount = 0;
fkMainConstraints =
mainCount == 0 ?
Constraint.
emptyArray
: new
Constraint[
mainCount];
mainCount = 0;
checkConstraints =
checkCount == 0 ?
Constraint.
emptyArray
: new
Constraint[
checkCount];
checkCount = 0;
colRefFK = new boolean[
columnCount];
colMainFK = new boolean[
columnCount];
for (int
i = 0;
i <
constraintList.length;
i++) {
switch (
constraintList[
i].
getConstraintType()) {
case
SchemaObject.
ConstraintTypes.
FOREIGN_KEY :
fkConstraints[
fkCount] =
constraintList[
i];
ArrayUtil.
intIndexesToBooleanArray(
constraintList[
i].
getRefColumns(),
colRefFK);
fkCount++;
break;
case
SchemaObject.
ConstraintTypes.
MAIN :
fkMainConstraints[
mainCount] =
constraintList[
i];
ArrayUtil.
intIndexesToBooleanArray(
constraintList[
i].
getMainColumns(),
colMainFK);
if (
constraintList[
i].
hasCoreTriggeredAction()) {
referentialActions++;
if (
constraintList[
i].
getDeleteAction()
==
SchemaObject.
ReferentialAction.
CASCADE) {
cascadingDeletes++;
}
}
mainCount++;
break;
case
SchemaObject.
ConstraintTypes.
CHECK :
if (
constraintList[
i].
isNotNull()) {
break;
}
checkConstraints[
checkCount] =
constraintList[
i];
checkCount++;
break;
}
}
}
void
verifyConstraintsIntegrity() {
for (int
i = 0;
i <
constraintList.length;
i++) {
Constraint c =
constraintList[
i];
if (
c.
getConstraintType() ==
SchemaObject.
ConstraintTypes
.
FOREIGN_KEY ||
c.
getConstraintType() ==
SchemaObject
.
ConstraintTypes.
MAIN) {
if (
c.
getMain()
!=
database.
schemaManager.
findUserTable(
c.
getMain().
getName().
name,
c.
getMain().
getName().
schema.
name)) {
throw
Error.
runtimeError(
ErrorCode.
U_S0500,
"FK mismatch : "
+
c.
getName().
name);
}
if (
c.
getRef()
!=
database.
schemaManager.
findUserTable(
c.
getRef().
getName().
name,
c.
getRef().
getName().
schema.
name)) {
throw
Error.
runtimeError(
ErrorCode.
U_S0500,
"FK mismatch : "
+
c.
getName().
name);
}
}
}
}
/**
* Returns the list of constraints.
*/
public
Constraint[]
getConstraints() {
return
constraintList;
}
/**
* Returns the list of FK constraints.
*/
public
Constraint[]
getFKConstraints() {
return
fkConstraints;
}
/**
* Returns the primary constraint.
*/
public
Constraint getPrimaryConstraint() {
return
hasPrimaryKey() ?
constraintList[0]
: null;
}
/** columnMap is null for deletes */
void
collectFKReadLocks(int[]
columnMap,
OrderedHashSet set) {
for (int
i = 0;
i <
fkMainConstraints.length;
i++) {
Constraint constraint =
fkMainConstraints[
i];
Table ref =
constraint.
getRef();
int[]
mainColumns =
constraint.
getMainColumns();
if (
ref == this) {
continue;
}
if (
columnMap == null) {
if (
constraint.
core.
hasDeleteAction) {
int[]
cols =
constraint.
getDeleteAction()
==
SchemaObject.
ReferentialAction.
CASCADE ? null
:
constraint
.
getRefColumns();
if (
set.
add(
ref.
getName())) {
ref.
collectFKReadLocks(
cols,
set);
}
}
} else if (
ArrayUtil.
haveCommonElement(
columnMap,
mainColumns)) {
if (
set.
add(
ref.
getName())) {
ref.
collectFKReadLocks(
constraint.
getRefColumns(),
set);
}
}
}
}
/** columnMap is null for deletes */
void
collectFKWriteLocks(int[]
columnMap,
OrderedHashSet set) {
for (int
i = 0;
i <
fkMainConstraints.length;
i++) {
Constraint constraint =
fkMainConstraints[
i];
Table ref =
constraint.
getRef();
int[]
mainColumns =
constraint.
getMainColumns();
if (
ref == this) {
continue;
}
if (
columnMap == null) {
if (
constraint.
core.
hasDeleteAction) {
int[]
cols =
constraint.
getDeleteAction()
==
SchemaObject.
ReferentialAction.
CASCADE ? null
:
constraint
.
getRefColumns();
if (
set.
add(
ref.
getName())) {
ref.
collectFKWriteLocks(
cols,
set);
}
}
} else if (
ArrayUtil.
haveCommonElement(
columnMap,
mainColumns)) {
if (
constraint.
core.
hasUpdateAction) {
if (
set.
add(
ref.
getName())) {
ref.
collectFKWriteLocks(
constraint.
getRefColumns(),
set);
}
}
}
}
}
Constraint getNotNullConstraintForColumn(int
colIndex) {
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
isNotNull() &&
c.
notNullColumnIndex ==
colIndex) {
return
c;
}
}
return null;
}
/**
* Returns the UNIQUE or PK constraint with the given column signature.
*/
Constraint getUniqueConstraintForColumns(int[]
cols) {
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
isUniqueWithColumns(
cols)) {
return
c;
}
}
return null;
}
/**
* Returns any foreign key constraint equivalent to the column sets
*/
Constraint getFKConstraintForColumns(
Table tableMain, int[]
mainCols,
int[]
refCols) {
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
isEquivalent(
tableMain,
mainCols, this,
refCols)) {
return
c;
}
}
return null;
}
/**
* Returns any unique Constraint using this index
*
* @param index
*/
public
Constraint getUniqueOrPKConstraintForIndex(
Index index) {
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
getMainIndex() ==
index && (
c
.
getConstraintType() ==
SchemaObject.
ConstraintTypes
.
UNIQUE ||
c.
getConstraintType() ==
SchemaObject
.
ConstraintTypes.
PRIMARY_KEY)) {
return
c;
}
}
return null;
}
/**
* Returns the next constraint of a given type
*
* @param from
* @param type
*/
int
getNextConstraintIndex(int
from, int
type) {
for (int
i =
from,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
getConstraintType() ==
type) {
return
i;
}
}
return -1;
}
/**
* Performs the table level checks and adds a column to the table at the
* DDL level. Only used at table creation, not at alter column.
*/
public void
addColumn(
ColumnSchema column) {
String name =
column.
getName().
name;
if (
findColumn(
name) >= 0) {
throw
Error.
error(
ErrorCode.
X_42504,
name);
}
if (
column.
isIdentity()) {
if (
identityColumn != -1) {
throw
Error.
error(
ErrorCode.
X_42525,
name);
}
identityColumn =
columnCount;
identitySequence =
column.
getIdentitySequence();
}
addColumnNoCheck(
column);
}
public void
addColumnNoCheck(
ColumnSchema column) {
columnList.
add(
column.
getName().
name,
column);
columnCount++;
}
public boolean
hasGeneratedColumn() {
return
hasGeneratedValues;
}
public boolean
hasUpdatedColumn(int[]
colMap) {
return
hasUpdatedValues
&& !
ArrayUtil.
isAnyIntIndexInBooleanArray(
colMap,
colUpdated);
}
public boolean
hasLobColumn() {
return
hasLobColumn;
}
public boolean
hasIdentityColumn() {
return
identityColumn != -1;
}
/**
* Match two valid, equal length, columns arrays for type of columns for
* referential constraints
*
* @param col column array from this Table
* @param other the other Table object
* @param othercol column array from the other Table
*/
void
checkReferentialColumnsMatch(int[]
col,
Table other, int[]
othercol) {
for (int
i = 0;
i <
col.length;
i++) {
Type type =
colTypes[
col[
i]];
Type otherType =
other.
colTypes[
othercol[
i]];
if (!
type.
canCompareDirect(
otherType)) {
throw
Error.
error(
ErrorCode.
X_42562);
}
}
}
/**
* For removal or addition of columns, constraints and indexes
*
* HsqlName objects are used from the old tables but no object is reused.
*
* Does not work in this form for FK's as Constraint.ConstraintCore
* is not transferred to a referencing or referenced table
*/
Table moveDefinition(
Session session, int
newType,
ColumnSchema column,
Constraint constraint,
Index index, int
colIndex,
int
adjust,
OrderedHashSet dropConstraints,
OrderedHashSet dropIndexes) {
boolean
newPK = false;
if (
constraint != null
&&
constraint.
getConstraintType()
==
SchemaObject.
ConstraintTypes.
PRIMARY_KEY) {
newPK = true;
}
Table tn;
if (
isText) {
tn = new
TextTable(
database,
tableName,
newType);
((
TextTable)
tn).
dataSource = ((
TextTable) this).
dataSource;
((
TextTable)
tn).
isReversed = ((
TextTable) this).
isReversed;
((
TextTable)
tn).
isConnected = ((
TextTable) this).
isConnected;
} else {
tn = new
Table(
database,
tableName,
newType);
}
if (
tableType ==
TEMP_TABLE) {
tn.
persistenceScope =
persistenceScope;
}
tn.
tableSpace =
tableSpace;
for (int
i = 0;
i <
columnCount;
i++) {
ColumnSchema col = (
ColumnSchema)
columnList.
get(
i);
if (
i ==
colIndex) {
if (
column != null) {
tn.
addColumn(
column);
}
if (
adjust <= 0) {
continue;
}
}
col =
col.
duplicate();
col.
setPrimaryKey(false);
tn.
addColumn(
col);
}
if (
columnCount ==
colIndex) {
tn.
addColumn(
column);
}
int[]
pkCols = null;
if (
hasPrimaryKey()
&& !
dropConstraints.
contains(
getPrimaryConstraint().
getName())) {
pkCols =
getPrimaryKey();
pkCols =
ArrayUtil.
toAdjustedColumnArray(
pkCols,
colIndex,
adjust);
} else if (
newPK) {
pkCols =
constraint.
getMainColumns();
}
tn.
createPrimaryKey(
getIndex(0).
getName(),
pkCols, false);
for (int
i = 1;
i <
indexList.length;
i++) {
Index idx =
indexList[
i];
if (
dropIndexes.
contains(
idx.
getName())) {
continue;
}
int[]
colarr =
ArrayUtil.
toAdjustedColumnArray(
idx.
getColumns(),
colIndex,
adjust);
Index newIdx =
tn.
createIndexStructure(
idx.
getName(),
colarr,
idx.
getColumnDesc(), null,
idx.
isUnique(),
idx.
isConstraint(),
idx.
isForward());
newIdx.
setClustered(
idx.
isClustered());
tn.
addIndexStructure(
newIdx);
}
if (
index != null) {
index.
setTable(
tn);
tn.
addIndexStructure(
index);
}
HsqlArrayList newList = new
HsqlArrayList();
if (
newPK) {
constraint.
core.
mainIndex =
tn.
indexList[0];
constraint.
core.
mainTable =
tn;
constraint.
core.
mainTableName =
tn.
tableName;
newList.
add(
constraint);
}
for (int
i = 0;
i <
constraintList.length;
i++) {
Constraint c =
constraintList[
i];
if (
dropConstraints.
contains(
c.
getName())) {
continue;
}
c =
c.
duplicate();
c.
updateTable(
session, this,
tn,
colIndex,
adjust);
newList.
add(
c);
}
if (!
newPK &&
constraint != null) {
constraint.
updateTable(
session, this,
tn, -1, 0);
newList.
add(
constraint);
}
tn.
constraintList = new
Constraint[
newList.
size()];
newList.
toArray(
tn.
constraintList);
tn.
updateConstraintLists();
tn.
setBestRowIdentifiers();
tn.
triggerList =
triggerList;
tn.
triggerLists =
triggerLists;
for (int
i = 0;
i <
tn.
constraintList.length;
i++) {
tn.
constraintList[
i].
compile(
session,
tn);
}
for (int
i = 0;
i <
tn.
columnCount;
i++) {
tn.
getColumn(
i).
compile(
session,
tn);
}
return
tn;
}
/**
* Used for drop / retype column.
*/
void
checkColumnInCheckConstraint(int
colIndex) {
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
getConstraintType() ==
SchemaObject.
ConstraintTypes.
CHECK
&& !
c.
isNotNull() &&
c.
hasColumn(
colIndex)) {
HsqlName name =
c.
getName();
throw
Error.
error(
ErrorCode.
X_42502,
name.
getSchemaQualifiedStatementName());
}
}
}
/**
* Used for retype column. Checks whether column is in an FK or is
* referenced by a FK
* @param colIndex index
*/
void
checkColumnInFKConstraint(int
colIndex) {
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
hasColumn(
colIndex) && (
c.
getConstraintType() ==
SchemaObject
.
ConstraintTypes.
MAIN ||
c
.
getConstraintType() ==
SchemaObject.
ConstraintTypes
.
FOREIGN_KEY)) {
HsqlName name =
c.
getName();
throw
Error.
error(
ErrorCode.
X_42533,
name.
getSchemaQualifiedStatementName());
}
}
}
/**
* Returns list of constraints dependent only on one column
*/
OrderedHashSet getDependentConstraints(int
colIndex) {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
hasColumnOnly(
colIndex)) {
set.
add(
c);
}
}
return
set;
}
/**
* Returns list of constraints dependent on more than one column
*/
OrderedHashSet getContainingConstraints(int
colIndex) {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
hasColumnPlus(
colIndex)) {
set.
add(
c);
}
}
return
set;
}
OrderedHashSet getContainingIndexNames(int
colIndex) {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0,
size =
indexList.length;
i <
size;
i++) {
Index index =
indexList[
i];
if (
ArrayUtil.
find(
index.
getColumns(),
colIndex) != -1) {
set.
add(
index.
getName());
}
}
return
set;
}
/**
* Returns list of MAIN constraints dependent on this PK or UNIQUE constraint
*/
OrderedHashSet getDependentConstraints(
Constraint constraint) {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0,
size =
fkMainConstraints.length;
i <
size;
i++) {
Constraint c =
fkMainConstraints[
i];
if (
c.
core.
uniqueName ==
constraint.
getName()) {
set.
add(
c);
}
}
return
set;
}
public
OrderedHashSet getDependentExternalConstraints() {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
getConstraintType() ==
SchemaObject.
ConstraintTypes.
MAIN
||
c.
getConstraintType()
==
SchemaObject.
ConstraintTypes.
FOREIGN_KEY) {
if (
c.
core.
mainTable !=
c.
core.
refTable) {
set.
add(
c);
}
}
}
return
set;
}
public
OrderedHashSet getUniquePKConstraintNames() {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
getConstraintType() ==
SchemaObject.
ConstraintTypes.
UNIQUE
||
c.
getConstraintType()
==
SchemaObject.
ConstraintTypes.
PRIMARY_KEY) {
set.
add(
c.
getName());
}
}
return
set;
}
/**
* Used for column defaults and nullability. Checks whether column is in an
* FK with a given referential action type.
*
* @param colIndex index of column
* @param actionType referential action of the FK
*/
void
checkColumnInFKConstraint(int
colIndex, int
actionType) {
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
getConstraintType() ==
SchemaObject.
ConstraintTypes
.
FOREIGN_KEY &&
c
.
hasColumn(
colIndex) && (
actionType ==
c
.
getUpdateAction() ||
actionType ==
c
.
getDeleteAction())) {
HsqlName name =
c.
getName();
throw
Error.
error(
ErrorCode.
X_42533,
name.
getSchemaQualifiedStatementName());
}
}
}
/**
* Returns the identity column index.
*/
int
getIdentityColumnIndex() {
return
identityColumn;
}
/**
* Returns the index of given column name or throws if not found
*/
public int
getColumnIndex(
String name) {
int
i =
findColumn(
name);
if (
i == -1) {
throw
Error.
error(
ErrorCode.
X_42501,
name);
}
return
i;
}
/**
* Returns the index of given column name or -1 if not found.
*/
public int
findColumn(
String name) {
int
index =
columnList.
getIndex(
name);
return
index;
}
/**
* sets the flag for the presence of any default expression
*/
void
resetDefaultsFlag() {
hasDefaultValues = false;
hasGeneratedValues = false;
hasUpdatedValues = false;
hasNotNullColumns = false;
hasDomainColumns = false;
hasLobColumn = false;
for (int
i = 0;
i <
columnCount;
i++) {
hasDefaultValues |=
colDefaults[
i] != null;
hasGeneratedValues |=
colGenerated[
i];
hasUpdatedValues |=
colUpdated[
i];
hasNotNullColumns |=
colNotNull[
i];
if (
colTypes[
i].
isDomainType()) {
hasDomainColumns = true;
}
if (
colTypes[
i].
isLobType()) {
hasLobColumn = true;
}
}
}
public int[]
getBestRowIdentifiers() {
return
bestRowIdentifierCols;
}
public boolean
isBestRowIdentifiersStrict() {
return
bestRowIdentifierStrict;
}
public
Index getClusteredIndex() {
for (int
i = 0;
i <
indexList.length;
i++) {
if (
indexList[
i].
isClustered()) {
return
indexList[
i];
}
}
return null;
}
/**
* Finds an existing index for a column
*/
synchronized
Index getIndexForColumn(
Session session, int
col) {
int
i =
bestIndexForColumn[
col];
if (
i > -1) {
return
indexList[
i];
}
switch (
tableType) {
case
TableBase.
TEMP_TABLE :
case
TableBase.
INFO_SCHEMA_TABLE :
case
TableBase.
MODULE_TABLE :
case
TableBase.
FUNCTION_TABLE :
case
TableBase.
SYSTEM_SUBQUERY :
case
TableBase.
VIEW_TABLE : {
Index index =
createIndexForColumns(
session, new int[]{
col });
return
index;
}
}
return null;
}
boolean
isIndexed(int
colIndex) {
return
bestIndexForColumn[
colIndex] != -1;
}
int[]
getUniqueNotNullColumnGroup(boolean[]
usedColumns) {
for (int
i = 0,
count =
constraintList.length;
i <
count;
i++) {
Constraint constraint =
constraintList[
i];
if (
constraint.
getConstraintType()
==
SchemaObject.
ConstraintTypes.
UNIQUE) {
int[]
indexCols =
constraint.
getMainColumns();
if (
ArrayUtil.
areAllIntIndexesInBooleanArray(
indexCols,
colNotNull) &&
ArrayUtil
.
areAllIntIndexesInBooleanArray(
indexCols,
usedColumns)) {
return
indexCols;
}
} else if (
constraint.
getConstraintType()
==
SchemaObject.
ConstraintTypes.
PRIMARY_KEY) {
int[]
indexCols =
constraint.
getMainColumns();
if (
ArrayUtil.
areAllIntIndexesInBooleanArray(
indexCols,
usedColumns)) {
return
indexCols;
}
}
}
return null;
}
boolean
areColumnsNotNull(int[]
indexes) {
return
ArrayUtil.
areAllIntIndexesInBooleanArray(
indexes,
colNotNull);
}
/**
* Shortcut for creating default PK's.
*/
public void
createPrimaryKey() {
createPrimaryKey(null,
ValuePool.
emptyIntArray, false);
}
/**
* Creates a single or multi-column primary key and index. sets the
* colTypes array. Finalises the creation of the table. (fredt@users)
*/
public void
createPrimaryKey(
HsqlName indexName, int[]
columns,
boolean
columnsNotNull) {
if (
columns == null) {
columns =
ValuePool.
emptyIntArray;
}
for (int
i = 0;
i <
columns.length;
i++) {
getColumn(
columns[
i]).
setPrimaryKey(true);
}
setColumnStructures();
Type[]
primaryKeyTypes = new
Type[
columns.length];
ArrayUtil.
projectRow(
colTypes,
columns,
primaryKeyTypes);
HsqlName name =
indexName;
if (
name == null) {
name =
database.
nameManager.
newAutoName("IDX",
getSchemaName(),
getName(),
SchemaObject.
INDEX);
}
createPrimaryIndex(
columns,
primaryKeyTypes,
name);
setBestRowIdentifiers();
}
public void
createPrimaryKeyConstraint(
HsqlName indexName, int[]
columns,
boolean
columnsNotNull) {
createPrimaryKey(
indexName,
columns,
columnsNotNull);
Constraint c =
new
Constraint(
indexName, this,
getPrimaryIndex(),
SchemaObject.
ConstraintTypes.
PRIMARY_KEY);
addConstraint(
c);
}
void
setColumnStructures() {
if (
colTypes == null) {
colTypes = new
Type[
columnCount];
}
colDefaults = new
Expression[
columnCount];
colNotNull = new boolean[
columnCount];
emptyColumnCheckList = new boolean[
columnCount];
colGenerated = new boolean[
columnCount];
colUpdated = new boolean[
columnCount];
defaultColumnMap = new int[
columnCount];
for (int
i = 0;
i <
columnCount;
i++) {
setSingleColumnTypeVars(
i);
}
resetDefaultsFlag();
}
void
setColumnTypeVars(int
i) {
setSingleColumnTypeVars(
i);
resetDefaultsFlag();
}
private void
setSingleColumnTypeVars(int
i) {
ColumnSchema column =
getColumn(
i);
Type dataType =
column.
getDataType();
colTypes[
i] =
dataType;
colNotNull[
i] =
column.
isPrimaryKey() || !
column.
isNullable();
defaultColumnMap[
i] =
i;
if (
column.
isIdentity()) {
identitySequence =
column.
getIdentitySequence();
identityColumn =
i;
} else if (
identityColumn ==
i) {
identitySequence = null;
identityColumn = -1;
}
colDefaults[
i] =
column.
getDefaultExpression();
colGenerated[
i] =
column.
isGenerated();
colUpdated[
i] =
column.
isAutoUpdate();
}
/**
* Returns direct mapping array.
*/
int[]
getColumnMap() {
return
defaultColumnMap;
}
/**
* Returns empty mapping array.
*/
int[]
getNewColumnMap() {
return new int[
columnCount];
}
boolean[]
getColumnCheckList(int[]
columnIndexes) {
boolean[]
columnCheckList = new boolean[
columnCount];
for (int
i = 0;
i <
columnIndexes.length;
i++) {
int
index =
columnIndexes[
i];
if (
index > -1) {
columnCheckList[
index] = true;
}
}
return
columnCheckList;
}
int[]
findColumnIndexes(
String[]
list) {
int[]
cols = new int[
list.length];
for (int
i = 0;
i <
cols.length;
i++) {
cols[
i] =
findColumn(
list[
i]);
}
return
cols;
}
int[]
getColumnIndexes(
OrderedHashSet set) {
int[]
cols = new int[
set.
size()];
for (int
i = 0;
i <
cols.length;
i++) {
cols[
i] =
getColumnIndex((
String)
set.
get(
i));
if (
cols[
i] == -1) {
throw
Error.
error(
ErrorCode.
X_42501, (
String)
set.
get(
i));
}
}
return
cols;
}
int[]
getColumnIndexes(
HashMappedList list) {
int[]
cols = new int[
list.
size()];
for (int
i = 0;
i <
cols.length;
i++) {
cols[
i] = ((
Integer)
list.
get(
i)).
intValue();
}
return
cols;
}
/**
* Returns the Column object at the given index
*/
public
ColumnSchema getColumn(int
i) {
return (
ColumnSchema)
columnList.
get(
i);
}
public
OrderedHashSet getColumnNameSet(int[]
columnIndexes) {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0;
i <
columnIndexes.length;
i++) {
set.
add(((
ColumnSchema)
columnList.
get(
i)).
getName());
}
return
set;
}
public
OrderedHashSet getColumnNameSet(boolean[]
columnCheckList) {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0;
i <
columnCheckList.length;
i++) {
if (
columnCheckList[
i]) {
set.
add(
columnList.
get(
i));
}
}
return
set;
}
public void
getColumnNames(boolean[]
columnCheckList,
Set set) {
for (int
i = 0;
i <
columnCheckList.length;
i++) {
if (
columnCheckList[
i]) {
set.
add(((
ColumnSchema)
columnList.
get(
i)).
getName());
}
}
}
public
OrderedHashSet getColumnNameSet() {
OrderedHashSet set = new
OrderedHashSet();
for (int
i = 0;
i <
columnCount;
i++) {
set.
add(((
ColumnSchema)
columnList.
get(
i)).
getName());
}
return
set;
}
/**
* Returns array for a new row with SQL DEFAULT value for each column n
* where exists[n] is false. This provides default values only where
* required and avoids evaluating these values where they will be
* overwritten.
*/
public
Object[]
getNewRowData(
Session session) {
Object[]
data = new
Object[
columnCount];
int
i;
if (
hasDefaultValues) {
for (
i = 0;
i <
columnCount;
i++) {
Expression def =
colDefaults[
i];
if (
def != null) {
data[
i] =
def.
getValue(
session,
colTypes[
i]);
}
}
}
return
data;
}
boolean
hasTrigger(int
trigVecIndex) {
return
triggerLists[
trigVecIndex].length != 0;
}
/**
* Adds a trigger.
*/
void
addTrigger(
TriggerDef td,
HsqlName otherName) {
int
index =
triggerList.length;
if (
otherName != null) {
int
pos =
getTriggerIndex(
otherName.
name);
if (
pos != -1) {
index =
pos + 1;
}
}
triggerList = (
TriggerDef[])
ArrayUtil.
toAdjustedArray(
triggerList,
td,
index, 1);
TriggerDef[]
list =
triggerLists[
td.
triggerType];
index =
list.length;
if (
otherName != null) {
for (int
i = 0;
i <
list.length;
i++) {
TriggerDef trigger =
list[
i];
if (
trigger.
getName().
name.
equals(
otherName.
name)) {
index =
i + 1;
break;
}
}
}
list = (
TriggerDef[])
ArrayUtil.
toAdjustedArray(
list,
td,
index, 1);
triggerLists[
td.
triggerType] =
list;
}
/**
* Returns a trigger.
*/
TriggerDef getTrigger(
String name) {
for (int
i =
triggerList.length - 1;
i >= 0;
i--) {
if (
triggerList[
i].
getName().
name.
equals(
name)) {
return
triggerList[
i];
}
}
return null;
}
public int
getTriggerIndex(
String name) {
for (int
i = 0;
i <
triggerList.length;
i++) {
if (
triggerList[
i].
getName().
name.
equals(
name)) {
return
i;
}
}
return -1;
}
/**
* Drops a trigger.
*/
void
removeTrigger(
TriggerDef trigger) {
TriggerDef td = null;
for (int
i = 0;
i <
triggerList.length;
i++) {
td =
triggerList[
i];
if (
td.
getName().
name.
equals(
trigger.
getName().
name)) {
td.
terminate();
triggerList =
(
TriggerDef[])
ArrayUtil.
toAdjustedArray(
triggerList,
null,
i, -1);
break;
}
}
if (
td == null) {
return;
}
int
index =
td.
triggerType;
// look in each trigger in list
for (int
j = 0;
j <
triggerLists[
index].length;
j++) {
td =
triggerLists[
index][
j];
if (
td.
getName().
name.
equals(
trigger.
getName().
name)) {
triggerLists[
index] = (
TriggerDef[])
ArrayUtil.
toAdjustedArray(
triggerLists[
index], null,
j, -1);
break;
}
}
}
/**
* Used when dropping all triggers.
*/
void
releaseTriggers() {
// look in each trigger list of each type of trigger
for (int
i = 0;
i <
TriggerDef.
NUM_TRIGS;
i++) {
for (int
j = 0;
j <
triggerLists[
i].length;
j++) {
triggerLists[
i][
j].
terminate();
}
triggerLists[
i] =
TriggerDef.
emptyArray;
}
triggerList =
TriggerDef.
emptyArray;
}
void
terminateTriggers() {
// look in each trigger list of each type of trigger
for (int
i = 0;
i <
TriggerDef.
NUM_TRIGS;
i++) {
for (int
j = 0;
j <
triggerLists[
i].length;
j++) {
triggerLists[
i][
j].
terminate();
}
}
}
/**
* Returns the index of the Index object of the given name or -1 if not found.
*/
int
getIndexIndex(
String indexName) {
Index[]
indexes =
indexList;
for (int
i = 0;
i <
indexes.length;
i++) {
if (
indexName.
equals(
indexes[
i].
getName().
name)) {
return
i;
}
}
// no such index
return -1;
}
/**
* Returns the Index object of the given name or null if not found.
*/
Index getIndex(
String indexName) {
Index[]
indexes =
indexList;
int
i =
getIndexIndex(
indexName);
return
i == -1 ? null
:
indexes[
i];
}
/**
* Returns the Index object of the given name or null if not found.
*/
Index getUserIndex(
String indexName) {
Index[]
indexes =
indexList;
for (int
i = 0;
i <
indexes.length;
i++) {
if (
indexName.
equals(
indexes[
i].
getName().
name)) {
if (!
indexes[
i].
isConstraint()) {
return
indexes[
i];
}
}
}
return null;
}
/**
* Returns the Index object of the given name or null if not found.
*/
Index getSystemIndex(
String indexName) {
Index[]
indexes =
indexList;
for (int
i = 0;
i <
indexes.length;
i++) {
if (
indexName.
equals(
indexes[
i].
getName().
name)) {
if (
indexes[
i].
isConstraint()) {
return
indexes[
i];
}
}
}
return null;
}
/**
* Return the position of the constraint within the list
*/
int
getConstraintIndex(
String constraintName) {
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
if (
constraintList[
i].
getName().
name.
equals(
constraintName)) {
return
i;
}
}
return -1;
}
/**
* return the named constraint
*/
public
Constraint getConstraint(
String constraintName) {
int
i =
getConstraintIndex(
constraintName);
return (
i < 0) ? null
:
constraintList[
i];
}
/**
* Returns any unique Constraint using this index
*
* @param index
*/
public
Constraint getUniqueConstraintForIndex(
Index index) {
for (int
i = 0,
size =
constraintList.length;
i <
size;
i++) {
Constraint c =
constraintList[
i];
if (
c.
getMainIndex() ==
index) {
if (
c.
getConstraintType() ==
SchemaObject.
ConstraintTypes
.
PRIMARY_KEY ||
c.
getConstraintType() ==
SchemaObject
.
ConstraintTypes.
UNIQUE) {
return
c;
}
}
}
return null;
}
/**
* remove a named constraint
*/
void
removeConstraint(
String name) {
int
index =
getConstraintIndex(
name);
if (
index != -1) {
removeConstraint(
index);
}
}
void
removeConstraint(int
index) {
constraintList =
(
Constraint[])
ArrayUtil.
toAdjustedArray(
constraintList, null,
index, -1);
updateConstraintLists();
}
void
renameColumn(
ColumnSchema column,
String newName, boolean
isquoted) {
String oldname =
column.
getName().
name;
int
i =
getColumnIndex(
oldname);
columnList.
setKey(
i,
newName);
column.
getName().
rename(
newName,
isquoted);
}
void
renameColumn(
ColumnSchema column,
HsqlName newName) {
String oldname =
column.
getName().
name;
int
i =
getColumnIndex(
oldname);
if (
findColumn(
newName.
name) != -1) {
throw
Error.
error(
ErrorCode.
X_42504);
}
columnList.
setKey(
i,
newName.
name);
column.
getName().
rename(
newName);
}
public
TriggerDef[]
getTriggers() {
return
triggerList;
}
public boolean
isWritable() {
return !
isReadOnly && !
database.
databaseReadOnly
&& !(
database.
isFilesReadOnly() && (
isCached ||
isText));
}
public boolean
isInsertable() {
return
isWritable();
}
public boolean
isUpdatable() {
return
isWritable();
}
public boolean
isTriggerInsertable() {
return false;
}
public boolean
isTriggerUpdatable() {
return false;
}
public boolean
isTriggerDeletable() {
return false;
}
public int[]
getUpdatableColumns() {
return
defaultColumnMap;
}
public
Table getBaseTable() {
return this;
}
public int[]
getBaseTableColumnMap() {
return
defaultColumnMap;
}
/**
* Used to create an index automatically for system and temp tables.
* Used for internal operation tables with null Session param.
*/
Index createIndexForColumns(
Session session, int[]
columns) {
Index index = null;
HsqlName indexName =
database.
nameManager.
newAutoName("IDX_T",
getSchemaName(),
getName(),
SchemaObject.
INDEX);
try {
index =
createAndAddIndexStructure(
session,
indexName,
columns,
null, null, false, false,
false);
} catch (
Throwable t) {
return null;
}
return
index;
}
void
fireTriggers(
Session session, int
trigVecIndex,
RowSetNavigatorDataChange rowSet) {
if (!
database.
isReferentialIntegrity()) {
return;
}
TriggerDef[]
trigVec =
triggerLists[
trigVecIndex];
for (int
i = 0,
size =
trigVec.length;
i <
size;
i++) {
TriggerDef td =
trigVec[
i];
boolean
sqlTrigger =
td instanceof
TriggerDefSQL;
if (
td.
hasOldTable()) {
//
}
td.
pushPair(
session, null, null);
}
}
void
fireTriggers(
Session session, int
trigVecIndex,
RowSetNavigator rowSet) {
if (!
database.
isReferentialIntegrity()) {
return;
}
TriggerDef[]
trigVec =
triggerLists[
trigVecIndex];
for (int
i = 0,
size =
trigVec.length;
i <
size;
i++) {
TriggerDef td =
trigVec[
i];
boolean
sqlTrigger =
td instanceof
TriggerDefSQL;
if (
td.
hasOldTable()) {
//
}
td.
pushPair(
session, null, null);
}
}
/**
* Fires all row-level triggers of the given set (trigger type)
*
*/
void
fireTriggers(
Session session, int
trigVecIndex,
Object[]
oldData,
Object[]
newData, int[]
cols) {
if (!
database.
isReferentialIntegrity()) {
return;
}
TriggerDef[]
trigVec =
triggerLists[
trigVecIndex];
for (int
i = 0,
size =
trigVec.length;
i <
size;
i++) {
TriggerDef td =
trigVec[
i];
boolean
sqlTrigger =
td instanceof
TriggerDefSQL;
if (
cols != null &&
td.
getUpdateColumnIndexes() != null
&& !
ArrayUtil.
haveCommonElement(
td.
getUpdateColumnIndexes(),
cols)) {
continue;
}
if (
td.
isForEachRow()) {
switch (
td.
triggerType) {
case
Trigger.
INSERT_BEFORE_ROW :
break;
case
Trigger.
INSERT_AFTER_ROW :
if (!
sqlTrigger) {
newData =
(
Object[])
ArrayUtil.
duplicateArray(
newData);
}
break;
case
Trigger.
UPDATE_AFTER_ROW :
if (!
sqlTrigger) {
oldData =
(
Object[])
ArrayUtil.
duplicateArray(
oldData);
newData =
(
Object[])
ArrayUtil.
duplicateArray(
newData);
}
break;
case
Trigger.
UPDATE_BEFORE_ROW :
case
Trigger.
DELETE_BEFORE_ROW :
case
Trigger.
DELETE_AFTER_ROW :
if (!
sqlTrigger) {
oldData =
(
Object[])
ArrayUtil.
duplicateArray(
oldData);
}
break;
}
td.
pushPair(
session,
oldData,
newData);
} else {
td.
pushPair(
session, null, null);
}
}
}
/**
* Enforce max field sizes according to SQL column definition.
* SQL92 13.8
*/
public void
enforceRowConstraints(
Session session,
Object[]
data) {
for (int
i = 0;
i <
columnCount;
i++) {
Type type =
colTypes[
i];
ColumnSchema column;
if (
hasDomainColumns &&
type.
isDomainType()) {
Constraint[]
constraints =
type.
userTypeModifier.
getConstraints();
column =
getColumn(
i);
for (int
j = 0;
j <
constraints.length;
j++) {
constraints[
j].
checkCheckConstraint(
session, this,
column,
data[
i]);
}
}
if (
colNotNull[
i] &&
data[
i] == null) {
String constraintName;
Constraint c =
getNotNullConstraintForColumn(
i);
if (
c == null) {
if (
ArrayUtil.
find(
getPrimaryKey(),
i) > -1) {
c =
getPrimaryConstraint();
}
}
constraintName =
c == null ? ""
:
c.
getName().
name;
column =
getColumn(
i);
String[]
info = new
String[] {
constraintName,
tableName.
statementName,
column.
getName().
statementName
};
throw
Error.
error(null,
ErrorCode.
X_23502,
ErrorCode.
COLUMN_CONSTRAINT,
info);
}
}
}
public void
enforceTypeLimits(
Session session,
Object[]
data) {
int
i = 0;
try {
for (;
i <
columnCount;
i++) {
data[
i] =
colTypes[
i].
convertToTypeLimits(
session,
data[
i]);
}
} catch (
HsqlException e) {
int
code =
e.
getErrorCode();
if (
code == -
ErrorCode.
X_22001 ||
code == -
ErrorCode.
X_22003
||
code == -
ErrorCode.
X_22008) {
ColumnSchema column =
getColumn(
i);
String[]
info = new
String[] {
"",
tableName.
statementName,
column.
getName().
statementName
};
throw
Error.
error(
e,
code,
ErrorCode.
COLUMN_CONSTRAINT,
info);
}
throw
e;
}
}
int
indexTypeForColumn(
Session session, int
col) {
int
i =
bestIndexForColumn[
col];
if (
i > -1) {
return
indexList[
i].
isUnique()
&&
indexList[
i].
getColumnCount() == 1 ?
Index.
INDEX_UNIQUE
:
Index
.
INDEX_NON_UNIQUE;
}
switch (
tableType) {
case
TableBase.
TEMP_TABLE :
case
TableBase.
INFO_SCHEMA_TABLE :
case
TableBase.
MODULE_TABLE :
case
TableBase.
FUNCTION_TABLE :
case
TableBase.
SYSTEM_SUBQUERY :
case
TableBase.
VIEW_TABLE : {
return
Index.
INDEX_NON_UNIQUE;
}
}
return
Index.
INDEX_NONE;
}
/**
* Finds an existing index for a column group - for persistent tables
*/
synchronized
Index getIndexForColumns(
Session session, int[]
cols) {
int
i =
bestIndexForColumn[
cols[0]];
if (
i > -1) {
return
indexList[
i];
}
return null;
}
/**
* Finds an existing index for an ordered full column group
*/
Index getFullIndexForColumns(int[]
cols) {
for (int
i = 0;
i <
indexList.length;
i++) {
if (
ArrayUtil.
haveEqualArrays(
indexList[
i].
getColumns(),
cols,
cols.length)) {
return
indexList[
i];
}
}
return null;
}
/**
* Finds an existing index for an unordered full column group
*/
Index getIndexForColumns(int[]
cols) {
for (int
i = 0;
i <
indexList.length;
i++) {
if (
ArrayUtil.
haveEqualSets(
indexList[
i].
getColumns(),
cols,
cols.length)) {
return
indexList[
i];
}
}
return null;
}
/**
* Finds an existing index for a column set or create one for temporary
* tables.
*
* synchronized required for shared INFORMATION_SCHEMA etc. tables
*/
synchronized
IndexUse[]
getIndexForColumns(
Session session,
OrderedIntHashSet set, int
opType, boolean
ordered) {
if (
set.
isEmpty()) {
return
Index.
emptyUseArray;
}
IndexUse[]
indexUse =
findIndexForColumns(
session,
set,
opType,
ordered);
if (
indexUse.length == 0) {
Index selected = null;
// index is not full;
switch (
tableType) {
case
TableBase.
TEMP_TABLE :
case
TableBase.
INFO_SCHEMA_TABLE :
case
TableBase.
MODULE_TABLE :
case
TableBase.
FUNCTION_TABLE :
case
TableBase.
SYSTEM_SUBQUERY :
case
TableBase.
VIEW_TABLE : {
selected =
createIndexForColumns(
session,
set.
toArray());
break;
}
}
if (
selected != null) {
indexUse =
selected.
asArray();
}
}
return
indexUse;
}
IndexUse[]
findIndexForColumns(
Session session,
OrderedIntHashSet set,
int
opType, boolean
ordered) {
IndexUse[]
indexUse =
Index.
emptyUseArray;
if (
set.
isEmpty()) {
return
Index.
emptyUseArray;
}
for (int
i = 0,
count =
indexList.length;
i <
count;
i++) {
Index currentIndex =
getIndex(
i);
int[]
indexcols =
currentIndex.
getColumns();
int
matchCount =
ordered ?
set.
getOrderedStartMatchCount(
indexcols)
:
set.
getStartMatchCount(
indexcols);
if (
matchCount == 0) {
continue;
}
if (
matchCount ==
set.
size()) {
return
currentIndex.
asArray();
}
if (
matchCount ==
currentIndex.
getColumnCount()) {
if (
currentIndex.
isUnique()) {
return
currentIndex.
asArray();
}
}
if (
indexUse.length == 0
&&
matchCount ==
currentIndex.
getColumnCount()) {
indexUse =
currentIndex.
asArray();
} else {
IndexUse[]
newList = new
IndexUse[
indexUse.length + 1];
ArrayUtil.
copyArray(
indexUse,
newList,
indexUse.length);
newList[
newList.length - 1] = new
IndexUse(
currentIndex,
matchCount);
indexUse =
newList;
}
}
return
indexUse;
}
/**
* Returns an index on all the columns
*/
public
Index getFullIndex(
Session session) {
if (
fullIndex == null) {
fullIndex =
getFullIndexForColumns(
defaultColumnMap);
if (
fullIndex == null) {
fullIndex =
createIndexForColumns(
session,
defaultColumnMap);
}
}
return
fullIndex;
}
/**
* Return the list of file pointers to root nodes for this table's
* indexes.
*/
public final long[]
getIndexRootsArray() {
PersistentStore store =
database.
persistentStoreCollection.
getStore(this);
long[]
roots = new long[
indexList.length];
for (int
index = 0;
index <
indexList.length;
index++) {
CachedObject accessor =
store.
getAccessor(
indexList[
index]);
roots[
index] =
accessor == null ? -1
:
accessor.
getPos();
}
return
roots;
}
/**
* Sets the index roots of a cached table to specified file
* pointers. If a
* file pointer is -1 then the particular index root is null. A null index
* root signifies an empty table. Accordingly, all index roots should be
* null or all should be a valid file pointer/reference.
*/
public void
setIndexRoots(long[]
roots, long[]
uniqueSize,
long
cardinality) {
if (!
isCached) {
throw
Error.
error(
ErrorCode.
X_42501,
tableName.
name);
}
PersistentStore store =
database.
persistentStoreCollection.
getStore(this);
for (int
index = 0;
index <
indexList.length;
index++) {
store.
setAccessor(
indexList[
index],
roots[
index]);
}
for (int
index = 0;
index <
indexList.length;
index++) {
store.
setElementCount(
indexList[
index],
cardinality,
uniqueSize[
index]);
}
}
public void
setIndexRoots(long[]
roots) {
if (!
isCached) {
throw
Error.
error(
ErrorCode.
X_42501,
tableName.
name);
}
PersistentStore store =
database.
persistentStoreCollection.
getStore(this);
for (int
index = 0;
index <
indexList.length;
index++) {
store.
setAccessor(
indexList[
index],
roots[
index]);
}
}
/**
* Sets the index roots.
*/
void
setIndexRoots(
Session session,
String s) {
if (!
isCached) {
throw
Error.
error(
ErrorCode.
X_42501,
tableName.
name);
}
int
indexCount =
getIndexCount();
ParserDQL p = new
ParserDQL(
session, new
Scanner(
session,
s), null);
long[]
roots = new long[
indexCount];
long[]
uniqueSize = new long[
indexCount];
long
cardinality = -1;
p.
read();
for (int
index = 0;
index <
indexCount;
index++) {
long
v =
p.
readBigint();
roots[
index] =
v;
}
try {
for (int
index = 0;
index <
indexCount;
index++) {
long
v =
p.
readBigint();
uniqueSize[
index] =
v;
}
cardinality =
p.
readBigint();
} catch (
Exception e) {
// version 1.x database
}
setIndexRoots(
roots,
uniqueSize,
cardinality);
}
void
generateAndCheckData(
Session session,
Object[]
data) {
if (
hasGeneratedValues) {
setGeneratedColumns(
session,
data);
}
enforceTypeLimits(
session,
data);
if (
hasDomainColumns ||
hasNotNullColumns) {
enforceRowConstraints(
session,
data);
}
}
/**
* Mid level method for inserting single rows. Performs constraint checks and
* fires row level triggers.
*/
Row insertSingleRow(
Session session,
PersistentStore store,
Object[]
data,
int[]
changedCols) {
generateAndCheckData(
session,
data);
if (
isView) {
// may have domain column
return null;
}
Row row = (
Row)
store.
getNewCachedObject(
session,
data, true);
session.
addInsertAction(this,
store,
row,
changedCols);
return
row;
}
/**
* Multi-row insert method. Used for CREATE TABLE AS ... queries.
*/
void
insertIntoTable(
Session session,
Result result) {
PersistentStore store =
getRowStore(
session);
RowSetNavigator nav =
result.
initialiseNavigator();
while (
nav.
next()) {
Object[]
data =
nav.
getCurrent();
Object[]
newData =
(
Object[])
ArrayUtil.
resizeArrayIfDifferent(
data,
columnCount);
insertData(
session,
store,
newData);
}
}
/**
*
*/
public void
insertNoCheckFromLog(
Session session,
Object[]
data) {
systemUpdateIdentityValue(
data);
PersistentStore store =
getRowStore(
session);
Row row = (
Row)
store.
getNewCachedObject(
session,
data, true);
session.
addInsertAction(this,
store,
row, null);
}
/**
* Used for system table inserts. No checks. No identity
* columns.
*/
public int
insertSys(
Session session,
PersistentStore store,
Result ins) {
RowSetNavigator nav =
ins.
getNavigator();
int
count = 0;
while (
nav.
next()) {
insertSys(
session,
store,
nav.
getCurrent());
count++;
}
return
count;
}
/**
* Used for subquery inserts. No checks. No identity
* columns.
*/
void
insertResult(
Session session,
PersistentStore store,
Result ins) {
RowSetNavigator nav =
ins.
initialiseNavigator();
while (
nav.
next()) {
Object[]
data =
nav.
getCurrent();
Object[]
newData =
(
Object[])
ArrayUtil.
resizeArrayIfDifferent(
data,
columnCount);
insertData(
session,
store,
newData);
}
}
/**
* Not for general use.
* Used by ScriptReader to unconditionally insert a row into
* the table when the .script file is read.
*/
public void
insertFromScript(
Session session,
PersistentStore store,
Object[]
data) {
systemUpdateIdentityValue(
data);
if (
session.
database.
getProperties().
isVersion18()) {
for (int
i = 0;
i <
columnCount;
i++) {
if (
data[
i] != null) {
int
length;
if (
colTypes[
i].
isCharacterType()
||
colTypes[
i].
isBinaryType()) {
if (
data[
i] instanceof
String) {
length = ((
String)
data[
i]).
length();
} else if (
data[
i] instanceof
BinaryData) {
length =
(int) ((
BinaryData)
data[
i]).
length(
session);
} else {
throw
Error.
runtimeError(
ErrorCode.
X_07000,
"Table");
}
if (
length >
colTypes[
i].
precision) {
length = ((
length / 10) + 1) * 10;
colTypes[
i] =
Type.
getType(
colTypes[
i].
typeCode,
colTypes[
i].
getCharacterSet(),
colTypes[
i].
getCollation(),
length, 0);
ColumnSchema column =
getColumn(
i);
column.
setType(
colTypes[
i]);
}
}
}
}
}
insertData(
session,
store,
data);
}
/**
* For system operations outside transaction control
*/
public void
insertData(
Session session,
PersistentStore store,
Object[]
data) {
Row row = (
Row)
store.
getNewCachedObject(
session,
data, false);
store.
indexRow(
session,
row);
}
/**
* Used by the system tables only
*/
public void
insertSys(
Session session,
PersistentStore store,
Object[]
data) {
Row row = (
Row)
store.
getNewCachedObject(
session,
data, false);
store.
indexRow(
session,
row);
}
/**
* If there is an identity column in the table, sets
* the value and/or adjusts the identity value for the table.
*/
protected void
setIdentityColumn(
Session session,
Object[]
data) {
if (
identityColumn != -1) {
Number id = (
Number)
data[
identityColumn];
if (
identitySequence.
getName() == null) {
if (
id == null) {
id = (
Number)
identitySequence.
getValueObject();
data[
identityColumn] =
id;
} else {
identitySequence.
userUpdate(
id.
longValue());
}
} else {
if (
id == null) {
id = (
Number)
session.
sessionData.
getSequenceValue(
identitySequence);
data[
identityColumn] =
id;
}
}
if (
session != null) {
session.
setLastIdentity(
id);
}
}
}
public void
setGeneratedColumns(
Session session,
Object[]
data) {
if (
hasGeneratedValues) {
for (int
i = 0;
i <
colGenerated.length;
i++) {
if (
colGenerated[
i]) {
Expression e =
getColumn(
i).
getGeneratingExpression();
RangeIterator range =
session.
sessionContext.
getCheckIterator(
getDefaultRanges()[0]);
range.
setCurrent(
data);
data[
i] =
e.
getValue(
session,
colTypes[
i]);
}
}
}
}
public void
setUpdatedColumns(
Session session,
Object[]
data) {
if (
hasUpdatedValues) {
for (int
i = 0;
i <
colUpdated.length;
i++) {
if (
colUpdated[
i]) {
Expression e =
getColumn(
i).
getUpdateExpression();
data[
i] =
e.
getValue(
session,
colTypes[
i]);
}
}
}
}
public void
systemSetIdentityColumn(
Session session,
Object[]
data) {
if (
identityColumn != -1) {
Number id = (
Number)
data[
identityColumn];
if (
id == null) {
id = (
Number)
identitySequence.
getValueObject();
data[
identityColumn] =
id;
} else {
identitySequence.
userUpdate(
id.
longValue());
}
}
}
/**
* If there is an identity column in the table, sets
* the max identity value.
*/
public void
systemUpdateIdentityValue(
Object[]
data) {
if (
identityColumn != -1) {
Number id = (
Number)
data[
identityColumn];
if (
id != null) {
identitySequence.
systemUpdate(
id.
longValue());
}
}
}
/**
* For log statements. Find a single row to delete.
*/
public
Row getDeleteRowFromLog(
Session session,
Object[]
data) {
Row row = null;
PersistentStore store =
getRowStore(
session);
if (
hasPrimaryKey()) {
Index index =
getPrimaryIndex();
int[]
colsSequence =
index.
getDefaultColumnMap();
RowIterator it =
index.
findFirstRow(
session,
store,
data,
colsSequence);
it.
next();
row =
it.
getCurrentRow();
it.
release();
} else if (
bestIndex == null) {
RowIterator it =
rowIterator(
session);
while (
it.
next()) {
row =
it.
getCurrentRow();
if (
Table.
compareRows(
session,
row.
getData(),
data,
defaultColumnMap,
colTypes) == 0) {
break;
}
}
it.
release();
} else {
RowIterator it =
bestIndex.
findFirstRow(
session,
store,
data);
while (
it.
next()) {
row =
it.
getCurrentRow();
Object[]
rowdata =
row.
getData();
// reached end of range
if (
bestIndex.
compareRowNonUnique(
session,
rowdata,
data,
bestIndex.
getColumns()) != 0) {
row = null;
break;
}
if (
Table.
compareRows(
session,
rowdata,
data,
defaultColumnMap,
colTypes) == 0) {
break;
}
}
it.
release();
}
return
row;
}
public
RowIterator rowIteratorClustered(
Session session) {
PersistentStore store =
getRowStore(
session);
Index index =
getClusteredIndex();
if (
index == null) {
index =
getPrimaryIndex();
}
return
index.
firstRow(
session,
store, 0, null);
}
public
RowIterator rowIteratorClustered(
PersistentStore store) {
Index index =
getClusteredIndex();
if (
index == null) {
index =
getPrimaryIndex();
}
return
index.
firstRow(
store);
}
/**
* Path used for all stores
*/
public
PersistentStore getRowStore(
Session session) {
if (
store != null) {
return
store;
}
if (
isSessionBased) {
return
session.
sessionData.
persistentStoreCollection.
getStore(
this);
}
return
database.
persistentStoreCollection.
getStore(this);
}
public
QueryExpression getQueryExpression() {
return null;
}
public
Expression getDataExpression() {
return null;
}
public void
prepareTable(
Session session) {}
public void
materialise(
Session session) {}
public void
materialiseCorrelated(
Session session) {}
}