use of org.apache.derby.iapi.sql.dictionary.TableDescriptor in project derby by apache.
the class SystemProcedures method SYSCS_INPLACE_COMPRESS_TABLE.
/**
* Implementation of SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE().
* <p>
* Code which implements the following system procedure:
*
* void SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE(
* IN SCHEMANAME VARCHAR(128),
* IN TABLENAME VARCHAR(128),
* IN PURGE_ROWS SMALLINT,
* IN DEFRAGMENT_ROWS SMALLINT,
* IN TRUNCATE_END SMALLINT)
* <p>
* Use the SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE system procedure to reclaim
* unused, allocated space in a table and its indexes. Typically, unused allocated
* space exists when a large amount of data is deleted from a table, and there
* have not been subsequent inserts to use the space freed by the deletes.
* By default, Derby does not return unused space to the operating system. For
* example, once a page has been allocated to a table or index, it is not
* automatically returned to the operating system until the table or index is
* destroyed. SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE allows you to return unused
* space to the operating system.
* <p>
* This system procedure can be used to force 3 levels of in place compression
* of a SQL table: PURGE_ROWS, DEFRAGMENT_ROWS, TRUNCATE_END. Unlike
* SYSCS_UTIL.SYSCS_COMPRESS_TABLE() all work is done in place in the existing
* table/index.
* <p>
* Syntax:
* SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE(
* IN SCHEMANAME VARCHAR(128),
* IN TABLENAME VARCHAR(128),
* IN PURGE_ROWS SMALLINT,
* IN DEFRAGMENT_ROWS SMALLINT,
* IN TRUNCATE_END SMALLINT)
* <p>
* SCHEMANAME:
* An input argument of type VARCHAR(128) that specifies the schema of the table. Passing a null will result in an error.
* <p>
* TABLENAME:
* An input argument of type VARCHAR(128) that specifies the table name of the
* table. The string must exactly match the case of the table name, and the
* argument of "Fred" will be passed to SQL as the delimited identifier 'Fred'.
* Passing a null will result in an error.
* <p>
* PURGE_ROWS:
* If PURGE_ROWS is set to non-zero then a single pass is made through the table
* which will purge committed deleted rows from the table. This space is then
* available for future inserted rows, but remains allocated to the table.
* As this option scans every page of the table, it's performance is linearly
* related to the size of the table.
* <p>
* DEFRAGMENT_ROWS:
* If DEFRAGMENT_ROWS is set to non-zero then a single defragment pass is made
* which will move existing rows from the end of the table towards the front
* of the table. The goal of the defragment run is to empty a set of pages
* at the end of the table which can then be returned to the OS by the
* TRUNCATE_END option. It is recommended to only run DEFRAGMENT_ROWS, if also
* specifying the TRUNCATE_END option. This option scans the whole table and
* needs to update index entries for every base table row move, and thus execution
* time is linearly related to the size of the table.
* <p>
* TRUNCATE_END:
* If TRUNCATE_END is set to non-zero then all contiguous pages at the end of
* the table will be returned to the OS. Running the PURGE_ROWS and/or
* DEFRAGMENT_ROWS passes options may increase the number of pages affected.
* This option itself does no scans of the table, so performs on the order of a
* few system calls.
* <p>
* SQL example:
* To compress a table called CUSTOMER in a schema called US, using all
* available compress options:
* call SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE('US', 'CUSTOMER', 1, 1, 1);
*
* To quickly just return the empty free space at the end of the same table,
* this option will run much quicker than running all phases but will likely
* return much less space:
* call SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE('US', 'CUSTOMER', 0, 0, 1);
*
* Java example:
* To compress a table called CUSTOMER in a schema called US, using all
* available compress options:
*
* CallableStatement cs = conn.prepareCall
* ("CALL SYSCS_UTIL.SYSCS_COMPRESS_TABLE(?, ?, ?, ?, ?)");
* cs.setString(1, "US");
* cs.setString(2, "CUSTOMER");
* cs.setShort(3, (short) 1);
* cs.setShort(4, (short) 1);
* cs.setShort(5, (short) 1);
* cs.execute();
*
* To quickly just return the empty free space at the end of the same table,
* this option will run much quicker than running all phases but will likely
* return much less space:
*
* CallableStatement cs = conn.prepareCall
* ("CALL SYSCS_UTIL.SYSCS_COMPRESS_TABLE(?, ?, ?, ?, ?)");
* cs.setString(1, "US");
* cs.setString(2, "CUSTOMER");
* cs.setShort(3, (short) 0);
* cs.setShort(4, (short) 0);
* cs.setShort(5, (short) 1);
* cs.execute();
*
* <p>
* It is recommended that the SYSCS_UTIL.SYSCS_COMPRESS_TABLE procedure is
* issued in auto-commit mode.
* Note: This procedure acquires an exclusive table lock on the table being compressed. All statement plans dependent on the table or its indexes are invalidated. For information on identifying unused space, see the Derby Server and Administration Guide.
*
* TODO LIST:
* o defragment requires table level lock in nested user transaction, which
* will conflict with user lock on same table in user transaction.
*/
public static void SYSCS_INPLACE_COMPRESS_TABLE(String schema, String tablename, short purgeRows, short defragmentRows, short truncateEnd) throws SQLException {
// Inplace compress let's the user call compress on VTI but it
// is really a no-op. In order to avoid having to go throught
// the ALTER TABLE code just for a no-op, we simply do the check
// here and return if we are dealing with VTI.
LanguageConnectionContext lcc = ConnectionUtil.getCurrentLCC();
TransactionController tc = lcc.getTransactionExecute();
try {
DataDictionary data_dictionary = lcc.getDataDictionary();
SchemaDescriptor sd = data_dictionary.getSchemaDescriptor(schema, tc, true);
TableDescriptor td = data_dictionary.getTableDescriptor(tablename, sd, tc);
if (td != null && td.getTableType() == TableDescriptor.VTI_TYPE) {
return;
}
} catch (StandardException se) {
throw PublicAPI.wrapStandardException(se);
}
// Send all the other inplace compress requests to ALTER TABLE
// machinery
String escapedSchema = IdUtil.normalToDelimited(schema);
String escapedTableName = IdUtil.normalToDelimited(tablename);
String query = "alter table " + escapedSchema + "." + escapedTableName + " compress inplace" + (purgeRows != 0 ? " purge" : "") + (defragmentRows != 0 ? " defragment" : "") + (truncateEnd != 0 ? " truncate_end" : "");
Connection conn = getDefaultConn();
PreparedStatement ps = conn.prepareStatement(query);
ps.executeUpdate();
ps.close();
conn.close();
}
use of org.apache.derby.iapi.sql.dictionary.TableDescriptor in project derby by apache.
the class ConglomInfo method getConglomInfo.
private void getConglomInfo(LanguageConnectionContext lcc) throws StandardException {
DataDictionary dd = lcc.getDataDictionary();
if (schemaName == null) {
schemaName = lcc.getCurrentSchemaName();
}
ConglomerateDescriptor[] cds;
if (tableName != null) {
// if schemaName is null, it gets the default schema
SchemaDescriptor sd = dd.getSchemaDescriptor(schemaName, tc, true);
TableDescriptor td = dd.getTableDescriptor(tableName, sd, tc);
if (// table does not exist
td == null) {
// make empty conglom table
conglomTable = new ConglomInfo[0];
return;
}
cds = td.getConglomerateDescriptors();
} else // 0-arg constructor, no table name, get all conglomerates
{
cds = dd.getConglomerateDescriptors(null);
}
// initialize spaceTable
conglomTable = new ConglomInfo[cds.length];
for (int i = 0; i < cds.length; i++) {
String conglomerateName;
if (cds[i].isIndex()) {
conglomerateName = cds[i].getConglomerateName();
} else if (tableName != null) {
conglomerateName = tableName;
} else {
// 0-arg constructor. need to ask data dictionary for name of table
conglomerateName = dd.getTableDescriptor(cds[i].getTableID()).getName();
}
conglomTable[i] = new ConglomInfo(cds[i].getTableID().toString(), cds[i].getConglomerateNumber(), conglomerateName, cds[i].isIndex());
}
}
use of org.apache.derby.iapi.sql.dictionary.TableDescriptor 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.TableDescriptor 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.TableDescriptor 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