use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class ReportMaker method genrateIndexRow.
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>");
// attribute column
sb.append("<td>");
if (index.getAssumeunique()) {
tag(sb, "success", "AssumeUnique");
} else if (index.getUnique()) {
tag(sb, "success", "Unique");
} else {
tag(sb, "info", "Nonunique");
}
IndexAnnotation annotation = (IndexAnnotation) index.getAnnotation();
if (annotation == null) {
sb.append(" ");
tag(sb, "important", "Unused");
}
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");
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>");
}
if (annotation.statementsThatUseThis.size() > 0) {
assert (annotation.statementsThatUseThis.size() == 1);
sb.append("<p>Used by the LIMIT PARTITION ROWS Statement</p>");
}
}
sb.append("</td></tr>\n");
return sb.toString();
}
use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class SubPlanAssembler method determineIndexOrdering.
/**
* Determine if an index, which is in the AccessPath argument
* retval, can satisfy a parsed select statement's order by or
* window function ordering requirements.
*
* @param table only used here to validate base table names of ORDER BY columns' .
* @param bindingsForOrder restrictions on parameter settings that are prerequisite to the
* any ordering optimization determined here
* @param keyComponentCount the length of indexedExprs or indexedColRefs,
* ONE of which must be valid
* @param indexedExprs expressions for key components in the general case
* @param indexedColRefs column references for key components in the simpler case
* @param retval the eventual result of getRelevantAccessPathForIndex,
* the bearer of a (tentative) sortDirection determined here
* @param orderSpoilers positions of key components which MAY invalidate the tentative
* sortDirection
* @param bindingsForOrder restrictions on parameter settings that are prerequisite to the
* any ordering optimization determined here.
* @return the number of discovered orderSpoilers that will need to be recovered from,
* to maintain the established sortDirection - always 0 if no sort order was determined.
*/
private int determineIndexOrdering(StmtTableScan tableScan, int keyComponentCount, List<AbstractExpression> indexedExprs, List<ColumnRef> indexedColRefs, AccessPath retval, int[] orderSpoilers, List<AbstractExpression> bindingsForOrder) {
// Organize a little bit.
ParsedSelectStmt pss = (m_parsedStmt instanceof ParsedSelectStmt) ? ((ParsedSelectStmt) m_parsedStmt) : null;
boolean hasOrderBy = (m_parsedStmt.hasOrderByColumns() && (!m_parsedStmt.orderByColumns().isEmpty()));
boolean hasWindowFunctions = (pss != null && pss.hasWindowFunctionExpression());
//
if (!hasOrderBy && !hasWindowFunctions) {
return 0;
}
//
// We make a definition. Let S1 and S2 be sequences of expressions,
// and OS be an increasing sequence of indices into S2. Let erase(S2, OS) be
// the sequence of expressions which results from erasing all S2
// expressions whose indices are in OS. We say *S1 is a prefix of
// S2 with OS-singular values* if S1 is a prefix of erase(S2, OS).
// That is to say, if we erase the expressions in S2 whose indices are
// in OS, S1 is a prefix of the result.
//
// What expressions must we match?
// 1.) We have the parameters indexedExpressions and indexedColRefs.
// These are the expressions or column references in an index.
// Exactly one of them is non-null. Since these are both an
// indexed sequence of expression-like things, denote the
// non-null one IS.
// What expressions do we care about? We have two kinds.
// 1.) The expressions from the statement level order by clause, OO.
// This sequence of expressions must be a prefix of IS with OS
// singular values for some sequence OS. The sequence OS will be
// called the order spoilers. Later on we will test that the
// index expressions at the positions in OS can have only a
// single value.
// 2.) The expressions in a window function's partition by list, WP,
// followed by the expressions in the window function's
// order by list, WO. The partition by functions are a set not
// a sequence. We need to find a sequence of expressions, S,
// such that S is a permutation of P and S+WO is a singular prefix
// of IS.
//
// So, in both cases, statement level order by and window function, we are looking for
// a sequence of expressions, S1, and a list of IS indices, OS, such
// that S1 is a prefix of IS with OS-singular values.
//
// If the statement level order by expression list is not a prefix of
// the index, we still care to know about window functions. The reverse
// is not true. If there are window functions but they all fail to match the index,
// we must give up on this index, even if the statement level order
// by list is still matching. This is because the window functions will
// require sorting before the statement level order by clause's
// sort, and this window function sort will invalidate the statement level
// order by sort.
//
// Note also that it's possible that the statement level order by and
// the window function order by are compatible. So this index may provide
// all the sorting needed.
//
// There need to be enough indexed expressions to provide full sort coverage.
// More indexed expressions are ok.
//
// We keep a scoreboard which keeps track of everything. All the window
// functions and statement level order by functions are kept in the scoreboard.
//
WindowFunctionScoreboard windowFunctionScores = new WindowFunctionScoreboard(m_parsedStmt, tableScan);
// indexCtr is an index into the index expressions or columns.
for (int indexCtr = 0; !windowFunctionScores.isDone() && indexCtr < keyComponentCount; indexCtr += 1) {
// Figure out what to do with index expression or column at indexCtr.
// First, fetch it out.
AbstractExpression indexExpr = (indexedExprs == null) ? null : indexedExprs.get(indexCtr);
ColumnRef indexColRef = (indexedColRefs == null) ? null : indexedColRefs.get(indexCtr);
// Then see if it matches something. If
// this doesn't match one thing it may match
// another. If it doesn't match anything, it may
// be an order spoiler, which we will maintain in
// the scoreboard.
windowFunctionScores.matchIndexEntry(new ExpressionOrColumn(indexCtr, tableScan, indexExpr, SortDirectionType.INVALID, indexColRef));
}
//
return windowFunctionScores.getResult(retval, orderSpoilers, bindingsForOrder);
}
use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class CatalogSchemaTools method toSchema.
/**
* Convert a Table catalog object into the proper SQL DDL, including all indexes,
* constraints, and foreign key references.
* Also returns just the CREATE TABLE statement, since, like all good methods,
* it should have two purposes....
* It would be nice to have a separate method to just generate the CREATE TABLE,
* but we use that pass to also figure out what separate constraint and index
* SQL DDL needs to be generated, so instead, we opt to build the CREATE TABLE DDL
* separately as we go here, and then fill it in to the StringBuilder being used
* to construct the full canonical DDL at the appropriate time.
* @param sb - the schema being built
* @param catalog_tbl - object to be analyzed
* @param viewQuery - the Query if this Table is a View
* @param isExportOnly Is this a export table.
* @param streamPartitionColumn stream partition column
* @param streamTarget - true if this Table is an Export Table
* @return SQL Schema text representing the CREATE TABLE statement to generate the table
*/
public static String toSchema(StringBuilder sb, Table catalog_tbl, String viewQuery, boolean isExportOnly, String streamPartitionColumn, String streamTarget) {
assert (!catalog_tbl.getColumns().isEmpty());
boolean tableIsView = (viewQuery != null);
// We need the intermediate results of building the table schema string so that
// we can return the full CREATE TABLE statement, so accumulate it separately
final StringBuilder table_sb = new StringBuilder();
final Set<Index> skip_indexes = new HashSet<>();
final Set<Constraint> skip_constraints = new HashSet<>();
if (tableIsView) {
table_sb.append("CREATE VIEW ").append(catalog_tbl.getTypeName()).append(" (");
} else {
if (isExportOnly) {
table_sb.append("CREATE STREAM ").append(catalog_tbl.getTypeName());
if (streamPartitionColumn != null && viewQuery == null) {
table_sb.append(" PARTITION ON COLUMN ").append(streamPartitionColumn);
}
//Default target means no target.
if (streamTarget != null && !streamTarget.equalsIgnoreCase(Constants.DEFAULT_EXPORT_CONNECTOR_NAME)) {
table_sb.append(" EXPORT TO TARGET ").append(streamTarget);
}
} else {
table_sb.append("CREATE TABLE ").append(catalog_tbl.getTypeName());
}
table_sb.append(" (");
}
// Columns
String add = "\n";
for (Column catalog_col : CatalogUtil.getSortedCatalogItems(catalog_tbl.getColumns(), "index")) {
VoltType col_type = VoltType.get((byte) catalog_col.getType());
if (tableIsView) {
table_sb.append(add).append(spacer).append(catalog_col.getTypeName());
add = ",\n";
continue;
}
table_sb.append(add).append(spacer).append(catalog_col.getTypeName()).append(" ").append(col_type.toSQLString()).append(col_type.isVariableLength() && catalog_col.getSize() > 0 ? "(" + catalog_col.getSize() + (catalog_col.getInbytes() ? " BYTES" : "") + ")" : "");
// Default value
String defaultvalue = catalog_col.getDefaultvalue();
//VoltType defaulttype = VoltType.get((byte)catalog_col.getDefaulttype());
boolean nullable = catalog_col.getNullable();
// TODO: Shouldn't have to check whether the string contains "null"
if (defaultvalue == null) {
} else if (defaultvalue.toLowerCase().equals("null") && nullable) {
defaultvalue = null;
} else {
if (col_type == VoltType.TIMESTAMP) {
if (defaultvalue.startsWith("CURRENT_TIMESTAMP")) {
defaultvalue = "CURRENT_TIMESTAMP";
} else {
assert (defaultvalue.matches("[0-9]+"));
long epoch = Long.parseLong(defaultvalue);
Date d = new Date(epoch / 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
defaultvalue = "\'" + sdf.format(d) + "." + StringUtils.leftPad(String.valueOf(epoch % 1000000), 6, "0") + "\'";
}
} else {
// XXX: if (defaulttype != VoltType.VOLTFUNCTION) {
// TODO: Escape strings properly
defaultvalue = defaultvalue.replace("\'", "\'\'");
defaultvalue = "'" + defaultvalue + "'";
}
}
if (defaultvalue == null) {
table_sb.append((!nullable ? " NOT NULL" : ""));
} else {
table_sb.append(" DEFAULT ").append(defaultvalue != null ? defaultvalue : "NULL").append(!nullable ? " NOT NULL" : "");
}
// Single-column constraints
for (ConstraintRef catalog_const_ref : catalog_col.getConstraints()) {
Constraint catalog_const = catalog_const_ref.getConstraint();
ConstraintType const_type = ConstraintType.get(catalog_const.getType());
// Check if there is another column in our table with the same constraint
// If there is, then we need to add it to the end of the table definition
boolean found = false;
for (Column catalog_other_col : catalog_tbl.getColumns()) {
if (catalog_other_col.equals(catalog_col))
continue;
if (catalog_other_col.getConstraints().getIgnoreCase(catalog_const.getTypeName()) != null) {
found = true;
break;
}
}
if (!found) {
switch(const_type) {
case FOREIGN_KEY:
{
Table catalog_fkey_tbl = catalog_const.getForeignkeytable();
Column catalog_fkey_col = null;
for (ColumnRef ref : catalog_const.getForeignkeycols()) {
catalog_fkey_col = ref.getColumn();
// Nasty hack to get first item
break;
}
assert (catalog_fkey_col != null);
table_sb.append(" REFERENCES ").append(catalog_fkey_tbl.getTypeName()).append(" (").append(catalog_fkey_col.getTypeName()).append(")");
skip_constraints.add(catalog_const);
break;
}
default:
}
}
}
add = ",\n";
}
// Constraints
for (Constraint catalog_const : catalog_tbl.getConstraints()) {
if (skip_constraints.contains(catalog_const))
continue;
ConstraintType const_type = ConstraintType.get(catalog_const.getType());
// Primary Keys / Unique Constraints
if (const_type == ConstraintType.PRIMARY_KEY || const_type == ConstraintType.UNIQUE) {
Index catalog_idx = catalog_const.getIndex();
if (!tableIsView) {
// Get the ConstraintType.
table_sb.append(add).append(spacer);
if (!catalog_const.getTypeName().startsWith(HSQLInterface.AUTO_GEN_PREFIX)) {
table_sb.append("CONSTRAINT ").append(catalog_const.getTypeName()).append(" ");
}
if (const_type == ConstraintType.PRIMARY_KEY || const_type == ConstraintType.UNIQUE) {
if (const_type == ConstraintType.PRIMARY_KEY) {
table_sb.append("PRIMARY KEY (");
} else {
if (catalog_idx.getAssumeunique()) {
table_sb.append("ASSUMEUNIQUE (");
} else {
table_sb.append("UNIQUE (");
}
}
String col_add = "";
if (catalog_idx.getExpressionsjson() != null && !catalog_idx.getExpressionsjson().equals("")) {
String exprStrings = new String();
StmtTargetTableScan tableScan = new StmtTargetTableScan(catalog_tbl);
try {
List<AbstractExpression> expressions = AbstractExpression.fromJSONArrayString(catalog_idx.getExpressionsjson(), tableScan);
String sep = "";
for (AbstractExpression expr : expressions) {
exprStrings += sep + expr.explain(catalog_tbl.getTypeName());
sep = ",";
}
} catch (JSONException e) {
}
table_sb.append(col_add).append(exprStrings);
} else {
for (ColumnRef catalog_colref : CatalogUtil.getSortedCatalogItems(catalog_idx.getColumns(), "index")) {
table_sb.append(col_add).append(catalog_colref.getColumn().getTypeName());
col_add = ", ";
}
// FOR
}
table_sb.append(")");
}
}
if (catalog_idx.getTypeName().startsWith(HSQLInterface.AUTO_GEN_PREFIX) || catalog_idx.getTypeName().startsWith(HSQLInterface.AUTO_GEN_MATVIEW)) {
skip_indexes.add(catalog_idx);
}
// Foreign Key
} else if (const_type == ConstraintType.FOREIGN_KEY) {
Table catalog_fkey_tbl = catalog_const.getForeignkeytable();
String col_add = "";
String our_columns = "";
String fkey_columns = "";
for (ColumnRef catalog_colref : catalog_const.getForeignkeycols()) {
// The name of the ColumnRef is the column in our base table
Column our_column = catalog_tbl.getColumns().getIgnoreCase(catalog_colref.getTypeName());
assert (our_column != null);
our_columns += col_add + our_column.getTypeName();
Column fkey_column = catalog_colref.getColumn();
assert (fkey_column != null);
fkey_columns += col_add + fkey_column.getTypeName();
col_add = ", ";
}
table_sb.append(add).append(spacer + "CONSTRAINT ").append(catalog_const.getTypeName()).append(" FOREIGN KEY (").append(our_columns).append(") REFERENCES ").append(catalog_fkey_tbl.getTypeName()).append(" (").append(fkey_columns).append(")");
}
skip_constraints.add(catalog_const);
}
if (catalog_tbl.getTuplelimit() != Integer.MAX_VALUE) {
table_sb.append(add).append(spacer + "LIMIT PARTITION ROWS ").append(String.valueOf(catalog_tbl.getTuplelimit()));
String deleteStmt = CatalogUtil.getLimitPartitionRowsDeleteStmt(catalog_tbl);
if (deleteStmt != null) {
if (deleteStmt.endsWith(";")) {
// StatementCompiler appends the semicolon, we don't want it here.
deleteStmt = deleteStmt.substring(0, deleteStmt.length() - 1);
}
table_sb.append("\n" + spacer + spacer + "EXECUTE (").append(deleteStmt).append(")");
}
}
if (viewQuery != null) {
table_sb.append("\n) AS \n");
table_sb.append(spacer).append(viewQuery).append(";\n");
} else {
table_sb.append("\n);\n");
}
// We've built the full CREATE TABLE statement for this table,
// Append the generated table schema to the canonical DDL StringBuilder
sb.append(table_sb.toString());
// Partition Table for regular tables (non-streams)
if (catalog_tbl.getPartitioncolumn() != null && viewQuery == null && !isExportOnly) {
sb.append("PARTITION TABLE ").append(catalog_tbl.getTypeName()).append(" ON COLUMN ").append(catalog_tbl.getPartitioncolumn().getTypeName()).append(";\n");
}
// All other Indexes
for (Index catalog_idx : catalog_tbl.getIndexes()) {
if (skip_indexes.contains(catalog_idx))
continue;
if (catalog_idx.getUnique()) {
if (catalog_idx.getAssumeunique()) {
sb.append("CREATE ASSUMEUNIQUE INDEX ");
} else {
sb.append("CREATE UNIQUE INDEX ");
}
} else {
sb.append("CREATE INDEX ");
}
sb.append(catalog_idx.getTypeName()).append(" ON ").append(catalog_tbl.getTypeName()).append(" (");
add = "";
String jsonstring = catalog_idx.getExpressionsjson();
if (jsonstring.isEmpty()) {
for (ColumnRef catalog_colref : CatalogUtil.getSortedCatalogItems(catalog_idx.getColumns(), "index")) {
sb.append(add).append(catalog_colref.getColumn().getTypeName());
add = ", ";
}
} else {
List<AbstractExpression> indexedExprs = null;
try {
indexedExprs = AbstractExpression.fromJSONArrayString(jsonstring, new StmtTargetTableScan(catalog_tbl));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (indexedExprs != null) {
for (AbstractExpression expr : indexedExprs) {
sb.append(add).append(expr.explain(catalog_tbl.getTypeName()));
add = ", ";
}
}
}
sb.append(")");
String jsonPredicate = catalog_idx.getPredicatejson();
if (!jsonPredicate.isEmpty()) {
try {
AbstractExpression predicate = AbstractExpression.fromJSONString(jsonPredicate, new StmtTargetTableScan(catalog_tbl));
sb.append(" WHERE ").append(predicate.explain(catalog_tbl.getTypeName()));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
sb.append(";\n");
}
if (catalog_tbl.getIsdred()) {
sb.append("DR TABLE ").append(catalog_tbl.getTypeName()).append(";\n");
}
sb.append("\n");
// statement to whoever might be interested (DDLCompiler, I'm looking in your direction)
return table_sb.toString();
}
use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class DefaultProcedureManager method generateCrudPKeyWhereClause.
/**
* Helper to generate a WHERE pkey_col1 = ?, pkey_col2 = ? ...; clause.
* @param partitioncolumn partitioning column for the table
* @param pkey constraint from the catalog
* @param paramoffset 0-based counter of parameters in the full sql statement so far
* @param sb string buffer accumulating the sql statement
* @return offset in the index of the partition column
*/
private static int generateCrudPKeyWhereClause(Column partitioncolumn, Constraint pkey, StringBuilder sb) {
// Sort the catalog index columns by index column order.
ArrayList<ColumnRef> indexColumns = new ArrayList<ColumnRef>(pkey.getIndex().getColumns().size());
for (ColumnRef c : pkey.getIndex().getColumns()) {
indexColumns.add(c);
}
Collections.sort(indexColumns, new ColumnRefComparator());
boolean first = true;
int partitionOffset = -1;
sb.append(" WHERE ");
for (ColumnRef pkc : indexColumns) {
if (!first)
sb.append(" AND ");
first = false;
sb.append("(" + pkc.getColumn().getName() + " = ?" + ")");
if (pkc.getColumn() == partitioncolumn) {
partitionOffset = pkc.getIndex();
}
}
return partitionOffset;
}
use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class DefaultProcedureManager method build.
private void build() {
for (Table table : m_db.getTables()) {
String prefix = table.getTypeName() + '.';
if (CatalogUtil.isTableExportOnly(m_db, table)) {
Column partitioncolumn = table.getPartitioncolumn();
if (partitioncolumn != null) {
int partitionIndex = partitioncolumn.getIndex();
addShimProcedure(prefix + "insert", table, null, true, partitionIndex, partitioncolumn, false);
} else {
addShimProcedure(prefix + "insert", table, null, true, -1, null, false);
}
continue;
}
// skip views XXX why no get by pkey?
if (table.getMaterializer() != null) {
continue;
}
// select/delete/update crud requires pkey. Pkeys are stored as constraints.
final CatalogMap<Constraint> constraints = table.getConstraints();
final Iterator<Constraint> it = constraints.iterator();
Constraint pkey = null;
while (it.hasNext()) {
Constraint constraint = it.next();
if (constraint.getType() == ConstraintType.PRIMARY_KEY.getValue()) {
pkey = constraint;
break;
}
}
if (table.getIsreplicated()) {
// Creating multi-partition insert procedures for replicated table
addShimProcedure(prefix + "insert", table, null, true, -1, null, false);
// Creating multi-partition delete/update/upsert procedures for replicated table with pkey
if (pkey != null) {
addShimProcedure(prefix + "delete", table, pkey, false, -1, null, false);
addShimProcedure(prefix + "update", table, pkey, true, -1, null, false);
addShimProcedure(prefix + "upsert", table, null, true, -1, null, false);
}
continue;
}
// get the partition column
final Column partitioncolumn = table.getPartitioncolumn();
// this check is an accommodation for some tests that don't flesh out a catalog
if (partitioncolumn == null) {
continue;
}
final int partitionIndex = partitioncolumn.getIndex();
// all partitioned tables get insert crud procs
addShimProcedure(prefix + "insert", table, null, true, partitionIndex, partitioncolumn, false);
// Skip creation of CRUD select/delete/update for partitioned table if no primary key is declared.
if (pkey == null) {
continue;
}
// Primary key must include the partition column for the table
// for select/delete/update
int pkeyPartitionIndex = -1;
CatalogMap<ColumnRef> pkeycols = pkey.getIndex().getColumns();
Iterator<ColumnRef> pkeycolsit = pkeycols.iterator();
while (pkeycolsit.hasNext()) {
ColumnRef colref = pkeycolsit.next();
if (colref.getColumn().equals(partitioncolumn)) {
pkeyPartitionIndex = colref.getIndex();
break;
}
}
// if primary key does not include the partitioning column.
if (pkeyPartitionIndex < 0) {
continue;
}
int columnCount = table.getColumns().size();
// select, delete, update and upsert here (insert generated above)
// these next 3 prefix params with the pkey so the partition on the index of the partition column
// within the pkey
addShimProcedure(prefix + "select", table, pkey, false, pkeyPartitionIndex, partitioncolumn, true);
addShimProcedure(prefix + "delete", table, pkey, false, pkeyPartitionIndex, partitioncolumn, false);
// update partitions on the pkey column after the regular column
addShimProcedure(prefix + "update", table, pkey, true, columnCount + pkeyPartitionIndex, partitioncolumn, false);
// upsert partitions like a regular insert
addShimProcedure(prefix + "upsert", table, null, true, partitionIndex, partitioncolumn, false);
}
}
Aggregations