use of org.voltdb.catalog.Statement in project voltdb by VoltDB.
the class ReportMaker method generateSchemaRow.
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 Streams");
} 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());
// computing unused indexes
int unusedIndexes = 0;
for (Index index : table.getIndexes()) {
IndexAnnotation indexAnnotation = (IndexAnnotation) index.getAnnotation();
if (indexAnnotation == null) {
unusedIndexes++;
}
}
if (unusedIndexes != 0) {
sb.append(" (" + unusedIndexes + " unused)");
}
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()));
if (CatalogUtil.getLimitPartitionRowsDeleteStmt(table) != null) {
sb.append("<small>enforced by DELETE statement</small>");
}
} 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 = escapeHtml4(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>");
}
}
// LIMIT PARTITION ROW statement may also use the index in this table, prepare the information for report
if (!table.getTuplelimitdeletestmt().isEmpty()) {
assert (table.getTuplelimitdeletestmt().size() == 1);
Statement stmt = table.getTuplelimitdeletestmt().iterator().next();
for (String tableDotIndexPair : stmt.getIndexesused().split(",")) {
if (tableDotIndexPair.length() == 0) {
continue;
}
String[] parts = tableDotIndexPair.split("\\.", 2);
assert (parts.length == 2);
if (parts.length != 2) {
continue;
}
String tableName = parts[0];
String indexName = parts[1];
if (!table.getTypeName().equals(tableName)) {
continue;
}
Index i = table.getIndexes().get(indexName);
assert (i != null);
IndexAnnotation ia = (IndexAnnotation) i.getAnnotation();
if (ia == null) {
ia = new IndexAnnotation();
i.setAnnotation(ia);
}
ia.statementsThatUseThis.add(stmt);
}
}
if (table.getIndexes().size() > 0) {
sb.append(generateIndexesTable(table));
} else {
sb.append("<p>No indexes defined on table.</p>\n");
}
// Generate explainview report.
if (table.getMaterializer() != null) {
sb.append(generateExplainViewTable(table));
}
sb.append("</td></tr>\n");
return sb.toString();
}
use of org.voltdb.catalog.Statement in project voltdb by VoltDB.
the class LoadSinglepartitionTable method run.
/**
* These parameters, with the exception of ctx, map to user provided values.
*
* @param ctx Internal API provided to all system procedures.
* @param partitionParam Partitioning parameter used to match invocation to partition.
* @param tableName Name of persistent, parititoned table receiving data.
* @param table A VoltTable with schema matching the target table containing data to load.
* It's assumed that each row in this table partitions to the same partition
* as the other rows, and to the same partition as the partition parameter.
* @param upsertMode True if using upsert instead of insert. If using insert, this proc
* will fail if there are any uniqueness constraints violated.
* @return The number of rows modified. This will be inserts in insert mode, but in upsert
* mode, this will be the sum of inserts and updates.
* @throws VoltAbortException on any failure, but the most common failures are non-matching
* partitioning or unique constraint violations.
*/
public long run(SystemProcedureExecutionContext ctx, byte[] partitionParam, String tableName, byte upsertMode, VoltTable table) throws VoltAbortException {
// if tableName is replicated, fail.
// otherwise, create a VoltTable for each partition and
// split up the incoming table .. then send those partial
// tables to the appropriate sites.
// Get the metadata object for the table in question from the global metadata/config
// store, the Catalog.
Table catTable = ctx.getDatabase().getTables().getIgnoreCase(tableName);
if (catTable == null) {
throw new VoltAbortException("Table not present in catalog.");
}
// if tableName is replicated, fail.
if (catTable.getIsreplicated()) {
throw new VoltAbortException(String.format("LoadSinglepartitionTable incompatible with replicated table %s.", tableName));
}
// convert from 8bit signed integer (byte) to boolean
boolean isUpsert = (upsertMode != 0);
// upsert requires a primary key on the table to work
if (isUpsert) {
boolean hasPkey = false;
for (Constraint c : catTable.getConstraints()) {
if (c.getType() == ConstraintType.PRIMARY_KEY.getValue()) {
hasPkey = true;
break;
}
}
if (!hasPkey) {
throw new VoltAbortException(String.format("The --update argument cannot be used for LoadingSinglePartionTable because the table %s does not have a primary key. " + "Either remove the --update argument or add a primary key to the table.", tableName));
}
}
// action should be either "insert" or "upsert"
final String action = (isUpsert ? "upsert" : "insert");
// fix any case problems
tableName = catTable.getTypeName();
// check that the schema of the input matches
int columnCount = table.getColumnCount();
//////////////////////////////////////////////////////////////////////
// Find the insert/upsert statement for this table
// This is actually the big trick this procedure does.
// It borrows the insert plan from the auto-generated insert procedure
// named "TABLENAME.insert" or "TABLENAME.upsert".
// We don't like it when users do this stuff, but it is safe in this
// case.
//
// Related code to read is org.voltdb.DefaultProcedureManager, which
// manages all of the default (CRUD) procedures created lazily for
// each table in the database, including the plans used here.
//
String crudProcName = String.format("%s.%s", tableName, action);
Procedure p = ctx.ensureDefaultProcLoaded(crudProcName);
if (p == null) {
throw new VoltAbortException(String.format("Unable to locate auto-generated CRUD %s statement for table %s", action, tableName));
}
// statements of all single-statement procs are named "sql"
Statement catStmt = p.getStatements().get(VoltDB.ANON_STMT_NAME);
if (catStmt == null) {
throw new VoltAbortException(String.format("Unable to find SQL statement for found table %s: BAD", tableName));
}
// Create a SQLStmt instance on the fly
// This unusual to do, as they are typically required to be final instance variables.
// This only works because the SQL text and plan is identical from the borrowed procedure.
SQLStmt stmt = new SQLStmt(catStmt.getSqltext());
m_runner.initSQLStmt(stmt, catStmt);
long queued = 0;
long executed = 0;
// make sure at the start of the table
table.resetRowPosition();
// iterate over the rows queueing a sql statement for each row to insert
for (int i = 0; table.advanceRow(); ++i) {
Object[] params = new Object[columnCount];
// get the parameters from the volt table
for (int col = 0; col < columnCount; ++col) {
params[col] = table.get(col, table.getColumnType(col));
}
// queue an insert and count it
voltQueueSQL(stmt, params);
++queued;
// 100 is an arbitrary number
if ((i % 100) == 0) {
executed += executeSQL();
}
}
// execute any leftover batched statements
if (queued > executed) {
executed += executeSQL();
}
return executed;
}
use of org.voltdb.catalog.Statement in project voltdb by VoltDB.
the class RealVoltDB method printDiagnosticInformation.
public static void printDiagnosticInformation(CatalogContext context, String procName, LoadedProcedureSet procSet) {
StringBuilder sb = new StringBuilder();
final CatalogMap<Procedure> catalogProcedures = context.database.getProcedures();
PureJavaCrc32C crc = new PureJavaCrc32C();
sb.append("Statements within " + procName + ": ").append("\n");
for (final Procedure proc : catalogProcedures) {
if (proc.getTypeName().equals(procName)) {
for (Statement stmt : proc.getStatements()) {
// compute hash for determinism check
crc.reset();
String sqlText = stmt.getSqltext();
crc.update(sqlText.getBytes(Constants.UTF8ENCODING));
int hash = (int) crc.getValue();
sb.append("Statement Hash: ").append(hash);
sb.append(", Statement SQL: ").append(sqlText);
for (PlanFragment frag : stmt.getFragments()) {
byte[] planHash = Encoder.hexDecode(frag.getPlanhash());
long planId = ActivePlanRepository.getFragmentIdForPlanHash(planHash);
String stmtText = ActivePlanRepository.getStmtTextForPlanHash(planHash);
byte[] jsonPlan = ActivePlanRepository.planForFragmentId(planId);
sb.append(", Plan Fragment Id:").append(planId);
sb.append(", Plan Stmt Text:").append(stmtText);
sb.append(", Json Plan:").append(new String(jsonPlan));
}
sb.append("\n");
}
}
}
sb.append("Default CRUD Procedures: ").append("\n");
for (Entry<String, Procedure> pair : context.m_defaultProcs.m_defaultProcMap.entrySet()) {
crc.reset();
String sqlText = DefaultProcedureManager.sqlForDefaultProc(pair.getValue());
crc.update(sqlText.getBytes(Constants.UTF8ENCODING));
int hash = (int) crc.getValue();
sb.append("Statement Hash: ").append(hash);
sb.append(", Statement SQL: ").append(sqlText);
ProcedureRunner runner = procSet.getProcByName(pair.getValue().getTypeName());
for (Statement stmt : runner.getCatalogProcedure().getStatements()) {
for (PlanFragment frag : stmt.getFragments()) {
byte[] planHash = Encoder.hexDecode(frag.getPlanhash());
long planId = ActivePlanRepository.getFragmentIdForPlanHash(planHash);
String stmtText = ActivePlanRepository.getStmtTextForPlanHash(planHash);
byte[] jsonPlan = ActivePlanRepository.planForFragmentId(planId);
sb.append(", Plan Fragment Id:").append(planId);
sb.append(", Plan Stmt Text:").append(stmtText);
sb.append(", Json Plan:").append(new String(jsonPlan));
}
}
sb.append("\n");
}
hostLog.error(sb.toString());
}
use of org.voltdb.catalog.Statement in project voltdb by VoltDB.
the class VoltCompiler method compileProcedures.
/**
* @param db the database entry in the catalog
* @param hsql an interface to the hsql frontend, initialized and potentially reused by the caller.
* @param classDependencies
* @param voltDdlTracker non-standard VoltDB schema annotations
* @param whichProcs indicates which ddl-defined procedures to load: none, single-statement, or all
* @throws VoltCompilerException
*/
private void compileProcedures(Database db, HSQLInterface hsql, Collection<ProcedureDescriptor> allProcs, Collection<Class<?>> classDependencies, DdlProceduresToLoad whichProcs, CatalogMap<Procedure> prevProcsIfAny, InMemoryJarfile jarOutput) throws VoltCompilerException {
// build a cache of previous SQL stmts
m_previousCatalogStmts.clear();
if (prevProcsIfAny != null) {
for (Procedure prevProc : prevProcsIfAny) {
for (Statement prevStmt : prevProc.getStatements()) {
addStatementToCache(prevStmt);
}
}
}
// dependencies for its "dry run" on an unchanged application ddl file.
if (whichProcs == DdlProceduresToLoad.ALL_DDL_PROCEDURES) {
// Add all the class dependencies to the output jar
for (final Class<?> classDependency : classDependencies) {
addClassToJar(jarOutput, classDependency);
}
}
final List<ProcedureDescriptor> procedures = new ArrayList<>();
procedures.addAll(allProcs);
// Actually parse and handle all the Procedures
for (final ProcedureDescriptor procedureDescriptor : procedures) {
final String procedureName = procedureDescriptor.m_className;
if (procedureDescriptor.m_singleStmt == null) {
m_currentFilename = procedureName.substring(procedureName.lastIndexOf('.') + 1);
m_currentFilename += ".class";
} else if (whichProcs == DdlProceduresToLoad.ONLY_SINGLE_STATEMENT_PROCEDURES) {
// for all the single-statement procedures of an unchanged application ddl file.
continue;
} else {
m_currentFilename = procedureName;
}
ProcedureCompiler.compile(this, hsql, m_estimates, db, procedureDescriptor, jarOutput);
}
// done handling files
m_currentFilename = NO_FILENAME;
// allow gc to reclaim any cache memory here
m_previousCatalogStmts.clear();
}
use of org.voltdb.catalog.Statement in project voltdb by VoltDB.
the class VoltCompiler method getCachedStatement.
/** Look for a match from the previous catalog that matches the key + sql */
Statement getCachedStatement(String keyPrefix, String sql) {
String key = keyPrefix + sql;
Statement candidate = m_previousCatalogStmts.get(key);
if (candidate == null) {
++m_stmtCacheMisses;
return null;
}
// check that no underlying tables have been modified since the proc had been compiled
String[] tablesTouched = candidate.getTablesread().split(",");
for (String tableName : tablesTouched) {
if (m_dirtyTables.contains(tableName.toLowerCase())) {
++m_stmtCacheMisses;
return null;
}
}
tablesTouched = candidate.getTablesupdated().split(",");
for (String tableName : tablesTouched) {
if (m_dirtyTables.contains(tableName.toLowerCase())) {
++m_stmtCacheMisses;
return null;
}
}
++m_stmtCacheHits;
//printStmtCacheStats();
return candidate;
}
Aggregations