diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index de05f830d..75a9feddb 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -9946,7 +9946,13 @@ CastExpression CastExpression(): ")" ) | - type=ColDataType() { retval.setColDataType(type); } + ( + type=ColDataType() { retval.setColDataType(type); } + // MySQL casts to an array of the given type when a multi-valued index key part is + // defined, e.g. CAST(data->'$.zips' AS UNSIGNED ARRAY). ARRAY reads as a further + // word of the type, the way INT UNSIGNED already does. + [ { type.setDataType(type.getDataType() + " ARRAY"); } ] + ) ) // BigQuery FORMAT clause diff --git a/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java index d0365054e..38827001c 100644 --- a/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java @@ -13,6 +13,7 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Assertions; @@ -155,4 +156,18 @@ void testNestedCompositeTypeCastIssue2341() throws JSQLParserException { Assertions.assertEquals(1, parenthesedCast.size()); Assertions.assertInstanceOf(CastExpression.class, parenthesedCast.get(0)); } + + @Test + public void testCastToArrayIssue2490() throws JSQLParserException { + // MySQL casts to an array of the given type when a multi-valued index key part is + // defined, and accepts the same cast anywhere else an expression is allowed. + assertSqlCanBeParsedAndDeparsed("SELECT CAST(data -> '$.zips' AS UNSIGNED ARRAY) FROM t"); + assertSqlCanBeParsedAndDeparsed("SELECT CAST(x AS CHAR (10) ARRAY) FROM t"); + + PlainSelect select = (PlainSelect) CCJSqlParserUtil + .parse("SELECT CAST(data -> '$.zips' AS UNSIGNED ARRAY) FROM t"); + CastExpression cast = Assertions.assertInstanceOf(CastExpression.class, + select.getSelectItem(0).getExpression()); + Assertions.assertEquals("UNSIGNED ARRAY", cast.getColDataType().getDataType()); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java index d9344e1b4..a18215b79 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java @@ -2414,4 +2414,10 @@ public void testAlterTableAddIndexKeyPartWithPrefixLengthAndDirectionIssue2490() assertSqlCanBeParsedAndDeparsed("ALTER TABLE t ADD INDEX i33 (c1 (20) ASC)"); assertSqlCanBeParsedAndDeparsed("ALTER TABLE t ADD UNIQUE INDEX i34 (c1 (10) DESC)"); } + + @Test + public void testAlterTableAddMultiValuedIndexIssue2490() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "ALTER TABLE t ADD INDEX i31 ((CAST(data -> '$.zips' AS UNSIGNED ARRAY)))"); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java index dea34d192..a12456591 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java @@ -234,4 +234,10 @@ public void testCreateFullTextAndSpatialIndexIssue2490() throws JSQLParserExcept assertSqlCanBeParsedAndDeparsed("CREATE FULLTEXT INDEX i18 ON t (body) WITH PARSER ngram"); assertSqlCanBeParsedAndDeparsed("CREATE SPATIAL INDEX i19 ON t (g)"); } + + @Test + public void testCreateMultiValuedIndexIssue2490() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "CREATE INDEX i20 ON t ((CAST(data -> '$.zips' AS UNSIGNED ARRAY)))"); + } }