use of org.apache.derby.iapi.sql.dictionary.ColumnDescriptor in project derby by apache.
the class ConsistencyChecker method checkTable.
/**
* Check the named table, ensuring that all of its indexes are consistent
* with the base table.
* Use this
* method only within an SQL-J statement; do not call it directly.
* <P>When tables are consistent, the method returns true. Otherwise, the method throws an exception.
* <p>To check the consistency of a single table:
* <p><code>
* VALUES ConsistencyChecker::checkTable(<i>SchemaName</i>, <i>TableName</i>)</code></p>
* <P>For example, to check the consistency of the table <i>APP.Flights</i>:
* <p><code>
* VALUES ConsistencyChecker::checkTable('APP', 'FLIGHTS')</code></p>
* <p>To check the consistency of all of the tables in the 'APP' schema,
* stopping at the first failure:
*
* <P><code>SELECT tablename, ConsistencyChecker::checkTable(<br>
* 'APP', tablename)<br>
* FROM sys.sysschemas s, sys.systables t
* WHERE s.schemaname = 'APP' AND s.schemaid = t.schemaid</code>
*
* <p> To check the consistency of an entire database, stopping at the first failure:
*
* <p><code>SELECT schemaname, tablename,<br>
* ConsistencyChecker::checkTable(schemaname, tablename)<br>
* FROM sys.sysschemas s, sys.systables t<br>
* WHERE s.schemaid = t.schemaid</code>
*
* @param schemaName The schema name of the table.
* @param tableName The name of the table
*
* @return true, if the table is consistent, exception thrown if inconsistent
*
* @exception SQLException Thrown if some inconsistency
* is found, or if some unexpected
* exception is thrown..
*/
public static boolean checkTable(String schemaName, String tableName) throws SQLException {
DataDictionary dd;
TableDescriptor td;
long baseRowCount = -1;
TransactionController tc;
ConglomerateDescriptor heapCD;
ConglomerateDescriptor indexCD;
ExecRow baseRow;
ExecRow indexRow;
RowLocation rl = null;
RowLocation scanRL = null;
ScanController scan = null;
int[] baseColumnPositions;
int baseColumns = 0;
DataValueFactory dvf;
long indexRows;
ConglomerateController baseCC = null;
ConglomerateController indexCC = null;
SchemaDescriptor sd;
ConstraintDescriptor constraintDesc;
LanguageConnectionContext lcc = ConnectionUtil.getCurrentLCC();
tc = lcc.getTransactionExecute();
try {
// make sure that application code doesn't bypass security checks
// by calling this public entry point
SecurityUtil.authorize(Securable.CHECK_TABLE);
dd = lcc.getDataDictionary();
dvf = lcc.getDataValueFactory();
ExecutionFactory ef = lcc.getLanguageConnectionFactory().getExecutionFactory();
sd = dd.getSchemaDescriptor(schemaName, tc, true);
td = dd.getTableDescriptor(tableName, sd, tc);
if (td == null) {
throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, schemaName + "." + tableName);
}
/* Skip views */
if (td.getTableType() == TableDescriptor.VIEW_TYPE) {
return true;
}
/* Open the heap for reading */
baseCC = tc.openConglomerate(td.getHeapConglomerateId(), false, 0, TransactionController.MODE_TABLE, TransactionController.ISOLATION_SERIALIZABLE);
/* Check the consistency of the heap */
baseCC.checkConsistency();
heapCD = td.getConglomerateDescriptor(td.getHeapConglomerateId());
/* Get a row template for the base table */
baseRow = ef.getValueRow(td.getNumberOfColumns());
/* Fill the row with nulls of the correct type */
ColumnDescriptorList cdl = td.getColumnDescriptorList();
int cdlSize = cdl.size();
for (int index = 0; index < cdlSize; index++) {
ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index);
baseRow.setColumn(cd.getPosition(), cd.getType().getNull());
}
/* Look at all the indexes on the table */
ConglomerateDescriptor[] cds = td.getConglomerateDescriptors();
for (int index = 0; index < cds.length; index++) {
indexCD = cds[index];
/* Skip the heap */
if (!indexCD.isIndex())
continue;
/* Check the internal consistency of the index */
indexCC = tc.openConglomerate(indexCD.getConglomerateNumber(), false, 0, TransactionController.MODE_TABLE, TransactionController.ISOLATION_SERIALIZABLE);
indexCC.checkConsistency();
indexCC.close();
indexCC = null;
if (indexCD.isConstraint()) {
constraintDesc = dd.getConstraintDescriptor(td, indexCD.getUUID());
if (constraintDesc == null) {
throw StandardException.newException(SQLState.LANG_OBJECT_NOT_FOUND, "CONSTRAINT for INDEX", indexCD.getConglomerateName());
}
}
/*
** Set the base row count when we get to the first index.
** We do this here, rather than outside the index loop, so
** we won't do the work of counting the rows in the base table
** if there are no indexes to check.
*/
if (baseRowCount < 0) {
scan = tc.openScan(heapCD.getConglomerateNumber(), // hold
false, // not forUpdate
0, TransactionController.MODE_TABLE, TransactionController.ISOLATION_SERIALIZABLE, RowUtil.EMPTY_ROW_BITSET, // startKeyValue
null, // not used with null start posn.
0, // qualifier
null, // stopKeyValue
null, // not used with null stop posn.
0);
/* Also, get the row location template for index rows */
rl = scan.newRowLocationTemplate();
scanRL = scan.newRowLocationTemplate();
for (baseRowCount = 0; scan.next(); baseRowCount++) ;
/* Empty statement */
scan.close();
scan = null;
}
baseColumnPositions = indexCD.getIndexDescriptor().baseColumnPositions();
baseColumns = baseColumnPositions.length;
FormatableBitSet indexColsBitSet = new FormatableBitSet();
for (int i = 0; i < baseColumns; i++) {
indexColsBitSet.grow(baseColumnPositions[i]);
indexColsBitSet.set(baseColumnPositions[i] - 1);
}
/* Get one row template for the index scan, and one for the fetch */
indexRow = ef.getValueRow(baseColumns + 1);
/* Fill the row with nulls of the correct type */
for (int column = 0; column < baseColumns; column++) {
/* Column positions in the data dictionary are one-based */
ColumnDescriptor cd = td.getColumnDescriptor(baseColumnPositions[column]);
indexRow.setColumn(column + 1, cd.getType().getNull());
}
/* Set the row location in the last column of the index row */
indexRow.setColumn(baseColumns + 1, rl);
/* Do a full scan of the index */
scan = tc.openScan(indexCD.getConglomerateNumber(), // hold
false, // not forUpdate
0, TransactionController.MODE_TABLE, TransactionController.ISOLATION_SERIALIZABLE, (FormatableBitSet) null, // startKeyValue
null, // not used with null start posn.
0, // qualifier
null, // stopKeyValue
null, // not used with null stop posn.
0);
DataValueDescriptor[] baseRowIndexOrder = new DataValueDescriptor[baseColumns];
DataValueDescriptor[] baseObjectArray = baseRow.getRowArray();
for (int i = 0; i < baseColumns; i++) {
baseRowIndexOrder[i] = baseObjectArray[baseColumnPositions[i] - 1];
}
/* Get the index rows and count them */
for (indexRows = 0; scan.fetchNext(indexRow.getRowArray()); indexRows++) {
/*
** Get the base row using the RowLocation in the index row,
** which is in the last column.
*/
RowLocation baseRL = (RowLocation) indexRow.getColumn(baseColumns + 1);
boolean base_row_exists = baseCC.fetch(baseRL, baseObjectArray, indexColsBitSet);
/* Throw exception if fetch() returns false */
if (!base_row_exists) {
String indexName = indexCD.getConglomerateName();
throw StandardException.newException(SQLState.LANG_INCONSISTENT_ROW_LOCATION, (schemaName + "." + tableName), indexName, baseRL.toString(), indexRow.toString());
}
/* Compare all the column values */
for (int column = 0; column < baseColumns; column++) {
DataValueDescriptor indexColumn = indexRow.getColumn(column + 1);
DataValueDescriptor baseColumn = baseRowIndexOrder[column];
/*
** With this form of compare(), null is considered equal
** to null.
*/
if (indexColumn.compare(baseColumn) != 0) {
ColumnDescriptor cd = td.getColumnDescriptor(baseColumnPositions[column]);
throw StandardException.newException(SQLState.LANG_INDEX_COLUMN_NOT_EQUAL, indexCD.getConglomerateName(), td.getSchemaName(), td.getName(), baseRL.toString(), cd.getColumnName(), indexColumn.toString(), baseColumn.toString(), indexRow.toString());
}
}
}
/* Clean up after the index scan */
scan.close();
scan = null;
/*
** The index is supposed to have the same number of rows as the
** base conglomerate.
*/
if (indexRows != baseRowCount) {
throw StandardException.newException(SQLState.LANG_INDEX_ROW_COUNT_MISMATCH, indexCD.getConglomerateName(), td.getSchemaName(), td.getName(), Long.toString(indexRows), Long.toString(baseRowCount));
}
}
/* check that all constraints have backing index */
ConstraintDescriptorList constraintDescList = dd.getConstraintDescriptors(td);
for (int index = 0; index < constraintDescList.size(); index++) {
constraintDesc = constraintDescList.elementAt(index);
if (constraintDesc.hasBackingIndex()) {
ConglomerateDescriptor conglomDesc;
conglomDesc = td.getConglomerateDescriptor(constraintDesc.getConglomerateId());
if (conglomDesc == null) {
throw StandardException.newException(SQLState.LANG_OBJECT_NOT_FOUND, "INDEX for CONSTRAINT", constraintDesc.getConstraintName());
}
}
}
} catch (StandardException se) {
throw PublicAPI.wrapStandardException(se);
} finally {
try {
/* Clean up before we leave */
if (baseCC != null) {
baseCC.close();
baseCC = null;
}
if (indexCC != null) {
indexCC.close();
indexCC = null;
}
if (scan != null) {
scan.close();
scan = null;
}
} catch (StandardException se) {
throw PublicAPI.wrapStandardException(se);
}
}
return true;
}
use of org.apache.derby.iapi.sql.dictionary.ColumnDescriptor in project derby by apache.
the class DataDictionaryImpl method computeAutoincRowLocations.
/**
* @see DataDictionary#computeAutoincRowLocations
*/
public RowLocation[] computeAutoincRowLocations(TransactionController tc, TableDescriptor td) throws StandardException {
int size;
if (!(td.tableHasAutoincrement()))
return null;
size = td.getNumberOfColumns();
RowLocation[] rla = new RowLocation[size];
for (int i = 0; i < size; i++) {
ColumnDescriptor cd = td.getColumnDescriptor(i + 1);
if (cd.isAutoincrement())
rla[i] = computeRowLocation(tc, td, cd.getColumnName());
}
return rla;
}
use of org.apache.derby.iapi.sql.dictionary.ColumnDescriptor in project derby by apache.
the class DataDictionaryImpl method upgrade_addColumns.
/**
* Upgrade an existing catalog by adding columns.
*
* @param rowFactory Associated with this catalog.
* @param newColumnIDs Array of 1-based column ids.
* @param tc Transaction controller
*
* @exception StandardException Standard Derby error policy
*/
public void upgrade_addColumns(CatalogRowFactory rowFactory, int[] newColumnIDs, TransactionController tc) throws StandardException {
int columnID;
SystemColumn currentColumn;
SystemColumn[] columns = rowFactory.buildColumnList();
ExecRow templateRow = rowFactory.makeEmptyRowForCurrentVersion();
int columnCount = newColumnIDs.length;
SchemaDescriptor sd = getSystemSchemaDescriptor();
TableDescriptor td;
long conglomID;
// table/column descriptor until after we add and populate the new column.
if (rowFactory instanceof SYSTABLESRowFactory) {
td = dataDescriptorGenerator.newTableDescriptor("SYSTABLES", sd, TableDescriptor.BASE_TABLE_TYPE, TableDescriptor.ROW_LOCK_GRANULARITY);
td.setUUID(getUUIDForCoreTable("SYSTABLES", sd.getUUID().toString(), tc));
conglomID = coreInfo[SYSTABLES_CORE_NUM].getHeapConglomerate();
} else if (rowFactory instanceof SYSCOLUMNSRowFactory) {
td = dataDescriptorGenerator.newTableDescriptor("SYSCOLUMNS", sd, TableDescriptor.BASE_TABLE_TYPE, TableDescriptor.ROW_LOCK_GRANULARITY);
td.setUUID(getUUIDForCoreTable("SYSCOLUMNS", sd.getUUID().toString(), tc));
conglomID = coreInfo[SYSCOLUMNS_CORE_NUM].getHeapConglomerate();
} else {
td = getTableDescriptor(rowFactory.getCatalogName(), sd, tc);
conglomID = td.getHeapConglomerateId();
}
widenConglomerate(templateRow, newColumnIDs, conglomID, tc);
ColumnDescriptor[] cdArray = new ColumnDescriptor[columnCount];
for (int ix = 0; ix < columnCount; ix++) {
columnID = newColumnIDs[ix];
// from 1 to 0 based
currentColumn = columns[columnID - 1];
cdArray[ix] = makeColumnDescriptor(currentColumn, columnID, td);
}
addDescriptorArray(cdArray, td, SYSCOLUMNS_CATALOG_NUM, false, tc);
}
use of org.apache.derby.iapi.sql.dictionary.ColumnDescriptor in project derby by apache.
the class DataDictionaryImpl method examineTriggerNodeAndCols.
/**
* Get the trigger action string associated with the trigger after the
* references to old/new transition tables/variables in trigger action
* sql provided by CREATE TRIGGER have been transformed eg
* DELETE FROM t WHERE c = old.c
* turns into
* DELETE FROM t WHERE c = org.apache.derby.iapi.db.Factory::
* getTriggerExecutionContext().getOldRow().
* getInt(columnNumberFor'C'inRuntimeResultset)
* or
* DELETE FROM t WHERE c in (SELECT c FROM OLD)
* turns into
* DELETE FROM t WHERE c in
* (SELECT c FROM new TriggerOldTransitionTable OLD)
*
* @param actionStmt This is needed to get access to the various nodes
* generated by the Parser for the trigger action sql. These nodes will be
* used to find REFERENCEs column nodes.
*
* @param oldReferencingName The name specified by the user for REFERENCEs
* to old row columns
*
* @param newReferencingName The name specified by the user for REFERENCEs
* to new row columns
*
* @param triggerDefinition The original trigger action text provided by
* the user during CREATE TRIGGER time.
*
* @param referencedCols Trigger is defined on these columns (will be null
* in case of INSERT AND DELETE Triggers. Can also be null for DELETE
* Triggers if UPDATE trigger is not defined on specific column(s))
*
* @param referencedColsInTriggerAction what columns does the trigger
* action reference through old/new transition variables (may be null)
*
* @param actionOffset offset of start of action clause
*
* @param triggerTableDescriptor Table descriptor for trigger table
*
* @param triggerEventMask TriggerDescriptor.TRIGGER_EVENT_XXX
*
* @param createTriggerTime True if here for CREATE TRIGGER,
* false if here because an invalidated row level trigger with
* REFERENCEd columns has been fired and hence trigger action
* sql associated with SPSDescriptor may be invalid too.
*
* @return Transformed trigger action sql
* @throws StandardException
*/
public int[] examineTriggerNodeAndCols(Visitable actionStmt, String oldReferencingName, String newReferencingName, String triggerDefinition, int[] referencedCols, int[] referencedColsInTriggerAction, int actionOffset, TableDescriptor triggerTableDescriptor, int triggerEventMask, boolean createTriggerTime, List<int[]> replacements) throws StandardException {
// If we are dealing with database created in 10.8 and prior,
// then we must be in soft upgrade mode. For such databases,
// we want to generate trigger action sql which assumes that
// all columns are getting read from the trigger table. We
// need to do this to maintain backward compatibility.
boolean in10_9_orHigherVersion = checkVersion(DataDictionary.DD_VERSION_DERBY_10_9, null);
StringBuilder newText = new StringBuilder();
int start = 0;
// Total Number of columns in the trigger table
int numberOfColsInTriggerTable = triggerTableDescriptor.getNumberOfColumns();
// The purpose of following array(triggerColsAndTriggerActionCols)
// is to identify all the trigger columns and all the columns from
// the trigger action which are referenced though old/new
// transition variables(in other words, accessed through the
// REFERENCING clause section of CREATE TRIGGER sql). This array
// will be initialized to -1 at the beginning. By the end of this
// method, all the columns referenced by the trigger action
// through the REFERENCING clause and all the trigger columns will
// have their column positions in the trigger table noted in this
// array.
// eg
// CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1
// REFERENCING OLD AS oldt NEW AS newt
// FOR EACH ROW UPDATE table2 SET c24=oldt.c14;
// For the trigger above, triggerColsAndTriggerActionCols will
// finally have [-1,2,-1,4,-1] This list will include all the
// columns that need to be fetched into memory during trigger
// execution. All the columns with their entries marked -1 will
// not be read into memory because they are not referenced in the
// trigger action through old/new transition variables and they are
// not recognized as trigger columns.
int[] triggerColsAndTriggerActionCols = new int[numberOfColsInTriggerTable];
/**
* It identifies all the trigger action columns and is initialized to -1.
*/
int[] triggerActionColsOnly = new int[numberOfColsInTriggerTable];
java.util.Arrays.fill(triggerActionColsOnly, -1);
if (referencedCols == null) {
// FOR EACH ROW UPDATE table2 SET c24=oldt.c14;
for (int i = 0; i < numberOfColsInTriggerTable; i++) {
triggerColsAndTriggerActionCols[i] = i + 1;
}
} else {
// This means that this row level trigger is an UPDATE trigger
// defined on specific column(s).
java.util.Arrays.fill(triggerColsAndTriggerActionCols, -1);
for (int i = 0; i < referencedCols.length; i++) {
// Make a note of this trigger column's column position in
// triggerColsAndTriggerActionCols. This will tell us that
// this column needs to be read in when the trigger fires.
// eg for the CREATE TRIGGER below, we will make a note of
// column c12's position in triggerColsAndTriggerActionCols
// eg
// CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1
// REFERENCING OLD AS oldt NEW AS newt
// FOR EACH ROW UPDATE table2 SET c24=oldt.c14;
triggerColsAndTriggerActionCols[referencedCols[i] - 1] = referencedCols[i];
}
}
if (referencedColsInTriggerAction != null) {
for (int i = 0; i < referencedColsInTriggerAction.length; i++) {
if (referencedColsInTriggerAction[i] > 0)
triggerColsAndTriggerActionCols[referencedColsInTriggerAction[i] - 1] = referencedColsInTriggerAction[i];
}
}
/* we need to sort on position in string, beetle 4324
*/
SortedSet<ColumnReference> refs = getTransitionVariables(actionStmt, oldReferencingName, newReferencingName);
if (createTriggerTime) {
// usage of trigger action columns again in 10.9
for (ColumnReference ref : refs) {
TableName tableName = ref.getQualifiedTableName();
checkInvalidTriggerReference(tableName.getTableName(), oldReferencingName, newReferencingName, triggerEventMask);
String colName = ref.getColumnName();
ColumnDescriptor triggerColDesc;
// FOR EACH ROW UPDATE table2 SET c24=oldt.c14567;
if ((triggerColDesc = triggerTableDescriptor.getColumnDescriptor(colName)) == null) {
throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND, tableName + "." + colName);
}
if (in10_9_orHigherVersion) {
int triggerColDescPosition = triggerColDesc.getPosition();
triggerColsAndTriggerActionCols[triggerColDescPosition - 1] = triggerColDescPosition;
triggerActionColsOnly[triggerColDescPosition - 1] = triggerColDescPosition;
referencedColsInTriggerAction[triggerColDescPosition - 1] = triggerColDescPosition;
}
}
} else {
// REFERENCING clause. DERBY-4887
if (referencedCols != null && referencedColsInTriggerAction != null) {
for (int i = 0; i < referencedColsInTriggerAction.length; i++) {
triggerColsAndTriggerActionCols[referencedColsInTriggerAction[i] - 1] = referencedColsInTriggerAction[i];
}
}
}
Arrays.sort(triggerColsAndTriggerActionCols);
// Now that we know what columns we need for trigger columns and
// trigger action columns, we can get rid of remaining -1 entries
// for the remaining columns from trigger table.
// eg
// CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1
// REFERENCING OLD AS oldt NEW AS newt
// FOR EACH ROW UPDATE table2 SET c24=oldt.c14;
// For the above trigger, before the justTheRequiredColumns() call,
// the content of triggerColsAndTriggerActionCols array were as
// follows [-1, 2, -1, 4, -1]
// After the justTheRequiredColumns() call below,
// triggerColsAndTriggerActionCols will have [2,4]. What this means
// that, at run time, during trigger execution, these are the only
// 2 column positions that will be read into memory from the
// trigger table. The columns in other column positions are not
// needed for trigger execution.
triggerColsAndTriggerActionCols = justTheRequiredColumns(triggerColsAndTriggerActionCols, triggerTableDescriptor);
return triggerColsAndTriggerActionCols;
}
use of org.apache.derby.iapi.sql.dictionary.ColumnDescriptor in project derby by apache.
the class DataDictionaryImpl method addSystemTableToDictionary.
/**
* Add the required entries to the data dictionary for a System table.
*/
private void addSystemTableToDictionary(TabInfoImpl ti, SchemaDescriptor sd, TransactionController tc, DataDescriptorGenerator ddg) throws StandardException {
CatalogRowFactory crf = ti.getCatalogRowFactory();
String name = ti.getTableName();
long conglomId = ti.getHeapConglomerate();
SystemColumn[] columnList = crf.buildColumnList();
UUID heapUUID = crf.getCanonicalHeapUUID();
String heapName = crf.getCanonicalHeapName();
TableDescriptor td;
UUID toid;
int columnCount;
SystemColumn column;
// add table to the data dictionary
columnCount = columnList.length;
td = ddg.newTableDescriptor(name, sd, TableDescriptor.SYSTEM_TABLE_TYPE, TableDescriptor.ROW_LOCK_GRANULARITY);
td.setUUID(crf.getCanonicalTableUUID());
addDescriptor(td, sd, SYSTABLES_CATALOG_NUM, false, tc);
toid = td.getUUID();
/* Add the conglomerate for the heap */
ConglomerateDescriptor cgd = ddg.newConglomerateDescriptor(conglomId, heapName, false, null, false, heapUUID, toid, sd.getUUID());
addDescriptor(cgd, sd, SYSCONGLOMERATES_CATALOG_NUM, false, tc);
/* Create the columns */
ColumnDescriptor[] cdlArray = new ColumnDescriptor[columnCount];
for (int columnNumber = 0; columnNumber < columnCount; columnNumber++) {
column = columnList[columnNumber];
if (SanityManager.DEBUG) {
if (column == null) {
SanityManager.THROWASSERT("column " + columnNumber + " for table " + ti.getTableName() + " is null");
}
}
cdlArray[columnNumber] = makeColumnDescriptor(column, columnNumber + 1, td);
}
addDescriptorArray(cdlArray, td, SYSCOLUMNS_CATALOG_NUM, false, tc);
// now add the columns to the cdl of the table.
ColumnDescriptorList cdl = td.getColumnDescriptorList();
for (int i = 0; i < columnCount; i++) cdl.add(cdlArray[i]);
}
Aggregations