|
|
What this is
This file is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Other links
The source code
/* Copyright (c) 2001-2004, 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.lib.HashMappedList;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.jdbc.jdbcResultSet;
// boucherb@users 200404xx - fixed broken CALL statement result set unwrapping;
// fixed broken support for prepared SELECT...INTO
/**
* Provides execution of CompiledStatement objects.
*
* If multiple threads access a CompiledStatementExecutor.execute()
* concurrently, they must be synchronized externally, relative to both
* this object's Session and the Session's Database object. Internally, this
* is accomplished in Session.execute() by synchronizing on the Session
* object's Database object.
*
* @author boucherb@users
* @version 1.7.2
* @since HSQLDB 1.7.2
*/
final class CompiledStatementExecutor {
private Session session;
private Result updateResult;
private Result emptyResult;
/**
* Creates a new instance of CompiledStatementExecutor.
*
* @param session the context in which to perform the execution
*/
CompiledStatementExecutor(Session session) {
this.session = session;
updateResult = new Result(ResultConstants.UPDATECOUNT);
emptyResult = new Result(ResultConstants.UPDATECOUNT);
}
/**
* Executes a generic CompiledStatement. Execution includes first building
* any subquery result dependencies and clearing them after the main result
* is built.
*
* @return the result of executing the statement
* @param cs any valid CompiledStatement
*/
Result execute(CompiledStatement cs) {
Result result = null;
DatabaseManager.gc();
try {
cs.materializeSubQueries(session);
result = executeImpl(cs);
} catch (Throwable t) {
//t.printStackTrace();
result = new Result(t, cs.sql);
}
// clear redundant data
cs.dematerializeSubQueries();
if (result == null) {
result = emptyResult;
}
return result;
}
/**
* Executes a generic CompiledStatement. Execution excludes building
* subquery result dependencies and clearing them after the main result
* is built.
*
* @param cs any valid CompiledStatement
* @throws HsqlException if a database access error occurs
* @return the result of executing the statement
*/
private Result executeImpl(CompiledStatement cs) throws HsqlException {
switch (cs.type) {
case CompiledStatement.SELECT :
return executeSelectStatement(cs);
case CompiledStatement.INSERT_SELECT :
return executeInsertSelectStatement(cs);
case CompiledStatement.INSERT_VALUES :
return executeInsertValuesStatement(cs);
case CompiledStatement.UPDATE :
return executeUpdateStatement(cs);
case CompiledStatement.DELETE :
return executeDeleteStatement(cs);
case CompiledStatement.CALL :
return executeCallStatement(cs);
case CompiledStatement.DDL :
return executeDDLStatement(cs);
default :
throw Trace.error(
Trace.INTERNAL_unknown_internal_statement_type);
}
}
/**
* Executes a CALL statement. It is assumed that the argument is
* of the correct type.
*
* @param cs a CompiledStatement of type CompiledStatement.CALL
* @throws HsqlException if a database access error occurs
* @return the result of executing the statement
*/
private Result executeCallStatement(CompiledStatement cs)
throws HsqlException {
Expression e = cs.expression; // representing CALL
Object o = e.getValue(session); // expression return value
Result r;
if (o instanceof Result) {
return (Result) o;
} else if (o instanceof jdbcResultSet) {
return ((jdbcResultSet) o).rResult;
}
r = Result.newSingleColumnResult(DIProcedureInfo.RETURN_COLUMN_NAME,
e.getDataType());
Object[] row = new Object[1];
row[0] = o;
r.metaData.sClassName[0] = e.getValueClassName();
r.add(row);
return r;
}
/**
* Executes a DELETE statement. It is assumed that the argument is
* of the correct type.
*
* @param cs a CompiledStatement of type CompiledStatement.DELETE
* @throws HsqlException if a database access error occurs
* @return the result of executing the statement
*/
private Result executeDeleteStatement(CompiledStatement cs)
throws HsqlException {
Table table = cs.targetTable;
TableFilter filter = cs.tf;
int count = 0;
if (filter.findFirst()) {
Expression c = cs.condition;
HsqlArrayList del;
del = new HsqlArrayList();
if (c == null) {
do {
del.add(filter.currentRow);
} while (filter.next());
count = table.delete(session, del);
} else {
do {
if (c.test(session)) {
del.add(filter.currentRow);
}
} while (filter.next());
count = table.delete(session, del);
}
}
updateResult.iUpdateCount = count;
return updateResult;
}
/**
* Executes an INSERT_SELECT statement. It is assumed that the argument
* is of the correct type.
*
* @param cs a CompiledStatement of type CompiledStatement.INSERT_SELECT
* @throws HsqlException if a database access error occurs
* @return the result of executing the statement
*/
private Result executeInsertSelectStatement(CompiledStatement cs)
throws HsqlException {
Table t = cs.targetTable;
Select s = cs.select;
int[] ct = t.getColumnTypes(); // column types
Result r = s.getResult(session, session.getMaxRows());
Record rc = r.rRoot;
int[] cm = cs.columnMap; // column map
boolean[] ccl = cs.checkColumns; // column check list
int len = cm.length;
Object[] row;
int count;
boolean success = false;
session.beginNestedTransaction();
try {
while (rc != null) {
row = t.getNewRowData(session, ccl);
for (int i = 0; i < len; i++) {
int j = cm[i];
if (ct[j] != r.metaData.colType[i]) {
row[j] = Column.convertObject(rc.data[i], ct[j]);
} else {
row[j] = rc.data[i];
}
}
rc.data = row;
rc = rc.next;
}
count = t.insert(session, r);
success = true;
} finally {
session.endNestedTransaction(!success);
}
updateResult.iUpdateCount = count;
return updateResult;
}
/**
* Executes an INSERT_VALUES statement. It is assumed that the argument
* is of the correct type.
*
* @param cs a CompiledStatement of type CompiledStatement.INSERT_VALUES
* @throws HsqlException if a database access error occurs
* @return the result of executing the statement
*/
private Result executeInsertValuesStatement(CompiledStatement cs)
throws HsqlException {
Table t = cs.targetTable;
Object[] row = t.getNewRowData(session, cs.checkColumns);
int[] cm = cs.columnMap; // column map
Expression[] acve = cs.columnValues;
Expression cve;
int[] ct = t.getColumnTypes(); // column types
int ci; // column index
int len = acve.length;
for (int i = 0; i < len; i++) {
cve = acve[i];
ci = cm[i];
row[ci] = cve.getValue(session, ct[ci]);
}
t.insert(session, row);
updateResult.iUpdateCount = 1;
return updateResult;
}
/**
* Executes a SELECT statement. It is assumed that the argument
* is of the correct type.
*
* @param cs a CompiledStatement of type CompiledStatement.SELECT
* @throws HsqlException if a database access error occurs
* @return the result of executing the statement
*/
private Result executeSelectStatement(CompiledStatement cs)
throws HsqlException {
Select select = cs.select;
Result result;
if (select.sIntoTable != null) {
// session level user rights
session.checkDDLWrite();
if (session.getDatabase()
.findUserTable(session, select.sIntoTable
.name) != null || session.getDatabase().dInfo
.getSystemTable(session, select.sIntoTable
.name) != null) {
throw Trace.error(Trace.TABLE_ALREADY_EXISTS,
select.sIntoTable.name);
}
result = select.getResult(session, session.getMaxRows());
result = session.dbCommandInterpreter.processSelectInto(result,
select.sIntoTable, select.intoType);
session.getDatabase().setMetaDirty(false);
} else {
result = select.getResult(session, session.getMaxRows());
}
return result;
}
/**
* Executes an UPDATE statement. It is assumed that the argument
* is of the correct type.
*
* @param cs a CompiledStatement of type CompiledStatement.UPDATE
* @throws HsqlException if a database access error occurs
* @return the result of executing the statement
*/
private Result executeUpdateStatement(CompiledStatement cs)
throws HsqlException {
Table table = cs.targetTable;
TableFilter filter = cs.tf;
int count = 0;
if (filter.findFirst()) {
int[] colmap = cs.columnMap; // column map
Expression[] colvalues = cs.columnValues;
Expression condition = cs.condition; // update condition
int len = colvalues.length;
HashMappedList rowset = new HashMappedList();
int size = table.getColumnCount();
int[] coltypes = table.getColumnTypes();
boolean success = false;
do {
if (condition == null || condition.test(session)) {
try {
Row row = filter.currentRow;
Object[] ni = table.getNewRow();
System.arraycopy(row.getData(), 0, ni, 0, size);
for (int i = 0; i < len; i++) {
int ci = colmap[i];
ni[ci] = colvalues[i].getValue(session,
coltypes[ci]);
}
rowset.add(row, ni);
} catch (HsqlInternalException e) {}
}
} while (filter.next());
session.beginNestedTransaction();
try {
count = table.update(session, rowset, colmap);
success = true;
} finally {
// update failed (constraint violation) or succeeded
session.endNestedTransaction(!success);
}
}
updateResult.iUpdateCount = count;
return updateResult;
}
/**
* Executes a DDL statement. It is assumed that the argument
* is of the correct type.
*
* @param cs a CompiledStatement of type CompiledStatement.DDL
* @throws HsqlException if a database access error occurs
* @return the result of executing the statement
*/
private Result executeDDLStatement(CompiledStatement cs)
throws HsqlException {
return session.sqlExecuteDirectNoPreChecks(cs.sql);
}
}
|