PHOENIX-2304 NullPointerException when using an index and a char array (Julian Jaffe, Navis, James Taylor)
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
index 9448443..53a13be 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
@@ -46,9 +46,9 @@
/**
- * Various SQLException Information. Including a vender-specific errorcode and a standard SQLState.
- *
- *
+ * Various SQLException Information. Including a vendor-specific errorcode and a standard SQLState.
+ *
+ *
* @since 1.0
*/
public enum SQLExceptionCode {
@@ -59,7 +59,7 @@
IO_EXCEPTION(101, "08000", "Unexpected IO exception."),
MALFORMED_CONNECTION_URL(102, "08001", "Malformed connection url."),
CANNOT_ESTABLISH_CONNECTION(103, "08004", "Unable to establish connection."),
-
+
/**
* Data Exception (errorcode 02, sqlstate 22)
*/
@@ -74,19 +74,17 @@
VALUE_IN_UPSERT_NOT_CONSTANT(204, "22008", "Values in UPSERT must evaluate to a constant."),
MALFORMED_URL(205, "22009", "Malformed URL."),
DATA_EXCEEDS_MAX_CAPACITY(206, "22003", "The data exceeds the max capacity for the data type."),
- MISSING_CHAR_LENGTH(207, "22003", "Missing length for CHAR."),
- NONPOSITIVE_CHAR_LENGTH(208, "22003", "CHAR or VARCHAR must have a positive length."),
+ MISSING_MAX_LENGTH(207, "22004", "Max length must be specified for type."),
+ NONPOSITIVE_MAX_LENGTH(208, "22006", "Max length must have a positive length for type."),
DECIMAL_PRECISION_OUT_OF_RANGE(209, "22003", "Decimal precision outside of range. Should be within 1 and " + PDataType.MAX_PRECISION + "."),
- MISSING_BINARY_LENGTH(210, "22003", "Missing length for BINARY."),
- NONPOSITIVE_BINARY_LENGTH(211, "22003", "BINARY must have a positive length."),
SERVER_ARITHMETIC_ERROR(212, "22012", "Arithmetic error on server."),
VALUE_OUTSIDE_RANGE(213,"22003","Value outside range."),
VALUE_IN_LIST_NOT_CONSTANT(214, "22008", "Values in IN must evaluate to a constant."),
SINGLE_ROW_SUBQUERY_RETURNS_MULTIPLE_ROWS(215, "22015", "Single-row sub-query returns more than one row."),
SUBQUERY_RETURNS_DIFFERENT_NUMBER_OF_FIELDS(216, "22016", "Sub-query must return the same number of fields as the left-hand-side expression of 'IN'."),
- AMBIGUOUS_JOIN_CONDITION(217, "22017", "Amibiguous or non-equi join condition specified. Consider using table list with where clause."),
- CONSTRAINT_VIOLATION(218, "22018", "Constraint violatioin."),
-
+ AMBIGUOUS_JOIN_CONDITION(217, "22017", "Ambiguous or non-equi join condition specified. Consider using table list with where clause."),
+ CONSTRAINT_VIOLATION(218, "22018", "Constraint violation."),
+
/**
* Constraint Violation (errorcode 03, sqlstate 23)
*/
@@ -97,13 +95,13 @@
}
}),
CANNOT_INDEX_COLUMN_ON_TYPE(302, "23100", "The column cannot be index due to its type."),
-
+
/**
* Invalid Cursor State (errorcode 04, sqlstate 24)
*/
CURSOR_BEFORE_FIRST_ROW(401, "24015","Cursor before first row."),
CURSOR_PAST_LAST_ROW(402, "24016", "Cursor past last row."),
-
+
/**
* Syntax Error or Access Rule Violation (errorcode 05, sqlstate 42)
*/
@@ -152,22 +150,22 @@
* Invalid Transaction State (errorcode 05, sqlstate 25)
*/
READ_ONLY_CONNECTION(518,"25502","Mutations are not permitted for a read-only connection."),
-
+
VARBINARY_ARRAY_NOT_SUPPORTED(519, "42896", "VARBINARY ARRAY is not supported"),
-
+
/**
* Expression Index exceptions.
*/
- AGGREGATE_EXPRESSION_NOT_ALLOWED_IN_INDEX(520, "42897", "Aggreagaate expression not allowed in an index"),
+ AGGREGATE_EXPRESSION_NOT_ALLOWED_IN_INDEX(520, "42897", "Aggregate expression not allowed in an index"),
NON_DETERMINISTIC_EXPRESSION_NOT_ALLOWED_IN_INDEX(521, "42898", "Non-deterministic expression not allowed in an index"),
STATELESS_EXPRESSION_NOT_ALLOWED_IN_INDEX(522, "42899", "Stateless expression not allowed in an index"),
- /**
+ /**
* Union All related errors
*/
SELECT_COLUMN_NUM_IN_UNIONALL_DIFFS(525, "42902", "SELECT column number differs in a Union All query is not allowed"),
SELECT_COLUMN_TYPE_IN_UNIONALL_DIFFS(526, "42903", "SELECT column types differ in a Union All query is not allowed"),
-
+
/**
* Row timestamp column related errors
*/
@@ -177,10 +175,10 @@
ROWTIMESTAMP_COL_INVALID_TYPE(530, "42907", "A column can be added as ROW_TIMESTAMP only if it is of type DATE, BIGINT, TIME OR TIMESTAMP"),
ROWTIMESTAMP_NOT_ALLOWED_ON_VIEW(531, "42908", "Declaring a column as row_timestamp is not allowed for views"),
INVALID_SCN(532, "42909", "Value of SCN cannot be less than zero"),
- /**
+ /**
* HBase and Phoenix specific implementation defined sub-classes.
* Column family related exceptions.
- *
+ *
* For the following exceptions, use errorcode 10.
*/
SINGLE_PK_MAY_NOT_BE_NULL(1000, "42I00", "Single column primary key may not be NULL."),
@@ -237,11 +235,11 @@
NO_MUTABLE_INDEXES(1026, "42Y85", "Mutable secondary indexes are only supported for HBase version " + MetaDataUtil.decodeHBaseVersionAsString(PhoenixDatabaseMetaData.MUTABLE_SI_VERSION_THRESHOLD) + " and above."),
INVALID_FILTER_ON_IMMUTABLE_ROWS(1027, "42Y86", "All columns referenced in a WHERE clause must be available in every index for a table with immutable rows."),
INVALID_INDEX_STATE_TRANSITION(1028, "42Y87", "Invalid index state transition."),
- INVALID_MUTABLE_INDEX_CONFIG(1029, "42Y88", "Mutable secondary indexes must have the "
- + IndexManagementUtil.WAL_EDIT_CODEC_CLASS_KEY + " property set to "
+ INVALID_MUTABLE_INDEX_CONFIG(1029, "42Y88", "Mutable secondary indexes must have the "
+ + IndexManagementUtil.WAL_EDIT_CODEC_CLASS_KEY + " property set to "
+ IndexManagementUtil.INDEX_WAL_EDIT_CODEC_CLASS_NAME + " in the hbase-sites.xml of every region server"),
-
-
+
+
CANNOT_CREATE_TENANT_SPECIFIC_TABLE(1030, "42Y89", "Cannot create table for tenant-specific connection"),
DEFAULT_COLUMN_FAMILY_ONLY_ON_CREATE_TABLE(1034, "42Y93", "Default column family may only be specified when creating a table."),
INSUFFICIENT_MULTI_TENANT_COLUMNS(1040, "42Y96", "A MULTI_TENANT table must have two or more PK columns with the first column being NOT NULL."),
@@ -255,8 +253,8 @@
CANNOT_ALTER_PROPERTY(1051, "43A08", "Property can be specified or changed only when creating a table"),
CANNOT_SET_PROPERTY_FOR_COLUMN_NOT_ADDED(1052, "43A09", "Property cannot be specified for a column family that is not being added or modified"),
CANNOT_SET_TABLE_PROPERTY_ADD_COLUMN(1053, "43A10", "Table level property cannot be set when adding a column"),
-
- NO_LOCAL_INDEXES(1054, "43A11", "Local secondary indexes are not supported for HBase versions " +
+
+ NO_LOCAL_INDEXES(1054, "43A11", "Local secondary indexes are not supported for HBase versions " +
MetaDataUtil.decodeHBaseVersionAsString(PhoenixDatabaseMetaData.MIN_LOCAL_SI_VERSION_DISALLOW) + " through " + MetaDataUtil.decodeHBaseVersionAsString(PhoenixDatabaseMetaData.MAX_LOCAL_SI_VERSION_DISALLOW) + " inclusive."),
UNALLOWED_LOCAL_INDEXES(1055, "43A12", "Local secondary indexes are configured to not be allowed."),
DESC_VARBINARY_NOT_SUPPORTED(1056, "43A13", "Descending VARBINARY columns not supported"),
@@ -288,18 +286,18 @@
SEQUENCE_VAL_REACHED_MAX_VALUE(1212, "42Z12", "Reached MAXVALUE of sequence"),
SEQUENCE_VAL_REACHED_MIN_VALUE(1213, "42Z13", "Reached MINVALUE of sequence"),
INCREMENT_BY_MUST_NOT_BE_ZERO(1214, "42Z14", "Sequence INCREMENT BY value cannot be zero"),
- NUM_SEQ_TO_ALLOCATE_MUST_BE_CONSTANT(1215, "42Z15", "Sequence NEXT n VALUES FOR must be a postive integer or constant." ),
+ NUM_SEQ_TO_ALLOCATE_MUST_BE_CONSTANT(1215, "42Z15", "Sequence NEXT n VALUES FOR must be a positive integer or constant." ),
NUM_SEQ_TO_ALLOCATE_NOT_SUPPORTED(1216, "42Z16", "Sequence NEXT n VALUES FOR is not supported for Sequences with the CYCLE flag" ),
-
+
/** Parser error. (errorcode 06, sqlState 42P) */
- PARSER_ERROR(601, "42P00", "Syntax error.", Factory.SYTAX_ERROR),
- MISSING_TOKEN(602, "42P00", "Syntax error.", Factory.SYTAX_ERROR),
- UNWANTED_TOKEN(603, "42P00", "Syntax error.", Factory.SYTAX_ERROR),
- MISMATCHED_TOKEN(604, "42P00", "Syntax error.", Factory.SYTAX_ERROR),
- UNKNOWN_FUNCTION(605, "42P00", "Syntax error.", Factory.SYTAX_ERROR),
-
+ PARSER_ERROR(601, "42P00", "Syntax error.", Factory.SYNTAX_ERROR),
+ MISSING_TOKEN(602, "42P00", "Syntax error.", Factory.SYNTAX_ERROR),
+ UNWANTED_TOKEN(603, "42P00", "Syntax error.", Factory.SYNTAX_ERROR),
+ MISMATCHED_TOKEN(604, "42P00", "Syntax error.", Factory.SYNTAX_ERROR),
+ UNKNOWN_FUNCTION(605, "42P00", "Syntax error.", Factory.SYNTAX_ERROR),
+
/**
- * Implementation defined class. Execution exceptions (errorcode 11, sqlstate XCL).
+ * Implementation defined class. Execution exceptions (errorcode 11, sqlstate XCL).
*/
RESULTSET_CLOSED(1101, "XCL01", "ResultSet is closed."),
GET_TABLE_REGIONS_FAIL(1102, "XCL02", "Cannot get all table regions"),
@@ -316,7 +314,7 @@
}),
CANNOT_SPLIT_LOCAL_INDEX(1109,"XCL09", "Local index may not be pre-split"),
CANNOT_SALT_LOCAL_INDEX(1110,"XCL10", "Local index may not be salted"),
-
+
/**
* Implementation defined class. Phoenix internal error. (errorcode 20, sqlstate INT).
*/
@@ -359,7 +357,7 @@
private final Factory factory;
private SQLExceptionCode(int errorCode, String sqlState, String message) {
- this(errorCode, sqlState, message, Factory.DEFAULTY);
+ this(errorCode, sqlState, message, Factory.DEFAULT);
}
private SQLExceptionCode(int errorCode, String sqlState, String message, Factory factory) {
@@ -391,7 +389,7 @@
}
public static interface Factory {
- public static final Factory DEFAULTY = new Factory() {
+ public static final Factory DEFAULT = new Factory() {
@Override
public SQLException newException(SQLExceptionInfo info) {
@@ -399,7 +397,7 @@
}
};
- public static final Factory SYTAX_ERROR = new Factory() {
+ public static final Factory SYNTAX_ERROR = new Factory() {
@Override
public SQLException newException(SQLExceptionInfo info) {
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java
index ebee43b..278b4aa 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java
@@ -22,12 +22,9 @@
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.exception.SQLExceptionInfo;
import org.apache.phoenix.schema.SortOrder;
-import org.apache.phoenix.schema.types.PBinary;
-import org.apache.phoenix.schema.types.PChar;
import org.apache.phoenix.schema.types.PDataType;
import org.apache.phoenix.schema.types.PDecimal;
import org.apache.phoenix.schema.types.PVarbinary;
-import org.apache.phoenix.schema.types.PVarchar;
import org.apache.phoenix.util.SchemaUtil;
import com.google.common.base.Preconditions;
@@ -42,7 +39,7 @@
*/
public class ColumnDef {
private final ColumnName columnDefName;
- private PDataType dataType;
+ private final PDataType dataType;
private final Boolean isNull;
private final Integer maxLength;
private final Integer scale;
@@ -52,98 +49,91 @@
private final Integer arrSize;
private final String expressionStr;
private final boolean isRowTimestamp;
-
+
ColumnDef(ColumnName columnDefName, String sqlTypeName, boolean isArray, Integer arrSize, Boolean isNull, Integer maxLength,
- Integer scale, boolean isPK, SortOrder sortOrder, String expressionStr, boolean isRowTimestamp) {
- try {
- Preconditions.checkNotNull(sortOrder);
- PDataType localType = null;
- this.columnDefName = columnDefName;
- this.isArray = isArray;
- // TODO : Add correctness check for arrSize. Should this be ignored as in postgres
- // Also add what is the limit that we would support. Are we going to support a
- // fixed size or like postgres allow infinite. May be the data types max limit can
- // be used for the array size (May be too big)
- if(this.isArray) {
- localType = sqlTypeName == null ? null : PDataType.fromTypeId(PDataType.sqlArrayType(SchemaUtil.normalizeIdentifier(sqlTypeName)));
- this.dataType = sqlTypeName == null ? null : PDataType.fromSqlTypeName(SchemaUtil.normalizeIdentifier(sqlTypeName));
- this.arrSize = arrSize; // Can only be non negative based on parsing
- if (this.dataType == PVarbinary.INSTANCE) {
- throw new SQLExceptionInfo.Builder(SQLExceptionCode.VARBINARY_ARRAY_NOT_SUPPORTED)
- .setColumnName(columnDefName.getColumnName()).build().buildException();
- }
- } else {
- this.dataType = sqlTypeName == null ? null : PDataType.fromSqlTypeName(SchemaUtil.normalizeIdentifier(sqlTypeName));
- this.arrSize = null;
- }
-
- this.isNull = isNull;
- if (this.dataType == PChar.INSTANCE) {
- if (maxLength == null) {
- throw new SQLExceptionInfo.Builder(SQLExceptionCode.MISSING_CHAR_LENGTH)
- .setColumnName(columnDefName.getColumnName()).build().buildException();
- }
- if (maxLength < 1) {
- throw new SQLExceptionInfo.Builder(SQLExceptionCode.NONPOSITIVE_CHAR_LENGTH)
- .setColumnName(columnDefName.getColumnName()).build().buildException();
- }
- scale = null;
- } else if (this.dataType == PVarchar.INSTANCE) {
- if (maxLength != null && maxLength < 1) {
- throw new SQLExceptionInfo.Builder(SQLExceptionCode.NONPOSITIVE_CHAR_LENGTH)
- .setColumnName(columnDefName.getColumnName()).build().buildException();
- }
- scale = null;
- } else if (this.dataType == PDecimal.INSTANCE) {
- // for deciaml, 1 <= maxLength <= PDataType.MAX_PRECISION;
- if (maxLength != null) {
- if (maxLength < 1 || maxLength > PDataType.MAX_PRECISION) {
- throw new SQLExceptionInfo.Builder(SQLExceptionCode.DECIMAL_PRECISION_OUT_OF_RANGE)
- .setColumnName(columnDefName.getColumnName()).build().buildException();
- }
- // When a precision is specified and a scale is not specified, it is set to 0.
- //
- // This is the standard as specified in
- // http://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT1832
- // and
- // http://docs.oracle.com/javadb/10.6.2.1/ref/rrefsqlj15260.html.
- // Otherwise, if scale is bigger than maxLength, just set it to the maxLength;
- //
- // When neither a precision nor a scale is specified, the precision and scale is
- // ignored. All decimal are stored with as much decimal points as possible.
- scale = scale == null ? PDataType.DEFAULT_SCALE : scale > maxLength ? maxLength : scale;
- }
- } else if (this.dataType == PBinary.INSTANCE) {
- if (maxLength == null) {
- throw new SQLExceptionInfo.Builder(SQLExceptionCode.MISSING_BINARY_LENGTH)
- .setColumnName(columnDefName.getColumnName()).build().buildException();
- }
- if (maxLength < 1) {
- throw new SQLExceptionInfo.Builder(SQLExceptionCode.NONPOSITIVE_BINARY_LENGTH)
- .setColumnName(columnDefName.getColumnName()).build().buildException();
- }
- scale = null;
- } else {
- // ignore maxLength and scale for other types.
- maxLength = null;
- scale = null;
- }
- this.maxLength = maxLength;
- this.scale = scale;
- this.isPK = isPK;
- this.sortOrder = sortOrder;
- if(this.isArray) {
- this.dataType = localType;
- }
- this.expressionStr = expressionStr;
- this.isRowTimestamp = isRowTimestamp;
- } catch (SQLException e) {
- throw new ParseException(e);
- }
+ Integer scale, boolean isPK, SortOrder sortOrder, String expressionStr, boolean isRowTimestamp) {
+ try {
+ Preconditions.checkNotNull(sortOrder);
+ PDataType baseType;
+ PDataType dataType;
+ this.columnDefName = columnDefName;
+ // TODO : Add correctness check for arrSize. Should this be ignored as in postgres
+ // Also add what is the limit that we would support. Are we going to support a
+ // fixed size or like postgres allow infinite. May be the data types max limit can
+ // be used for the array size (May be too big)
+ if (isArray) {
+ this.isArray = true;
+ dataType = sqlTypeName == null ? null : PDataType.fromTypeId(PDataType.sqlArrayType(SchemaUtil.normalizeIdentifier(sqlTypeName)));
+ baseType = sqlTypeName == null ? null : PDataType.fromSqlTypeName(SchemaUtil.normalizeIdentifier(sqlTypeName));
+ this.arrSize = arrSize; // Can only be non negative based on parsing
+ if (baseType == PVarbinary.INSTANCE) {
+ throw new SQLExceptionInfo.Builder(SQLExceptionCode.VARBINARY_ARRAY_NOT_SUPPORTED)
+ .setColumnName(columnDefName.getColumnName()).build().buildException();
+ }
+ } else {
+ baseType = dataType = sqlTypeName == null ? null : PDataType.fromSqlTypeName(SchemaUtil.normalizeIdentifier(sqlTypeName));
+ if (this.isArray = dataType != null && dataType.isArrayType()) {
+ baseType = PDataType.arrayBaseType(dataType);
+ }
+ this.arrSize = null;
+ }
+
+ this.isNull = isNull;
+ if (baseType == PDecimal.INSTANCE) {
+ // for deciaml, 1 <= maxLength <= PDataType.MAX_PRECISION;
+ if (maxLength == null) {
+ scale = null;
+ } else {
+ if (maxLength < 1 || maxLength > PDataType.MAX_PRECISION) {
+ throw new SQLExceptionInfo.Builder(SQLExceptionCode.DECIMAL_PRECISION_OUT_OF_RANGE)
+ .setColumnName(columnDefName.getColumnName()).build().buildException();
+ }
+ // When a precision is specified and a scale is not specified, it is set to 0.
+ //
+ // This is the standard as specified in
+ // http://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT1832
+ // and
+ // http://docs.oracle.com/javadb/10.6.2.1/ref/rrefsqlj15260.html.
+ // Otherwise, if scale is bigger than maxLength, just set it to the maxLength;
+ //
+ // When neither a precision nor a scale is specified, the precision and scale is
+ // ignored. All decimal are stored with as much decimal points as possible.
+ scale = scale == null ? PDataType.DEFAULT_SCALE : scale > maxLength ? maxLength : scale;
+ }
+ } else {
+ if (maxLength != null && maxLength < 1) {
+ throw new SQLExceptionInfo.Builder(SQLExceptionCode.NONPOSITIVE_MAX_LENGTH)
+ .setColumnName(columnDefName.getColumnName()).build().buildException();
+ }
+ scale = null;
+ if (baseType == null) {
+ maxLength = null;
+ } else if (baseType.isFixedWidth()) {
+ if (baseType.getByteSize() == null) {
+ if (maxLength == null) {
+ throw new SQLExceptionInfo.Builder(SQLExceptionCode.MISSING_MAX_LENGTH)
+ .setColumnName(columnDefName.getColumnName()).build().buildException();
+ }
+ } else {
+ maxLength = null;
+ }
+ }
+ }
+ this.maxLength = maxLength;
+ this.scale = scale;
+ this.isPK = isPK;
+ this.sortOrder = sortOrder;
+ this.dataType = dataType;
+ this.expressionStr = expressionStr;
+ this.isRowTimestamp = isRowTimestamp;
+ } catch (SQLException e) {
+ throw new ParseException(e);
+ }
}
+
ColumnDef(ColumnName columnDefName, String sqlTypeName, Boolean isNull, Integer maxLength,
Integer scale, boolean isPK, SortOrder sortOrder, String expressionStr, boolean isRowTimestamp) {
- this(columnDefName, sqlTypeName, false, 0, isNull, maxLength, scale, isPK, sortOrder, expressionStr, isRowTimestamp);
+ this(columnDefName, sqlTypeName, false, 0, isNull, maxLength, scale, isPK, sortOrder, expressionStr, isRowTimestamp);
}
public ColumnName getColumnDefName() {
@@ -175,45 +165,45 @@
public boolean isPK() {
return isPK;
}
-
+
public SortOrder getSortOrder() {
- return sortOrder;
+ return sortOrder;
}
-
- public boolean isArray() {
- return isArray;
- }
- public Integer getArraySize() {
- return arrSize;
- }
+ public boolean isArray() {
+ return isArray;
+ }
- public String getExpression() {
- return expressionStr;
- }
-
- public boolean isRowTimestamp() {
- return isRowTimestamp;
- }
- @Override
+ public Integer getArraySize() {
+ return arrSize;
+ }
+
+ public String getExpression() {
+ return expressionStr;
+ }
+
+ public boolean isRowTimestamp() {
+ return isRowTimestamp;
+ }
+ @Override
public String toString() {
- StringBuilder buf = new StringBuilder(columnDefName.getColumnNode().toString());
- buf.append(' ');
+ StringBuilder buf = new StringBuilder(columnDefName.getColumnNode().toString());
+ buf.append(' ');
buf.append(dataType.getSqlTypeName());
if (maxLength != null) {
buf.append('(');
buf.append(maxLength);
if (scale != null) {
- buf.append(',');
- buf.append(scale); // has both max length and scale. For ex- decimal(10,2)
+ buf.append(',');
+ buf.append(scale); // has both max length and scale. For ex- decimal(10,2)
}
buf.append(')');
- }
+ }
if (isArray) {
buf.append(' ');
buf.append(PDataType.ARRAY_TYPE_SUFFIX);
buf.append(' ');
}
- return buf.toString();
- }
-}
+ return buf.toString();
+ }
+}
\ No newline at end of file
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
index cd51683..e528d3b 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
@@ -38,6 +38,7 @@
import org.apache.phoenix.jdbc.PhoenixStatement;
import org.apache.phoenix.query.BaseConnectionlessQueryTest;
import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.PColumn;
import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.QueryUtil;
@@ -390,6 +391,22 @@
assertEquals("CLIENT PARALLEL 1-WAY SKIP SCAN ON 15 KEYS OVER INDEX_TEST_TABLE_INDEX_F ['1','1111'] - ['5','3333']", QueryUtil.getExplainPlan(rs));
}
+ @Test
+ public void testCharArrayLength() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ conn.createStatement().execute(
+ "CREATE TABLE TEST.TEST (testInt INTEGER, testCharArray CHAR(3)[], testByteArray BINARY(7)[], " +
+ "CONSTRAINT test_pk PRIMARY KEY(testInt)) DEFAULT_COLUMN_FAMILY='T'");
+ conn.createStatement().execute("CREATE INDEX TEST_INDEX ON TEST.TEST (testInt) INCLUDE (testCharArray, testByteArray)");
+ PhoenixStatement stmt = conn.createStatement().unwrap(PhoenixStatement.class);
+
+ QueryPlan plan = stmt.optimizeQuery("SELECT /*+ INDEX(TEST.TEST TEST_INDEX)*/ testCharArray,testByteArray FROM TEST.TEST");
+ List<PColumn> columns = plan.getTableRef().getTable().getColumns();
+ assertEquals(3, columns.size());
+ assertEquals(3, columns.get(1).getMaxLength().intValue());
+ assertEquals(7, columns.get(2).getMaxLength().intValue());
+ }
+
private void testAssertQueryPlanDetails(boolean multitenant, boolean useIndex, boolean salted) throws Exception {
String sql;
PreparedStatement stmt;
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java b/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
index 63c9e42..5363042 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
@@ -376,41 +376,41 @@
@Test
public void testParseCreateTableInlinePrimaryKeyWithOrder() throws Exception {
- for (String order : new String[]{"asc", "desc"}) {
+ for (String order : new String[]{"asc", "desc"}) {
String s = "create table core.entity_history_archive (id char(15) primary key ${o})".replace("${o}", order);
- CreateTableStatement stmt = (CreateTableStatement)new SQLParser((s)).parseStatement();
- List<ColumnDef> columnDefs = stmt.getColumnDefs();
- assertEquals(1, columnDefs.size());
- assertEquals(SortOrder.fromDDLValue(order), columnDefs.iterator().next().getSortOrder());
- }
+ CreateTableStatement stmt = (CreateTableStatement)new SQLParser((s)).parseStatement();
+ List<ColumnDef> columnDefs = stmt.getColumnDefs();
+ assertEquals(1, columnDefs.size());
+ assertEquals(SortOrder.fromDDLValue(order), columnDefs.iterator().next().getSortOrder());
+ }
}
@Test
public void testParseCreateTableOrderWithoutPrimaryKeyFails() throws Exception {
- for (String order : new String[]{"asc", "desc"}) {
- String stmt = "create table core.entity_history_archive (id varchar(20) ${o})".replace("${o}", order);
- try {
- new SQLParser((stmt)).parseStatement();
- fail("Expected parse exception to be thrown");
- } catch (SQLException e) {
- String errorMsg = "ERROR 603 (42P00): Syntax error. Unexpected input. Expecting \"RPAREN\", got \"${o}\"".replace("${o}", order);
- assertTrue("Expected message to contain \"" + errorMsg + "\" but got \"" + e.getMessage() + "\"", e.getMessage().contains(errorMsg));
- }
- }
+ for (String order : new String[]{"asc", "desc"}) {
+ String stmt = "create table core.entity_history_archive (id varchar(20) ${o})".replace("${o}", order);
+ try {
+ new SQLParser((stmt)).parseStatement();
+ fail("Expected parse exception to be thrown");
+ } catch (SQLException e) {
+ String errorMsg = "ERROR 603 (42P00): Syntax error. Unexpected input. Expecting \"RPAREN\", got \"${o}\"".replace("${o}", order);
+ assertTrue("Expected message to contain \"" + errorMsg + "\" but got \"" + e.getMessage() + "\"", e.getMessage().contains(errorMsg));
+ }
+ }
}
@Test
public void testParseCreateTablePrimaryKeyConstraintWithOrder() throws Exception {
- for (String order : new String[]{"asc", "desc"}) {
- String s = "create table core.entity_history_archive (id CHAR(15), name VARCHAR(150), constraint pk primary key (id ${o}, name ${o}))".replace("${o}", order);
- CreateTableStatement stmt = (CreateTableStatement)new SQLParser((s)).parseStatement();
- PrimaryKeyConstraint pkConstraint = stmt.getPrimaryKeyConstraint();
- List<Pair<ColumnName,SortOrder>> columns = pkConstraint.getColumnNames();
- assertEquals(2, columns.size());
- for (Pair<ColumnName,SortOrder> pair : columns) {
- assertEquals(SortOrder.fromDDLValue(order), pkConstraint.getColumnWithSortOrder(pair.getFirst()).getSecond());
- }
- }
+ for (String order : new String[]{"asc", "desc"}) {
+ String s = "create table core.entity_history_archive (id CHAR(15), name VARCHAR(150), constraint pk primary key (id ${o}, name ${o}))".replace("${o}", order);
+ CreateTableStatement stmt = (CreateTableStatement)new SQLParser((s)).parseStatement();
+ PrimaryKeyConstraint pkConstraint = stmt.getPrimaryKeyConstraint();
+ List<Pair<ColumnName,SortOrder>> columns = pkConstraint.getColumnNames();
+ assertEquals(2, columns.size());
+ for (Pair<ColumnName,SortOrder> pair : columns) {
+ assertEquals(SortOrder.fromDDLValue(order), pkConstraint.getColumnWithSortOrder(pair.getFirst()).getSecond());
+ }
+ }
}
@Test
@@ -439,30 +439,31 @@
}
@Test
- public void testCreateSequence() throws Exception {
- String sql = ((
- "create sequence foo.bar\n" +
- "start with 0\n" +
- "increment by 1\n"));
- parseQuery(sql);
- }
-
- @Test
- public void testNextValueForSelect() throws Exception {
- String sql = ((
- "select next value for foo.bar \n" +
- "from core.custom_entity_data\n"));
- parseQuery(sql);
- }
-
- @Test
+ public void testCreateSequence() throws Exception {
+ String sql = ((
+ "create sequence foo.bar\n" +
+ "start with 0\n" +
+ "increment by 1\n"));
+ parseQuery(sql);
+ }
+
+ @Test
+ public void testNextValueForSelect() throws Exception {
+ String sql = ((
+ "select next value for foo.bar \n" +
+ "from core.custom_entity_data\n"));
+ parseQuery(sql);
+ }
+
+ @Test
public void testNextValueForWhere() throws Exception {
String sql = ((
"upsert into core.custom_entity_data\n" +
"select next value for foo.bar from core.custom_entity_data\n"));
parseQuery(sql);
}
-
+
+ @Test
public void testBadCharDef() throws Exception {
try {
String sql = ("CREATE TABLE IF NOT EXISTS testBadVarcharDef" +
@@ -470,7 +471,7 @@
parseQuery(sql);
fail("Should have caught bad char definition.");
} catch (SQLException e) {
- assertTrue(e.getMessage(), e.getMessage().contains("ERROR 208 (22003): CHAR or VARCHAR must have a positive length. columnName=COL"));
+ assertEquals(SQLExceptionCode.NONPOSITIVE_MAX_LENGTH.getErrorCode(), e.getErrorCode());
}
try {
String sql = ("CREATE TABLE IF NOT EXISTS testBadVarcharDef" +
@@ -478,7 +479,7 @@
parseQuery(sql);
fail("Should have caught bad char definition.");
} catch (SQLException e) {
- assertTrue(e.getMessage(), e.getMessage().contains("ERROR 207 (22003): Missing length for CHAR. columnName=COL"));
+ assertEquals(SQLExceptionCode.MISSING_MAX_LENGTH.getErrorCode(), e.getErrorCode());
}
}
@@ -490,7 +491,7 @@
parseQuery(sql);
fail("Should have caught bad varchar definition.");
} catch (SQLException e) {
- assertTrue(e.getMessage(), e.getMessage().contains("ERROR 208 (22003): CHAR or VARCHAR must have a positive length. columnName=COL"));
+ assertEquals(SQLExceptionCode.NONPOSITIVE_MAX_LENGTH.getErrorCode(), e.getErrorCode());
}
}
@@ -522,7 +523,7 @@
parseQuery(sql);
fail("Should have caught bad binary definition.");
} catch (SQLException e) {
- assertTrue(e.getMessage(), e.getMessage().contains("ERROR 211 (22003): BINARY must have a positive length. columnName=COL"));
+ assertEquals(SQLExceptionCode.NONPOSITIVE_MAX_LENGTH.getErrorCode(), e.getErrorCode());
}
try {
String sql = ("CREATE TABLE IF NOT EXISTS testBadVarcharDef" +
@@ -530,7 +531,7 @@
parseQuery(sql);
fail("Should have caught bad char definition.");
} catch (SQLException e) {
- assertTrue(e.getMessage(), e.getMessage().contains("ERROR 210 (22003): Missing length for BINARY. columnName=COL"));
+ assertEquals(SQLExceptionCode.MISSING_MAX_LENGTH.getErrorCode(), e.getErrorCode());
}
}