示例#1
0
  // silly helper to add datasources for a table catalog object
  private void addDataSources(Table table, int hostId, List<Pair<Integer, Long>> partitions) {
    for (Pair<Integer, Long> p : partitions) {
      Integer partition = p.getFirst();
      Long site = p.getSecond();

      /*
       * IOException can occur if there is a problem
       * with the persistent aspects of the datasource storage
       */
      try {
        HashMap<String, ExportDataSource> dataSourcesForPartition =
            m_dataSourcesByPartition.get(partition);
        if (dataSourcesForPartition == null) {
          dataSourcesForPartition = new HashMap<String, ExportDataSource>();
          m_dataSourcesByPartition.put(partition, dataSourcesForPartition);
        }
        ExportDataSource exportDataSource =
            new ExportDataSource(
                m_onSourceDrained,
                "database",
                table.getTypeName(),
                partition,
                site,
                table.getSignature(),
                m_timestamp,
                table.getColumns(),
                m_directory.getPath());
        m_numSources++;
        exportLog.info(
            "Creating ExportDataSource for table "
                + table.getTypeName()
                + " signature "
                + table.getSignature()
                + " partition id "
                + partition);
        dataSourcesForPartition.put(table.getSignature(), exportDataSource);
      } catch (IOException e) {
        VoltDB.crashLocalVoltDB(
            "Error creating datasources for table " + table.getTypeName() + " host id " + hostId,
            true,
            e);
      }
    }
  }
 // Even though this function applies generally to expressions and tables and not just to TVEs as
 // such,
 // this function is somewhat TVE-related because TVEs DO represent the points where expression
 // trees
 // depend on tables.
 public static boolean isOperandDependentOnTable(AbstractExpression expr, Table table) {
   for (TupleValueExpression tve : ExpressionUtil.getTupleValueExpressions(expr)) {
     // TODO: This clumsy testing of table names regardless of table aliases is
     // EXACTLY why we can't have nice things like self-joins.
     if (table.getTypeName().equals(tve.getTableName())) {
       return true;
     }
   }
   return false;
 }
 @Override
 public void resolveForTable(Table table) {
   assert (table != null);
   // It MAY be that for the case in which this function is called (expression indexes), the
   // column's
   // table name is not specified (and not missed?).
   // It is possible to "correct" that here by cribbing it from the supplied table (base table for
   // the index)
   // -- not bothering for now.
   Column column = table.getColumns().getExact(m_columnName);
   assert (column != null);
   m_tableName = table.getTypeName();
   m_columnIndex = column.getIndex();
   setTypeSizeAndInBytes(column);
 }
示例#4
0
 @Override
 public boolean computeEstimatesRecursively(
     PlanStatistics stats,
     Cluster cluster,
     Database db,
     DatabaseEstimates estimates,
     ScalarValueHints[] paramHints) {
   Table target = db.getTables().getIgnoreCase(m_targetTableName);
   assert (target != null);
   DatabaseEstimates.TableEstimates tableEstimates =
       estimates.getEstimatesForTable(target.getTypeName());
   stats.incrementStatistic(0, StatsField.TUPLES_READ, tableEstimates.maxTuples);
   m_estimatedOutputTupleCount = tableEstimates.maxTuples;
   return true;
 }
