@@ -2003,6 +2003,7 @@ String NonReservedWord() :
20032003 | tk=<K_COLUMN:"COLUMN">
20042004 | tk=<K_COLUMNS:"COLUMNS">
20052005 | tk=<K_COMMIT:"COMMIT">
2006+ | tk=<K_COPY: "COPY">
20062007 | tk=<K_COMMENT:"COMMENT">
20072008 | tk=<K_COMMENTS:"COMMENTS">
20082009 | tk=<K_COMPLETION:"COMPLETION">
@@ -2964,6 +2965,8 @@ Statement SingleStatement() :
29642965 |
29652966 LOOKAHEAD({ getToken(1).kind == K_DEALLOCATE }) stm = DeallocateStatement()
29662967 |
2968+ LOOKAHEAD({ getToken(1).kind == K_COPY }) stm = CopyStatement()
2969+ |
29672970 stm = PurgeStatement()
29682971 |
29692972 stm = SessionStatement()
@@ -4365,6 +4368,46 @@ RenameTableStatement RenameTableStatement(): {
43654368 }
43664369}
43674370
4371+ /**
4372+ * DuckDB's COPY table [(columns)] FROM path [(options)] and
4373+ * COPY {table | (query)} TO path [(options)].
4374+ */
4375+ CopyStatement CopyStatement() #CopyStatement:
4376+ {
4377+ CopyStatement copyStatement = new CopyStatement();
4378+ ExpressionList<Column> columns = null;
4379+ List<String> options = new ArrayList<String>();
4380+ String option;
4381+ Select select;
4382+ Table table;
4383+ Token token;
4384+ }
4385+ {
4386+ <K_COPY>
4387+ (
4388+ LOOKAHEAD(2) "(" select=Select() ")" { copyStatement.setSelect(select); }
4389+ |
4390+ table=Table() { copyStatement.setTable(table); }
4391+ [ LOOKAHEAD(2) "(" columns=ColumnList() ")" { copyStatement.setColumns(columns); } ]
4392+ )
4393+ (
4394+ <K_FROM> { copyStatement.setFrom(true); }
4395+ |
4396+ <K_TO>
4397+ )
4398+ (
4399+ token=<S_CHAR_LITERAL> { copyStatement.setPath(token.image); }
4400+ |
4401+ token=<S_IDENTIFIER> { copyStatement.setPath(token.image); }
4402+ )
4403+ [
4404+ LOOKAHEAD(2) "(" option=DatabaseOption() { options.add(option); }
4405+ ( "," option=DatabaseOption() { options.add(option); } )*
4406+ ")" { copyStatement.setOptions(options); }
4407+ ]
4408+ { return copyStatement; }
4409+ }
4410+
43684411/**
43694412 * PREPARE name AS statement, storing a parameterised statement for later EXECUTE.
43704413 */
@@ -4463,22 +4506,35 @@ AttachStatement AttachStatement() #AttachStatement:
44634506 { return attachStatement; }
44644507}
44654508
4466- /** One ATTACH option, such as READ_ONLY or TYPE SQLITE. */
4467- String DatabaseOption():
4468- {
4509+ /**
4510+ * One ATTACH or COPY option, such as READ_ONLY, TYPE SQLITE or FORMAT PARQUET. Option names and
4511+ * values are free-form keywords, so the tokens are collected verbatim up to the next comma or the
4512+ * closing bracket.
4513+ */
4514+ JAVACODE
4515+ String DatabaseOption() {
44694516 StringBuilder builder = new StringBuilder();
4470- String name;
4471- Token token;
4472- }
4473- {
4474- (
4475- name=RelObjectName() { if (builder.length() > 0) builder.append(" "); builder.append(name); }
4476- |
4477- token=<S_CHAR_LITERAL> { if (builder.length() > 0) builder.append(" "); builder.append(token.image); }
4478- |
4479- token=<S_LONG> { if (builder.length() > 0) builder.append(" "); builder.append(token.image); }
4480- )+
4481- { return builder.toString(); }
4517+ int depth = 0;
4518+ while (true) {
4519+ Token token = getToken(1);
4520+ if (token == null || token.kind == EOF) {
4521+ break;
4522+ }
4523+ if (depth == 0 && (",".equals(token.image) || ")".equals(token.image))) {
4524+ break;
4525+ }
4526+ if ("(".equals(token.image)) {
4527+ depth++;
4528+ } else if (")".equals(token.image)) {
4529+ depth--;
4530+ }
4531+ getNextToken();
4532+ if (builder.length() > 0) {
4533+ builder.append(" ");
4534+ }
4535+ builder.append(token.image);
4536+ }
4537+ return builder.toString();
44824538}
44834539
44844540/**
@@ -12890,7 +12946,9 @@ List<String> IndexAlgorithmOrLockOption():
1289012946{
1289112947 ( keyword=<K_ALGORITHM> | keyword=<K_LOCK> ) { option.add(keyword.image); }
1289212948 [ "=" { option.add("="); } ]
12893- ( value=<K_DEFAULT> | value=<K_NONE> | value=<K_EXCLUSIVE> | value=<S_IDENTIFIER> )
12949+ // COPY is one of MySQL's ALGORITHM values and also starts the COPY statement
12950+ ( value=<K_DEFAULT> | value=<K_NONE> | value=<K_EXCLUSIVE> | value=<K_COPY>
12951+ | value=<S_IDENTIFIER> )
1289412952 { option.add(value.image); return option; }
1289512953}
1289612954
0 commit comments