use of org.voltdb.compiler.VoltCompiler.VoltCompilerException in project voltdb by VoltDB.
the class DDLCompiler method loadSchema.
/**
* Compile a DDL schema from an abstract reader
* @param reader abstract DDL reader
* @param db database
* @param whichProcs which type(s) of procedures to load
* @throws VoltCompiler.VoltCompilerException
*/
void loadSchema(Reader reader, Database db, DdlProceduresToLoad whichProcs) throws VoltCompiler.VoltCompilerException {
m_currLineNo = 1;
DDLStatement stmt = getNextStatement(reader, m_compiler);
while (stmt != null) {
// Some statements are processed by VoltDB and the rest are handled by HSQL.
processVoltDBStatements(db, whichProcs, stmt);
stmt = getNextStatement(reader, m_compiler);
}
try {
reader.close();
} catch (IOException e) {
throw m_compiler.new VoltCompilerException("Error closing schema file");
}
// process extra classes
m_tracker.addExtraClasses(m_classMatcher.getMatchedClassList());
// possibly save some memory
m_classMatcher.clear();
}
use of org.voltdb.compiler.VoltCompiler.VoltCompilerException in project voltdb by VoltDB.
the class DDLCompiler method processCreateStreamStatement.
/**
* Process a VoltDB-specific create stream DDL statement
*
* @param stmt
* DDL statement string
* @param db
* @param whichProcs
* @throws VoltCompilerException
*/
private void processCreateStreamStatement(DDLStatement stmt, Database db, DdlProceduresToLoad whichProcs) throws VoltCompilerException {
String statement = stmt.statement;
Matcher statementMatcher = SQLParser.matchCreateStream(statement);
if (statementMatcher.matches()) {
// check the table portion
String tableName = checkIdentifierStart(statementMatcher.group(1), statement);
String targetName = null;
String columnName = null;
// Parse the EXPORT and PARTITION clauses.
if ((statementMatcher.groupCount() > 1) && (statementMatcher.group(2) != null) && (!statementMatcher.group(2).isEmpty())) {
String clauses = statementMatcher.group(2);
Matcher matcher = SQLParser.matchAnyCreateStreamStatementClause(clauses);
int start = 0;
while (matcher.find(start)) {
start = matcher.end();
if (matcher.group(1) != null) {
// Add target info if it's an Export clause. Only one is allowed
if (targetName != null) {
throw m_compiler.new VoltCompilerException("Only one Export clause is allowed for CREATE STREAM.");
}
targetName = matcher.group(1);
} else {
// Add partition info if it's a PARTITION clause. Only one is allowed.
if (columnName != null) {
throw m_compiler.new VoltCompilerException("Only one PARTITION clause is allowed for CREATE STREAM.");
}
columnName = matcher.group(2);
}
}
}
VoltXMLElement tableXML = m_schema.findChild("table", tableName.toUpperCase());
if (tableXML != null) {
tableXML.attributes.put("stream", "true");
} else {
throw m_compiler.new VoltCompilerException(String.format("Invalid STREAM statement: table %s does not exist", tableName));
}
// process partition if specified
if (columnName != null) {
tableXML.attributes.put("partitioncolumn", columnName.toUpperCase());
// Column validity check done by VoltCompiler in post-processing
// mark the table as dirty for the purposes of caching sql statements
m_compiler.markTableAsDirty(tableName);
}
// process export
targetName = (targetName != null) ? checkIdentifierStart(targetName, statement) : Constants.DEFAULT_EXPORT_CONNECTOR_NAME;
if (tableXML.attributes.containsKey("drTable") && "ENABLE".equals(tableXML.attributes.get("drTable"))) {
throw m_compiler.new VoltCompilerException(String.format("Invalid CREATE STREAM statement: table %s is a DR table.", tableName));
} else {
tableXML.attributes.put("export", targetName);
}
} else {
throw m_compiler.new VoltCompilerException(String.format("Invalid CREATE STREAM statement: \"%s\", " + "expected syntax: CREATE STREAM <table> [PARTITION ON COLUMN <column-name>] [EXPORT TO TARGET <target>] (column datatype, ...); ", statement.substring(0, statement.length() - 1)));
}
}
use of org.voltdb.compiler.VoltCompiler.VoltCompilerException in project voltdb by VoltDB.
the class DDLCompiler method checkValidPartitionTableIndex.
private void checkValidPartitionTableIndex(Index index, Column partitionCol, String tableName) throws VoltCompilerException {
// skip checking for non-unique indexes.
if (!index.getUnique()) {
return;
}
boolean containsPartitionColumn = false;
String jsonExpr = index.getExpressionsjson();
// if this is a pure-column index...
if (jsonExpr.isEmpty()) {
for (ColumnRef cref : index.getColumns()) {
Column col = cref.getColumn();
// unique index contains partitioned column
if (col.equals(partitionCol)) {
containsPartitionColumn = true;
break;
}
}
} else // if this is a fancy expression-based index...
{
try {
int partitionColIndex = partitionCol.getIndex();
List<AbstractExpression> indexExpressions = AbstractExpression.fromJSONArrayString(jsonExpr, null);
for (AbstractExpression expr : indexExpressions) {
if (expr instanceof TupleValueExpression && ((TupleValueExpression) expr).getColumnIndex() == partitionColIndex) {
containsPartitionColumn = true;
break;
}
}
} catch (JSONException e) {
// danger will robinson
e.printStackTrace();
assert (false);
}
}
if (containsPartitionColumn) {
if (index.getAssumeunique()) {
String exceptionMsg = String.format("ASSUMEUNIQUE is not valid " + "for an index that includes the partitioning column. Please use UNIQUE instead.");
throw m_compiler.new VoltCompilerException(exceptionMsg);
}
} else if (!index.getAssumeunique()) {
// Throw compiler exception.
String indexName = index.getTypeName();
String keyword = "";
if (indexName.startsWith(HSQLInterface.AUTO_GEN_PRIMARY_KEY_PREFIX)) {
indexName = "PRIMARY KEY";
keyword = "PRIMARY KEY";
} else {
indexName = "UNIQUE INDEX " + indexName;
keyword = "UNIQUE";
}
String exceptionMsg = "Invalid use of " + keyword + ". The " + indexName + " on the partitioned table " + tableName + " does not include the partitioning column " + partitionCol.getName() + ". See the documentation for the 'CREATE TABLE' and 'CREATE INDEX' commands and the 'ASSUMEUNIQUE' keyword.";
throw m_compiler.new VoltCompilerException(exceptionMsg);
}
}
use of org.voltdb.compiler.VoltCompiler.VoltCompilerException in project voltdb by VoltDB.
the class DDLCompiler method handlePartitions.
void handlePartitions(Database db) throws VoltCompilerException {
// Actually parse and handle all the partitions
// this needs to happen before procedures are compiled
String msg = "In database, ";
final CatalogMap<Table> tables = db.getTables();
for (Table table : tables) {
String tableName = table.getTypeName();
if (m_tracker.m_partitionMap.containsKey(tableName.toLowerCase())) {
String colName = m_tracker.m_partitionMap.get(tableName.toLowerCase());
// because it defaults to replicated in the catalog.
if (colName != null) {
assert (tables.getIgnoreCase(tableName) != null);
if (m_matViewMap.containsKey(table)) {
msg += "the materialized view is automatically partitioned based on its source table. " + "Invalid PARTITION statement on view table " + tableName + ".";
throw m_compiler.new VoltCompilerException(msg);
}
final Column partitionCol = table.getColumns().getIgnoreCase(colName);
// make sure the column exists
if (partitionCol == null) {
msg += "PARTITION has unknown COLUMN '" + colName + "'";
throw m_compiler.new VoltCompilerException(msg);
}
// make sure the column is marked not-nullable
if (partitionCol.getNullable() == true) {
msg += "Partition column '" + tableName + "." + colName + "' is nullable. " + "Partition columns must be constrained \"NOT NULL\".";
throw m_compiler.new VoltCompilerException(msg);
}
// verify that the partition column is a supported type
VoltType pcolType = VoltType.get((byte) partitionCol.getType());
switch(pcolType) {
case TINYINT:
case SMALLINT:
case INTEGER:
case BIGINT:
case STRING:
case VARBINARY:
break;
default:
msg += "Partition column '" + tableName + "." + colName + "' is not a valid type. " + "Partition columns must be an integer, varchar or varbinary type.";
throw m_compiler.new VoltCompilerException(msg);
}
table.setPartitioncolumn(partitionCol);
table.setIsreplicated(false);
// Check valid indexes, whether they contain the partition column or not.
for (Index index : table.getIndexes()) {
checkValidPartitionTableIndex(index, partitionCol, tableName);
}
}
}
}
}
use of org.voltdb.compiler.VoltCompiler.VoltCompilerException in project voltdb by VoltDB.
the class DDLCompiler method addColumnToCatalog.
private static void addColumnToCatalog(Table table, VoltXMLElement node, SortedMap<Integer, VoltType> columnTypes, Map<String, Column> columnMap, VoltCompiler compiler) throws VoltCompilerException {
assert node.name.equals("column");
String name = node.attributes.get("name");
String typename = node.attributes.get("valuetype");
String nullable = node.attributes.get("nullable");
String sizeString = node.attributes.get("size");
int index = Integer.valueOf(node.attributes.get("index"));
String defaultvalue = null;
String defaulttype = null;
int defaultFuncID = -1;
// Default Value
for (VoltXMLElement child : node.children) {
if (child.name.equals("default")) {
for (VoltXMLElement inner_child : child.children) {
// Value
if (inner_child.name.equals("value")) {
// There should be only one default value/type.
assert (defaulttype == null);
defaultvalue = inner_child.attributes.get("value");
defaulttype = inner_child.attributes.get("valuetype");
assert (defaulttype != null);
} else if (inner_child.name.equals("function")) {
// There should be only one default value/type.
assert (defaulttype == null);
defaultFuncID = Integer.parseInt(inner_child.attributes.get("function_id"));
defaultvalue = inner_child.attributes.get("name");
defaulttype = inner_child.attributes.get("valuetype");
assert (defaulttype != null);
}
}
}
}
if (defaulttype != null) {
// fyi: Historically, VoltType class initialization errors get reported on this line (?).
defaulttype = Integer.toString(VoltType.typeFromString(defaulttype).getValue());
}
// replace newlines in default values
if (defaultvalue != null) {
defaultvalue = defaultvalue.replace('\n', ' ');
defaultvalue = defaultvalue.replace('\r', ' ');
}
// fyi: Historically, VoltType class initialization errors get reported on this line (?).
VoltType type = VoltType.typeFromString(typename);
columnTypes.put(index, type);
if (defaultFuncID == -1) {
if (defaultvalue != null && (type == VoltType.DECIMAL || type == VoltType.NUMERIC)) {
// Until we support deserializing scientific notation in the EE, we'll
// coerce default values to plain notation here. See ENG-952 for more info.
BigDecimal temp = new BigDecimal(defaultvalue);
defaultvalue = temp.toPlainString();
}
} else {
// Concat function name and function id, format: NAME:ID
// Used by PlanAssembler:getNextInsertPlan().
defaultvalue = defaultvalue + ":" + String.valueOf(defaultFuncID);
}
Column column = table.getColumns().add(name);
// need to set other column data here (default, nullable, etc)
column.setName(name);
column.setIndex(index);
column.setType(type.getValue());
column.setNullable(Boolean.valueOf(nullable));
int size = type.getMaxLengthInBytes();
boolean inBytes = false;
if (node.attributes.containsKey("bytes")) {
inBytes = Boolean.valueOf(node.attributes.get("bytes"));
}
// Determine the length of columns with a variable-length type
if (type.isVariableLength()) {
int userSpecifiedSize = 0;
if (sizeString != null) {
userSpecifiedSize = Integer.parseInt(sizeString);
}
if (userSpecifiedSize == 0) {
// So size specified in the column definition. Either:
// - the user-specified size is zero (unclear how this would happen---
// if someone types VARCHAR(0) HSQL will complain)
// - or the sizeString was null, meaning that the size specifier was
// omitted.
// Choose an appropriate default for the type.
size = type.defaultLengthForVariableLengthType();
} else {
if (userSpecifiedSize < 0 || (inBytes && userSpecifiedSize > VoltType.MAX_VALUE_LENGTH)) {
String msg = type.toSQLString() + " column " + name + " in table " + table.getTypeName() + " has unsupported length " + sizeString;
throw compiler.new VoltCompilerException(msg);
}
if (!inBytes && type == VoltType.STRING) {
if (userSpecifiedSize > VoltType.MAX_VALUE_LENGTH_IN_CHARACTERS) {
String msg = String.format("The size of VARCHAR column %s in table %s greater than %d " + "will be enforced as byte counts rather than UTF8 character counts. " + "To eliminate this warning, specify \"VARCHAR(%d BYTES)\"", name, table.getTypeName(), VoltType.MAX_VALUE_LENGTH_IN_CHARACTERS, userSpecifiedSize);
compiler.addWarn(msg);
inBytes = true;
}
}
if (userSpecifiedSize < type.getMinLengthInBytes()) {
String msg = type.toSQLString() + " column " + name + " in table " + table.getTypeName() + " has length of " + sizeString + " which is shorter than " + type.getMinLengthInBytes() + ", " + "the minimum allowed length for the type.";
throw compiler.new VoltCompilerException(msg);
}
size = userSpecifiedSize;
}
}
column.setInbytes(inBytes);
column.setSize(size);
column.setDefaultvalue(defaultvalue);
if (defaulttype != null)
column.setDefaulttype(Integer.parseInt(defaulttype));
columnMap.put(name, column);
}
Aggregations