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;
  }
  protected void reflect() {
    // fill in the sql for single statement procs
    if (m_catProc.getHasjava() == false) {
      try {
        Map<String, Field> stmtMap =
            ProcedureCompiler.getValidSQLStmts(null, m_procedureName, m_procedure.getClass(), true);
        Field f = stmtMap.get(VoltDB.ANON_STMT_NAME);
        assert (f != null);
        SQLStmt stmt = (SQLStmt) f.get(m_procedure);
        Statement statement = m_catProc.getStatements().get(VoltDB.ANON_STMT_NAME);
        stmt.sqlText = statement.getSqltext().getBytes(VoltDB.UTF8ENCODING);
        m_cachedSingleStmt.stmt = stmt;

        int numParams = m_catProc.getParameters().size();
        m_paramTypes = new Class<?>[numParams];
        m_paramTypeIsPrimitive = new boolean[numParams];
        m_paramTypeIsArray = new boolean[numParams];
        m_paramTypeComponentType = new Class<?>[numParams];

        for (ProcParameter param : m_catProc.getParameters()) {
          VoltType type = VoltType.get((byte) param.getType());
          if (type == VoltType.INTEGER) {
            type = VoltType.BIGINT;
          } else if (type == VoltType.SMALLINT) {
            type = VoltType.BIGINT;
          } else if (type == VoltType.TINYINT) {
            type = VoltType.BIGINT;
          } else if (type == VoltType.NUMERIC) {
            type = VoltType.FLOAT;
          }

          m_paramTypes[param.getIndex()] = type.classFromType();
          m_paramTypeIsPrimitive[param.getIndex()] = m_paramTypes[param.getIndex()].isPrimitive();
          m_paramTypeIsArray[param.getIndex()] = param.getIsarray();
          assert (m_paramTypeIsArray[param.getIndex()] == false);
          m_paramTypeComponentType[param.getIndex()] = null;

          // rtb: what is broken (ambiguous?) that is being patched here?
          // hack to fixup varbinary support for statement procedures
          if (m_paramTypes[param.getIndex()] == byte[].class) {
            m_paramTypeComponentType[param.getIndex()] = byte.class;
            m_paramTypeIsArray[param.getIndex()] = true;
          }
        }
      } catch (Exception e) {
        // shouldn't throw anything outside of the compiler
        e.printStackTrace();
      }
    } else {
      // parse the java run method
      Method[] methods = m_procedure.getClass().getDeclaredMethods();

      for (final Method m : methods) {
        String name = m.getName();
        if (name.equals("run")) {
          if (Modifier.isPublic(m.getModifiers()) == false) continue;
          m_procMethod = m;
          m_paramTypes = m.getParameterTypes();
          int tempParamTypesLength = m_paramTypes.length;

          m_paramTypeIsPrimitive = new boolean[tempParamTypesLength];
          m_paramTypeIsArray = new boolean[tempParamTypesLength];
          m_paramTypeComponentType = new Class<?>[tempParamTypesLength];
          for (int ii = 0; ii < tempParamTypesLength; ii++) {
            m_paramTypeIsPrimitive[ii] = m_paramTypes[ii].isPrimitive();
            m_paramTypeIsArray[ii] = m_paramTypes[ii].isArray();
            m_paramTypeComponentType[ii] = m_paramTypes[ii].getComponentType();
          }
        }
      }

      if (m_procMethod == null) {
        throw new RuntimeException(
            "No \"run\" method found in: " + m_procedure.getClass().getName());
      }
    }

    // iterate through the fields and deal with sql statements
    Map<String, Field> stmtMap = null;
    try {
      stmtMap =
          ProcedureCompiler.getValidSQLStmts(null, m_procedureName, m_procedure.getClass(), true);
    } catch (Exception e1) {
      // shouldn't throw anything outside of the compiler
      e1.printStackTrace();
      return;
    }

    Field[] fields = new Field[stmtMap.size()];
    int index = 0;
    for (Field f : stmtMap.values()) {
      fields[index++] = f;
    }
    for (final Field f : fields) {
      String name = f.getName();
      Statement s = m_catProc.getStatements().get(name);
      if (s != null) {
        try {
          /*
           * Cache all the information we need about the statements in this stored
           * procedure locally instead of pulling them from the catalog on
           * a regular basis.
           */
          SQLStmt stmt = (SQLStmt) f.get(m_procedure);

          // done in a static method in an abstract class so users don't call it
          initSQLStmt(stmt, s);

        } catch (IllegalArgumentException e) {
          e.printStackTrace();
        } catch (IllegalAccessException e) {
          e.printStackTrace();
        }
        // LOG.fine("Found statement " + name);
      }
    }
  }
