Skip to content

Commit e781b3f

Browse files
authored
fix(parser): support CAST to an array type for MySQL multi-valued indexes (#2506)
MySQL defines a multi-valued index key part by casting to an array, e.g. CAST(data->'$.zips' AS UNSIGNED ARRAY). The trailing ARRAY keyword was not reachable, so both the CREATE INDEX and the ALTER TABLE form failed to parse. ARRAY is accepted as a further word of the cast target type, the way INT UNSIGNED already is, so no model change is needed and the deparsed statement round trips. It is added to the CAST production only, where MySQL allows it, which leaves the ARRAY<type> constructor form untouched. Closes the last open group of #2490.
1 parent d8d054a commit e781b3f

4 files changed

Lines changed: 34 additions & 1 deletion

File tree

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9955,7 +9955,13 @@ CastExpression CastExpression():
99559955
")"
99569956
)
99579957
|
9958-
type=ColDataType() { retval.setColDataType(type); }
9958+
(
9959+
type=ColDataType() { retval.setColDataType(type); }
9960+
// MySQL casts to an array of the given type when a multi-valued index key part is
9961+
// defined, e.g. CAST(data->'$.zips' AS UNSIGNED ARRAY). ARRAY reads as a further
9962+
// word of the type, the way INT UNSIGNED already does.
9963+
[ <K_ARRAY_LITERAL> { type.setDataType(type.getDataType() + " ARRAY"); } ]
9964+
)
99599965
)
99609966

99619967
// BigQuery FORMAT clause

src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import net.sf.jsqlparser.JSQLParserException;
1515
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
16+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
1617
import net.sf.jsqlparser.statement.select.PlainSelect;
1718
import net.sf.jsqlparser.test.TestUtils;
1819
import org.junit.jupiter.api.Assertions;
@@ -155,4 +156,18 @@ void testNestedCompositeTypeCastIssue2341() throws JSQLParserException {
155156
Assertions.assertEquals(1, parenthesedCast.size());
156157
Assertions.assertInstanceOf(CastExpression.class, parenthesedCast.get(0));
157158
}
159+
160+
@Test
161+
public void testCastToArrayIssue2490() throws JSQLParserException {
162+
// MySQL casts to an array of the given type when a multi-valued index key part is
163+
// defined, and accepts the same cast anywhere else an expression is allowed.
164+
assertSqlCanBeParsedAndDeparsed("SELECT CAST(data -> '$.zips' AS UNSIGNED ARRAY) FROM t");
165+
assertSqlCanBeParsedAndDeparsed("SELECT CAST(x AS CHAR (10) ARRAY) FROM t");
166+
167+
PlainSelect select = (PlainSelect) CCJSqlParserUtil
168+
.parse("SELECT CAST(data -> '$.zips' AS UNSIGNED ARRAY) FROM t");
169+
CastExpression cast = Assertions.assertInstanceOf(CastExpression.class,
170+
select.getSelectItem(0).getExpression());
171+
Assertions.assertEquals("UNSIGNED ARRAY", cast.getColDataType().getDataType());
172+
}
158173
}

src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2414,4 +2414,10 @@ public void testAlterTableAddIndexKeyPartWithPrefixLengthAndDirectionIssue2490()
24142414
assertSqlCanBeParsedAndDeparsed("ALTER TABLE t ADD INDEX i33 (c1 (20) ASC)");
24152415
assertSqlCanBeParsedAndDeparsed("ALTER TABLE t ADD UNIQUE INDEX i34 (c1 (10) DESC)");
24162416
}
2417+
2418+
@Test
2419+
public void testAlterTableAddMultiValuedIndexIssue2490() throws JSQLParserException {
2420+
assertSqlCanBeParsedAndDeparsed(
2421+
"ALTER TABLE t ADD INDEX i31 ((CAST(data -> '$.zips' AS UNSIGNED ARRAY)))");
2422+
}
24172423
}

src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,4 +234,10 @@ public void testCreateFullTextAndSpatialIndexIssue2490() throws JSQLParserExcept
234234
assertSqlCanBeParsedAndDeparsed("CREATE FULLTEXT INDEX i18 ON t (body) WITH PARSER ngram");
235235
assertSqlCanBeParsedAndDeparsed("CREATE SPATIAL INDEX i19 ON t (g)");
236236
}
237+
238+
@Test
239+
public void testCreateMultiValuedIndexIssue2490() throws JSQLParserException {
240+
assertSqlCanBeParsedAndDeparsed(
241+
"CREATE INDEX i20 ON t ((CAST(data -> '$.zips' AS UNSIGNED ARRAY)))");
242+
}
237243
}

0 commit comments

Comments
 (0)