Skip to content

Commit

Permalink
Merge pull request #141 from VoltDB/ENG-3475
Browse files Browse the repository at this point in the history
ENG-3475 Support for CREATE PROCEDURE FROM CLASS <class-name>, and PARTITION PROC...
  • Loading branch information
Stefano Santoro committed Aug 23, 2012
2 parents 391083d + 5824c92 commit cd5de97
Show file tree
Hide file tree
Showing 15 changed files with 1,329 additions and 179 deletions.
380 changes: 320 additions & 60 deletions src/frontend/org/voltdb/compiler/DDLCompiler.java

Large diffs are not rendered by default.

131 changes: 131 additions & 0 deletions src/frontend/org/voltdb/compiler/PartitionMap.java
@@ -0,0 +1,131 @@
/* This file is part of VoltDB.
* Copyright (C) 2008-2012 VoltDB Inc.
*
* VoltDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VoltDB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VoltDB. If not, see <http://www.gnu.org/licenses/>.
*/

package org.voltdb.compiler;

import static org.voltdb.compiler.ProcedureCompiler.deriveShortProcedureName;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.voltdb.compiler.VoltCompiler.ProcedureDescriptor;
import org.voltdb.compiler.VoltCompiler.VoltCompilerException;

/**
* Maintains and validates partition info.
* Maps between table names and partition column names,
* and procedures and their respective partition info
* Column name is null if replicated.
*/
public class PartitionMap {
final VoltCompiler m_compiler;
final Map<String, String> m_map = new HashMap<String, String>();
final Map<String, ProcedureDescriptor> m_procedureMap =
new HashMap<String, ProcedureDescriptor>();

/**
* Constructor needs a compiler instance to throw VoltCompilerException.
* @param compiler VoltCompiler instance
*/
public PartitionMap(VoltCompiler compiler) {
m_compiler = compiler;
}

/**
* Add a table/column partition mapping for a PARTITION/REPLICATE statements.
* Validate input data and reject duplicates.
*
* @param tableName table name
* @param colName column name
* @throws VoltCompilerException
*/
void put(String tableName, String colName) throws VoltCompilerException
{
// where is table and column validity checked?
if (tableName.length() == 0) {
throw m_compiler.new VoltCompilerException("PARTITION or REPLICATE has no TABLE specified");
}

if (m_map.containsKey(tableName.toLowerCase())) {
throw m_compiler.new VoltCompilerException(String.format(
"Partitioning already specified for table \"%s\"", tableName));
}

m_map.put(tableName.toLowerCase(), colName);
}

/**
* Tracks the given procedure descriptor if it is not already tracked
* @param descriptor a {@link VoltCompiler.ProcedureDescriptor}
* @throws VoltCompilerException if it is already tracked
*/
void add(ProcedureDescriptor descriptor) throws VoltCompilerException
{
assert descriptor != null;

String className = descriptor.m_className;
assert className != null && ! className.trim().isEmpty();

String shortName = deriveShortProcedureName(className);

if( m_procedureMap.containsKey(shortName)) {
throw m_compiler.new VoltCompilerException(String.format(
"Procedure \"%s\" is already defined", className));
}

m_procedureMap.put(shortName, descriptor);
}

/**
* Associates the given partition info to the given tracked procedure
* @param procedureName the short name of the procedure name
* @param partitionInfo the partition info to associate with the procedure
* @throws VoltCompilerException when there is no corresponding tracked
* procedure
*/
void addProcedurePartitionInfoTo( String procedureName, String partitionInfo)
throws VoltCompilerException {

assert procedureName != null && ! procedureName.trim().isEmpty();
assert partitionInfo != null && ! partitionInfo.trim().isEmpty();

ProcedureDescriptor descriptor = m_procedureMap.get(procedureName);
if( descriptor == null) {
throw m_compiler.new VoltCompilerException(String.format(
"Partition in referencing an undefined procedure \"%s\"",
procedureName));
}

// need to re-instantiate as descriptor fields are final
descriptor = m_compiler.new ProcedureDescriptor(
descriptor.m_authGroups,
descriptor.m_className,
partitionInfo);

m_procedureMap.put(procedureName, descriptor);
}

/**
* gets the list of tracked procedure descriptors
* @return the list of tracked procedure descriptors
*/
Collection<ProcedureDescriptor> getProcedureDescriptors() {
return m_procedureMap.values();
}

}
34 changes: 32 additions & 2 deletions src/frontend/org/voltdb/compiler/ProcedureCompiler.java
Expand Up @@ -119,6 +119,21 @@ public static Map<String, Field> getValidSQLStmts(VoltCompiler compiler, String
return retval; return retval;
} }


/**
* get the short name of the class (no package)
* @param className fully qualified (or not) class name
* @return short name of the class (no package)
*/
static String deriveShortProcedureName( String className) {
if( className == null || className.trim().isEmpty()) {
return null;
}
String[] parts = className.split("\\.");
String shortName = parts[parts.length - 1];

return shortName;
}