示例#5
0
  /**
   * Parse tables and parameters
   *
   * @param root
   * @param db
   */
  @Override
  void parseTablesAndParams(VoltXMLElement stmtNode) {

    assert (stmtNode.children.size() > 1);
    tableList.clear();
    for (VoltXMLElement childSQL : stmtNode.children) {
      if (childSQL.name.equalsIgnoreCase(SELECT_NODE_NAME)) {
        AbstractParsedStmt childStmt = new ParsedSelectStmt(this.m_paramValues, this.m_db);
        childStmt.parseTablesAndParams(childSQL);
        m_children.add(childStmt);

        // So far T UNION T (as well as T JOIN T) are not handled properly
        // by the fragmentizer. Need to give an error if any table is mentioned
        // in the UNION TREE more than once.
        if (childStmt.scanColumns != null) {
          for (Table table : childStmt.tableList) {
            String tableName = table.getTypeName();
            if (m_uniqueTables.contains(tableName)) {
              // The table is not 'unique' across the union
              throw new PlanningErrorException(
                  "Table " + tableName + " appears more than once in the union statement");
            } else {
              m_uniqueTables.add(tableName);
            }
          }
        } else {
          throw new PlanningErrorException("Scan columns are NULL the UNION statement");
        }
        // Add statement's tables to the consolidated list
        tableList.addAll(childStmt.tableList);
      } else if (childSQL.name.equalsIgnoreCase(UNION_NODE_NAME)) {
        ParsedUnionStmt childStmt = new ParsedUnionStmt(this.m_paramValues, this.m_db);
        // Pass already accumulated unique tables to the child union
        childStmt.m_uniqueTables = m_uniqueTables;
        childStmt.parseTablesAndParams(childSQL);
        m_children.add(childStmt);
        // Add statement's tables to the consolidated list
        tableList.addAll(childStmt.tableList);
        // Child's unique tables now contains the consolidated list
        m_uniqueTables = childStmt.m_uniqueTables;
      } else {
        throw new PlanningErrorException("Unexpected Element in UNION statement: " + childSQL.name);
      }
    }
  }
  @Override
  public Callable<Boolean> createSetup(
      String file_path,
      String file_nonce,
      long txnId,
      Map<Integer, Long> partitionTransactionIds,
      JSONObject jsData,
      SystemProcedureExecutionContext context,
      VoltTable result,
      Map<String, Map<Integer, Pair<Long, Long>>> exportSequenceNumbers,
      SiteTracker tracker,
      HashinatorSnapshotData hashinatorData,
      long timestamp) {
    assert SnapshotSiteProcessor.ExecutionSitesCurrentlySnapshotting.isEmpty();

    final IndexSnapshotRequestConfig config =
        new IndexSnapshotRequestConfig(jsData, context.getDatabase());
    final Map<Integer, Long> pidToLocalHSIds = findLocalSources(config.partitionRanges, tracker);

    // mark snapshot start in registry
    final AtomicInteger numTables = new AtomicInteger(config.tables.length);
    m_snapshotRecord =
        SnapshotRegistry.startSnapshot(
            txnId, context.getHostId(), file_path, file_nonce, SnapshotFormat.INDEX, config.tables);

    // create table tasks
    for (Table table : config.tables) {
      createTasksForTable(
          table, config.partitionRanges, pidToLocalHSIds, numTables, m_snapshotRecord);
      result.addRow(
          context.getHostId(),
          CoreUtils.getHostnameOrAddress(),
          table.getTypeName(),
          "SUCCESS",
          "");
    }

    return null;
  }
  /** For each site, generate a task for each target it has for this table. */
  private void createTasksForTable(
      Table table,
      Collection<IndexSnapshotRequestConfig.PartitionRanges> partitionRanges,
      Map<Integer, Long> pidToLocalHSIDs,
      AtomicInteger numTables,
      SnapshotRegistry.Snapshot snapshotRecord) {
    // no work on this node
    if (pidToLocalHSIDs.isEmpty()) {
      return;
    }

    // create a null data target
    final DevNullSnapshotTarget dataTarget = new DevNullSnapshotTarget();
    final Runnable onClose =
        new TargetStatsClosure(dataTarget, table.getTypeName(), numTables, snapshotRecord);
    dataTarget.setOnCloseHandler(onClose);
    m_targets.add(dataTarget);

    // go over all local sites, create a task for each source site
    for (IndexSnapshotRequestConfig.PartitionRanges partitionRange : partitionRanges) {
      Long localHSId = pidToLocalHSIDs.get(partitionRange.partitionId);

      // The partition may not exist on this node. If so, keep calm and carry on
      if (localHSId != null) {
        // based on the source partition, the predicate is different
        final SnapshotTableTask task =
            new SnapshotTableTask(
                table,
                new SnapshotDataFilter[0],
                createIndexExpressionForTable(table, partitionRange.ranges),
                false);
        task.setTarget(dataTarget);

        placeTask(task, Arrays.asList(localHSId));
      }
    }
  }
示例#8
0
 @Override
 public String getTableName() {
   return m_table.getTypeName();
 }
