* @param columnExpressionList the comma separated column expression list (cannot be <code>null</code>)
* @param indexNode the index node whose column expression list is being processed (cannot be <code>null</code>)
*/
private void parseIndexColumnExpressionList( final String columnExpressionList,
final AstNode indexNode ) {
final DdlTokenStream tokens = new DdlTokenStream(columnExpressionList, DdlTokenStream.ddlTokenizer(false), false);
tokens.start();
tokens.consume(L_PAREN); // must have opening paren
int numLeft = 1;
int numRight = 0;
// must have content between the parens
if (!tokens.matches(R_PAREN)) {
final List<String> possibleColumns = new ArrayList<String>(); // dimension table columns
final List<String> functions = new ArrayList<String>(); // functions, constants
final StringBuilder text = new StringBuilder();
boolean isFunction = false;
while (tokens.hasNext()) {
if (tokens.canConsume(COMMA)) {
if (isFunction) {
functions.add(text.toString());
} else {
possibleColumns.add(text.toString());
}
text.setLength(0); // clear out
isFunction = false;
continue;
}
if (tokens.matches(L_PAREN)) {
isFunction = true;
++numLeft;
} else if (tokens.matches("ASC") || tokens.matches("DESC")) {
text.append(SPACE);
} else if (tokens.matches(R_PAREN)) {
if (numLeft == ++numRight) {
if (isFunction) {
functions.add(text.toString());
} else {
possibleColumns.add(text.toString());
}
break;
}
}
text.append(tokens.consume());
}
if (!possibleColumns.isEmpty()) {
List<AstNode> tableNodes = null;
final boolean tableIndex = indexNode.hasMixin(OracleDdlLexicon.TYPE_CREATE_TABLE_INDEX_STATEMENT);
// find appropriate table nodes
if (tableIndex) {
// table index so find table node
final String tableName = (String)indexNode.getProperty(OracleDdlLexicon.TABLE_NAME);
final AstNode parent = indexNode.getParent();
final List<AstNode> nodes = parent.childrenWithName(tableName);
if (!nodes.isEmpty()) {
if (nodes.size() == 1) {
tableNodes = nodes;
} else {
// this should not be possible but check none the less
for (final AstNode node : nodes) {
if (node.hasMixin(StandardDdlLexicon.TYPE_CREATE_TABLE_STATEMENT)) {
tableNodes = new ArrayList<AstNode>(1);
tableNodes.add(node);
break;
}
}
}
}
} else {
// must be bitmap-join
tableNodes = indexNode.getChildren(StandardDdlLexicon.TYPE_TABLE_REFERENCE);
}
if ((tableNodes != null) && !tableNodes.isEmpty()) {
boolean processed = false;
for (String possibleColumn : possibleColumns) {
// first determine any ordering
final int ascIndex = possibleColumn.toUpperCase().indexOf(" ASC");
final boolean asc = (ascIndex != -1);
final int descIndex = possibleColumn.toUpperCase().indexOf(" DESC");
boolean desc = (descIndex != -1);
// adjust column name if there is ordering
if (asc) {
possibleColumn = possibleColumn.substring(0, ascIndex);
} else if (desc) {
possibleColumn = possibleColumn.substring(0, descIndex);
}
if (tableIndex) {
if (tableNodes.isEmpty()) {
if (asc) {
functions.add(possibleColumn + SPACE + "ASC");
} else if (desc) {
functions.add(possibleColumn + SPACE + "DESC");
} else {
functions.add(possibleColumn);
}
} else {
// only one table reference. need to find column.
final AstNode tableNode = tableNodes.get(0);
final List<AstNode> columnNodes = tableNode.getChildren(StandardDdlLexicon.TYPE_COLUMN_DEFINITION);
if (!columnNodes.isEmpty()) {
// find column
for (final AstNode colNode : columnNodes) {
if (colNode.getName().toUpperCase().equals(possibleColumn.toUpperCase())) {
final AstNode colRef = nodeFactory().node(possibleColumn,
indexNode,
TYPE_COLUMN_REFERENCE);
if (asc || desc) {
colRef.addMixin(OracleDdlLexicon.TYPE_INDEX_ORDERABLE);
if (asc) {
colRef.setProperty(OracleDdlLexicon.INDEX_ORDER, "ASC");
} else {
colRef.setProperty(OracleDdlLexicon.INDEX_ORDER, "DESC");
}
}
processed = true;
break;
}
}
}
if (!processed) {
if (asc) {
functions.add(possibleColumn + SPACE + "ASC");
} else if (desc) {
functions.add(possibleColumn + SPACE + "DESC");
} else {
functions.add(possibleColumn);
}
processed = true;
}
}
} else {
// bitmap-join
for (final AstNode dimensionTableNode : tableNodes) {
if (possibleColumn.toUpperCase().startsWith(dimensionTableNode.getName().toUpperCase() + PERIOD)) {
final AstNode colRef = nodeFactory().node(possibleColumn, indexNode, TYPE_COLUMN_REFERENCE);
if (asc || desc) {
colRef.addMixin(OracleDdlLexicon.TYPE_INDEX_ORDERABLE);
if (asc) {
colRef.setProperty(OracleDdlLexicon.INDEX_ORDER, "ASC");
} else {
colRef.setProperty(OracleDdlLexicon.INDEX_ORDER, "DESC");
}
}
processed = true;
break;
}
}
// probably a constant or function
if (!processed) {
if (asc) {
functions.add(possibleColumn + SPACE + "ASC");
} else if (desc) {
functions.add(possibleColumn + SPACE + "DESC");
} else {
functions.add(possibleColumn);
}
processed = true;
}
}
}
}
}
if (!functions.isEmpty()) {
indexNode.setProperty(OracleDdlLexicon.OTHER_INDEX_REFS, functions);
}
}
if (numLeft != numRight) {
throw new ParsingException(tokens.nextPosition());
}
tokens.consume(R_PAREN); // must have closing paren
}