static void compileJavaProcedure(VoltCompiler compiler, HSQLInterface hsql, static void compileJavaProcedure(VoltCompiler compiler, HSQLInterface hsql,
DatabaseEstimates estimates, Catalog catalog, Database db, DatabaseEstimates estimates, Catalog catalog, Database db,
Expand All @@ -137,8 +152,7 @@ static void compileJavaProcedure(VoltCompiler compiler, HSQLInterface hsql,
} }


// get the short name of the class (no package) // get the short name of the class (no package)
String[] parts = className.split("\\."); String shortName = deriveShortProcedureName(className);
String shortName = parts[parts.length - 1];


// add an entry to the catalog // add an entry to the catalog
final Procedure procedure = db.getProcedures().add(shortName); final Procedure procedure = db.getProcedures().add(shortName);
Expand All @@ -159,15 +173,31 @@ static void compileJavaProcedure(VoltCompiler compiler, HSQLInterface hsql,
// get the annotation // get the annotation
// first try to get one that has been passed from the compiler // first try to get one that has been passed from the compiler
ProcInfoData info = compiler.getProcInfoOverride(shortName); 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 // then check for the usual one in the class itself
// and create a ProcInfo.Data instance for it // and create a ProcInfo.Data instance for it
if (info == null) { if (info == null) {
info = new ProcInfoData(); info = new ProcInfoData();
ProcInfo annotationInfo = procClass.getAnnotation(ProcInfo.class); ProcInfo annotationInfo = procClass.getAnnotation(ProcInfo.class);
// error out if partition info is present in both ddl and annotation
if (annotationInfo != null && 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);
}
if (annotationInfo != null) { if (annotationInfo != null) {
info.partitionInfo = annotationInfo.partitionInfo(); info.partitionInfo = annotationInfo.partitionInfo();
info.singlePartition = annotationInfo.singlePartition(); info.singlePartition = annotationInfo.singlePartition();
} }
else if (ddlInfo != null) {
info = ddlInfo;
}
} }
assert(info != null); assert(info != null);


Expand Down
64 changes: 0 additions & 64 deletions src/frontend/org/voltdb/compiler/TablePartitionMap.java

This file was deleted.

19 changes: 17 additions & 2 deletions src/frontend/org/voltdb/compiler/VoltCompiler.java
Expand Up @@ -246,6 +246,18 @@ class ProcedureDescriptor {
m_builtInStmt = false; m_builtInStmt = false;
} }


ProcedureDescriptor (final ArrayList<String> authGroups, final String className, String partitionString) {
assert(className != null);
assert(partitionString != null);

m_authGroups = authGroups;
m_className = className;
m_singleStmt = null;
m_joinOrder = null;
m_partitionString = partitionString;
m_builtInStmt = false;
}

ProcedureDescriptor (final ArrayList<String> authGroups, final String className, ProcedureDescriptor (final ArrayList<String> authGroups, final String className,
final String singleStmt, final String joinOrder, final String partitionString, final String singleStmt, final String joinOrder, final String partitionString,
boolean builtInStmt) boolean builtInStmt)
Expand Down Expand Up @@ -497,7 +509,7 @@ void compileDatabaseNode(DatabaseType database) throws VoltCompilerException {
final ArrayList<String> schemas = new ArrayList<String>(); final ArrayList<String> schemas = new ArrayList<String>();
final ArrayList<ProcedureDescriptor> procedures = new ArrayList<ProcedureDescriptor>(); final ArrayList<ProcedureDescriptor> procedures = new ArrayList<ProcedureDescriptor>();
final ArrayList<Class<?>> classDependencies = new ArrayList<Class<?>>(); final ArrayList<Class<?>> classDependencies = new ArrayList<Class<?>>();
final TablePartitionMap partitionMap = new TablePartitionMap(this); final PartitionMap partitionMap = new PartitionMap(this);


final String databaseName = database.getName(); final String databaseName = database.getName();


Expand Down Expand Up @@ -532,7 +544,7 @@ void compileDatabaseNode(DatabaseType database) throws VoltCompilerException {
// procedures/procedure // procedures/procedure
if (database.getProcedures() != null) { if (database.getProcedures() != null) {
for (ProceduresType.Procedure proc : database.getProcedures().getProcedure()) { for (ProceduresType.Procedure proc : database.getProcedures().getProcedure()) {
procedures.add(getProcedure(proc)); partitionMap.add(getProcedure(proc));
} }
} }


Expand Down Expand Up @@ -671,6 +683,9 @@ void compileDatabaseNode(DatabaseType database) throws VoltCompilerException {
List<ProcedureDescriptor> autoCrudProcedures = generateCrud(m_catalog); List<ProcedureDescriptor> autoCrudProcedures = generateCrud(m_catalog);
procedures.addAll(autoCrudProcedures); procedures.addAll(autoCrudProcedures);


// Add procedures read from DDL and project file
procedures.addAll( partitionMap.getProcedureDescriptors());

// Actually parse and handle all the Procedures // Actually parse and handle all the Procedures
for (final ProcedureDescriptor procedureDescriptor : procedures) { for (final ProcedureDescriptor procedureDescriptor : procedures) {
final String procedureName = procedureDescriptor.m_className; final String procedureName = procedureDescriptor.m_className;
Expand Down

0 comments on commit cd5de97

Please sign in to comment.