示例#9
0
  /** Determine which parameter is the partition indicator */
  static void parsePartitionInfo(
      VoltCompiler compiler, Database db, Procedure procedure, String info)
      throws VoltCompilerException {

    assert (procedure.getSinglepartition() == true);

    // check this isn't empty
    if (info.length() == 0) {
      String msg =
          "Missing or Truncated PartitionInfo in attribute for procedure: "
              + procedure.getClassname();
      throw compiler.new VoltCompilerException(msg);
    }

    // split on the colon
    String[] parts = info.split(":");

    // if the colon doesn't split well, we have a problem
    if (parts.length != 2) {
      String msg =
          "Possibly invalid PartitionInfo in attribute for procedure: " + procedure.getClassname();
      throw compiler.new VoltCompilerException(msg);
    }

    // relabel the parts for code readability
    String columnInfo = parts[0].trim();
    int paramIndex = Integer.parseInt(parts[1].trim());

    int paramCount = procedure.getParameters().size();
    if ((paramIndex < 0) || (paramIndex >= paramCount)) {
      String msg =
          "PartitionInfo specifies invalid parameter index for procedure: "
              + procedure.getClassname();
      throw compiler.new VoltCompilerException(msg);
    }

    // locate the parameter
    procedure.setPartitionparameter(paramIndex);

    // split the columninfo
    parts = columnInfo.split("\\.");
    if (parts.length != 2) {
      String msg =
          "Possibly invalid PartitionInfo in attribute for procedure: " + procedure.getClassname();
      throw compiler.new VoltCompilerException(msg);
    }

    // relabel the parts for code readability
    String tableName = parts[0].trim();
    String columnName = parts[1].trim();

    // locate the partition column
    CatalogMap<Table> tables = db.getTables();
    for (Table table : tables) {
      if (table.getTypeName().equalsIgnoreCase(tableName)) {
        CatalogMap<Column> columns = table.getColumns();
        Column partitionColumn = table.getPartitioncolumn();
        if (partitionColumn == null) {
          String msg =
              String.format(
                  "PartitionInfo for procedure %s references table %s which has no partition column (may be replicated).",
                  procedure.getClassname(), table.getTypeName());
          throw compiler.new VoltCompilerException(msg);
        }

        for (Column column : columns) {
          if (column.getTypeName().equalsIgnoreCase(columnName)) {
            if (partitionColumn.getTypeName().equals(column.getTypeName())) {
              procedure.setPartitioncolumn(column);
              procedure.setPartitiontable(table);
              return;
            } else {
              String msg =
                  "PartitionInfo for procedure "
                      + procedure.getClassname()
                      + " refers to a column in schema which is not a partition key.";
              throw compiler.new VoltCompilerException(msg);
            }
          }
        }
      }
    }

    String msg =
        "PartitionInfo for procedure "
            + procedure.getClassname()
            + " refers to a column in schema which can't be found.";
    throw compiler.new VoltCompilerException(msg);
  }
示例#10
0
  @Override
  public String toString() {
    String retval = "SQL:\n\t" + sql + "\n";

    retval += "PARAMETERS:\n\t";
    for (VoltType param : paramList) {
      retval += param.toString() + " ";
    }

    retval += "\nTABLE SOURCES:\n\t";
    for (Table table : tableList) {
      retval += table.getTypeName() + " ";
    }

    retval += "\nSCAN COLUMNS:\n";
    if (scanColumns != null) {
      for (String table : scanColumns.keySet()) {
        retval += "\tTable: " + table + ":\n";
        for (SchemaColumn col : scanColumns.get(table)) {
          retval += "\t\tColumn: " + col.getColumnName() + ": ";
          retval += col.getExpression().toString() + "\n";
        }
      }
    } else {
      retval += "\tALL\n";
    }

    if (where != null) {
      retval += "\nWHERE:\n";
      retval += "\t" + where.toString() + "\n";

      retval += "WHERE SELECTION LIST:\n";
      int i = 0;
      for (AbstractExpression expr : whereSelectionList)
        retval += "\t(" + String.valueOf(i++) + ") " + expr.toString() + "\n";

      retval += "NO TABLE SELECTION LIST:\n";
      i = 0;
      for (AbstractExpression expr : noTableSelectionList)
        retval += "\t(" + String.valueOf(i++) + ") " + expr.toString() + "\n";

      retval += "TABLE FILTER LIST:\n";
      for (Entry<Table, ArrayList<AbstractExpression>> pair : tableFilterList.entrySet()) {
        i = 0;
        retval += "\tTABLE: " + pair.getKey().getTypeName() + "\n";
        for (AbstractExpression expr : pair.getValue())
          retval += "\t\t(" + String.valueOf(i++) + ") " + expr.toString() + "\n";
      }

      retval += "JOIN CLAUSE LIST:\n";
      for (Entry<TablePair, ArrayList<AbstractExpression>> pair : joinSelectionList.entrySet()) {
        i = 0;
        retval +=
            "\tTABLES: "
                + pair.getKey().t1.getTypeName()
                + " and "
                + pair.getKey().t2.getTypeName()
                + "\n";
        for (AbstractExpression expr : pair.getValue())
          retval += "\t\t(" + String.valueOf(i++) + ") " + expr.toString() + "\n";
      }
    }
    return retval;
  }
