diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharactorDataType.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharactorDataType.java index 28b8b4e41b..b14b1bb3a7 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharactorDataType.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharactorDataType.java @@ -20,8 +20,13 @@ import com.alibaba.druid.sql.ast.SQLDataTypeImpl; @SuppressWarnings("serial") public class SQLCharactorDataType extends SQLDataTypeImpl { - private String charSetName; - private String collate; + private String charSetName; + private String collate; + + private String charType; + + public final static String CHAR_TYPE_BYTE = "BYTE"; + public final static String CHAR_TYPE_CHAR = "CHAR"; public SQLCharactorDataType(String name){ super(name); @@ -43,4 +48,12 @@ public class SQLCharactorDataType extends SQLDataTypeImpl { this.collate = collate; } + public String getCharType() { + return charType; + } + + public void setCharType(String charType) { + this.charType = charType; + } + } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java index c09bb8ef66..635c91c47c 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java @@ -35,6 +35,7 @@ import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryOperator; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; +import com.alibaba.druid.sql.ast.statement.SQLCharactorDataType; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.dialect.oracle.ast.OracleOrderBy; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAggregateExpr; @@ -66,6 +67,14 @@ import com.alibaba.druid.sql.parser.SQLExprParser; import com.alibaba.druid.sql.parser.Token; public class OracleExprParser extends SQLExprParser { + + + + + + + + public boolean allowStringAdditive = false; /** @@ -91,6 +100,17 @@ public class OracleExprParser extends SQLExprParser { this.lexer.nextToken(); } + protected boolean isCharType(String dataTypeName) { + return "varchar2".equalsIgnoreCase(dataTypeName) // + || "nvarchar2".equalsIgnoreCase(dataTypeName) // + || "char".equalsIgnoreCase(dataTypeName) // + || "varchar".equalsIgnoreCase(dataTypeName) // + || "nchar".equalsIgnoreCase(dataTypeName) // + || "nvarchar".equalsIgnoreCase(dataTypeName) // + // + ; + } + public SQLDataType parseDataType() { if (lexer.token() == Token.DEFAULT || lexer.token() == Token.NOT || lexer.token() == Token.NULL) { @@ -100,6 +120,28 @@ public class OracleExprParser extends SQLExprParser { SQLName typeExpr = name(); String typeName = typeExpr.toString(); + if (isCharType(typeName)) { + SQLCharactorDataType charType = new SQLCharactorDataType(typeName); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + + charType.getArguments().add(this.expr()); + + if (identifierEquals("CHAR")) { + lexer.nextToken(); + charType.setCharType(SQLCharactorDataType.CHAR_TYPE_CHAR); + } else if (identifierEquals("BYTE")) { + lexer.nextToken(); + charType.setCharType(SQLCharactorDataType.CHAR_TYPE_BYTE); + } + + accept(Token.RPAREN); + } + + return parseCharTypeRest(charType); + } + if (lexer.token() == Token.PERCENT) { lexer.nextToken(); if (identifierEquals("TYPE")) { @@ -113,7 +155,7 @@ public class OracleExprParser extends SQLExprParser { } } - SQLDataType dataType = new SQLDataTypeImpl(typeName); + SQLDataType dataType = new SQLDataTypeImpl(typeName); return parseDataTypeRest(dataType); } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index 705a72de2a..6fbb3196c7 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1134,6 +1134,18 @@ public class SQLExprParser extends SQLParser { SQLName typeExpr = name(); String typeName = typeExpr.toString(); + + if (isCharType(typeName)) { + SQLCharactorDataType charType = new SQLCharactorDataType(typeName); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + charType.getArguments().add(this.expr()); + accept(Token.RPAREN); + } + + return parseCharTypeRest(charType); + } if ("character".equalsIgnoreCase(typeName) && "varying".equalsIgnoreCase(lexer.stringVal())) { typeName += ' ' + lexer.stringVal(); @@ -1149,16 +1161,12 @@ public class SQLExprParser extends SQLParser { lexer.nextToken(); exprList(dataType.getArguments()); accept(Token.RPAREN); - - return parseCharTypeRest(dataType); } return dataType; } - protected boolean isCharType(SQLDataType dataType) { - String dataTypeName = dataType.getName(); - + protected boolean isCharType(String dataTypeName) { return "char".equalsIgnoreCase(dataTypeName) // || "varchar".equalsIgnoreCase(dataTypeName) || "nchar".equalsIgnoreCase(dataTypeName) @@ -1168,7 +1176,7 @@ public class SQLExprParser extends SQLParser { } protected SQLDataType parseCharTypeRest(SQLDataType dataType) { - if (!isCharType(dataType)) { + if (!isCharType(dataType.getName())) { return dataType; } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleCreateTableTest12.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleCreateTableTest12.java new file mode 100644 index 0000000000..179185bada --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleCreateTableTest12.java @@ -0,0 +1,83 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * Licensed 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.druid.bvt.sql.oracle; + +import java.util.List; + +import junit.framework.Assert; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; + +public class OracleCreateTableTest12 extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "create table CARD_MONEYOPERATION (" + // + "ID varchar2(50 char) not null, " + // + "DDBH varchar2(50 char) not null, " + // + "IDNO varchar2(18 char), " + // + "JKKH varchar2(50 char) not null, " + // + "JYDW varchar2(50 char), " + // + "JYJE number(19,2) not null, " + // + "JYNO varchar2(50 char), " + // + "JYZT number(19,0) not null, " + // + "NAME varchar2(10 char), " + // + "OPDATE timestamp, " + // + "REMARK varchar2(50 char), " + // + "TYPE varchar2(20 char) not null, " + // + "OPID varchar2(50 char), " + // + "primary key (ID)" + // + ") "; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("relationships : " + visitor.getRelationships()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + Assert.assertEquals(1, visitor.getTables().size()); + + Assert.assertEquals(13, visitor.getColumns().size()); + + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "ID"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "DDBH"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "IDNO"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "JKKH"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "JYDW"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "JYJE"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "JYNO"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "JYZT"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "NAME"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "OPDATE"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "REMARK"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "TYPE"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("CARD_MONEYOPERATION", "OPID"))); + } +}