Exemple #3
0
  static String generateProcedureRow(Procedure procedure) {
    StringBuilder sb = new StringBuilder();
    sb.append("<tr class='primaryrow'>");

    // column 1: procedure name
    String anchor = procedure.getTypeName().toLowerCase();
    sb.append(
        "<td style='white-space: nowrap'><i id='p-"
            + anchor
            + "--icon' class='icon-chevron-right'></i> <a href='#p-");
    sb.append(anchor).append("' id='p-").append(anchor).append("' class='togglex'>");
    sb.append(procedure.getTypeName());
    sb.append("</a></td>");

    // column 2: parameter types
    sb.append("<td>");
    List<ProcParameter> params =
        CatalogUtil.getSortedCatalogItems(procedure.getParameters(), "index");
    List<String> paramTypes = new ArrayList<String>();
    for (ProcParameter param : params) {
      String paramType = VoltType.get((byte) param.getType()).name();
      if (param.getIsarray()) {
        paramType += "[]";
      }
      paramTypes.add(paramType);
    }
    if (paramTypes.size() == 0) {
      sb.append("<i>None</i>");
    }
    sb.append(StringUtils.join(paramTypes, ", "));
    sb.append("</td>");

    // column 3: partitioning
    sb.append("<td>");
    if (procedure.getSinglepartition()) {
      tag(sb, "success", "Single");
    } else {
      tag(sb, "warning", "Multi");
    }
    sb.append("</td>");

    // column 4: read/write
    sb.append("<td>");
    if (procedure.getReadonly()) {
      tag(sb, "success", "Read");
    } else {
      tag(sb, "warning", "Write");
    }
    sb.append("</td>");

    // column 5: access
    sb.append("<td>");
    List<String> groupNames = new ArrayList<String>();
    for (GroupRef groupRef : procedure.getAuthgroups()) {
      groupNames.add(groupRef.getGroup().getTypeName());
    }
    if (groupNames.size() == 0) {
      sb.append("<i>None</i>");
    }
    sb.append(StringUtils.join(groupNames, ", "));
    sb.append("</td>");

    // column 6: attributes
    sb.append("<td>");
    if (procedure.getHasjava()) {
      tag(sb, "info", "Java");
    } else {
      tag(sb, null, "Single-Stmt");
    }
    boolean isND = false;
    int scanCount = 0;
    for (Statement stmt : procedure.getStatements()) {
      scanCount += stmt.getSeqscancount();
      if (!stmt.getIscontentdeterministic() || !stmt.getIsorderdeterministic()) {
        isND = false;
      }
    }
    if (isND) {
      tag(sb, "inverse", "Determinism");
    }
    if (scanCount > 0) {
      tag(sb, "important", "Scans");
    }
    sb.append("</td>");

    sb.append("</tr>\n");

    // BUILD THE DROPDOWN FOR THE STATEMENT/DETAIL TABLE

    sb.append(
        "<tr class='tablesorter-childRow'><td class='invert' colspan='6' id='p-"
            + procedure.getTypeName().toLowerCase()
            + "--dropdown'>\n");

    // output partitioning parameter info
    if (procedure.getSinglepartition()) {
      String pTable = procedure.getPartitioncolumn().getParent().getTypeName();
      String pColumn = procedure.getPartitioncolumn().getTypeName();
      int pIndex = procedure.getPartitionparameter();

      sb.append(
          String.format(
              "<p>Partitioned on parameter %d which maps to column %s"
                  + " of table <a class='invert' href='#s-%s'>%s</a>.</p>",
              pIndex, pColumn, pTable, pTable));
    }

    // output what schema this interacts with
    ProcedureAnnotation annotation = (ProcedureAnnotation) procedure.getAnnotation();
    if (annotation != null) {
      // make sure tables appear in only one category
      annotation.tablesRead.removeAll(annotation.tablesUpdated);

      if (annotation.tablesRead.size() > 0) {
        sb.append("<p>Read-only access to tables: ");
        List<String> tables = new ArrayList<String>();
        for (Table table : annotation.tablesRead) {
          tables.add("<a href='#s-" + table.getTypeName() + "'>" + table.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(tables, ", "));
        sb.append("</p>");
      }
      if (annotation.tablesUpdated.size() > 0) {
        sb.append("<p>Read/Write access to tables: ");
        List<String> tables = new ArrayList<String>();
        for (Table table : annotation.tablesUpdated) {
          tables.add("<a href='#s-" + table.getTypeName() + "'>" + table.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(tables, ", "));
        sb.append("</p>");
      }
      if (annotation.indexesUsed.size() > 0) {
        sb.append("<p>Uses indexes: ");
        List<String> indexes = new ArrayList<String>();
        for (Index index : annotation.indexesUsed) {
          Table table = (Table) index.getParent();
          indexes.add(
              "<a href='#s-"
                  + table.getTypeName()
                  + "-"
                  + index.getTypeName()
                  + "'>"
                  + index.getTypeName()
                  + "</a>");
        }
        sb.append(StringUtils.join(indexes, ", "));
        sb.append("</p>");
      }
    }

    sb.append(generateStatementsTable(procedure));

    sb.append("</td></tr>\n");

    return sb.toString();
  }