示例#11
0
  protected boolean createSetupInternal(
      String file_path,
      String file_nonce,
      long txnId,
      Map<Integer, Long> partitionTransactionIds,
      JSONObject jsData,
      SystemProcedureExecutionContext context,
      String hostname,
      final VoltTable result,
      Map<String, Map<Integer, Pair<Long, Long>>> exportSequenceNumbers,
      SiteTracker tracker,
      long timestamp)
      throws IOException {
    assert (SnapshotSiteProcessor.ExecutionSitesCurrentlySnapshotting.isEmpty());

    /*
     * List of partitions to include if this snapshot is
     * going to be deduped. Attempts to break up the work
     * by seeding and RNG selecting
     * a random replica to do the work. Will not work in failure
     * cases, but we don't use dedupe when we want durability.
     */
    List<Long> sitesToInclude = CSVSnapshotWritePlan.computeDedupedLocalSites(txnId, tracker);
    // If there's no work to do on this host, just claim success and get out:
    if (sitesToInclude.isEmpty() && !tracker.isFirstHost()) {
      return false;
    }

    NativeSnapshotWritePlan.createFileBasedCompletionTasks(
        file_path,
        file_nonce,
        txnId,
        partitionTransactionIds,
        context,
        exportSequenceNumbers,
        timestamp);

    final List<Table> tables = SnapshotUtil.getTablesToSave(context.getDatabase());
    final AtomicInteger numTables = new AtomicInteger(tables.size());
    final SnapshotRegistry.Snapshot snapshotRecord =
        SnapshotRegistry.startSnapshot(
            txnId,
            context.getHostId(),
            file_path,
            file_nonce,
            SnapshotFormat.CSV,
            tables.toArray(new Table[0]));

    SnapshotDataTarget sdt = null;
    boolean noTargetsCreated = true;

    final ArrayList<SnapshotTableTask> partitionedSnapshotTasks =
        new ArrayList<SnapshotTableTask>();
    final ArrayList<SnapshotTableTask> replicatedSnapshotTasks = new ArrayList<SnapshotTableTask>();
    for (final Table table : tables) {
      /*
       * For a deduped csv snapshot, only produce the replicated tables on the "leader"
       * host.
       */
      if (table.getIsreplicated() && !tracker.isFirstHost()) {
        snapshotRecord.removeTable(table.getTypeName());
        continue;
      }

      File saveFilePath = null;
      saveFilePath =
          SnapshotUtil.constructFileForTable(
              table, file_path, file_nonce, SnapshotFormat.CSV, context.getHostId());

      try {
        sdt = new SimpleFileSnapshotDataTarget(saveFilePath, !table.getIsreplicated());

        m_targets.add(sdt);
        final Runnable onClose =
            new TargetStatsClosure(sdt, table.getTypeName(), numTables, snapshotRecord);
        sdt.setOnCloseHandler(onClose);

        List<SnapshotDataFilter> filters = new ArrayList<SnapshotDataFilter>();
        filters.add(new CSVSnapshotFilter(CatalogUtil.getVoltTable(table), ',', null));

        final SnapshotTableTask task =
            new SnapshotTableTask(
                table.getRelativeIndex(),
                sdt,
                filters.toArray(new SnapshotDataFilter[filters.size()]),
                table.getIsreplicated(),
                table.getTypeName());

        if (table.getIsreplicated()) {
          replicatedSnapshotTasks.add(task);
        } else {
          partitionedSnapshotTasks.add(task);
        }

        noTargetsCreated = false;
        result.addRow(context.getHostId(), hostname, table.getTypeName(), "SUCCESS", "");
      } catch (IOException ex) {
        handleTargetCreationError(
            sdt, context, file_nonce, hostname, table.getTypeName(), ex, result);
      }
    }

    if (noTargetsCreated) {
      SnapshotRegistry.discardSnapshot(snapshotRecord);
    }

    // CSV snapshots do the partitioned work only on the specified sites for de-duping,
    // but since we've pre-filtered the replicated task list to only contain entries on
    // one node, we can go ahead and distribute them across all of the sites on that node.
    placePartitionedTasks(partitionedSnapshotTasks, sitesToInclude);
    placeReplicatedTasks(replicatedSnapshotTasks, tracker.getSitesForHost(context.getHostId()));
    return noTargetsCreated;
  }
