/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb.compiler.statements; import java.util.regex.Matcher; import org.apache.commons.lang3.StringUtils; import org.voltdb.compiler.DDLCompiler; import org.voltdb.compiler.DDLCompiler.StatementProcessor; import org.voltdb.compiler.VoltCompiler.ProcedureDescriptor; import org.voltdb.compiler.VoltCompiler.VoltCompilerException; import org.voltdb.parser.SQLParser; /** * This class serves as the base class of two CREATE PROCEDURE processors, * it has some functions that are shared by the two processors. */ public abstract class CreateProcedure extends StatementProcessor { public CreateProcedure(DDLCompiler ddlCompiler) { super(ddlCompiler); } protected static class CreateProcedurePartitionData { String tableName = null; String columnName = null; String parameterNo = null; } /** * Parse and validate the substring containing ALLOW and PARTITION * clauses for CREATE PROCEDURE. * @param clauses the substring to parse * @param descriptor procedure descriptor populated with role names from ALLOW clause * @return parsed and validated partition data or null if there was no PARTITION clause * @throws VoltCompilerException */ protected CreateProcedurePartitionData parseCreateProcedureClauses( ProcedureDescriptor descriptor, String clauses) throws VoltCompilerException { // Nothing to do if there were no clauses. // Null means there's no partition data to return. // There's also no roles to add. if (clauses == null || clauses.isEmpty()) { return null; } CreateProcedurePartitionData data = null; Matcher matcher = SQLParser.matchAnyCreateProcedureStatementClause(clauses); int start = 0; while (matcher.find(start)) { start = matcher.end(); if (matcher.group(1) != null) { // Add roles if it's an ALLOW clause. More that one ALLOW clause is okay. for (String roleName : StringUtils.split(matcher.group(1), ',')) { // Don't put the same role in the list more than once. String roleNameFixed = roleName.trim().toLowerCase(); if (!descriptor.m_authGroups.contains(roleNameFixed)) { descriptor.m_authGroups.add(roleNameFixed); } } } else { // Add partition info if it's a PARTITION clause. Only one is allowed. if (data != null) { throw m_compiler.new VoltCompilerException( "Only one PARTITION clause is allowed for CREATE PROCEDURE."); } data = new CreateProcedurePartitionData(); data.tableName = matcher.group(2); data.columnName = matcher.group(3); data.parameterNo = matcher.group(4); } } return data; } protected void addProcedurePartitionInfo( String procName, CreateProcedurePartitionData data, String statement) throws VoltCompilerException { assert(procName != null); // Will be null when there is no optional partition clause. if (data == null) { return; } assert(data.tableName != null); assert(data.columnName != null); // Check the identifiers. checkIdentifierStart(procName, statement); checkIdentifierStart(data.tableName, statement); checkIdentifierStart(data.columnName, statement); // if not specified default parameter index to 0 if (data.parameterNo == null) { data.parameterNo = "0"; } String partitionInfo = String.format("%s.%s: %s", data.tableName, data.columnName, data.parameterNo); m_tracker.addProcedurePartitionInfoTo(procName, partitionInfo); } }