/** * For convenience, serialization is accomplished with this single method, but deserialization is * piecemeal via the static methods userParamsFromBuffer and planArrayFromBuffer with no dummy * "AdHocPlannedStmtBatch receiver" instance required. */ public ByteBuffer flattenPlanArrayToBuffer() throws IOException { int size = 0; // sizeof batch ParameterSet userParamCache = null; if (work.userParamSet == null) { userParamCache = ParameterSet.emptyParameterSet(); } else { Object[] typedUserParams = new Object[work.userParamSet.length]; int ii = 0; for (AdHocPlannedStatement cs : plannedStatements) { for (VoltType paramType : cs.core.parameterTypes) { if (ii >= typedUserParams.length) { String errorMsg = "Too few actual arguments were passed for the parameters in the sql statement(s): (" + typedUserParams.length + " vs. " + ii + ")"; // Volt-TYPE-Exception is slightly cheating, here, should there be a more general // VoltArgumentException? throw new VoltTypeException(errorMsg); } typedUserParams[ii] = ParameterConverter.tryToMakeCompatible( paramType.classFromType(), work.userParamSet[ii]); // System.out.println("DEBUG typed parameter: " + work.userParamSet[ii] + // "using type: " + paramType + "as: " + typedUserParams[ii]); ii++; } } // Each parameter referenced in each statements should be represented // exactly once in userParams. if (ii < typedUserParams.length) { // Volt-TYPE-Exception is slightly cheating, here, should there be a more general // VoltArgumentException? String errorMsg = "Too many actual arguments were passed for the parameters in the sql statement(s): (" + typedUserParams.length + " vs. " + ii + ")"; throw new VoltTypeException(errorMsg); } userParamCache = ParameterSet.fromArrayNoCopy(typedUserParams); } size += userParamCache.getSerializedSize(); size += 2; // sizeof batch for (AdHocPlannedStatement cs : plannedStatements) { size += cs.getSerializedSize(); } ByteBuffer buf = ByteBuffer.allocate(size); userParamCache.flattenToBuffer(buf); buf.putShort((short) plannedStatements.size()); for (AdHocPlannedStatement cs : plannedStatements) { cs.flattenToBuffer(buf); } return buf; }
/** * Java version of table schema change. - Supports adding columns with default values (or null if * none specified) - Supports dropping columns. - Supports widening of columns. * * <p>Note, this might fail in wierd ways if you ask it to do more than what the EE version can * do. It's not really set up to test the negative cases. */ public static void migrateTable(VoltTable source, VoltTable dest) throws Exception { Map<Integer, Integer> indexMap = new TreeMap<Integer, Integer>(); for (int i = 0; i < dest.getColumnCount(); i++) { String destColName = dest.getColumnName(i); for (int j = 0; j < source.getColumnCount(); j++) { String srcColName = source.getColumnName(j); if (srcColName.equals(destColName)) { indexMap.put(i, j); } } } assert (dest.getRowCount() == 0); source.resetRowPosition(); while (source.advanceRow()) { Object[] row = new Object[dest.getColumnCount()]; // get the values from the source table or defaults for (int i = 0; i < dest.getColumnCount(); i++) { if (indexMap.containsKey(i)) { int sourcePos = indexMap.get(i); row[i] = source.get(sourcePos, source.getColumnType(sourcePos)); } else { row[i] = dest.getColumnDefaultValue(i); // handle no default specified if (row[i] == TableShorthand.ColMeta.NO_DEFAULT_VALUE) { if (dest.getColumnNullable(i)) { row[i] = null; } else { throw new RuntimeException( String.format( "New column %s needs a default value in migration", dest.getColumnName(i))); } } } // make the values the core types of the target table VoltType destColType = dest.getColumnType(i); Class<?> descColClass = destColType.classFromType(); row[i] = ParameterConverter.tryToMakeCompatible(descColClass, row[i]); // check the result type in an assert assert (ParameterConverter.verifyParameterConversion(row[i], descColClass)); } dest.addRow(row); } }
/* * Return the partitioning value (if any) for an SP statement batch. * It may have come from a number of sources: * - an explicit override -- such as for AdHocSpForTest or an ad hoc statement queued * from an SP stored proc (which currently dummies up a null value) * - a user-provided parameter to an ad hoc that the planner determined to be the * partitioning parameter. * - a planner-extracted parameter from an ad hoc that the planner determined to be the * partitioning parameter. * - a constant from an ad hoc that the planner determined to be the * partitioning parameter (after opting out of or failing parameterization). */ public Object partitionParam() { if (work.userPartitionKey != null) { return work.userPartitionKey[0]; } if (partitionParamIndex > -1 && work.userParamSet != null && work.userParamSet.length > partitionParamIndex) { Object userParamValue = work.userParamSet[partitionParamIndex]; if (partitionParamType == null) { return userParamValue; } else { return ParameterConverter.tryToMakeCompatible( partitionParamType.classFromType(), userParamValue); } } return partitionParamValue; }
/** * Given the type of the targeting partition parameter and an object, coerce the object to the * correct type and hash it. * * @return The partition best set up to execute the procedure. * @throws Exception */ public static int getPartitionForParameter(int partitionType, Object invocationParameter) throws Exception { final VoltType partitionParamType = VoltType.get((byte) partitionType); // Special case: if the user supplied a string for a number column, // try to do the conversion. This makes it substantially easier to // load CSV data or other untyped inputs that match DDL without // requiring the loader to know precise the schema. if ((invocationParameter != null) && (invocationParameter.getClass() == String.class) && (partitionParamType.isNumber())) { invocationParameter = ParameterConverter.stringToLong(invocationParameter, partitionParamType.classFromType()); } return hashToPartition(invocationParameter); }
public ClientResponseImpl call(Object... paramListIn) { // verify per-txn state has been reset assert (m_statusCode == ClientResponse.UNINITIALIZED_APP_STATUS_CODE); assert (m_statusString == null); assert (m_cachedRNG == null); // reset the hash of results m_inputCRC.reset(); // use local var to avoid warnings about reassigning method argument Object[] paramList = paramListIn; ClientResponseImpl retval = null; // assert no sql is queued assert (m_batch.size() == 0); try { m_statsCollector.beginProcedure(); byte status = ClientResponse.SUCCESS; VoltTable[] results = null; // inject sysproc execution context as the first parameter. if (isSystemProcedure()) { final Object[] combinedParams = new Object[paramList.length + 1]; combinedParams[0] = m_systemProcedureContext; for (int i = 0; i < paramList.length; ++i) combinedParams[i + 1] = paramList[i]; // swap the lists. paramList = combinedParams; } if (paramList.length != m_paramTypes.length) { m_statsCollector.endProcedure(false, true, null, null); String msg = "PROCEDURE " + m_procedureName + " EXPECTS " + String.valueOf(m_paramTypes.length) + " PARAMS, BUT RECEIVED " + String.valueOf(paramList.length); status = ClientResponse.GRACEFUL_FAILURE; return getErrorResponse(status, msg, null); } for (int i = 0; i < m_paramTypes.length; i++) { try { paramList[i] = ParameterConverter.tryToMakeCompatible( m_paramTypeIsPrimitive[i], m_paramTypeIsArray[i], m_paramTypes[i], m_paramTypeComponentType[i], paramList[i]); } catch (Exception e) { m_statsCollector.endProcedure(false, true, null, null); String msg = "PROCEDURE " + m_procedureName + " TYPE ERROR FOR PARAMETER " + i + ": " + e.toString(); status = ClientResponse.GRACEFUL_FAILURE; return getErrorResponse(status, msg, null); } } boolean error = false; boolean abort = false; // run a regular java class if (m_catProc.getHasjava()) { try { if (log.isTraceEnabled()) { log.trace( "invoking... procMethod=" + m_procMethod.getName() + ", class=" + getClass().getName()); } try { Object rawResult = m_procMethod.invoke(m_procedure, paramList); results = getResultsFromRawResults(rawResult); } catch (IllegalAccessException e) { // If reflection fails, invoke the same error handling that other exceptions do throw new InvocationTargetException(e); } log.trace("invoked"); } catch (InvocationTargetException itex) { // itex.printStackTrace(); Throwable ex = itex.getCause(); if (ex instanceof VoltAbortException && !(ex instanceof EEException)) { abort = true; } else { error = true; } if (ex instanceof Error) { m_statsCollector.endProcedure(false, true, null, null); throw (Error) ex; } retval = getErrorResponse(ex); } } // single statement only work // (this could be made faster, but with less code re-use) else { assert (m_catProc.getStatements().size() == 1); try { m_cachedSingleStmt.params = getCleanParams(m_cachedSingleStmt.stmt, paramList); if (getHsqlBackendIfExists() != null) { // HSQL handling CatalogMap<StmtParameter> sparamsMap = m_cachedSingleStmt.stmt.catStmt.getParameters(); List<StmtParameter> sparams = CatalogUtil.getSortedCatalogItems(sparamsMap, "index"); VoltTable table = getHsqlBackendIfExists() .runSQLWithSubstitutions( m_cachedSingleStmt.stmt, m_cachedSingleStmt.params, sparams); results = new VoltTable[] {table}; } else { m_batch.add(m_cachedSingleStmt); results = voltExecuteSQL(true); } } catch (SerializableException ex) { retval = getErrorResponse(ex); } } // Record statistics for procedure call. StoredProcedureInvocation invoc = (m_txnState != null ? m_txnState.getInvocation() : null); ParameterSet paramSet = (invoc != null ? invoc.getParams() : null); m_statsCollector.endProcedure(abort, error, results, paramSet); // don't leave empty handed if (results == null) results = new VoltTable[0]; if (retval == null) retval = new ClientResponseImpl(status, m_statusCode, m_statusString, results, null); int hash = (int) m_inputCRC.getValue(); if ((retval.getStatus() == ClientResponse.SUCCESS) && (hash != 0)) { retval.setHash(hash); } if ((m_txnState != null) && // may be null for tests (m_txnState.getInvocation() != null) && (m_txnState.getInvocation().getType() == ProcedureInvocationType.REPLICATED)) { retval.convertResultsToHashForDeterminism(); } } finally { // finally at the call(..) scope to ensure params can be // garbage collected and that the queue will be empty for // the next call m_batch.clear(); // reset other per-txn state m_txnState = null; m_statusCode = ClientResponse.UNINITIALIZED_APP_STATUS_CODE; m_statusString = null; m_cachedRNG = null; m_cachedSingleStmt.params = null; m_cachedSingleStmt.expectation = null; m_seenFinalBatch = false; } return retval; }