/**
   * 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;
  }
Beispiel #2
0
  /**
   * 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;
 }
Beispiel #4
0
  /**
   * 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);
  }
Beispiel #5
0
  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;
  }