示例#12
0
  static String genrateIndexRow(Table table, Index index) {
    StringBuilder sb = new StringBuilder();
    sb.append("        <tr class='primaryrow2'>");

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

    // type column
    sb.append("<td>");
    sb.append(IndexType.get(index.getType()).toString());
    sb.append("</td>");

    // columns column
    sb.append("<td>");
    List<ColumnRef> cols = CatalogUtil.getSortedCatalogItems(index.getColumns(), "index");
    List<String> columnNames = new ArrayList<String>();
    for (ColumnRef colRef : cols) {
      columnNames.add(colRef.getColumn().getTypeName());
    }
    sb.append(StringUtils.join(columnNames, ", "));
    sb.append("</td>");

    // uniqueness column
    sb.append("<td>");
    if (index.getAssumeunique()) {
      tag(sb, "important", "AssumeUnique");
    } else if (index.getUnique()) {
      tag(sb, "important", "Unique");
    } else {
      tag(sb, "info", "Nonunique");
    }
    sb.append("</td>");

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

    // BUILD THE DROPDOWN FOR THE PLAN/DETAIL TABLE
    sb.append(
        "<tr class='dropdown2'><td colspan='5' id='s-"
            + table.getTypeName().toLowerCase()
            + "-"
            + index.getTypeName().toLowerCase()
            + "--dropdown'>\n");

    IndexAnnotation annotation = (IndexAnnotation) index.getAnnotation();
    if (annotation != null) {
      if (annotation.proceduresThatUseThis.size() > 0) {
        sb.append("<p>Used by procedures: ");
        List<String> procs = new ArrayList<String>();
        for (Procedure proc : annotation.proceduresThatUseThis) {
          procs.add("<a href='#p-" + proc.getTypeName() + "'>" + proc.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(procs, ", "));
        sb.append("</p>");
      }
    }

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

    return sb.toString();
  }
示例#13
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();
  }
示例#14
0
  static String genrateStatementRow(Procedure procedure, Statement statement) {
    StringBuilder sb = new StringBuilder();
    sb.append("        <tr class='primaryrow2'>");

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

    // sql column
    sb.append("<td><tt>");
    sb.append(statement.getSqltext());
    sb.append("</td></tt>");

    // params column
    sb.append("<td>");
    List<StmtParameter> params =
        CatalogUtil.getSortedCatalogItems(statement.getParameters(), "index");
    List<String> paramTypes = new ArrayList<String>();
    for (StmtParameter param : params) {
      paramTypes.add(VoltType.get((byte) param.getJavatype()).name());
    }
    if (paramTypes.size() == 0) {
      sb.append("<i>None</i>");
    }
    sb.append(StringUtils.join(paramTypes, ", "));
    sb.append("</td>");

    // r/w column
    sb.append("<td>");
    if (statement.getReadonly()) {
      tag(sb, "success", "Read");
    } else {
      tag(sb, "warning", "Write");
    }
    sb.append("</td>");

    // attributes
    sb.append("<td>");

    if (!statement.getIscontentdeterministic() || !statement.getIsorderdeterministic()) {
      tag(sb, "inverse", "Determinism");
    }

    if (statement.getSeqscancount() > 0) {
      tag(sb, "important", "Scans");
    }

    sb.append("</td>");

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

    // BUILD THE DROPDOWN FOR THE PLAN/DETAIL TABLE
    sb.append(
        "<tr class='dropdown2'><td colspan='5' id='p-"
            + procedure.getTypeName().toLowerCase()
            + "-"
            + statement.getTypeName().toLowerCase()
            + "--dropdown'>\n");

    sb.append("<div class='well well-small'><h4>Explain Plan:</h4>\n");
    StatementAnnotation annotation = (StatementAnnotation) statement.getAnnotation();
    if (annotation != null) {
      String plan = annotation.explainPlan;
      plan = plan.replace("\n", "<br/>");
      plan = plan.replace(" ", "&nbsp;");

      for (Table t : annotation.tablesRead) {
        String name = t.getTypeName().toUpperCase();
        String link = "\"<a href='#s-" + t.getTypeName() + "'>" + name + "</a>\"";
        plan = plan.replace("\"" + name + "\"", link);
      }
      for (Table t : annotation.tablesUpdated) {
        String name = t.getTypeName().toUpperCase();
        String link = "\"<a href='#s-" + t.getTypeName() + "'>" + name + "</a>\"";
        plan = plan.replace("\"" + name + "\"", link);
      }
      for (Index i : annotation.indexesUsed) {
        Table t = (Table) i.getParent();
        String name = i.getTypeName().toUpperCase();
        String link =
            "\"<a href='#s-" + t.getTypeName() + "-" + i.getTypeName() + "'>" + name + "</a>\"";
        plan = plan.replace("\"" + name + "\"", link);
      }

      sb.append("<tt>").append(plan).append("</tt>");
    } else {
      sb.append("<i>No SQL explain plan found.</i>\n");
    }
    sb.append("</div>\n");

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

    return sb.toString();
  }
