Java tutorial
/** * Copyright 2010 The Apache Software Foundation * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.wasp.plan.parser.druid; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLOrderingSpecification; import com.alibaba.druid.sql.ast.SQLPartitioningClause; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLDropIndexStatement; import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.ast.statement.SQLTableElement; import com.alibaba.druid.sql.ast.statement.SQLTruncateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.wasp.DataType; import com.alibaba.wasp.FConstants; import com.alibaba.wasp.FieldKeyWord; import com.alibaba.wasp.TableExistsException; import com.alibaba.wasp.TableNotFoundException; import com.alibaba.wasp.meta.FTable; import com.alibaba.wasp.meta.Field; import com.alibaba.wasp.meta.Index; import com.alibaba.wasp.meta.TableSchemaCacheReader; import com.alibaba.wasp.plan.AlterTablePlan; import com.alibaba.wasp.plan.CreateIndexPlan; import com.alibaba.wasp.plan.CreateTablePlan; import com.alibaba.wasp.plan.DescTablePlan; import com.alibaba.wasp.plan.DropIndexPlan; import com.alibaba.wasp.plan.DropTablePlan; import com.alibaba.wasp.plan.NotingTodoPlan; import com.alibaba.wasp.plan.ShowIndexesPlan; import com.alibaba.wasp.plan.ShowTablesPlan; import com.alibaba.wasp.plan.TruncateTablePlan; import com.alibaba.wasp.plan.parser.ParseContext; import com.alibaba.wasp.plan.parser.UnsupportedException; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlAlterTableChangeColumn; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlColumnDefinition; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlCreateIndexStatement; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlCreateTableStatement; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlDescribeStatement; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlDropTableStatement; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlPartitionByKey; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlShowCreateTableStatement; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlShowIndexesStatement; import com.alibaba.wasp.plan.parser.druid.dialect.WaspSqlShowTablesStatement; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.util.Bytes; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map.Entry; /** * Use Druid (https://github.com/AlibabaTech/druid) to parse the sql and * generate Execute Plan * */ public class DruidDDLParser extends DruidParser { private static final Log LOG = LogFactory.getLog(DruidDDLParser.class); /** * @param conf */ public DruidDDLParser(Configuration conf) { super(); this.setConf(conf); } /** * Parse sql and generate Execute Plan:CREATE,DROP,ALTER * */ @Override public void generatePlan(ParseContext context) throws IOException { SQLStatement stmt = context.getStmt(); MetaEventOperation metaEventOperation = new FMetaEventOperation(context.getTsr()); if (stmt instanceof WaspSqlCreateTableStatement) { // This is a Create Table SQL getCreateTablePlan(context, (WaspSqlCreateTableStatement) stmt, metaEventOperation); } else if (stmt instanceof WaspSqlCreateIndexStatement) { // This is a Create Index SQL getCreateIndexPlan(context, (WaspSqlCreateIndexStatement) stmt, metaEventOperation); } else if (stmt instanceof SQLDropTableStatement) { // This is a Drop Table SQL getDropTablePlan(context, (SQLDropTableStatement) stmt, metaEventOperation); } else if (stmt instanceof SQLDropIndexStatement) { // This is a Drop Index SQL getDropIndexPlan(context, (SQLDropIndexStatement) stmt, metaEventOperation); } else if (stmt instanceof MySqlAlterTableStatement) { // This is a Alter Table SQL getAlterTablePlan(context, (MySqlAlterTableStatement) stmt, metaEventOperation); } else if (stmt instanceof WaspSqlShowTablesStatement) { // This is a Show Tables SQL getShowTablesPlan(context, (WaspSqlShowTablesStatement) stmt, metaEventOperation); } else if (stmt instanceof WaspSqlShowCreateTableStatement) { // This is a Show Create Table SQL getShowCreateTablePlan(context, (WaspSqlShowCreateTableStatement) stmt, metaEventOperation); } else if (stmt instanceof WaspSqlDescribeStatement) { // This is a DESCRIBE SQL getDescribePlan(context, (WaspSqlDescribeStatement) stmt, metaEventOperation); } else if (stmt instanceof WaspSqlShowIndexesStatement) { // This is a SHOW INDEXES SQL getShowIndexesPlan(context, (WaspSqlShowIndexesStatement) stmt, metaEventOperation); } else if (stmt instanceof SQLTruncateStatement) { // This is a TRUNCATE TABLE SQL getTruncatePlan(context, (SQLTruncateStatement) stmt, metaEventOperation); } else { throw new UnsupportedException("Unsupported SQLStatement " + SQLUtils.toSQLString(stmt)); } } /** * Process TRUNCATE Table Statement and generate Execute Plan * */ private void getTruncatePlan(ParseContext context, SQLTruncateStatement sqlTruncateStatement, MetaEventOperation metaEventOperation) throws IOException { List<SQLExprTableSource> tableSources = sqlTruncateStatement.getTableSources(); List<String> tableNames = new ArrayList<String>(); for (SQLExprTableSource tableSource : tableSources) { String tablename = parseFromClause(tableSource); // check if table exists and get Table info metaEventOperation.checkAndGetTable(tablename, true); tableNames.add(tablename); } TruncateTablePlan truncateTable = new TruncateTablePlan(tableNames); context.setPlan(truncateTable); LOG.debug("TruncateTablePlan " + truncateTable.toString()); } /** * Process SHOW INDEXES Statement and generate Execute Plan * */ private void getShowIndexesPlan(ParseContext context, WaspSqlShowIndexesStatement sqlShowIndexesStatement, MetaEventOperation metaEventOperation) throws IOException { SQLName object = sqlShowIndexesStatement.getTable(); String tablename = parseName(object); // check if table exists and get Table info metaEventOperation.checkAndGetTable(tablename, true); ShowIndexesPlan showIndexesTable = new ShowIndexesPlan(tablename); context.setPlan(showIndexesTable); LOG.debug("ShowIndexesPlan " + showIndexesTable.toString()); } /** * Process Describe Table Statement and generate Execute Plan * */ private void getDescribePlan(ParseContext context, WaspSqlDescribeStatement sqlDescribeStatement, MetaEventOperation metaEventOperation) throws IOException { SQLName object = sqlDescribeStatement.getObject(); String tablename = parseName(object); // check if table exists and get Table info metaEventOperation.checkAndGetTable(tablename, true); DescTablePlan descTable = new DescTablePlan(tablename); context.setPlan(descTable); LOG.debug("DescTablePlan " + descTable.toString()); } /** * Process Show Tables Statement and generate Execute Plan * */ private void getShowTablesPlan(ParseContext context, WaspSqlShowTablesStatement sqlShowTablesStatement, MetaEventOperation metaEventOperation) throws IOException { ShowTablesPlan showTables = null; SQLExpr like = sqlShowTablesStatement.getLike(); SQLExpr where = sqlShowTablesStatement.getWhere(); if (like == null && where == null) { showTables = new ShowTablesPlan(ShowTablesPlan.ShowTablesType.ALL); } else if (like != null) { showTables = new ShowTablesPlan(ShowTablesPlan.ShowTablesType.LIKE); String likePattern = parseString(like); showTables.setLikePattern(likePattern); } else if (where != null) { throw new UnsupportedException("Show tables where not Unsupported!"); } context.setPlan(showTables); LOG.debug("ShowTablesPlan " + showTables.toString()); } /** * Process Show Create Table Statement and generate Execute Plan * */ private void getShowCreateTablePlan(ParseContext context, WaspSqlShowCreateTableStatement sqlShowCreateTableStatement, MetaEventOperation metaEventOperation) throws IOException { ShowTablesPlan showTables = new ShowTablesPlan(ShowTablesPlan.ShowTablesType.CREATE); SQLExpr name = sqlShowCreateTableStatement.getName(); String tablename = parseName(name); // check if table exists and get Table info metaEventOperation.checkAndGetTable(tablename, true); showTables.setTablename(tablename); context.setPlan(showTables); LOG.debug("ShowTablesPlan " + showTables.toString()); } /** * Process Alter Table Statement and generate Execute Plan * */ private void getAlterTablePlan(ParseContext context, MySqlAlterTableStatement sqlAlterTableStatement, MetaEventOperation metaEventOperation) throws IOException { SQLExprTableSource tableSource = sqlAlterTableStatement.getTableSource(); String tableName = parseFromClause(tableSource); // check if table exists and get Table info FTable oldTable = metaEventOperation.checkAndGetTable(tableName, true); FTable newTable = FTable.clone(oldTable); List<SQLAlterTableItem> items = sqlAlterTableStatement.getItems(); for (SQLAlterTableItem item : items) { if (item instanceof WaspSqlAlterTableChangeColumn) { // Alter Table Change Column WaspSqlAlterTableChangeColumn changeColumn = (WaspSqlAlterTableChangeColumn) item; SQLName columnName = changeColumn.getColumnName(); LinkedHashMap<String, Field> ftableColumns = newTable.getColumns(); String oldColumnName = parseName(columnName); // Table have this column and this column is not primary key metaEventOperation.checkFieldExists(oldTable, oldColumnName); metaEventOperation.checkFieldNotInPrimaryKeys(oldTable, oldColumnName); // Check column not in a index metaEventOperation.checkColumnNotInIndex(oldTable, oldColumnName); // Which column(index) to change Field field = ftableColumns.get(oldColumnName); // Change this Field SQLColumnDefinition newColumnDefinition = changeColumn.getNewColumnDefinition(); // ColumnFamily specify do not supported. if (newColumnDefinition instanceof WaspSqlColumnDefinition) { WaspSqlColumnDefinition waspSqlColumnDefinition = (WaspSqlColumnDefinition) newColumnDefinition; if (waspSqlColumnDefinition.getColumnFamily() != null) { throw new UnsupportedException("Alter Table, columnFamily specify do not supported."); } } if (newColumnDefinition.getDataType() != null) { field.setType(parse(newColumnDefinition.getDataType())); } String newColumnName = parseName(newColumnDefinition.getName()); if (!oldColumnName.equals(newColumnName)) { // Change column name for (Field f : ftableColumns.values()) { if (f.getName().equalsIgnoreCase(newColumnName)) { throw new UnsupportedException( "Unsupported. Rename one column to a column that already column " + newColumnName); } } field.setName(newColumnName); } } else if (item instanceof MySqlAlterTableAddColumn) { // Alter Table Add Column MySqlAlterTableAddColumn addColumn = (MySqlAlterTableAddColumn) item; List<SQLColumnDefinition> columns = addColumn.getColumns(); boolean first = addColumn.isFirst(); SQLName afterColumn = addColumn.getAfterColumn(); LinkedHashMap<String, Field> ftableColumns = newTable.getColumns(); List<Field> addFields = convertColumnDefForAlterTable(columns); // check Duplicate column name metaEventOperation.areLegalTableColumns(ftableColumns.values(), addFields); // Do not support add ColumnFamily dynamic right now. metaEventOperation.checkColumnFamilyName(ftableColumns.values(), addFields); if (first) { this.addFieldByPosition(-1, addFields, ftableColumns, newTable); } else if (afterColumn != null) { int index = getIndex(parseName(afterColumn), ftableColumns); this.addFieldByPosition(index, addFields, ftableColumns, newTable); } else { int index = ftableColumns.size() - 1; this.addFieldByPosition(index, addFields, ftableColumns, newTable); } } else if (item instanceof SQLAlterTableDropColumnItem) { // Alter Table Drop Column SQLAlterTableDropColumnItem dropColumn = (SQLAlterTableDropColumnItem) item; SQLName columnName = dropColumn.getColumnName(); String cname = parseName(columnName); // This column is not primary key metaEventOperation.checkFieldNotInPrimaryKeys(oldTable, cname); // Check column not in a index, if you want to drop the column you // should drop the index first metaEventOperation.checkColumnNotInIndex(oldTable, cname); LinkedHashMap<String, Field> ftableColumns = newTable.getColumns(); Field field = ftableColumns.remove(cname); if (field == null) { throw new UnsupportedException("Unsupported Do not find this column " + SQLUtils.toSQLString(((SQLAlterTableDropColumnItem) item).getColumnName())); } newTable.setColumns(ftableColumns); } else { throw new UnsupportedException(SQLUtils.toSQLString(item) + " SQLAlterTableItem Unsupported"); } } AlterTablePlan alterTable = new AlterTablePlan(oldTable, newTable); context.setPlan(alterTable); LOG.debug("AlterTablePlan " + alterTable.toString()); } private void addFieldByPosition(int index, List<Field> addFields, LinkedHashMap<String, Field> ftableColumns, FTable newTable) { LinkedHashMap<String, Field> finalColumns = new LinkedHashMap<String, Field>(); int i = 0; if (index < 0) { for (Field addField : addFields) { finalColumns.put(addField.getName(), addField); } } for (Field field : ftableColumns.values()) { if (index == i) { finalColumns.put(field.getName(), field); for (Field addField : addFields) { finalColumns.put(addField.getName(), addField); } } else { finalColumns.put(field.getName(), field); } i++; } newTable.setColumns(finalColumns); } /** * Process Drop Table Statement and generate Execute Plan * */ private void getDropTablePlan(ParseContext context, SQLDropTableStatement sqlDropTableStatement, MetaEventOperation metaEventOperation) throws IOException { List<SQLExprTableSource> tableSources = sqlDropTableStatement.getTableSources(); List<String> tableNames = new ArrayList<String>(tableSources.size()); boolean ifExists = ((WaspSqlDropTableStatement) sqlDropTableStatement).isIfExists(); for (SQLExprTableSource tableSource : tableSources) { String tableName = parseFromClause(tableSource); // check if table exists and get Table info try { metaEventOperation.checkAndGetTable(tableName, true); } catch (TableNotFoundException e) { if (!ifExists) { throw e; } else { continue; } } tableNames.add(tableName); } DropTablePlan dropTable = new DropTablePlan(tableNames); context.setPlan(dropTable); LOG.debug("DropTablePlan " + dropTable.toString()); } /** * Process Create Table Statement and generate Execute Plan * */ private void getCreateTablePlan(ParseContext context, WaspSqlCreateTableStatement waspSqlCreateTableStatement, MetaEventOperation metaEventOperation) throws IOException { /** * example String sql3 = "CREATE TABLE User {Required Int64 user_id; * Required String name; Optional String phone;} primary key(user_id),ENTITY * GROUP ROOT, Entity Group Key(user_id);" ; String sql4 = "CREATE TABLE * Photo { Required Int64 user_id columnfamily cf comment 'aaa'; Required * Int32 photo_id comment 'child primary key'; Required Int64 time; Required * String full_url; Optional String thumbnail_url; Repeated String tag; } * primary key(user_id, photo_id) IN TABLE user,ENTITY GROUP KEY(user_id) * references User;"; */ // Table Info SQLExprTableSource tableSource = waspSqlCreateTableStatement.getTableSource(); String tableName = parseFromClause(tableSource); // Check Table Name is legal. metaEventOperation.isLegalTableName(tableName); // Check if the table exists boolean tableNotExit = metaEventOperation.checkTableNotExists(tableName, true); if (!tableNotExit) { if (waspSqlCreateTableStatement.isIfNotExiists()) { context.setPlan(new NotingTodoPlan()); LOG.debug("table " + tableName + " exits , isIfNotExiists is true, ignore"); return; } else { throw new TableExistsException(tableName + " is already exists!"); } } // Table category. WaspSqlCreateTableStatement.TableCategory category = waspSqlCreateTableStatement.getCategory(); FTable.TableType tableType = FTable.TableType.CHILD; if (category != null && category == WaspSqlCreateTableStatement.TableCategory.ROOT) { tableType = FTable.TableType.ROOT; } // Primary Key. List<SQLExpr> primaryKeysSQLExpr = waspSqlCreateTableStatement.getPrimaryKeys(); // table columns. List<SQLTableElement> tableElementList = waspSqlCreateTableStatement.getTableElementList(); // columns info LinkedHashMap<String, Field> columns = new LinkedHashMap<String, Field>(); for (SQLTableElement element : tableElementList) { Field field = parse(element); columns.put(field.getName(), field); } // Check if columns are legal. metaEventOperation.areLegalTableColumns(null, columns.values()); checkFamilyLegal(columns.values(), metaEventOperation); // Primary keys check will be done in this following method LinkedHashMap<String, Field> primaryKeys = parse(primaryKeysSQLExpr, columns); long createTime = System.currentTimeMillis(); long lastAccessTime = createTime; String owner = "me"; FTable table = new FTable(null, tableName, tableType, owner, createTime, lastAccessTime, columns, primaryKeys, primaryKeys.entrySet().iterator().next().getValue()); SQLExpr entityGroupKeySQLExpr = waspSqlCreateTableStatement.getEntityGroupKey(); Field entityGroupKey = primaryKeys.get(parseName(entityGroupKeySQLExpr)); if (entityGroupKey == null) { throw new UnsupportedException(entityGroupKeySQLExpr + " is ForeignKey, but don't in primaryKeys."); } table.setEntityGroupKey(entityGroupKey); if (tableType == FTable.TableType.CHILD) { String parentName = parseFromClause(waspSqlCreateTableStatement.getInTableName()); table.setParentName(parentName); if (!parentName.equals(parseFromClause(waspSqlCreateTableStatement.getReferenceTable()))) { throw new UnsupportedException(" in table " + waspSqlCreateTableStatement.getInTableName() + " != references table " + waspSqlCreateTableStatement.getReferenceTable()); } // Check parent's EGK equals child's EGK. TableSchemaCacheReader reader = TableSchemaCacheReader.getInstance(configuration); FTable parentTable = reader.getSchema(parentName); if (parentTable == null) { parentTable = TableSchemaCacheReader.getService(reader.getConf()).getTable(tableName); } if (parentTable == null) { throw new TableNotFoundException("Not found parent table:" + parentName); } if (!parentTable.getEntityGroupKey().getName().equals(table.getEntityGroupKey().getName())) { throw new UnsupportedException( "Parent" + parentName + "'s egk doesn't equals Child" + tableName + "'s egk."); } // Check child's PKS contains parent's PKS. for (Field parentPrimaryKey : parentTable.getPrimaryKeys().values()) { boolean found = table.getPrimaryKeys().containsKey(parentPrimaryKey.getName()); if (!found) { throw new UnsupportedException("Child's pks must contains parent's pks."); } } } SQLPartitioningClause partitioning = waspSqlCreateTableStatement.getPartitioning(); byte[][] splitKeys = null; if (partitioning != null) { if (table.isRootTable()) { if (partitioning instanceof WaspSqlPartitionByKey) { WaspSqlPartitionByKey partitionKey = (WaspSqlPartitionByKey) partitioning; byte[] start = convert(null, partitionKey.getStart()); byte[] end = convert(null, partitionKey.getEnd()); int partitionCount = convertToInt(partitionKey.getPartitionCount()); splitKeys = Bytes.split(start, end, partitionCount - 3); } else { throw new UnsupportedException("Unsupported SQLPartitioningClause " + partitioning); } } else { throw new UnsupportedException("Partition by only supported for Root Table"); } } CreateTablePlan createTable = new CreateTablePlan(table, splitKeys); context.setPlan(createTable); LOG.debug("CreateTablePlan " + createTable.toString()); } private void checkFamilyLegal(Collection<Field> newColumns, MetaEventOperation metaEventOperation) throws IOException { for (Field newColumn : newColumns) { if (!newColumn.getFamily().equals(FConstants.COLUMNFAMILYNAME_STR)) { metaEventOperation.isLegalFamilyName(newColumn.getFamily()); } } } private LinkedHashMap<String, Field> parse(List<SQLExpr> particularColumns, LinkedHashMap<String, Field> columns) throws UnsupportedException { LinkedHashMap<String, Field> particularFields = new LinkedHashMap<String, Field>(particularColumns.size()); for (SQLExpr expr : particularColumns) { String name = parseName(expr); Field field = columns.get(name); if (field == null) { throw new UnsupportedException("Unsupported table don't have this primaryKey " + expr); } particularFields.put(name, field); } return particularFields; } private Field parse(SQLTableElement tableElement) throws UnsupportedException { Field field = null; FieldKeyWord keyWord = null; if (tableElement instanceof WaspSqlColumnDefinition) { WaspSqlColumnDefinition column = (WaspSqlColumnDefinition) tableElement; if (column.getColumnConstraint() == FieldKeyWord.REQUIRED) { keyWord = FieldKeyWord.REQUIRED; } else if (column.getColumnConstraint() == FieldKeyWord.OPTIONAL) { keyWord = FieldKeyWord.OPTIONAL; } else if (column.getColumnConstraint() == FieldKeyWord.REPEATED) { keyWord = FieldKeyWord.REPEATED; } else { throw new UnsupportedException("Unsupported ColumnConstraint " + column.getColumnConstraint()); } SQLName name = column.getName(); SQLDataType dataType = column.getDataType(); SQLName columnFamilyName = column.getColumnFamily(); String columnFamily = FConstants.COLUMNFAMILYNAME_STR; if (columnFamilyName != null) { columnFamily = parseName(columnFamilyName); } field = new Field(keyWord, columnFamily, parseName(name), parse(dataType), column.getComment()); return field; } else { throw new UnsupportedException("Unsupported SQLColumnDefinition " + tableElement); } } /** * Process Drop Index Statement and generate Execute Plan * */ private void getDropIndexPlan(ParseContext context, SQLDropIndexStatement sqlDropIndexStatement, MetaEventOperation metaEventOperation) throws IOException { SQLExpr indexNameExpr = sqlDropIndexStatement.getIndexName(); SQLExpr table = sqlDropIndexStatement.getTableName(); String tableName = parseName(table); // check if table exists and get Table info FTable ftable = metaEventOperation.checkAndGetTable(tableName, true); String indexName = parseName(indexNameExpr); metaEventOperation.checkIndexExists(ftable, indexName); DropIndexPlan dropIndex = new DropIndexPlan(indexName, tableName); context.setPlan(dropIndex); LOG.debug("DropIndexPlan " + dropIndex.toString()); } /** * Process Create Index Statement and generate Execute Plan * */ private void getCreateIndexPlan(ParseContext context, WaspSqlCreateIndexStatement sqlCreateIndexStatement, MetaEventOperation metaEventOperation) throws IOException { // Index Name SQLName name = sqlCreateIndexStatement.getName(); String indexName = parseName(name); metaEventOperation.isLegalIndexName(indexName); LOG.debug("Create Index SQL IndexName " + name); // Table Name SQLName table = sqlCreateIndexStatement.getTable(); String tableName = parseName(table); LOG.debug("Create Index SQL TableName " + table); // check if table exists and get Table info FTable fTable = metaEventOperation.checkAndGetTable(tableName, true); // check the index not exists metaEventOperation.checkIndexNotExists(fTable, indexName); // Field List<SQLSelectOrderByItem> items = sqlCreateIndexStatement.getItems(); LinkedHashSet<String> columns = new LinkedHashSet<String>(items.size()); List<String> desc = new ArrayList<String>(); for (SQLSelectOrderByItem item : items) { String columnName = parseName(item.getExpr()); if (columns.contains(columnName)) { throw new UnsupportedException("Index have two same field '" + columnName + "'"); } else { columns.add(columnName); } if (item.getType() == SQLOrderingSpecification.DESC) { desc.add(columnName); } } if (!metaEventOperation.isLegalDescFields(fTable, desc)) { throw new UnsupportedException("Currently we only support the ascending and descending time field."); } List<String> colList = new ArrayList<String>(); colList.addAll(columns); if (metaEventOperation.arePrimaryKeys(fTable, colList)) { throw new UnsupportedException("Index keys is Primary Keys."); } if (metaEventOperation.containPrimaryKeys(fTable, colList)) { throw new UnsupportedException("Index keys contain all Primary Keys."); } LinkedHashMap<String, Field> indexKeys = metaEventOperation.checkAndGetFields(fTable, columns); // Check the indexKeys whether have Duplicate column name metaEventOperation.areLegalTableColumns(null, indexKeys.values()); Index index = new Index(indexName, tableName, indexKeys); // Check if two index have the same columns and the same columns order metaEventOperation.checkTwoIndexWithSameColumn(fTable, index); index.setDesc(desc); index.setStoring(parse(sqlCreateIndexStatement.getStoringCols(), fTable.getColumns())); CreateIndexPlan createIndexPlan = new CreateIndexPlan(index); context.setPlan(createIndexPlan); LOG.debug("CreateIndexPlan " + createIndexPlan.toString()); } public int getIndex(String name, LinkedHashMap<String, Field> columns) throws UnsupportedException { Iterator<Entry<String, Field>> iter = columns.entrySet().iterator(); int i = 0; while (iter.hasNext()) { Field field = iter.next().getValue(); if (field.getName().equals(name)) { return i; } i++; } throw new UnsupportedException(name + " is not in set"); } public static List<Field> convertColumnDefForAlterTable(List<SQLColumnDefinition> columns) throws UnsupportedException { List<Field> addFields = new ArrayList<Field>(); for (SQLColumnDefinition sqlColumnDefinition : columns) { addFields.add(convertColumnDefForAlterTable(sqlColumnDefinition)); } return addFields; } private static Field convertColumnDefForAlterTable(SQLColumnDefinition column) throws UnsupportedException { Field field = new Field(); if (column instanceof WaspSqlColumnDefinition) { WaspSqlColumnDefinition waspColumn = (WaspSqlColumnDefinition) column; if (waspColumn.getComment() != null) { field.setComment(waspColumn.getComment()); } if (waspColumn.getColumnFamily() != null) { field.setFamily(parseName(waspColumn.getColumnFamily())); } else { field.setFamily(FConstants.COLUMNFAMILYNAME_STR); } field.setKeyWord(FieldKeyWord.OPTIONAL); field.setName(parseName(column.getName())); field.setType(parse(column.getDataType())); } else { field.setComment(column.getComment()); field.setFamily(FConstants.COLUMNFAMILYNAME_STR); field.setKeyWord(FieldKeyWord.OPTIONAL); field.setName(parseName(column.getName())); field.setType(parse(column.getDataType())); } return field; } public static DataType parse(SQLDataType dataType) throws UnsupportedException { String typeName = dataType.getName(); if (typeName.equalsIgnoreCase("INT32")) { return DataType.INT32; } else if (typeName.equalsIgnoreCase("INT64")) { return DataType.INT64; } else if (typeName.equalsIgnoreCase("STRING")) { return DataType.STRING; } else if (typeName.equalsIgnoreCase("FLOAT")) { return DataType.FLOAT; } else if (typeName.equalsIgnoreCase("DOUBLE")) { return DataType.DOUBLE; } else if (typeName.equalsIgnoreCase("PROTOBUF")) { return DataType.PROTOBUF; } else if (typeName.equalsIgnoreCase("DATETIME")) { return DataType.DATETIME; } else { throw new UnsupportedException("Unsupported SQLDataType " + dataType); } } }