Skip to content

Commit d4a2627

Browse files
committed
fix(parser): support CAST to an array type for MySQL multi-valued indexes
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 9fc38bd commit d4a2627

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
@@ -9946,7 +9946,13 @@ CastExpression CastExpression():
99469946
")"
99479947
)
99489948
|
9949-
type=ColDataType() { retval.setColDataType(type); }
9949+
(
9950+
type=ColDataType() { retval.setColDataType(type); }
9951+
// MySQL casts to an array of the given type when a multi-valued index key part is
9952+
// defined, e.g. CAST(data->'$.zips' AS UNSIGNED ARRAY). ARRAY reads as a further
9953+
// word of the type, the way INT UNSIGNED already does.
9954+
[ <K_ARRAY_LITERAL> { type.setDataType(type.getDataType() + " ARRAY"); } ]
9955+
)
99509956
)
99519957

99529958
// 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)