public void testGetTypeInfo() throws Exception { String schema = "create table Table1 (Column1 varchar(200) not null, Column2 integer);" + "partition table Table1 on column Column1;" + "create procedure proc1 as select * from Table1 where Column1=?;" + "partition procedure proc1 on table Table1 column Column1;" + "create procedure proc2 as select * from Table1 where Column2=?;"; VoltCompiler c = compileForDDLTest2(schema); JdbcDatabaseMetaDataGenerator dut = new JdbcDatabaseMetaDataGenerator(c.getCatalog(), null, new InMemoryJarfile(testout_jar)); VoltTable typeInfo = dut.getMetaData("typEINfo"); System.out.println(typeInfo); // just do some minor sanity checks on size of table and that it contains the types // we expect HashMap<String, VoltType> expectedTypes = new HashMap<String, VoltType>(); for (VoltType type : VoltType.values()) { if (type.isJdbcVisible()) { expectedTypes.put(type.toSQLString().toUpperCase(), type); } } assertEquals(expectedTypes.size(), typeInfo.getRowCount()); assertEquals(18, typeInfo.getColumnCount()); typeInfo.resetRowPosition(); while (typeInfo.advanceRow()) { String gotName = typeInfo.getString("TYPE_NAME"); VoltType expectedType = expectedTypes.remove(gotName); assertTrue(expectedType != null); } assertTrue(expectedTypes.isEmpty()); }
public void testGetClasses() throws Exception { String schema = "create table Table1 (Column1 varchar(200) not null, Column2 integer);" + "partition table Table1 on column Column1;" + "create procedure proc1 as select * from Table1 where Column1=?;" + "partition procedure proc1 on table Table1 column Column1;" + "create procedure proc2 as select * from Table1 where Column2=?;" + "import class org.voltdb_testprocs.fullddlfeatures.*;" + "create procedure from class org.voltdb_testprocs.fullddlfeatures.testImportProc;"; VoltCompiler c = compileForDDLTest2(schema); JdbcDatabaseMetaDataGenerator dut = new JdbcDatabaseMetaDataGenerator(c.getCatalog(), null, new InMemoryJarfile(testout_jar)); VoltTable classes = dut.getMetaData("classes"); System.out.println(classes); assertTrue( VoltTableTestHelpers.moveToMatchingRow( classes, "CLASS_NAME", "org.voltdb_testprocs.fullddlfeatures.testImportProc")); assertEquals(1, classes.get("VOLT_PROCEDURE", VoltType.INTEGER)); assertEquals(1, classes.get("ACTIVE_PROC", VoltType.INTEGER)); assertTrue( VoltTableTestHelpers.moveToMatchingRow( classes, "CLASS_NAME", "org.voltdb_testprocs.fullddlfeatures.testCreateProcFromClassProc")); assertEquals(1, classes.get("VOLT_PROCEDURE", VoltType.INTEGER)); assertEquals(0, classes.get("ACTIVE_PROC", VoltType.INTEGER)); assertTrue( VoltTableTestHelpers.moveToMatchingRow( classes, "CLASS_NAME", "org.voltdb_testprocs.fullddlfeatures.NoMeaningClass")); assertEquals(0, classes.get("VOLT_PROCEDURE", VoltType.INTEGER)); assertEquals(0, classes.get("ACTIVE_PROC", VoltType.INTEGER)); }
public void testGetPrimaryKeys() throws Exception { String schema = "create table Table1 (Column1 smallint not null, constraint primary1 primary key (Column1));" + "partition table Table1 on column Column1;" + "create table Table2 (Column2 smallint not null, Column3 smallint not null, Column4 smallint not null, " + " constraint primary2 primary key (Column2, Column3, Column4));" + "create procedure sample as select * from Table1;"; VoltCompiler c = compileForDDLTest2(schema); System.out.println(c.getCatalog().serialize()); JdbcDatabaseMetaDataGenerator dut = new JdbcDatabaseMetaDataGenerator(c.getCatalog(), null, new InMemoryJarfile(testout_jar)); VoltTable pkeys = dut.getMetaData("PrimaryKeys"); System.out.println(pkeys); assertEquals(6, pkeys.getColumnCount()); assertEquals(4, pkeys.getRowCount()); assertTrue(VoltTableTestHelpers.moveToMatchingRow(pkeys, "COLUMN_NAME", "Column1")); assertEquals("TABLE1", pkeys.get("TABLE_NAME", VoltType.STRING)); assertEquals((short) 1, pkeys.get("KEY_SEQ", VoltType.SMALLINT)); assertEquals("PRIMARY1", pkeys.get("PK_NAME", VoltType.STRING)); assertTrue(VoltTableTestHelpers.moveToMatchingRow(pkeys, "COLUMN_NAME", "Column2")); assertEquals("TABLE2", pkeys.get("TABLE_NAME", VoltType.STRING)); assertEquals((short) 1, pkeys.get("KEY_SEQ", VoltType.SMALLINT)); assertEquals("PRIMARY2", pkeys.get("PK_NAME", VoltType.STRING)); assertTrue(VoltTableTestHelpers.moveToMatchingRow(pkeys, "COLUMN_NAME", "Column3")); assertEquals("TABLE2", pkeys.get("TABLE_NAME", VoltType.STRING)); assertEquals((short) 2, pkeys.get("KEY_SEQ", VoltType.SMALLINT)); assertEquals("PRIMARY2", pkeys.get("PK_NAME", VoltType.STRING)); assertTrue(VoltTableTestHelpers.moveToMatchingRow(pkeys, "COLUMN_NAME", "Column4")); assertEquals("TABLE2", pkeys.get("TABLE_NAME", VoltType.STRING)); assertEquals((short) 3, pkeys.get("KEY_SEQ", VoltType.SMALLINT)); assertEquals("PRIMARY2", pkeys.get("PK_NAME", VoltType.STRING)); }
public void testGetProcedureColumns() throws Exception { String schema = "create table Table1 (Column1 varchar(200) not null, Column2 integer);" + "partition table Table1 on column Column1;" + "create procedure proc1 as select * from Table1 where Column1=?;" + "partition procedure proc1 on table Table1 column Column1;" + "create procedure proc2 as select * from Table1 where Column2=?;"; VoltCompiler c = compileForDDLTest2(schema); System.out.println(c.getCatalog().serialize()); DefaultProcedureManager defaultProcs = new DefaultProcedureManager(c.getCatalogDatabase()); JdbcDatabaseMetaDataGenerator dut = new JdbcDatabaseMetaDataGenerator( c.getCatalog(), defaultProcs, new InMemoryJarfile(testout_jar)); VoltTable params = dut.getMetaData("ProcedureColumns"); System.out.println(params); assertEquals(20, params.getColumnCount()); assertEquals(4, params.getRowCount()); // 2 real and 2 crud inserts assertTrue(VoltTableTestHelpers.moveToMatchingRow(params, "PROCEDURE_NAME", "proc1")); assertEquals("param0", params.get("COLUMN_NAME", VoltType.STRING)); assertEquals(VoltType.MAX_VALUE_LENGTH, params.get("PRECISION", VoltType.INTEGER)); assertEquals(VoltType.MAX_VALUE_LENGTH, params.get("LENGTH", VoltType.INTEGER)); assertEquals(VoltType.MAX_VALUE_LENGTH, params.get("CHAR_OCTET_LENGTH", VoltType.INTEGER)); assertEquals("PARTITION_PARAMETER", params.get("REMARKS", VoltType.STRING)); assertTrue(VoltTableTestHelpers.moveToMatchingRow(params, "PROCEDURE_NAME", "proc2")); assertEquals("param0", params.get("COLUMN_NAME", VoltType.STRING)); assertEquals( VoltType.INTEGER.getLengthInBytesForFixedTypes() * 8 - 1, params.get("PRECISION", VoltType.INTEGER)); assertEquals( VoltType.INTEGER.getLengthInBytesForFixedTypes(), params.get("LENGTH", VoltType.INTEGER)); assertWithNullCheck(null, params.get("CHAR_OCTET_LENGTH", VoltType.INTEGER), params); assertWithNullCheck(null, params.get("REMARKS", VoltType.STRING), params); }
public static void main(final String[] args) { // Parse arguments if (args.length < 5 || args.length > 6) { System.err.println( "VoltCompiler [project file] [hosts] [sites per host] [leader IP] [output JAR] [k-safety factor (optional/future)] "); System.exit(1); } final String projectPath = args[0]; final int hostCount = Integer.parseInt(args[1]); final int siteCount = Integer.parseInt(args[2]); final String leaderAddress = args[3]; final String outputJar = args[4]; int k_factor = 0; if (args.length == 6) { k_factor = Integer.parseInt(args[5]); } // Compile and exit with error code if we failed final ClusterConfig cluster_config = new ClusterConfig(hostCount, siteCount, k_factor, leaderAddress); final VoltCompiler compiler = new VoltCompiler(); final boolean success = compiler.compile(projectPath, cluster_config, outputJar, System.out, null); if (!success) { System.exit(-1); } }
private VoltCompiler compileForDDLTest2(String ddl) throws Exception { String ddlPath = getPathForSchema(ddl); final VoltCompiler compiler = new VoltCompiler(); boolean success = compiler.compileFromDDL(testout_jar, ddlPath); assertTrue("Catalog compile failed!", success); return compiler; }
public boolean compile( final String jarPath, final int sitesPerHost, final int hostCount, final int replication, final String leaderAddress) { VoltCompiler compiler = new VoltCompiler(); if (m_replicatedSecondaryIndexesEnabled) { compiler.enableVerticalPartitionOptimizations(); } return compile(compiler, jarPath, sitesPerHost, hostCount, replication, leaderAddress); }
public void testGetTables() throws Exception { String schema = "create table Table1 (Column1 varchar(10) not null, Column2 integer);" + "partition table Table1 on column Column1;" + "create table Table2 (Column1 integer);" + "create view View1 (Column1, num) as select Column1, count(*) from Table1 group by Column1;" + "create view View2 (Column2, num) as select Column2, count(*) from Table1 group by Column2;" + "create table Export1 (Column1 integer);" + "export table Export1;" + "create table Export2 (Column1 integer);" + "export table Export2 to stream foo;" + "create procedure sample as select * from Table1;"; VoltCompiler c = compileForDDLTest2(schema); System.out.println(c.getCatalog().serialize()); JdbcDatabaseMetaDataGenerator dut = new JdbcDatabaseMetaDataGenerator(c.getCatalog(), null, new InMemoryJarfile(testout_jar)); VoltTable tables = dut.getMetaData("tables"); System.out.println(tables); assertEquals(10, tables.getColumnCount()); assertEquals(6, tables.getRowCount()); assertTrue(VoltTableTestHelpers.moveToMatchingRow(tables, "TABLE_NAME", "Table1")); assertTrue(tables.get("TABLE_TYPE", VoltType.STRING).equals("TABLE")); assertTrue(tables.get("REMARKS", VoltType.STRING).equals("{\"partitionColumn\":\"COLUMN1\"}")); assertTrue(VoltTableTestHelpers.moveToMatchingRow(tables, "TABLE_NAME", "Table2")); assertTrue(tables.get("TABLE_TYPE", VoltType.STRING).equals("TABLE")); assertEquals(null, tables.get("REMARKS", VoltType.STRING)); assertTrue(VoltTableTestHelpers.moveToMatchingRow(tables, "TABLE_NAME", "View1")); assertTrue(tables.get("TABLE_TYPE", VoltType.STRING).equals("VIEW")); assertTrue( tables .get("REMARKS", VoltType.STRING) .equals( new JSONObject("{\"partitionColumn\":\"COLUMN1\",\"sourceTable\":\"TABLE1\"}") .toString())); assertTrue(VoltTableTestHelpers.moveToMatchingRow(tables, "TABLE_NAME", "View2")); assertTrue(tables.get("TABLE_TYPE", VoltType.STRING).equals("VIEW")); assertTrue( tables .get("REMARKS", VoltType.STRING) .equals( new JSONObject("{\"partitionColumn\":\"COLUMN1\",\"sourceTable\":\"TABLE1\"}") .toString())); assertTrue(VoltTableTestHelpers.moveToMatchingRow(tables, "TABLE_NAME", "Export1")); assertTrue(tables.get("TABLE_TYPE", VoltType.STRING).equals("EXPORT")); assertTrue(VoltTableTestHelpers.moveToMatchingRow(tables, "TABLE_NAME", "Export2")); assertTrue(tables.get("TABLE_TYPE", VoltType.STRING).equals("EXPORT")); assertFalse(VoltTableTestHelpers.moveToMatchingRow(tables, "TABLE_NAME", "NotATable")); }
public Catalog compile( final String jarPath, final int sitesPerHost, final int hostCount, final int replication, final String voltRoot) { VoltCompiler compiler = new VoltCompiler(); if (compile( compiler, jarPath, voltRoot, new DeploymentInfo(hostCount, sitesPerHost, replication, false, 0, false), m_ppdEnabled, m_snapshotPath, m_ppdPrefix)) { return compiler.getCatalog(); } else { return null; } }
static void compileSingleStmtProcedure( VoltCompiler compiler, HSQLInterface hsql, DatabaseEstimates estimates, Catalog catalog, Database db, ProcedureDescriptor procedureDescriptor) throws VoltCompiler.VoltCompilerException { final String className = procedureDescriptor.m_className; if (className.indexOf('@') != -1) { throw compiler.new VoltCompilerException("User procedure names can't contain \"@\"."); } // get the short name of the class (no package if a user procedure) // use the Table.<builtin> name (allowing the period) if builtin. String shortName = className; if (procedureDescriptor.m_builtInStmt == false) { String[] parts = className.split("\\."); shortName = parts[parts.length - 1]; } // add an entry to the catalog (using the full className) final Procedure procedure = db.getProcedures().add(shortName); for (String groupName : procedureDescriptor.m_authGroups) { final Group group = db.getGroups().get(groupName); if (group == null) { throw compiler .new VoltCompilerException( "Procedure " + className + " allows access by a role " + groupName + " that does not exist"); } final GroupRef groupRef = procedure.getAuthgroups().add(groupName); groupRef.setGroup(group); } procedure.setClassname(className); // sysprocs don't use the procedure compiler procedure.setSystemproc(false); procedure.setDefaultproc(procedureDescriptor.m_builtInStmt); procedure.setHasjava(false); // get the annotation // first try to get one that has been passed from the compiler ProcInfoData info = compiler.getProcInfoOverride(shortName); // then check for the usual one in the class itself // and create a ProcInfo.Data instance for it if (info == null) { info = new ProcInfoData(); if (procedureDescriptor.m_partitionString != null) { info.partitionInfo = procedureDescriptor.m_partitionString; info.singlePartition = true; } } assert (info != null); // ADD THE STATEMENT // add the statement to the catalog Statement catalogStmt = procedure.getStatements().add(VoltDB.ANON_STMT_NAME); // compile the statement StatementPartitioning partitioning = info.singlePartition ? StatementPartitioning.forceSP() : StatementPartitioning.forceMP(); // default to FASTER detmode because stmt procs can't feed read output into writes StatementCompiler.compileFromSqlTextAndUpdateCatalog( compiler, hsql, catalog, db, estimates, catalogStmt, procedureDescriptor.m_singleStmt, procedureDescriptor.m_joinOrder, DeterminismMode.FASTER, partitioning); // if the single stmt is not read only, then the proc is not read only boolean procHasWriteStmts = (catalogStmt.getReadonly() == false); // set the read onlyness of a proc procedure.setReadonly(procHasWriteStmts == false); int seqs = catalogStmt.getSeqscancount(); procedure.setHasseqscans(seqs > 0); // set procedure parameter types CatalogMap<ProcParameter> params = procedure.getParameters(); CatalogMap<StmtParameter> stmtParams = catalogStmt.getParameters(); // set the procedure parameter types from the statement parameter types int paramCount = 0; for (StmtParameter stmtParam : CatalogUtil.getSortedCatalogItems(stmtParams, "index")) { // name each parameter "param1", "param2", etc... ProcParameter procParam = params.add("param" + String.valueOf(paramCount)); procParam.setIndex(stmtParam.getIndex()); procParam.setIsarray(stmtParam.getIsarray()); procParam.setType(stmtParam.getJavatype()); paramCount++; } // parse the procinfo procedure.setSinglepartition(info.singlePartition); if (info.singlePartition) { parsePartitionInfo(compiler, db, procedure, info.partitionInfo); if (procedure.getPartitionparameter() >= params.size()) { String msg = "PartitionInfo parameter not a valid parameter for procedure: " + procedure.getClassname(); throw compiler.new VoltCompilerException(msg); } // TODO: The planner does not currently validate that a single-statement plan declared as // single-partition correctly uses // the designated parameter as a partitioning filter, maybe some day. // In theory, the PartitioningForStatement would confirm the use of (only) a parameter as a // partition key -- // or if the partition key was determined to be some other hard-coded constant (expression?) // it might display a warning // message that the passed parameter is assumed to be equal to that constant (expression). } else { if (partitioning.getCountOfIndependentlyPartitionedTables() == 1) { AbstractExpression statementPartitionExpression = partitioning.singlePartitioningExpressionForReport(); if (statementPartitionExpression != null) { // The planner has uncovered an overlooked opportunity to run the statement SP. String msg = null; if (statementPartitionExpression instanceof ParameterValueExpression) { msg = "This procedure would benefit from setting the attribute 'partitioninfo=" + partitioning.getFullColumnName() + ":" + ((ParameterValueExpression) statementPartitionExpression).getParameterIndex() + "'"; } else { String valueDescription = null; Object partitionValue = partitioning.getInferredPartitioningValue(); if (partitionValue == null) { // Statement partitioned on a runtime constant. This is likely to be cryptic, but // hopefully gets the idea across. valueDescription = "of " + statementPartitionExpression.explain(""); } else { valueDescription = partitionValue.toString(); // A simple constant value COULD have been a parameter. } msg = "This procedure would benefit from adding a parameter to be passed the value " + valueDescription + " and setting the attribute 'partitioninfo=" + partitioning.getFullColumnName() + ":" + paramCount + "'"; } compiler.addWarn(msg); } } } }
static void compileJavaProcedure( VoltCompiler compiler, HSQLInterface hsql, DatabaseEstimates estimates, Catalog catalog, Database db, ProcedureDescriptor procedureDescriptor, InMemoryJarfile jarOutput) throws VoltCompiler.VoltCompilerException { final String className = procedureDescriptor.m_className; final Language lang = procedureDescriptor.m_language; // Load the class given the class name Class<?> procClass = procedureDescriptor.m_class; // get the short name of the class (no package) String shortName = deriveShortProcedureName(className); // add an entry to the catalog final Procedure procedure = db.getProcedures().add(shortName); for (String groupName : procedureDescriptor.m_authGroups) { final Group group = db.getGroups().get(groupName); if (group == null) { throw compiler .new VoltCompilerException( "Procedure " + className + " allows access by a role " + groupName + " that does not exist"); } final GroupRef groupRef = procedure.getAuthgroups().add(groupName); groupRef.setGroup(group); } procedure.setClassname(className); // sysprocs don't use the procedure compiler procedure.setSystemproc(false); procedure.setDefaultproc(procedureDescriptor.m_builtInStmt); procedure.setHasjava(true); procedure.setLanguage(lang.name()); ProcedureAnnotation pa = (ProcedureAnnotation) procedure.getAnnotation(); if (pa == null) { pa = new ProcedureAnnotation(); procedure.setAnnotation(pa); } if (procedureDescriptor.m_scriptImpl != null) { // This is a Groovy or other Java derived procedure and we need to add an annotation with // the script to the Procedure element in the Catalog pa.scriptImpl = procedureDescriptor.m_scriptImpl; } // get the annotation // first try to get one that has been passed from the compiler ProcInfoData info = compiler.getProcInfoOverride(shortName); // check if partition info was set in ddl ProcInfoData ddlInfo = null; if (procedureDescriptor.m_partitionString != null && !procedureDescriptor.m_partitionString.trim().isEmpty()) { ddlInfo = new ProcInfoData(); ddlInfo.partitionInfo = procedureDescriptor.m_partitionString; ddlInfo.singlePartition = true; } // then check for the usual one in the class itself // and create a ProcInfo.Data instance for it if (info == null) { info = new ProcInfoData(); ProcInfo annotationInfo = procClass.getAnnotation(ProcInfo.class); // error out if partition info is present in both ddl and annotation if (annotationInfo != null) { if (ddlInfo != null) { String msg = "Procedure: " + shortName + " has partition properties defined both in "; msg += "class \"" + className + "\" and in the schema defintion file(s)"; throw compiler.new VoltCompilerException(msg); } // Prevent AutoGenerated DDL from including PARTITION PROCEDURE for this procedure. pa.classAnnotated = true; info.partitionInfo = annotationInfo.partitionInfo(); info.singlePartition = annotationInfo.singlePartition(); } else if (ddlInfo != null) { info = ddlInfo; } } else { pa.classAnnotated = true; } assert (info != null); // make sure multi-partition implies no partitoning info if (info.singlePartition == false) { if ((info.partitionInfo != null) && (info.partitionInfo.length() > 0)) { String msg = "Procedure: " + shortName + " is annotated as multi-partition"; msg += " but partitionInfo has non-empty value: \"" + info.partitionInfo + "\""; throw compiler.new VoltCompilerException(msg); } } // track if there are any writer statements and/or sequential scans and/or an overlooked common // partitioning parameter boolean procHasWriteStmts = false; boolean procHasSeqScans = false; // procWantsCommonPartitioning == true but commonPartitionExpression == null signifies a proc // for which the planner was requested to attempt to find an SP plan, but that was not possible // -- it had a replicated write or it had one or more partitioned reads that were not all // filtered by the same partition key value -- so it was planned as an MP proc. boolean procWantsCommonPartitioning = true; AbstractExpression commonPartitionExpression = null; String exampleSPstatement = null; Object exampleSPvalue = null; // iterate through the fields and get valid sql statements Map<String, Object> fields = lang.accept(procedureIntrospector(compiler), procClass); // determine if proc is read or read-write by checking if the proc contains any write sql stmts boolean readWrite = false; for (Object field : fields.values()) { if (!(field instanceof SQLStmt)) continue; SQLStmt stmt = (SQLStmt) field; QueryType qtype = QueryType.getFromSQL(stmt.getText()); if (!qtype.isReadOnly()) { readWrite = true; break; } } // default to FASTER determinism mode, which may favor non-deterministic plans // but if it's a read-write proc, use a SAFER planning mode wrt determinism. final DeterminismMode detMode = readWrite ? DeterminismMode.SAFER : DeterminismMode.FASTER; for (Entry<String, Object> entry : fields.entrySet()) { if (!(entry.getValue() instanceof SQLStmt)) continue; String stmtName = entry.getKey(); SQLStmt stmt = (SQLStmt) entry.getValue(); // add the statement to the catalog Statement catalogStmt = procedure.getStatements().add(stmtName); // compile the statement StatementPartitioning partitioning = info.singlePartition ? StatementPartitioning.forceSP() : StatementPartitioning.forceMP(); boolean cacheHit = StatementCompiler.compileFromSqlTextAndUpdateCatalog( compiler, hsql, catalog, db, estimates, catalogStmt, stmt.getText(), stmt.getJoinOrder(), detMode, partitioning); // if this was a cache hit or specified single, don't worry about figuring out more // partitioning if (partitioning.wasSpecifiedAsSingle() || cacheHit) { procWantsCommonPartitioning = false; // Don't try to infer what's already been asserted. // The planner does not currently attempt to second-guess a plan declared as // single-partition, maybe some day. // In theory, the PartitioningForStatement would confirm the use of (only) a parameter as a // partition key -- // or if the partition key was determined to be some other constant (expression?) it might // display an informational // message that the passed parameter is assumed to be equal to the hard-coded partition key // constant (expression). // Validate any inferred statement partitioning given the statement's possible usage, until // a contradiction is found. } else if (procWantsCommonPartitioning) { // Only consider statements that are capable of running SP with a partitioning parameter // that does not seem to // conflict with the partitioning of prior statements. if (partitioning.getCountOfIndependentlyPartitionedTables() == 1) { AbstractExpression statementPartitionExpression = partitioning.singlePartitioningExpressionForReport(); if (statementPartitionExpression != null) { if (commonPartitionExpression == null) { commonPartitionExpression = statementPartitionExpression; exampleSPstatement = stmt.getText(); exampleSPvalue = partitioning.getInferredPartitioningValue(); } else if (commonPartitionExpression.equals(statementPartitionExpression) || (statementPartitionExpression instanceof ParameterValueExpression && commonPartitionExpression instanceof ParameterValueExpression)) { // Any constant used for partitioning would have to be the same for all statements, // but // any statement parameter used for partitioning MIGHT come from the same proc // parameter as // any other statement's parameter used for partitioning. } else { procWantsCommonPartitioning = false; // appears to be different partitioning for different statements } } else { // There is a statement with a partitioned table whose partitioning column is // not equality filtered with a constant or param. Abandon all hope. procWantsCommonPartitioning = false; } // Usually, replicated-only statements in a mix with others have no effect on the MP/SP // decision } else if (partitioning.getCountOfPartitionedTables() == 0) { // but SP is strictly forbidden for DML, to maintain the consistency of the replicated // data. if (partitioning.getIsReplicatedTableDML()) { procWantsCommonPartitioning = false; } } else { // There is a statement with a partitioned table whose partitioning column is // not equality filtered with a constant or param. Abandon all hope. procWantsCommonPartitioning = false; } } // if a single stmt is not read only, then the proc is not read only if (catalogStmt.getReadonly() == false) { procHasWriteStmts = true; } if (catalogStmt.getSeqscancount() > 0) { procHasSeqScans = true; } } // MIGHT the planner have uncovered an overlooked opportunity to run all statements SP? if (procWantsCommonPartitioning && (commonPartitionExpression != null)) { String msg = null; if (commonPartitionExpression instanceof ParameterValueExpression) { msg = "This procedure might benefit from an @ProcInfo annotation designating parameter " + ((ParameterValueExpression) commonPartitionExpression).getParameterIndex() + " of statement '" + exampleSPstatement + "'"; } else { String valueDescription = null; if (exampleSPvalue == null) { // Statements partitioned on a runtime constant. This is likely to be cryptic, but // hopefully gets the idea across. valueDescription = "of " + commonPartitionExpression.explain(""); } else { valueDescription = exampleSPvalue.toString(); // A simple constant value COULD have been a parameter. } msg = "This procedure might benefit from an @ProcInfo annotation referencing an added parameter passed the value " + valueDescription; } compiler.addInfo(msg); } // set the read onlyness of a proc procedure.setReadonly(procHasWriteStmts == false); procedure.setHasseqscans(procHasSeqScans); for (Statement catalogStmt : procedure.getStatements()) { if (catalogStmt.getIscontentdeterministic() == false) { String potentialErrMsg = "Procedure " + shortName + " has a statement with a non-deterministic result - statement: \"" + catalogStmt.getSqltext() + "\" , reason: " + catalogStmt.getNondeterminismdetail(); // throw compiler.new VoltCompilerException(potentialErrMsg); compiler.addWarn(potentialErrMsg); } else if (catalogStmt.getIsorderdeterministic() == false) { String warnMsg; if (procHasWriteStmts) { String rwPotentialErrMsg = "Procedure " + shortName + " is RW and has a statement whose result has a non-deterministic ordering - statement: \"" + catalogStmt.getSqltext() + "\", reason: " + catalogStmt.getNondeterminismdetail(); // throw compiler.new VoltCompilerException(rwPotentialErrMsg); warnMsg = rwPotentialErrMsg; } else { warnMsg = "Procedure " + shortName + " has a statement with a non-deterministic result - statement: \"" + catalogStmt.getSqltext() + "\", reason: " + catalogStmt.getNondeterminismdetail(); } compiler.addWarn(warnMsg); } } // set procedure parameter types CatalogMap<ProcParameter> params = procedure.getParameters(); Class<?>[] paramTypes = lang.accept(procedureEntryPointParametersTypeExtractor, fields); for (int i = 0; i < paramTypes.length; i++) { Class<?> cls = paramTypes[i]; ProcParameter param = params.add(String.valueOf(i)); param.setIndex(i); // handle the case where the param is an array if (cls.isArray()) { param.setIsarray(true); cls = cls.getComponentType(); } else param.setIsarray(false); // boxed types are not supported parameters at this time if ((cls == Long.class) || (cls == Integer.class) || (cls == Short.class) || (cls == Byte.class) || (cls == Double.class) || (cls == Character.class) || (cls == Boolean.class)) { String msg = "Procedure: " + shortName + " has a parameter with a boxed type: "; msg += cls.getSimpleName(); msg += ". Replace this parameter with the corresponding primitive type and the procedure may compile."; throw compiler.new VoltCompilerException(msg); } else if ((cls == Float.class) || (cls == float.class)) { String msg = "Procedure: " + shortName + " has a parameter with type: "; msg += cls.getSimpleName(); msg += ". Replace this parameter type with double and the procedure may compile."; throw compiler.new VoltCompilerException(msg); } VoltType type; try { type = VoltType.typeFromClass(cls); } catch (VoltTypeException e) { // handle the case where the type is invalid String msg = "Procedure: " + shortName + " has a parameter with invalid type: "; msg += cls.getSimpleName(); throw compiler.new VoltCompilerException(msg); } catch (RuntimeException e) { String msg = "Procedure: " + shortName + " unexpectedly failed a check on a parameter of type: "; msg += cls.getSimpleName(); msg += " with error: "; msg += e.toString(); throw compiler.new VoltCompilerException(msg); } param.setType(type.getValue()); } // parse the procinfo procedure.setSinglepartition(info.singlePartition); if (info.singlePartition) { parsePartitionInfo(compiler, db, procedure, info.partitionInfo); if (procedure.getPartitionparameter() >= paramTypes.length) { String msg = "PartitionInfo parameter not a valid parameter for procedure: " + procedure.getClassname(); throw compiler.new VoltCompilerException(msg); } // check the type of partition parameter meets our high standards Class<?> partitionType = paramTypes[procedure.getPartitionparameter()]; Class<?>[] validPartitionClzzes = { Long.class, Integer.class, Short.class, Byte.class, long.class, int.class, short.class, byte.class, String.class, byte[].class }; boolean found = false; for (Class<?> candidate : validPartitionClzzes) { if (partitionType == candidate) found = true; } if (!found) { String msg = "PartitionInfo parameter must be a String or Number for procedure: " + procedure.getClassname(); throw compiler.new VoltCompilerException(msg); } VoltType columnType = VoltType.get((byte) procedure.getPartitioncolumn().getType()); VoltType paramType = VoltType.typeFromClass(partitionType); if (!columnType.canExactlyRepresentAnyValueOf(paramType)) { String msg = "Type mismatch between partition column and partition parameter for procedure " + procedure.getClassname() + " may cause overflow or loss of precision.\nPartition column is type " + columnType + " and partition parameter is type " + paramType; throw compiler.new VoltCompilerException(msg); } else if (!paramType.canExactlyRepresentAnyValueOf(columnType)) { String msg = "Type mismatch between partition column and partition parameter for procedure " + procedure.getClassname() + " does not allow the full range of partition key values.\nPartition column is type " + columnType + " and partition parameter is type " + paramType; compiler.addWarn(msg); } } // put the compiled code for this procedure into the jarfile // need to find the outermost ancestor class for the procedure in the event // that it's actually an inner (or inner inner...) class. // addClassToJar recursively adds all the children, which should include this // class Class<?> ancestor = procClass; while (ancestor.getEnclosingClass() != null) { ancestor = ancestor.getEnclosingClass(); } compiler.addClassToJar(jarOutput, ancestor); }
public boolean compile( final VoltCompiler compiler, final String jarPath, final String voltRoot, final DeploymentInfo deployment, final boolean ppdEnabled, final String snapshotPath, final String ppdPrefix) { assert (jarPath != null); assert (deployment == null || deployment.sitesPerHost >= 1); assert (deployment == null || deployment.hostCount >= 1); String deploymentVoltRoot = voltRoot; if (deployment != null) { if (voltRoot == null) { String voltRootPath = "/tmp/" + System.getProperty("user.name"); java.io.File voltRootFile = new java.io.File(voltRootPath); if (!voltRootFile.exists()) { if (!voltRootFile.mkdir()) { throw new RuntimeException( "Unable to create voltdbroot \"" + voltRootPath + "\" for test"); } } if (!voltRootFile.isDirectory()) { throw new RuntimeException( "voltdbroot \"" + voltRootPath + "\" for test exists but is not a directory"); } if (!voltRootFile.canRead()) { throw new RuntimeException( "voltdbroot \"" + voltRootPath + "\" for test exists but is not readable"); } if (!voltRootFile.canWrite()) { throw new RuntimeException( "voltdbroot \"" + voltRootPath + "\" for test exists but is not writable"); } if (!voltRootFile.canExecute()) { throw new RuntimeException( "voltdbroot \"" + voltRootPath + "\" for test exists but is not writable"); } deploymentVoltRoot = voltRootPath; } } m_voltRootPath = deploymentVoltRoot; // Add the DDL in the transformer to the schema files before compilation try { addLiteralSchema(transformer.toString()); transformer = new StringBuffer(); } catch (IOException e) { e.printStackTrace(); return false; } String[] schemaPath = m_schemas.toArray(new String[0]); compiler.setProcInfoOverrides(m_procInfoOverrides); if (m_diagnostics != null) { compiler.enableDetailedCapture(); } boolean success = false; try { success = compiler.compileFromDDL(jarPath, schemaPath); } catch (VoltCompilerException e1) { e1.printStackTrace(); return false; } m_diagnostics = compiler.harvestCapturedDetail(); if (m_compilerDebugPrintStream != null) { if (success) { compiler.summarizeSuccess(m_compilerDebugPrintStream, m_compilerDebugPrintStream, jarPath); } else { compiler.summarizeErrors(m_compilerDebugPrintStream, m_compilerDebugPrintStream); } } if (deployment != null) { try { m_pathToDeployment = writeDeploymentFile(deploymentVoltRoot, deployment); } catch (Exception e) { System.out.println("Failed to create deployment file in testcase."); e.printStackTrace(); System.out.println("hostcount: " + deployment.hostCount); System.out.println("sitesPerHost: " + deployment.sitesPerHost); System.out.println("replication: " + deployment.replication); System.out.println("voltRoot: " + deploymentVoltRoot); System.out.println("ppdEnabled: " + ppdEnabled); System.out.println("snapshotPath: " + snapshotPath); System.out.println("ppdPrefix: " + ppdPrefix); System.out.println("adminEnabled: " + deployment.useCustomAdmin); System.out.println("adminPort: " + deployment.adminPort); System.out.println("adminOnStartup: " + deployment.adminOnStartup); // sufficient to escape and fail test cases? throw new RuntimeException(e); } } return success; }
public void testGetIndexInfo() throws Exception { String schema = "create table Table1 (Column1 smallint ASSUMEUNIQUE, Column2 integer, Column3 bigint not null, Column4 integer, Column5 integer, " + " constraint pk_tree primary key (Column1, Column3));" + "partition table Table1 on column Column3;" + "create index Index1_tree on Table1 (Column2, Column3);" + "create index Index2_hash on Table1 (Column4, Column5);" + "create procedure sample as select * from Table1;"; VoltCompiler c = compileForDDLTest2(schema); System.out.println(c.getCatalog().serialize()); JdbcDatabaseMetaDataGenerator dut = new JdbcDatabaseMetaDataGenerator(c.getCatalog(), null, new InMemoryJarfile(testout_jar)); VoltTable indexes = dut.getMetaData("IndexInfo"); System.out.println(indexes); assertEquals(13, indexes.getColumnCount()); assertEquals(7, indexes.getRowCount()); assertTrue( VoltTableTestHelpers.moveToMatchingTupleRow( indexes, "INDEX_NAME", "INDEX1_TREE", "COLUMN_NAME", "Column2")); assertEquals("TABLE1", indexes.get("TABLE_NAME", VoltType.STRING)); assertEquals((byte) 1, indexes.get("NON_UNIQUE", VoltType.TINYINT)); assertEquals(java.sql.DatabaseMetaData.tableIndexOther, indexes.get("TYPE", VoltType.SMALLINT)); assertEquals((short) 1, indexes.get("ORDINAL_POSITION", VoltType.SMALLINT)); assertEquals("A", indexes.get("ASC_OR_DESC", VoltType.STRING)); assertTrue( VoltTableTestHelpers.moveToMatchingTupleRow( indexes, "INDEX_NAME", "INDEX1_TREE", "COLUMN_NAME", "Column3")); assertEquals("TABLE1", indexes.get("TABLE_NAME", VoltType.STRING)); assertEquals((byte) 1, indexes.get("NON_UNIQUE", VoltType.TINYINT)); assertEquals(java.sql.DatabaseMetaData.tableIndexOther, indexes.get("TYPE", VoltType.SMALLINT)); assertEquals((short) 2, indexes.get("ORDINAL_POSITION", VoltType.SMALLINT)); assertEquals("A", indexes.get("ASC_OR_DESC", VoltType.STRING)); assertTrue( VoltTableTestHelpers.moveToMatchingTupleRow( indexes, "INDEX_NAME", "INDEX2_HASH", "COLUMN_NAME", "Column4")); assertEquals("TABLE1", indexes.get("TABLE_NAME", VoltType.STRING)); assertEquals((byte) 1, indexes.get("NON_UNIQUE", VoltType.TINYINT)); assertEquals( java.sql.DatabaseMetaData.tableIndexHashed, indexes.get("TYPE", VoltType.SMALLINT)); assertEquals((short) 1, indexes.get("ORDINAL_POSITION", VoltType.SMALLINT)); assertEquals(null, indexes.get("ASC_OR_DESC", VoltType.STRING)); assertTrue( VoltTableTestHelpers.moveToMatchingTupleRow( indexes, "INDEX_NAME", "INDEX2_HASH", "COLUMN_NAME", "Column5")); assertEquals("TABLE1", indexes.get("TABLE_NAME", VoltType.STRING)); assertEquals((byte) 1, indexes.get("NON_UNIQUE", VoltType.TINYINT)); assertEquals( java.sql.DatabaseMetaData.tableIndexHashed, indexes.get("TYPE", VoltType.SMALLINT)); assertEquals((short) 2, indexes.get("ORDINAL_POSITION", VoltType.SMALLINT)); assertEquals(null, indexes.get("ASC_OR_DESC", VoltType.STRING)); assertTrue( VoltTableTestHelpers.moveToMatchingTupleRow( indexes, "INDEX_NAME", HSQLInterface.AUTO_GEN_CONSTRAINT_WRAPPER_PREFIX + "PK_TREE", "COLUMN_NAME", "Column1")); assertEquals("TABLE1", indexes.get("TABLE_NAME", VoltType.STRING)); assertEquals((byte) 0, indexes.get("NON_UNIQUE", VoltType.TINYINT)); assertEquals(java.sql.DatabaseMetaData.tableIndexOther, indexes.get("TYPE", VoltType.SMALLINT)); assertEquals((short) 1, indexes.get("ORDINAL_POSITION", VoltType.SMALLINT)); assertEquals("A", indexes.get("ASC_OR_DESC", VoltType.STRING)); assertTrue( VoltTableTestHelpers.moveToMatchingTupleRow( indexes, "INDEX_NAME", HSQLInterface.AUTO_GEN_CONSTRAINT_WRAPPER_PREFIX + "PK_TREE", "COLUMN_NAME", "Column3")); assertEquals("TABLE1", indexes.get("TABLE_NAME", VoltType.STRING)); assertEquals((byte) 0, indexes.get("NON_UNIQUE", VoltType.TINYINT)); assertEquals(java.sql.DatabaseMetaData.tableIndexOther, indexes.get("TYPE", VoltType.SMALLINT)); assertEquals((short) 2, indexes.get("ORDINAL_POSITION", VoltType.SMALLINT)); assertEquals("A", indexes.get("ASC_OR_DESC", VoltType.STRING)); assertTrue( VoltTableTestHelpers.moveToMatchingTupleRow( indexes, "INDEX_NAME", HSQLInterface.AUTO_GEN_CONSTRAINT_PREFIX + "TABLE1_COLUMN1", "COLUMN_NAME", "Column1")); assertEquals("TABLE1", indexes.get("TABLE_NAME", VoltType.STRING)); assertEquals((byte) 0, indexes.get("NON_UNIQUE", VoltType.TINYINT)); assertEquals(java.sql.DatabaseMetaData.tableIndexOther, indexes.get("TYPE", VoltType.SMALLINT)); assertEquals((short) 1, indexes.get("ORDINAL_POSITION", VoltType.SMALLINT)); assertEquals("A", indexes.get("ASC_OR_DESC", VoltType.STRING)); assertFalse(VoltTableTestHelpers.moveToMatchingRow(indexes, "COLUMN_NAME", "NotAColumn")); }
public void testGetColumns() throws Exception { HashMap<String, Object[]> refcolumns = new HashMap<String, Object[]>(); refcolumns.put( "Column1", new Object[] { java.sql.Types.VARCHAR, "VARCHAR", 200, null, null, java.sql.DatabaseMetaData.columnNoNulls, null, null, 200, 1, "NO" }); refcolumns.put( "Column2", new Object[] { java.sql.Types.TINYINT, "TINYINT", 7, null, 2, java.sql.DatabaseMetaData.columnNullable, null, null, null, 2, "YES" }); refcolumns.put( "Column3", new Object[] { java.sql.Types.SMALLINT, "SMALLINT", 15, null, 2, java.sql.DatabaseMetaData.columnNoNulls, "PARTITION_COLUMN", null, null, 1, "NO" }); refcolumns.put( "Column4", new Object[] { java.sql.Types.INTEGER, "INTEGER", 31, null, 2, java.sql.DatabaseMetaData.columnNullable, null, null, null, 2, "YES" }); refcolumns.put( "Column5", new Object[] { java.sql.Types.BIGINT, "BIGINT", 63, null, 2, java.sql.DatabaseMetaData.columnNoNulls, null, null, null, 3, "NO" }); refcolumns.put( "Column6", new Object[] { java.sql.Types.FLOAT, "FLOAT", 53, null, 2, java.sql.DatabaseMetaData.columnNullable, null, null, null, 1, "YES" }); refcolumns.put( "Column7", new Object[] { java.sql.Types.TIMESTAMP, "TIMESTAMP", 63, null, 2, java.sql.DatabaseMetaData.columnNoNulls, null, null, null, 2, "NO" }); refcolumns.put( "Column8", new Object[] { java.sql.Types.DECIMAL, "DECIMAL", VoltDecimalHelper.kDefaultPrecision, VoltDecimalHelper.kDefaultScale, 10, java.sql.DatabaseMetaData.columnNullable, null, null, null, 3, "YES" }); refcolumns.put( "Column9", new Object[] { java.sql.Types.VARBINARY, "VARBINARY", 250, null, null, java.sql.DatabaseMetaData.columnNoNulls, null, null, 250, 1, "NO" }); refcolumns.put( "Column10", new Object[] { java.sql.Types.VARCHAR, "VARCHAR", 200, null, null, java.sql.DatabaseMetaData.columnNullable, null, null, 200, 1, "YES" }); refcolumns.put( "Column11", new Object[] { java.sql.Types.INTEGER, "INTEGER", 31, null, 2, java.sql.DatabaseMetaData.columnNullable, null, null, null, 2, "YES" }); refcolumns.put( "Default1", new Object[] { java.sql.Types.TINYINT, "TINYINT", 7, null, 2, java.sql.DatabaseMetaData.columnNullable, null, "10", null, 1, "YES" }); refcolumns.put( "Default2", new Object[] { java.sql.Types.VARCHAR, "VARCHAR", 50, null, null, java.sql.DatabaseMetaData.columnNullable, null, "'DUDE'", 50, 2, "YES" }); String schema = "create table Table1 (Column1 varchar(200) not null, Column2 tinyint);" + "create table Table2 (Column3 smallint not null, Column4 integer, Column5 bigint not null);" + "partition table Table2 on column Column3;" + "create table Table3 (Column6 float, Column7 timestamp not null, Column8 decimal);" + "create table Table4 (Column9 varbinary(250) not null);" + "create view View1 (Column10, Column11) as select Column1, count(*) from Table1 group by Column1;" + "create table Table5 (Default1 tinyint default 10, Default2 varchar(50) default 'DUDE');" + "create procedure sample as select * from Table1;"; VoltCompiler c = compileForDDLTest2(schema); System.out.println(c.getCatalog().serialize()); JdbcDatabaseMetaDataGenerator dut = new JdbcDatabaseMetaDataGenerator(c.getCatalog(), null, new InMemoryJarfile(testout_jar)); VoltTable columns = dut.getMetaData("ColUmns"); System.out.println(columns); assertEquals(23, columns.getColumnCount()); assertEquals(13, columns.getRowCount()); for (Map.Entry<String, Object[]> entry : refcolumns.entrySet()) { verifyColumnData(entry.getKey(), columns, entry.getValue()); } }
public boolean compile( final VoltCompiler compiler, final String jarPath, final int sitesPerHost, final int hostCount, final int replication, final String leaderAddress) { assert (jarPath != null); assert (sitesPerHost >= 1); assert (hostCount >= 1); assert (leaderAddress != null); // this stuff could all be converted to org.voltdb.compiler.projectfile.* // jaxb objects and (WE ARE!) marshaled to XML. Just needs some elbow grease. DocumentBuilderFactory docFactory; DocumentBuilder docBuilder; Document doc; try { docFactory = DocumentBuilderFactory.newInstance(); docBuilder = docFactory.newDocumentBuilder(); doc = docBuilder.newDocument(); } catch (final ParserConfigurationException e) { e.printStackTrace(); return false; } // <project> final Element project = doc.createElement("project"); doc.appendChild(project); // <security> final Element security = doc.createElement("security"); security.setAttribute("enabled", Boolean.valueOf(m_securityEnabled).toString()); project.appendChild(security); // <database> final Element database = doc.createElement("database"); database.setAttribute("name", "database"); database.setAttribute("project", this.project_name); project.appendChild(database); buildDatabaseElement(doc, database); // boilerplate to write this DOM object to file. StreamResult result; try { final Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); result = new StreamResult(new StringWriter()); final DOMSource domSource = new DOMSource(doc); transformer.transform(domSource, result); } catch (final TransformerConfigurationException e) { e.printStackTrace(); return false; } catch (final TransformerFactoryConfigurationError e) { e.printStackTrace(); return false; } catch (final TransformerException e) { e.printStackTrace(); return false; } // String xml = result.getWriter().toString(); // System.out.println(xml); final File projectFile = writeStringToTempFile(result.getWriter().toString()); final String projectPath = projectFile.getPath(); LOG.debug("PROJECT XML: " + projectPath); ClusterConfig cc = (this.cluster_config.isEmpty() ? new ClusterConfig(hostCount, sitesPerHost, replication, leaderAddress) : this.cluster_config); final boolean success = compiler.compile(projectPath, cc, jarPath, m_compilerDebugPrintStream, m_procInfoOverrides); // HACK: If we have a ParameterMappingsSet that we need to apply // either from a file or a fixed mappings, then we have // to load the catalog into this JVM, apply the mappings, and then // update the jar file with the new catalog if (m_paramMappingsFile != null || m_paramMappings.isEmpty() == false) { File jarFile = new File(jarPath); Catalog catalog = CatalogUtil.loadCatalogFromJar(jarFile); assert (catalog != null); Database catalog_db = CatalogUtil.getDatabase(catalog); this.applyParameterMappings(catalog_db); // Construct a List of prefetchable Statements this.applyPrefetchableFlags(catalog_db); // Write it out! try { CatalogUtil.updateCatalogInJar(jarFile, catalog, m_paramMappingsFile); } catch (Exception ex) { String msg = "Failed to updated Catalog in jar file '" + jarPath + "'"; throw new RuntimeException(msg, ex); } } return success; }
public static final void addClassToJar(final Class<?> cls, final VoltCompiler compiler) throws VoltCompiler.VoltCompilerException { if (cachedAddedClasses.contains(cls)) { return; } else { cachedAddedClasses.add(cls); } for (final Class<?> nested : cls.getDeclaredClasses()) { addClassToJar(nested, compiler); } String packagePath = cls.getName(); packagePath = packagePath.replace('.', '/'); packagePath += ".class"; String realName = cls.getName(); realName = realName.substring(realName.lastIndexOf('.') + 1); realName += ".class"; final URL absolutePath = cls.getResource(realName); File file = null; InputStream fis = null; int fileSize = 0; try { file = new File(URLDecoder.decode(absolutePath.getFile(), "UTF-8")); fis = new FileInputStream(file); assert (file.canRead()); assert (file.isFile()); fileSize = (int) file.length(); } catch (final FileNotFoundException e) { try { final String contents = JarReader.readFileFromJarfile(absolutePath.getPath()); fis = new StringInputStream(contents); fileSize = contents.length(); } catch (final Exception e2) { final String msg = "Unable to locate classfile for " + realName; throw compiler.new VoltCompilerException(msg); } } catch (final UnsupportedEncodingException e) { e.printStackTrace(); System.exit(-1); } assert (fileSize > 0); int readSize = 0; final byte[] fileBytes = new byte[fileSize]; try { while (readSize < fileSize) { readSize = fis.read(fileBytes, readSize, fileSize - readSize); } } catch (final IOException e) { final String msg = "Unable to read (or completely read) classfile for " + realName; throw compiler.new VoltCompilerException(msg); } compiler.addEntryToJarOutput(packagePath, fileBytes); }