com.alibaba.wasp.plan.parser.druid.DruidParser.java Source code

Java tutorial

Introduction

Here is the source code for com.alibaba.wasp.plan.parser.druid.DruidParser.java

Source

/**
 * 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.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.expr.SQLNumberExpr;
import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement;
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.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.wasp.DataType;
import com.alibaba.wasp.meta.Field;
import com.alibaba.wasp.plan.parser.ParseContext;
import com.alibaba.wasp.plan.parser.Parser;
import com.alibaba.wasp.plan.parser.UnsupportedException;
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.WaspSqlParserUtils;
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.Configurable;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;

/**
 * Use Druid (https://github.com/AlibabaTech/druid) to parse the sql and
 * generate QueryPlan
 * 
 */
public abstract class DruidParser extends Parser implements Configurable {
    private static final Log LOG = LogFactory.getLog(DruidParser.class);

    protected Configuration configuration;

    public DruidParser() {
        super();
    }

    /**
     * @see org.apache.hadoop.conf.Configurable#getConf()
     */
    @Override
    public Configuration getConf() {
        return configuration;
    }

    /**
     * @see org.apache.hadoop.conf.Configurable#setConf(org.apache.hadoop.conf.Configuration)
     */
    @Override
    public void setConf(Configuration configuration) {
        this.configuration = configuration;
    }

    /**
     * Parse SQL into SQLStatement, assume just one SQLStatement, so return one
     * SQLStatement result.
     * 
     */
    @Override
    public void parseSqlToStatement(ParseContext context) throws IOException {
        LOG.debug("Parsing SQL " + context.getSql());
        SQLStatementParser parser = WaspSqlParserUtils.createSQLStatementParser(context.getSql(),
                WaspSqlParserUtils.WASP); // JdbcUtils.MYSQL
                                                                                                                                    // JdbcUtils.HBASE
                                                                                                                                    // WaspSqlParserUtils.WASP
        List<SQLStatement> stmtList = parser.parseStatementList();
        if (stmtList == null) {
            throw new UnsupportedException("Non SQLStatement");
        }
        if (stmtList.size() > 1) {
            throw new UnsupportedException(
                    "Multi SQLStatement Unsupported" + ", there is " + stmtList.size() + " SQLStatement");
        }
        // StmtList could be a list,but we only use an element.
        context.setStmt(stmtList.get(0));
    }

    /**
     * Parse The FROM clause. The FROM clause which indicates the table(s) from
     * which data is to be retrieved.
     */
    public String parseFromClause(SQLTableSource from) throws UnsupportedException {
        // only support SQLExprTableSource now
        if (from instanceof SQLExprTableSource) {
            SQLExprTableSource fromExpr = (SQLExprTableSource) from;
            SQLExpr expr = fromExpr.getExpr(); // SQLIdentifierExpr
            return parseName(expr);
        } else if (from instanceof SQLJoinTableSource) {
            // TODO impl join clause
            throw new UnsupportedException("Join clause Unsupported");
        } else if (from instanceof SQLSubqueryTableSource) {
            throw new UnsupportedException("Subquery clause Unsupported");
        } else {
            throw new UnsupportedException("Unsupported");
        }
    }

    public static String parseName(SQLExpr name) throws UnsupportedException {
        if (name instanceof SQLIdentifierExpr) {
            SQLIdentifierExpr id = (SQLIdentifierExpr) name;
            return id.getName();
        } else {
            throw new UnsupportedException("Non SQLIdentifierExpr Unsupported, this is " + name);
        }
    }

    /**
     * Fetch Field instance from columns used by column name.
     * 
     * @param name
     * @param columns
     * @return
     */
    public static Field get(String name, List<Field> columns) {
        for (Field field : columns) {
            if (field.getName().equals(name)) {
                return field;
            }
        }
        return null;
    }

    public static String parseString(SQLExpr value) throws UnsupportedException {
        if (value instanceof SQLCharExpr) {
            SQLCharExpr charexpr = (SQLCharExpr) value;
            return ((SQLCharExpr) charexpr).getText();
        } else {
            throw new UnsupportedException("Non SQLIdentifierExpr Unsupported, this is " + value);
        }
    }

    /**
     * Parse one column, get the column's name(String type)
     */
    public String parseColumn(SQLExpr column) throws UnsupportedException {
        return parseName(column);
    }

