/* Copyright (c) 2001-2009, 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.HSQLInterface.HSQLParseException; import org.hsqldb.ParserDQL.CompileContext; import org.hsqldb.RangeVariable.RangeIteratorBase; import org.hsqldb.navigator.RowSetNavigator; import org.hsqldb.navigator.RowSetNavigatorClient; import org.hsqldb.persist.PersistentStore; import org.hsqldb.result.Result; import org.hsqldb.types.Type; /** * Implementation of Statement for INSERT statements.<p> * * @author Fred Toussi (fredt@users dot sourceforge.net) * @version 1.9.0 * @since 1.9.0 */ public class StatementInsert extends StatementDML { /** * Instantiate this as an INSERT_VALUES statement. */ StatementInsert(Session session, Table targetTable, int[] columnMap, Expression insertExpression, boolean[] checkColumns, CompileContext compileContext) { super(StatementTypes.INSERT, StatementTypes.X_SQL_DATA_CHANGE, session.currentSchema); this.targetTable = targetTable; this.baseTable = targetTable.getBaseTable(); this.insertColumnMap = columnMap; this.insertCheckColumns = checkColumns; this.insertExpression = insertExpression; this.isTransactionStatement = true; setDatabseObjects(compileContext); checkAccessRights(session); } /** * Instantiate this as an INSERT_SELECT statement. */ StatementInsert(Session session, Table targetTable, int[] columnMap, boolean[] checkColumns, QueryExpression queryExpression, CompileContext compileContext) { super(StatementTypes.INSERT, StatementTypes.X_SQL_DATA_CHANGE, session.currentSchema); this.targetTable = targetTable; this.baseTable = targetTable.getBaseTable(); this.insertColumnMap = columnMap; this.insertCheckColumns = checkColumns; this.queryExpression = queryExpression; this.isTransactionStatement = true; setDatabseObjects(compileContext); checkAccessRights(session); } /** * Executes an INSERT_SELECT statement. It is assumed that the argument * is of the correct type. * * @return the result of executing the statement */ Result getResult(Session session) { Table table = baseTable; Result resultOut = null; RowSetNavigator generatedNavigator = null; PersistentStore store = session.sessionData.getRowStore(baseTable); if (generatedIndexes != null) { resultOut = Result.newUpdateCountResult(generatedResultMetaData, 0); generatedNavigator = resultOut.getChainedResult().getNavigator(); } RowSetNavigator newDataNavigator = queryExpression == null ? getInsertValuesNavigator(session) : getInsertSelectNavigator(session); Expression checkCondition = null; RangeIteratorBase checkIterator = null; if (targetTable != baseTable) { QuerySpecification select = ((TableDerived) targetTable).getQueryExpression() .getMainSelect(); checkCondition = select.checkQueryCondition; if (checkCondition != null) { checkIterator = select.rangeVariables[0].getIterator(session); } } while (newDataNavigator.hasNext()) { Object[] data = newDataNavigator.getNext(); if (checkCondition != null) { checkIterator.currentData = data; boolean check = checkCondition.testCondition(session); if (!check) { throw Error.error(ErrorCode.X_44000); } } table.insertRow(session, store, data); if (generatedNavigator != null) { Object[] generatedValues = getGeneratedColumns(data); generatedNavigator.add(generatedValues); } } newDataNavigator.beforeFirst(); table.fireAfterTriggers(session, Trigger.INSERT_AFTER, newDataNavigator); if (resultOut == null) { resultOut = Result.getUpdateCountResult(newDataNavigator.getSize()); } else { resultOut.setUpdateCount(newDataNavigator.getSize()); } return resultOut; } RowSetNavigator getInsertSelectNavigator(Session session) { Type[] colTypes = baseTable.getColumnTypes(); int[] columnMap = insertColumnMap; // Result result = queryExpression.getResult(session, 0); RowSetNavigator nav = result.initialiseNavigator(); Type[] sourceTypes = result.metaData.columnTypes; RowSetNavigatorClient newData = new RowSetNavigatorClient(2); while (nav.hasNext()) { Object[] data = baseTable.getNewRowData(session); Object[] sourceData = (Object[]) nav.getNext(); for (int i = 0; i < columnMap.length; i++) { int j = columnMap[i]; Type sourceType = sourceTypes[i]; data[j] = colTypes[j].convertToType(session, sourceData[i], sourceType); } newData.add(data); } return newData; } RowSetNavigator getInsertValuesNavigator(Session session) { Type[] colTypes = baseTable.getColumnTypes(); int[] columnMap = insertColumnMap; // Expression[] list = insertExpression.nodes; RowSetNavigatorClient newData = new RowSetNavigatorClient(list.length); for (int j = 0; j < list.length; j++) { Expression[] rowArgs = list[j].nodes; Object[] data = baseTable.getNewRowData(session); session.sessionData.startRowProcessing(); for (int i = 0; i < rowArgs.length; i++) { Expression e = rowArgs[i]; int colIndex = columnMap[i]; if (e.getType() == OpTypes.DEFAULT) { if (baseTable.identityColumn == colIndex) { continue; } data[colIndex] = baseTable.colDefaults[colIndex].getValue(session); continue; } data[colIndex] = colTypes[colIndex].convertToType(session, e.getValue(session), e.getDataType()); } newData.add(data); } return newData; } /*************** VOLTDB *********************/ private StringBuffer voltAppendInsertColumns(Session session, StringBuffer sb, String orig_indent) throws HSQLParseException { sb.append(orig_indent).append("<columns>\n"); String indent = orig_indent + HSQLInterface.XML_INDENT; for (int i = 0; i < insertColumnMap.length; i++) { sb.append(indent).append("<column table=\"").append(targetTable.tableName.name); sb.append("\" name=\"").append(targetTable.getColumn(insertColumnMap[i]).getName().name); sb.append("\">\n"); sb.append(insertExpression.nodes[0].nodes[i].voltGetXML(session, indent + HSQLInterface.XML_INDENT)).append("\n"); sb.append(indent).append("</column>\n"); } sb.append(orig_indent).append("</columns>"); return sb; } private StringBuffer voltAppendParameters(Session session, StringBuffer sb, String orig_indent) { sb.append(orig_indent).append("<parameters>\n"); String indent = orig_indent + HSQLInterface.XML_INDENT; for (int i = 0; i < parameters.length; i++) { sb.append(indent).append("<parameter index='").append(i).append("'"); Expression param = parameters[i]; sb.append(" id='").append(param.getUniqueId()).append("'"); sb.append(" type='").append(Types.getTypeName(param.getDataType().typeCode)).append("'"); sb.append(" />\n"); } sb.append(orig_indent).append("</parameters>"); return sb; } /** * VoltDB added method to get a non-catalog-dependent * representation of this HSQLDB object. * @param session The current Session object may be needed to resolve * some names. * @param indent A string of whitespace to be prepended to every line * in the resulting XML. * @return XML, correctly indented, representing this object. * @throws HSQLParseException */ String voltGetXML(Session session, String orig_indent) throws HSQLParseException { StringBuffer sb; sb = new StringBuffer(); String indent = orig_indent + HSQLInterface.XML_INDENT; switch (type) { case StatementTypes.INSERT : sb.append(orig_indent).append("<insert table=\""); sb.append(targetTable.getName().name).append("\">\n"); voltAppendInsertColumns(session, sb, indent).append('\n'); voltAppendParameters(session, sb, indent).append('\n'); sb.append(orig_indent).append("</insert>"); break; default : sb.append(orig_indent).append("<unknown/>"); break; } return sb.toString(); } }