org.teiid.modeshape.sequencer.ddl.AlterOptionsParser Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.modeshape.sequencer.ddl;
import java.util.ArrayList;
import java.util.List;
import org.modeshape.common.text.ParsingException;
import org.modeshape.common.util.StringUtil;
import org.teiid.modeshape.sequencer.ddl.TeiidDdlConstants.DdlStatement;
import org.teiid.modeshape.sequencer.ddl.TeiidDdlConstants.SchemaElementType;
import org.teiid.modeshape.sequencer.ddl.TeiidDdlConstants.TeiidReservedWord;
import org.teiid.modeshape.sequencer.ddl.node.AstNode;
/**
* A parser for the Teiid DDL statement.
*
*
* ALTER ( VIRTUAL | FOREIGN )? ( TABLE | VIEW | PROCEDURE ) ( | )
*
*/
final class AlterOptionsParser extends StatementParser {
AlterOptionsParser( final TeiidDdlParser teiidDdlParser ) {
super(teiidDdlParser);
}
/**
* {@inheritDoc}
*
* @see org.teiid.modeshape.sequencer.ddl.StatementParser#matches(org.teiid.modeshape.sequencer.ddl.DdlTokenStream)
*/
@Override
boolean matches( final DdlTokenStream tokens ) {
return tokens.matches(DdlStatement.ALTER_VIRTUAL_PROCEDURE.tokens())
|| tokens.matches(DdlStatement.ALTER_VIRTUAL_TABLE.tokens())
|| tokens.matches(DdlStatement.ALTER_VIRTUAL_VIEW.tokens())
|| tokens.matches(DdlStatement.ALTER_FOREIGN_PROCEDURE.tokens())
|| tokens.matches(DdlStatement.ALTER_FOREIGN_TABLE.tokens())
|| tokens.matches(DdlStatement.ALTER_FOREIGN_VIEW.tokens())
|| tokens.matches(DdlStatement.ALTER_PROCEDURE.tokens()) || tokens.matches(DdlStatement.ALTER_TABLE.tokens())
|| tokens.matches(DdlStatement.ALTER_VIEW.tokens());
}
/**
* {@inheritDoc}
*
* @see org.teiid.modeshape.sequencer.ddl.StatementParser#parse(org.teiid.modeshape.sequencer.ddl.DdlTokenStream,
* org.teiid.modeshape.sequencer.ddl.node.AstNode)
*/
@Override
AstNode parse( final DdlTokenStream tokens,
final AstNode parentNode ) throws ParsingException {
// ALTER TABLE
// ALTER TABLE
// ALTER VIEW
// ALTER VIEW
// ALTER PROCEDURE
// ALTER PROCEDURE
// ALTER VIRTUAL TABLE
// ALTER VIRTUAL TABLE
// ALTER VIRTUAL VIEW
// ALTER VIRTUAL VIEW
// ALTER VIRTUAL PROCEDURE
// ALTER VIRTUAL PROCEDURE
// ALTER FOREIGN TABLE
// ALTER FOREIGN TABLE
// ALTER FOREIGN VIEW
// ALTER FOREIGN VIEW
// ALTER FOREIGN PROCEDURE
// ALTER FOREIGN PROCEDURE
String nodeType = null;
SchemaElementType schemaElementType = null;
String refNodeType = null;
if (tokens.canConsume(DdlStatement.ALTER_TABLE.tokens())) {
nodeType = TeiidDdlLexicon.AlterOptions.TABLE_STATEMENT;
schemaElementType = SchemaElementType.FOREIGN;
refNodeType = TeiidDdlLexicon.CreateTable.TABLE_STATEMENT;
} else if (tokens.canConsume(DdlStatement.ALTER_VIEW.tokens())) {
nodeType = TeiidDdlLexicon.AlterOptions.VIEW_STATEMENT;
schemaElementType = SchemaElementType.FOREIGN;
refNodeType = TeiidDdlLexicon.CreateTable.VIEW_STATEMENT;
} else if (tokens.canConsume(DdlStatement.ALTER_PROCEDURE.tokens())) {
nodeType = TeiidDdlLexicon.AlterOptions.PROCEDURE_STATEMENT;
schemaElementType = SchemaElementType.FOREIGN;
refNodeType = TeiidDdlLexicon.CreateProcedure.PROCEDURE_STATEMENT;
} else if (tokens.canConsume(DdlStatement.ALTER_VIRTUAL_TABLE.tokens())) {
nodeType = TeiidDdlLexicon.AlterOptions.TABLE_STATEMENT;
schemaElementType = SchemaElementType.VIRTUAL;
refNodeType = TeiidDdlLexicon.CreateTable.TABLE_STATEMENT;
} else if (tokens.canConsume(DdlStatement.ALTER_VIRTUAL_VIEW.tokens())) {
nodeType = TeiidDdlLexicon.AlterOptions.VIEW_STATEMENT;
schemaElementType = SchemaElementType.VIRTUAL;
refNodeType = TeiidDdlLexicon.CreateTable.VIEW_STATEMENT;
} else if (tokens.canConsume(DdlStatement.ALTER_VIRTUAL_PROCEDURE.tokens())) {
nodeType = TeiidDdlLexicon.AlterOptions.PROCEDURE_STATEMENT;
schemaElementType = SchemaElementType.VIRTUAL;
refNodeType = TeiidDdlLexicon.CreateProcedure.PROCEDURE_STATEMENT;
} else if (tokens.canConsume(DdlStatement.ALTER_FOREIGN_TABLE.tokens())) {
nodeType = TeiidDdlLexicon.AlterOptions.TABLE_STATEMENT;
schemaElementType = SchemaElementType.FOREIGN;
refNodeType = TeiidDdlLexicon.CreateTable.TABLE_STATEMENT;
} else if (tokens.canConsume(DdlStatement.ALTER_FOREIGN_VIEW.tokens())) {
nodeType = TeiidDdlLexicon.AlterOptions.VIEW_STATEMENT;
schemaElementType = SchemaElementType.FOREIGN;
refNodeType = TeiidDdlLexicon.CreateTable.VIEW_STATEMENT;
} else if (tokens.canConsume(DdlStatement.ALTER_FOREIGN_PROCEDURE.tokens())) {
nodeType = TeiidDdlLexicon.AlterOptions.PROCEDURE_STATEMENT;
schemaElementType = SchemaElementType.FOREIGN;
refNodeType = TeiidDdlLexicon.CreateProcedure.PROCEDURE_STATEMENT;
} else {
throw new TeiidDdlParsingException(tokens, "Unparsable alter options statement");
}
assert (nodeType != null) : "Create alter options node type is null";
assert (schemaElementType != null) : "Create alter options schema element type is null";
assert (refNodeType != null) : "Create alter options reference node type is null";
// parse table reference
final String tableRefName = parseIdentifier(tokens);
final AstNode alterOptionsNode = getNodeFactory().node(tableRefName, parentNode, nodeType);
alterOptionsNode.setProperty(TeiidDdlLexicon.SchemaElement.TYPE, schemaElementType.toDdl());
// find referenced table node
final AstNode tableRefNode = getNode(parentNode, tableRefName, refNodeType);
// can't find referenced table
if (tableRefNode == null) {
//
// Causes a constraint violation exception as REFERENCE is mandatory
//
throw new TeiidDdlParsingException(tokens, "Alter options statement table reference '" + tableRefName + "' node not found");
}
alterOptionsNode.setProperty(TeiidDdlLexicon.AlterOptions.REFERENCE, tableRefNode);
// must have either a or a
if (!parseAlterOptionsList(tokens, alterOptionsNode) && !parseAlterColumnOptions(tokens, alterOptionsNode)) {
throw new TeiidDdlParsingException(tokens, "Unparsable alter options statement");
}
return alterOptionsNode;
}
/**
*
* ALTER ( COLUMN | PARAMETER )?
*
*
* @param tokens the tokens being processed (cannot be null
)
* @param alterOptionsNode the alter options node of the alter column options (cannot be null
)
* @return true
if an alter column options clause was successfully parsed
* @throws ParsingException if there is a problem parsing the alter options statement
*/
boolean parseAlterColumnOptions( final DdlTokenStream tokens,
final AstNode alterOptionsNode ) throws ParsingException {
// ALTER COLUMN
// ALTER PARAMATER
// ALTER
if (tokens.canConsume(TeiidReservedWord.ALTER.toDdl())) {
String nodeType = null;
if (tokens.canConsume(TeiidReservedWord.COLUMN.toDdl())) {
nodeType = TeiidDdlLexicon.AlterOptions.COLUMN;
} else if (tokens.canConsume(TeiidReservedWord.PARAMETER.toDdl())) {
nodeType = TeiidDdlLexicon.AlterOptions.PARAMETER;
} else {
nodeType = TeiidDdlLexicon.AlterOptions.COLUMN;
}
assert (nodeType != null) : "Alter column options node type is null";
final String refName = parseIdentifier(tokens);
final AstNode columnOptionsNode = getNodeFactory().node(refName, alterOptionsNode, nodeType);
// find referenced column/parameter
final AstNode refTableNode = (AstNode)alterOptionsNode.getProperty(TeiidDdlLexicon.AlterOptions.REFERENCE);
if (refTableNode == null) {
this.logger.debug("Table/procedure/view node not found for alter column '{0}'", refName);
} else {
String refPropType = null;
if (refTableNode.hasMixin(TeiidDdlLexicon.CreateProcedure.PROCEDURE_STATEMENT)) {
refPropType = TeiidDdlLexicon.CreateProcedure.PARAMETER;
} else {
refPropType = TeiidDdlLexicon.CreateTable.TABLE_ELEMENT;
}
final AstNode refNode = getNode(refTableNode, refName, refPropType);
// can't find referenced column node
if (refNode == null) {
this.logger.debug("Alter column options reference column node not found: {0}", refName);
}
columnOptionsNode.setProperty(TeiidDdlLexicon.AlterOptions.REFERENCE, refNode);
}
if (parseAlterOptionsList(tokens, columnOptionsNode)) {
return true; // well formed
}
throw new TeiidDdlParsingException(tokens, "Unparsable alter column options clause");
}
return false;
}
/**
*
* OPTIONS ( | ) ( ( | ) )*
*
* == ( ADD | SET )
*
* @param tokens the tokens being processed (cannot be null
)
* @param parentNode the parent node of the alter options list (cannot be null
)
* @return true
if an alter options list clause was successfully parsed; false
if not an alter
* options list clause
* @throws ParsingException if there is a problem parsing the alter options list clause
*/
@SuppressWarnings( "unchecked" )
boolean parseAlterOptionsList( final DdlTokenStream tokens,
final AstNode parentNode ) throws ParsingException {
// OPTIONS ()
// OPTIONS ()
// OPTIONS (, , , )
if (tokens.matches(TeiidReservedWord.OPTIONS.toDdl())) {
// must have opening paren
if (!tokens.canConsume(TeiidReservedWord.OPTIONS.toDdl(), L_PAREN)) {
throw new TeiidDdlParsingException(tokens, "Unparsable alter options list (left paren not found)");
}
if (tokens.matches(TeiidReservedWord.ADD.toDdl()) || tokens.matches(TeiidReservedWord.SET.toDdl())
|| tokens.matches(TeiidReservedWord.DROP.toDdl())) {
// create options list node
AstNode optionsListNode = null;
if (parentNode.hasMixin(TeiidDdlLexicon.AlterOptions.COLUMN)
|| parentNode.hasMixin(TeiidDdlLexicon.AlterOptions.PARAMETER)) {
optionsListNode = parentNode;
} else {
optionsListNode = getNodeFactory().node(TeiidDdlLexicon.AlterOptions.ALTERS,
parentNode,
TeiidDdlLexicon.AlterOptions.OPTIONS_LIST);
}
// will have one or more add, set, or drop clauses separated by comma
boolean keepParsing = tokens.hasNext();
boolean foundOption = false;
boolean foundComma = false;
while (keepParsing) {
if (tokens.canConsume(TeiidReservedWord.ADD.toDdl()) || tokens.canConsume(TeiidReservedWord.SET.toDdl())) {
final String option = parseIdentifier(tokens);
final String value = parseValue(tokens);
// only add if there is a value
if (!StringUtil.isBlank(value)) {
final AstNode optionsNode = getNodeFactory().node(option,
optionsListNode,
StandardDdlLexicon.TYPE_STATEMENT_OPTION);
optionsNode.setProperty(StandardDdlLexicon.VALUE, value);
}
foundOption = true;
foundComma = false;
} else if (tokens.canConsume(TeiidReservedWord.DROP.toDdl())) {
final String option = parseIdentifier(tokens);
List values = (List)optionsListNode.getProperty(TeiidDdlLexicon.AlterOptions.DROPPED);
if (values == null) {
values = new ArrayList();
}
values.add(option);
optionsListNode.setProperty(TeiidDdlLexicon.AlterOptions.DROPPED, values);
foundOption = true;
foundComma = false;
} else if (tokens.canConsume(COMMA)) {
// found comma before option
if (!foundOption) {
throw new TeiidDdlParsingException(tokens, "Unparsable alter options list (misplaced comma found)");
}
// 2 consecutive commas
if (foundComma) {
throw new TeiidDdlParsingException(tokens, "Unparsable alter options list (consecutive commas found)");
}
foundComma = true;
} else if (foundComma) {
throw new TeiidDdlParsingException(tokens, "Unparsable alter options list (comma found at end)");
} else {
keepParsing = false;
}
}
// must have ending paren
if (!tokens.canConsume(R_PAREN)) {
throw new TeiidDdlParsingException(tokens, "Unparsable alter options list (right paren not found)");
}
return true;
}
throw new TeiidDdlParsingException(tokens, "Unparsable alter options list (no add, set, or drop found)");
}
return false; // not an clause
}
@Override
protected void postProcess( AstNode rootNode ) {
}
}