    /**
     * Parse the SQLExpr value into byte value
     * 
     */
    public static byte[] convert(Field column, SQLExpr expr) throws UnsupportedException {
        if (expr instanceof SQLIntegerExpr) {// int, long
            Number number = ((SQLIntegerExpr) expr).getNumber();
            if (column != null) {
                return convert(column.getType(), number);
            } else {
                return convert(null, number);
            }
        } else if (expr instanceof SQLCharExpr) {// String
            String value = ((SQLCharExpr) expr).getText();
            if (column != null && column.getType() == DataType.DATETIME) {
                long timestamp = -1;
                try {
                    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    timestamp = formatter.parse(value).getTime();
                } catch (ParseException e) {
                    //TODO what should i do with the exception?
                    e.printStackTrace();
                }
                return Bytes.toBytes(timestamp);
            } else {
                return Bytes.toBytes(value);
            }
        } else if (expr instanceof SQLNumberExpr) {// float, double
            Number number = ((SQLNumberExpr) expr).getNumber();
            if (column != null) {
                return convert(column.getType(), number);
            } else {
                return convert(null, number);
            }
        } else if (expr instanceof SQLMethodInvokeExpr) { // Function
            return convert(column.getType(), (SQLMethodInvokeExpr) expr);
        }
        return null;
    }

    public static int convertToInt(SQLExpr expr) throws UnsupportedException {
        if (expr instanceof SQLIntegerExpr) {// int, long
            Number number = ((SQLIntegerExpr) expr).getNumber();
            return number.intValue();
        } else {
            throw new UnsupportedException("Input is not int or long, it is " + expr);
        }
    }

    public void checkType(Field field, SQLExpr value) throws UnsupportedException {
        DataType type = field.getType();
        if (type == DataType.INT32 || type == DataType.INT64) {
            if (value instanceof SQLIntegerExpr) {
                return; // OK
            }
        } else if (type == DataType.DOUBLE || type == DataType.FLOAT) {
            if (value instanceof SQLNumberExpr || value instanceof SQLIntegerExpr) {
                return; // OK
            }
        } else if (type == DataType.STRING) {
            if (value instanceof SQLCharExpr) {
                return; // OK
            }
        } else if (type == DataType.DATETIME) {
            if (value instanceof SQLCharExpr) {
                return; // OK
            } else if (value instanceof SQLMethodInvokeExpr) { // Function
                return; // OK
            }
        }
        throw new UnsupportedException("Unsupported DataType " + type + ", input is " + value);
    }

    /**
     * The abstract class Number is the superclass of classes BigDecimal,
     * BigInteger, Byte, Double, Float, Integer, Long, and Short. Subclasses of
     * Number must provide methods to convert the represented numeric value to
     * byte, double, float, int, long, and short.
     */
    public static byte[] convert(DataType type, Number number) throws UnsupportedException {
        // BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, and Short.
        if (number instanceof BigDecimal) {
            if (type == DataType.FLOAT) {
                return Bytes.toBytes(number.floatValue());
            } else if (type == DataType.DOUBLE) {
                return Bytes.toBytes(number.doubleValue());
            } else if (type == DataType.INT32) {
                return Bytes.toBytes(number.intValue());
            } else if (type == DataType.INT64) {
                return Bytes.toBytes(number.longValue());
            }
            return Bytes.toBytes((BigDecimal) number);
        } else if (number instanceof BigInteger) {
            throw new UnsupportedException(" BigInteger " + number + " Unsupported");
        } else if (number instanceof Byte) {
            return Bytes.toBytes((Byte) number);
        } else if (number instanceof Double) {
            double value = number.doubleValue();
            if (type == DataType.FLOAT) {
                return Bytes.toBytes((float) value);
            } else if (type == DataType.DOUBLE) {
                return Bytes.toBytes(value);
            } else if (type == DataType.INT32) {
                int iv = (int) value;
                return Bytes.toBytes(iv);
            } else if (type == DataType.INT64) {
                long lv = (long) value;
                return Bytes.toBytes(lv);
            }
        } else if (number instanceof Float) {
            float value = number.floatValue();
            if (type == DataType.FLOAT) {
                return Bytes.toBytes(value);
            } else if (type == DataType.DOUBLE) {
                return Bytes.toBytes((float) value);
            } else if (type == DataType.INT32) {
                int iv = (int) value;
                return Bytes.toBytes(iv);
            } else if (type == DataType.INT64) {
                long lv = (long) value;
                return Bytes.toBytes(lv);
            }
        } else if (number instanceof Integer) {
            int value = number.intValue();
            if (type == DataType.INT32) {
                return Bytes.toBytes((Integer) value);
            } else if (type == DataType.INT64) {
                return Bytes.toBytes((long) value);
            } else if (type == DataType.FLOAT) {
                float fv = (float) value;
                return Bytes.toBytes(fv);
            } else if (type == DataType.DOUBLE) {
                double fv = (double) value;
                return Bytes.toBytes(fv);
            }
        } else if (number instanceof Long) {
            long value = number.longValue();
            if (type == DataType.INT32) {
                return Bytes.toBytes((int) value);
            } else if (type == DataType.INT64) {
                return Bytes.toBytes(value);
            } else if (type == DataType.FLOAT) {
                float fv = (float) value;
                return Bytes.toBytes(fv);
            } else if (type == DataType.DOUBLE) {
                double fv = (double) value;
                return Bytes.toBytes(fv);
            }
        } else if (number instanceof Short) {
            return Bytes.toBytes((Short) number);
        }
        throw new UnsupportedException("Unknown Number:" + number + " Type:" + type + " Unsupported ");
    }