示例#15
0
  static String generateSchemaRow(Table table, boolean isExportTable) {
    StringBuilder sb = new StringBuilder();
    sb.append("<tr class='primaryrow'>");

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

    // column 2: type
    sb.append("<td>");
    if (table.getMaterializer() != null) {
      tag(sb, "info", "Materialized View");
    } else {
      if (isExportTable) {
        tag(sb, "inverse", "Export Table");
      } else {
        tag(sb, null, "Table");
      }
    }
    sb.append("</td>");

    // column 3: partitioning
    sb.append("<td style='whitespace: nowrap;'>");
    if (table.getIsreplicated()) {
      tag(sb, "warning", "Replicated");
    } else {
      tag(sb, "success", "Partitioned");
      Column partitionCol = table.getPartitioncolumn();
      if (partitionCol != null) {
        sb.append("<small> on " + partitionCol.getName() + "</small>");
      } else {
        Table matSrc = table.getMaterializer();
        if (matSrc != null) {
          sb.append("<small> with " + matSrc.getTypeName() + "</small>");
        }
      }
    }
    sb.append("</td>");

    // column 4: column count
    sb.append("<td>");
    sb.append(table.getColumns().size());
    sb.append("</td>");

    // column 5: index count
    sb.append("<td>");
    sb.append(table.getIndexes().size());
    sb.append("</td>");

    // column 6: has pkey
    sb.append("<td>");
    boolean found = false;
    for (Constraint constraint : table.getConstraints()) {
      if (ConstraintType.get(constraint.getType()) == ConstraintType.PRIMARY_KEY) {
        found = true;
        break;
      }
    }
    if (found) {
      tag(sb, "info", "Has-PKey");
    } else {
      tag(sb, null, "No-PKey");
    }
    sb.append("</td>");

    // column 6: has tuple limit
    sb.append("<td>");
    if (table.getTuplelimit() != Integer.MAX_VALUE) {
      tag(sb, "info", String.valueOf(table.getTuplelimit()));
    } else {
      tag(sb, null, "No-limit");
    }
    sb.append("</td>");

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

    // BUILD THE DROPDOWN FOR THE DDL / INDEXES DETAIL

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

    TableAnnotation annotation = (TableAnnotation) table.getAnnotation();
    if (annotation != null) {
      // output the DDL
      if (annotation.ddl == null) {
        sb.append("<p>MISSING DDL</p>\n");
      } else {
        String ddl = annotation.ddl;
        sb.append("<p><pre>" + ddl + "</pre></p>\n");
      }

      // make sure procs appear in only one category
      annotation.proceduresThatReadThis.removeAll(annotation.proceduresThatUpdateThis);

      if (annotation.proceduresThatReadThis.size() > 0) {
        sb.append("<p>Read-only by procedures: ");
        List<String> procs = new ArrayList<String>();
        for (Procedure proc : annotation.proceduresThatReadThis) {
          procs.add("<a href='#p-" + proc.getTypeName() + "'>" + proc.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(procs, ", "));
        sb.append("</p>");
      }
      if (annotation.proceduresThatUpdateThis.size() > 0) {
        sb.append("<p>Read/Write by procedures: ");
        List<String> procs = new ArrayList<String>();
        for (Procedure proc : annotation.proceduresThatUpdateThis) {
          procs.add("<a href='#p-" + proc.getTypeName() + "'>" + proc.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(procs, ", "));
        sb.append("</p>");
      }
    }

    if (table.getIndexes().size() > 0) {
      sb.append(generateIndexesTable(table));
    } else {
      sb.append("<p>No indexes defined on table.</p>\n");
    }

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

    return sb.toString();
  }