    /**
     * Function http://www.w3schools.com/sql/func_now.asp, current NOW() is supported.
     */
    public static byte[] convert(DataType type, SQLMethodInvokeExpr expr) throws UnsupportedException {
        String methodName = expr.getMethodName();
        if (methodName.equalsIgnoreCase("NOW")) { // Date Function 'NOW()'
            if (type == DataType.DATETIME) { // Type must be DATETIME
                return Bytes.toBytes(EnvironmentEdgeManager.currentTimeMillis());
            } else {
                throw new UnsupportedException(" DataType " + type + " not support " + " Function " + methodName);
            }
        } else {
            throw new UnsupportedException(" Functions " + methodName + " Unsupported");
        }
    }

    @Override
    public SQLType getSQLType(ParseContext context) throws IOException {
        parseSqlToStatement(context);
        SQLStatement stmt = context.getStmt();
        boolean isDDL = false;
        boolean isDQL = false;
        if (stmt instanceof WaspSqlCreateTableStatement) {
            // This is a Create Table SQL
            isDDL = true;
        } else if (stmt instanceof WaspSqlCreateIndexStatement) {
            // This is a Create Index SQL
            isDDL = true;
        } else if (stmt instanceof SQLDropTableStatement) {
            // This is a Drop Table SQL
            isDDL = true;
        } else if (stmt instanceof SQLDropIndexStatement) {
            // This is a Drop Index SQL
            isDDL = true;
        } else if (stmt instanceof MySqlAlterTableStatement) {
            // This is a Alter Table SQL
            isDDL = true;
        } else if (stmt instanceof WaspSqlShowTablesStatement) {
            // This is a Show Tables SQL
            isDDL = true;
        } else if (stmt instanceof WaspSqlShowCreateTableStatement) {
            // This is a Show Create Table SQL
            isDDL = true;
        } else if (stmt instanceof WaspSqlDescribeStatement) {
            // This is a DESCRIBE SQL
            isDDL = true;
        } else if (stmt instanceof WaspSqlShowIndexesStatement) {
            // This is a SHOW INDEXES SQL
            isDDL = true;
        } else if (stmt instanceof SQLSelectStatement) {
            // This is a Select SQL
            isDDL = false;
            isDQL = true;
        } else if (stmt instanceof SQLUpdateStatement) {
            // This is a Update SQL
            isDDL = false;
        } else if (stmt instanceof SQLInsertStatement) {
            // This is a Insert SQL
            isDDL = false;
        } else if (stmt instanceof SQLDeleteStatement) {
            // This is a Delete SQL
            isDDL = false;
        } else {
            throw new UnsupportedException("Unsupported SQLStatement " + SQLUtils.toSQLString(stmt));
        }
        if (isDDL) {
            return SQLType.DDL;
        } else if (isDQL) {
            return SQLType.DQL;
        } else {
            return SQLType.DML;
        }
    }
}