Merge lp:~mmcm/akiban-sql-parser/copy-statement into lp:~akiban-technologies/akiban-sql-parser/trunk
- copy-statement
- Merge into trunk
Proposed by
Mike McMahon
Status: | Merged |
---|---|
Approved by: | Nathan Williams |
Approved revision: | 283 |
Merged at revision: | 278 |
Proposed branch: | lp:~mmcm/akiban-sql-parser/copy-statement |
Merge into: | lp:~akiban-technologies/akiban-sql-parser/trunk |
Diff against target: |
888 lines (+628/-1) 23 files modified
src/main/java/com/akiban/sql/parser/CopyStatementNode.java (+270/-0) src/main/java/com/akiban/sql/parser/NodeFactoryImpl.java (+3/-0) src/main/java/com/akiban/sql/parser/NodeNames.java (+2/-0) src/main/java/com/akiban/sql/parser/NodeTypes.java (+1/-1) src/main/java/com/akiban/sql/unparser/NodeToString.java (+86/-0) src/main/javacc/SQLGrammar.jj (+132/-0) src/test/resources/com/akiban/sql/parser/copy-1.expected (+12/-0) src/test/resources/com/akiban/sql/parser/copy-1.sql (+1/-0) src/test/resources/com/akiban/sql/parser/copy-2.expected (+39/-0) src/test/resources/com/akiban/sql/parser/copy-2.sql (+1/-0) src/test/resources/com/akiban/sql/parser/copy-3.expected (+12/-0) src/test/resources/com/akiban/sql/parser/copy-3.sql (+1/-0) src/test/resources/com/akiban/sql/parser/copy-4.expected (+47/-0) src/test/resources/com/akiban/sql/parser/copy-4.sql (+1/-0) src/test/resources/com/akiban/sql/parser/copy-5.expected (+12/-0) src/test/resources/com/akiban/sql/parser/copy-5.sql (+1/-0) src/test/resources/com/akiban/sql/parser/junk-1.error (+1/-0) src/test/resources/com/akiban/sql/unparser/copy-3.expected (+1/-0) src/test/resources/com/akiban/sql/unparser/copy-3.sql (+1/-0) src/test/resources/com/akiban/sql/unparser/copy-5.expected (+1/-0) src/test/resources/com/akiban/sql/unparser/copy-5.sql (+1/-0) src/test/resources/com/akiban/sql/unparser/copy-6.expected (+1/-0) src/test/resources/com/akiban/sql/unparser/copy-6.sql (+1/-0) |
To merge this branch: | bzr merge lp:~mmcm/akiban-sql-parser/copy-statement |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Akiban Build User | Needs Fixing | ||
Nathan Williams | Approve | ||
Review via email: mp+141472@code.launchpad.net |
This proposal supersedes a proposal from 2012-12-28.
Commit message
Description of the change
Add a COPY statement, a subset of the one in Postgres plus a commit frequency.
The options part of the command is meant to be extensible, leaving us room for more formats than just CSV.
To post a comment you must log in.
Revision history for this message
Mike McMahon (mmcm) wrote : | # |
junk-1 is an existing test. It needs to change every time a new top-level statement is added, because its error message lists them all as valid parse alternatives.
Revision history for this message
Nathan Williams (nwilliams) wrote : | # |
Ah, right. Modified, not added, file.
Revision history for this message
Akiban Build User (build-akiban) wrote : | # |
There were 2 failures during build/test:
* job server-build failed at build number 3594: http://
* view must-pass failed: server-build is yellow
review:
Needs Fixing
Revision history for this message
Nathan Williams (nwilliams) wrote : | # |
Strange but unrelated.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'src/main/java/com/akiban/sql/parser/CopyStatementNode.java' |
2 | --- src/main/java/com/akiban/sql/parser/CopyStatementNode.java 1970-01-01 00:00:00 +0000 |
3 | +++ src/main/java/com/akiban/sql/parser/CopyStatementNode.java 2012-12-30 01:41:22 +0000 |
4 | @@ -0,0 +1,270 @@ |
5 | +/** |
6 | + * Copyright © 2012 Akiban Technologies, Inc. All rights |
7 | + * reserved. |
8 | + * |
9 | + * This program and the accompanying materials are made available |
10 | + * under the terms of the Eclipse Public License v1.0 which |
11 | + * accompanies this distribution, and is available at |
12 | + * http://www.eclipse.org/legal/epl-v10.html |
13 | + * |
14 | + * This program may also be available under different license terms. |
15 | + * For more information, see www.akiban.com or contact |
16 | + * licensing@akiban.com. |
17 | + * |
18 | + * Contributors: |
19 | + * Akiban Technologies, Inc. |
20 | + */ |
21 | + |
22 | +package com.akiban.sql.parser; |
23 | + |
24 | +import com.akiban.sql.StandardException; |
25 | + |
26 | +/** |
27 | + * An CopyStatementNode represents the COPY command. |
28 | + * |
29 | + */ |
30 | + |
31 | +public class CopyStatementNode extends StatementNode |
32 | +{ |
33 | + public static enum Mode { TO_TABLE, FROM_TABLE, FROM_SUBQUERY }; |
34 | + public static enum Format { CSV }; |
35 | + private Mode mode; |
36 | + private TableName tableName; |
37 | + private ResultColumnList columnList; |
38 | + private SubqueryNode subquery; |
39 | + private String filename; |
40 | + private Format format; |
41 | + private String delimiter, nullString, quote, escape, encoding; |
42 | + private boolean header; |
43 | + private long commitFrequency; |
44 | + |
45 | + /** |
46 | + * Initializer for an CopyStatementNode |
47 | + * |
48 | + * @param mode The copy direction. |
49 | + * @param subquery The derived table. |
50 | + * @param filename The file name or <code>null</code>. |
51 | + */ |
52 | + |
53 | + public void init(Object mode, Object subquery, Object filename) { |
54 | + this.mode = (Mode)mode; |
55 | + this.subquery = (SubqueryNode)subquery; |
56 | + this.filename = (String)filename; |
57 | + } |
58 | + |
59 | + /** |
60 | + * Initializer for an CopyStatementNode |
61 | + * |
62 | + * @param mode The copy direction. |
63 | + * @param tableName The table name. |
64 | + * @param columnList The list of columns. |
65 | + * @param filename The file name or <code>null</code>. |
66 | + */ |
67 | + |
68 | + public void init(Object mode, Object tableName, Object columnList, Object filename) { |
69 | + this.mode = (Mode)mode; |
70 | + this.tableName = (TableName)tableName; |
71 | + this.columnList = (ResultColumnList)columnList; |
72 | + this.filename = (String)filename; |
73 | + } |
74 | + |
75 | + public Mode getMode() { |
76 | + return mode; |
77 | + } |
78 | + public SubqueryNode getSubquery() { |
79 | + return subquery; |
80 | + } |
81 | + public TableName getTableName() { |
82 | + return tableName; |
83 | + } |
84 | + public ResultColumnList getColumnList() { |
85 | + return columnList; |
86 | + } |
87 | + public String getFilename() { |
88 | + return filename; |
89 | + } |
90 | + |
91 | + public Format getFormat() { |
92 | + return format; |
93 | + } |
94 | + public void setFormat(Format format) { |
95 | + this.format = format; |
96 | + } |
97 | + public String getDelimiter() { |
98 | + return delimiter; |
99 | + } |
100 | + public void setDelimiter(String delimiter) { |
101 | + this.delimiter = delimiter; |
102 | + } |
103 | + public String getNullString() { |
104 | + return nullString; |
105 | + } |
106 | + public void setNullString(String nullString) { |
107 | + this.nullString = nullString; |
108 | + } |
109 | + public boolean isHeader() { |
110 | + return header; |
111 | + } |
112 | + public void setHeader(boolean header) { |
113 | + this.header = header; |
114 | + } |
115 | + public String getQuote() { |
116 | + return quote; |
117 | + } |
118 | + public void setQuote(String quote) { |
119 | + this.quote = quote; |
120 | + } |
121 | + public String getEscape() { |
122 | + return escape; |
123 | + } |
124 | + public void setEscape(String escape) { |
125 | + this.escape = escape; |
126 | + } |
127 | + public String getEncoding() { |
128 | + return encoding; |
129 | + } |
130 | + public void setEncoding(String encoding) { |
131 | + this.encoding = encoding; |
132 | + } |
133 | + public long getCommitFrequency() { |
134 | + return commitFrequency; |
135 | + } |
136 | + public void setCommitFrequency(long commitFrequency) { |
137 | + this.commitFrequency = commitFrequency; |
138 | + } |
139 | + |
140 | + /** |
141 | + * Fill this node with a deep copy of the given node. |
142 | + */ |
143 | + public void copyFrom(QueryTreeNode node) throws StandardException { |
144 | + super.copyFrom(node); |
145 | + |
146 | + CopyStatementNode other = (CopyStatementNode)node; |
147 | + this.tableName = (TableName)getNodeFactory().copyNode(other.tableName, |
148 | + getParserContext()); |
149 | + this.subquery = (SubqueryNode)getNodeFactory().copyNode(other.subquery, |
150 | + getParserContext()); |
151 | + this.columnList = (ResultColumnList)getNodeFactory().copyNode(other.columnList, |
152 | + getParserContext()); |
153 | + this.filename = other.filename; |
154 | + this.format = other.format; |
155 | + this.delimiter = other.delimiter; |
156 | + this.nullString = other.nullString; |
157 | + this.quote = other.quote; |
158 | + this.escape = other.escape; |
159 | + this.encoding = other.encoding; |
160 | + } |
161 | + |
162 | + /** |
163 | + * Convert this object to a String. See comments in QueryTreeNode.java |
164 | + * for how this should be done for tree printing. |
165 | + * |
166 | + * @return This object as a String |
167 | + */ |
168 | + |
169 | + public String toString() { |
170 | + return "mode: " + mode + "\n" + |
171 | + "tableName: " + tableName + "\n" + |
172 | + "filename: " + filename + "\n" + |
173 | + "format: " + format + "\n" + |
174 | + "delimiter: " + delimiter + "\n" + |
175 | + "nullString: " + nullString + "\n" + |
176 | + "quote: " + quote + "\n" + |
177 | + "escape: " + escape + "\n" + |
178 | + "encoding: " + encoding + "\n" + |
179 | + "commitFrequency: " + commitFrequency + "\n" + |
180 | + super.toString(); |
181 | + } |
182 | + |
183 | + public String statementToString() { |
184 | + return "COPY"; |
185 | + } |
186 | + |
187 | + /** |
188 | + * Prints the sub-nodes of this object. See QueryTreeNode.java for |
189 | + * how tree printing is supposed to work. |
190 | + * |
191 | + * @param depth The depth of this node in the tree |
192 | + */ |
193 | + |
194 | + public void printSubNodes(int depth) { |
195 | + super.printSubNodes(depth); |
196 | + |
197 | + if (subquery != null) { |
198 | + printLabel(depth, "subquery: "); |
199 | + subquery.treePrint(depth + 1); |
200 | + } |
201 | + if (columnList != null) { |
202 | + printLabel(depth, "columnList: "); |
203 | + columnList.treePrint(depth + 1); |
204 | + } |
205 | + } |
206 | + |
207 | + /** |
208 | + * Accept the visitor for all visitable children of this node. |
209 | + * |
210 | + * @param v the visitor |
211 | + * |
212 | + * @exception StandardException on error |
213 | + */ |
214 | + void acceptChildren(Visitor v) throws StandardException { |
215 | + super.acceptChildren(v); |
216 | + |
217 | + if (subquery != null) { |
218 | + subquery = (SubqueryNode)subquery.accept(v); |
219 | + } |
220 | + if (columnList != null) { |
221 | + columnList = (ResultColumnList)columnList.accept(v); |
222 | + } |
223 | + } |
224 | + |
225 | + /** Turn the source portion into a regular Select query. */ |
226 | + public CursorNode asQuery() throws StandardException { |
227 | + NodeFactory nodeFactory = getNodeFactory(); |
228 | + SQLParserContext parserContext = getParserContext(); |
229 | + |
230 | + ResultSetNode resultSet; |
231 | + OrderByList orderBy = null; |
232 | + ValueNode offset = null, limit = null; |
233 | + if (subquery != null) { |
234 | + // Easy case: already specified as a subquery. |
235 | + resultSet = subquery.getResultSet(); |
236 | + orderBy = subquery.getOrderByList(); |
237 | + offset = subquery.getOffset(); |
238 | + limit = subquery.getFetchFirst(); |
239 | + } |
240 | + else { |
241 | + // Table case. |
242 | + FromList fromList = (FromList)nodeFactory.getNode(NodeTypes.FROM_LIST, |
243 | + parserContext); |
244 | + FromTable fromTable = (FromTable)nodeFactory.getNode(NodeTypes.FROM_BASE_TABLE, |
245 | + tableName, |
246 | + null, null, |
247 | + parserContext); |
248 | + fromList.addFromTable(fromTable); |
249 | + ResultColumnList selectList = columnList; |
250 | + if (selectList == null) { |
251 | + selectList = (ResultColumnList)nodeFactory.getNode(NodeTypes.RESULT_COLUMN_LIST, |
252 | + parserContext); |
253 | + ResultColumn star = (ResultColumn)nodeFactory.getNode(NodeTypes.ALL_RESULT_COLUMN, |
254 | + Boolean.FALSE, |
255 | + parserContext); |
256 | + selectList.addResultColumn(star); |
257 | + } |
258 | + resultSet = (SelectNode)nodeFactory.getNode(NodeTypes.SELECT_NODE, |
259 | + selectList, |
260 | + null, |
261 | + fromList, |
262 | + null, null, null, null, |
263 | + parserContext); |
264 | + } |
265 | + return (CursorNode)nodeFactory.getNode(NodeTypes.CURSOR_NODE, |
266 | + "SELECT", |
267 | + resultSet, |
268 | + null, |
269 | + orderBy, offset, limit, |
270 | + null, null, |
271 | + parserContext); |
272 | + } |
273 | + |
274 | +} |
275 | |
276 | === modified file 'src/main/java/com/akiban/sql/parser/NodeFactoryImpl.java' |
277 | --- src/main/java/com/akiban/sql/parser/NodeFactoryImpl.java 2012-12-13 23:27:56 +0000 |
278 | +++ src/main/java/com/akiban/sql/parser/NodeFactoryImpl.java 2012-12-30 01:41:22 +0000 |
279 | @@ -593,6 +593,9 @@ |
280 | case NodeTypes.EXPLAIN_STATEMENT_NODE: |
281 | return NodeNames.EXPLAIN_STATEMENT_NODE_NAME; |
282 | |
283 | + case NodeTypes.COPY_STATEMENT_NODE: |
284 | + return NodeNames.COPY_STATEMENT_NODE_NAME; |
285 | + |
286 | case NodeTypes.INDEX_COLUMN: |
287 | return NodeNames.INDEX_COLUMN_NAME; |
288 | |
289 | |
290 | === modified file 'src/main/java/com/akiban/sql/parser/NodeNames.java' |
291 | --- src/main/java/com/akiban/sql/parser/NodeNames.java 2012-12-13 23:01:21 +0000 |
292 | +++ src/main/java/com/akiban/sql/parser/NodeNames.java 2012-12-30 01:41:22 +0000 |
293 | @@ -118,6 +118,8 @@ |
294 | |
295 | static final String CONSTRAINT_DEFINITION_NODE_NAME = "com.akiban.sql.parser.ConstraintDefinitionNode"; |
296 | |
297 | + static final String COPY_STATEMENT_NODE_NAME = "com.akiban.sql.parser.CopyStatementNode"; |
298 | + |
299 | static final String CREATE_ALIAS_NODE_NAME = "com.akiban.sql.parser.CreateAliasNode"; |
300 | |
301 | static final String CREATE_INDEX_NODE_NAME = "com.akiban.sql.parser.CreateIndexNode"; |
302 | |
303 | === modified file 'src/main/java/com/akiban/sql/parser/NodeTypes.java' |
304 | --- src/main/java/com/akiban/sql/parser/NodeTypes.java 2012-12-13 22:33:51 +0000 |
305 | +++ src/main/java/com/akiban/sql/parser/NodeTypes.java 2012-12-30 01:41:22 +0000 |
306 | @@ -166,7 +166,7 @@ |
307 | public static final int AGGREGATE_NODE = 115; |
308 | public static final int COLUMN_DEFINITION_NODE = 116; |
309 | public static final int EXPLAIN_STATEMENT_NODE = 117; |
310 | - // 118 available |
311 | + public static final int COPY_STATEMENT_NODE = 118; |
312 | public static final int FK_CONSTRAINT_DEFINITION_NODE = 119; |
313 | public static final int FROM_VTI = 120; |
314 | public static final int MATERIALIZE_RESULT_SET_NODE = 121; |
315 | |
316 | === modified file 'src/main/java/com/akiban/sql/unparser/NodeToString.java' |
317 | --- src/main/java/com/akiban/sql/unparser/NodeToString.java 2012-12-13 23:46:31 +0000 |
318 | +++ src/main/java/com/akiban/sql/unparser/NodeToString.java 2012-12-30 01:41:22 +0000 |
319 | @@ -223,6 +223,8 @@ |
320 | return executeStatementNode((ExecuteStatementNode)node); |
321 | case NodeTypes.DEALLOCATE_STATEMENT_NODE: |
322 | return deallocateStatementNode((DeallocateStatementNode)node); |
323 | + case NodeTypes.COPY_STATEMENT_NODE: |
324 | + return copyStatementNode((CopyStatementNode)node); |
325 | default: |
326 | return "**UNKNOWN(" + node.getNodeType() +")**"; |
327 | } |
328 | @@ -1061,6 +1063,90 @@ |
329 | return "DEALLOCATE " + node.getName(); |
330 | } |
331 | |
332 | + protected String copyStatementNode(CopyStatementNode node) |
333 | + throws StandardException { |
334 | + StringBuilder str = new StringBuilder("COPY "); |
335 | + if (node.getSubquery() != null) { |
336 | + str.append("("); |
337 | + str.append(toString(node.getSubquery())); |
338 | + str.append(")"); |
339 | + } |
340 | + else { |
341 | + str.append(node.getTableName()); |
342 | + if (node.getColumnList() != null) { |
343 | + str.append("("); |
344 | + str.append(toString(node.getColumnList())); |
345 | + str.append(")"); |
346 | + } |
347 | + } |
348 | + switch (node.getMode()) { |
349 | + case FROM_TABLE: |
350 | + case FROM_SUBQUERY: |
351 | + str.append(" TO "); |
352 | + break; |
353 | + case TO_TABLE: |
354 | + str.append(" FROM "); |
355 | + break; |
356 | + } |
357 | + if (node.getFilename() != null) { |
358 | + str.append("'"); |
359 | + str.append(node.getFilename()); |
360 | + str.append("'"); |
361 | + } |
362 | + else if (node.getMode() == CopyStatementNode.Mode.TO_TABLE) { |
363 | + str.append("STDIN"); |
364 | + } |
365 | + else { |
366 | + str.append("STDOUT"); |
367 | + } |
368 | + boolean options = false; |
369 | + if (node.getFormat() != null) { |
370 | + options = copyOption(str, "FORMAT", node.getFormat().name(), options); |
371 | + } |
372 | + if (node.getDelimiter() != null) { |
373 | + options = copyOptionString(str, "DELIMITER", node.getDelimiter(), options); |
374 | + } |
375 | + if (node.getNullString() != null) { |
376 | + options = copyOptionString(str, "NULL", node.getNullString(), options); |
377 | + } |
378 | + if (node.isHeader()) { |
379 | + options = copyOption(str, "HEADER", "TRUE", options); |
380 | + } |
381 | + if (node.getQuote() != null) { |
382 | + options = copyOptionString(str, "QUOTE", node.getQuote(), options); |
383 | + } |
384 | + if (node.getEscape() != null) { |
385 | + options = copyOptionString(str, "ESCAPE", node.getEscape(), options); |
386 | + } |
387 | + if (node.getEncoding() != null) { |
388 | + options = copyOptionString(str, "ENCODING", node.getEncoding(), options); |
389 | + } |
390 | + if (node.getCommitFrequency() != 0) { |
391 | + options = copyOption(str, "COMMIT", node.getCommitFrequency() + " ROWS", options); |
392 | + } |
393 | + if (options) { |
394 | + str.append(")"); |
395 | + } |
396 | + return str.toString(); |
397 | + } |
398 | + |
399 | + protected boolean copyOptionString(StringBuilder str, String keyword, String value, boolean options) { |
400 | + return copyOption(str, keyword, "'" + value + "'", options); |
401 | + } |
402 | + |
403 | + protected boolean copyOption(StringBuilder str, String keyword, String value, boolean options) { |
404 | + if (!options) { |
405 | + str.append(" WITH ("); |
406 | + } |
407 | + else { |
408 | + str.append(", "); |
409 | + } |
410 | + str.append(keyword); |
411 | + str.append(" " ); |
412 | + str.append(value); |
413 | + return true; |
414 | + } |
415 | + |
416 | protected void doPrint(QueryTreeNode node, StringBuilder bd) throws StandardException |
417 | { |
418 | if (node instanceof RowConstructorNode) |
419 | |
420 | === modified file 'src/main/javacc/SQLGrammar.jj' |
421 | --- src/main/javacc/SQLGrammar.jj 2012-12-14 19:27:44 +0000 |
422 | +++ src/main/javacc/SQLGrammar.jj 2012-12-30 01:41:22 +0000 |
423 | @@ -2410,7 +2410,9 @@ |
424 | | <CLASS: "class"> |
425 | | <COMPRESS: "compress"> |
426 | | <CONTENT: "content"> |
427 | +| <COPY: "copy"> |
428 | | <CS: "cs"> |
429 | +| <CSV: "csv"> |
430 | | <CURSORS: "cursors"> |
431 | | <DAY_HOUR: "day_hour"> |
432 | | <DAY_MICROSECOND: "day_microsecond"> |
433 | @@ -2418,13 +2420,17 @@ |
434 | | <DAY_SECOND: "day_second"> |
435 | | <DB2SQL: "db2sql"> |
436 | | <DEFRAGMENT: "defragment"> |
437 | +| <DELIMITER: "delimiter"> |
438 | | <DIRTY: "dirty"> |
439 | | <DOCUMENT: "document"> |
440 | | <EACH: "each"> |
441 | | <EMPTY: "empty"> |
442 | +| <ENCODING: "encoding"> |
443 | | <EXCLUSIVE: "exclusive"> |
444 | | <FN: "fn"> |
445 | | <FORCE: "force"> |
446 | +| <FORMAT: "format"> |
447 | +| <HEADER: "header"> |
448 | | <HOUR_MICROSECOND: "hour_microsecond"> |
449 | | <HOUR_MINUTE: "hour_minute"> |
450 | | <HOUR_SECOND: "hour_second"> |
451 | @@ -2456,6 +2462,7 @@ |
452 | | <PROPERTIES: "properties"> |
453 | | <PURGE: "purge"> |
454 | | <QUARTER: "quarter"> |
455 | +| <_QUOTE: "quote"> |
456 | | <READS: "reads"> |
457 | | <REF: "ref"> |
458 | | <REFERENCING: "referencing"> |
459 | @@ -2477,6 +2484,8 @@ |
460 | | <SQRT: "sqrt"> |
461 | | <STABILITY: "stability"> |
462 | | <STATISTICS: "statistics"> |
463 | +| <STDIN: "stdin"> |
464 | +| <STDOUT: "stdout"> |
465 | | <STRIP: "strip"> |
466 | | <STYLE: "style"> |
467 | | <TRIGGER: "trigger"> |
468 | @@ -3000,6 +3009,8 @@ |
469 | statementNode = explainStatement() |
470 | | |
471 | statementNode = transactionControlStatement() |
472 | +| |
473 | + statementNode = copyStatement() |
474 | ) |
475 | { |
476 | return statementNode; |
477 | @@ -14223,6 +14234,118 @@ |
478 | } |
479 | } |
480 | |
481 | +StatementNode |
482 | +copyStatement() throws StandardException : |
483 | +{ |
484 | + CopyStatementNode stmt; |
485 | +} |
486 | +{ |
487 | + <COPY> stmt = copyStatementBase() |
488 | + [ [<WITH>] <LEFT_PAREN> copyOption(stmt) |
489 | + ( <COMMA> copyOption(stmt) )* |
490 | + <RIGHT_PAREN> ] |
491 | + { |
492 | + return stmt; |
493 | + } |
494 | +} |
495 | + |
496 | +CopyStatementNode |
497 | +copyStatementBase() throws StandardException : |
498 | +{ |
499 | + CopyStatementNode.Mode mode; |
500 | + TableName tableName = null; |
501 | + ResultColumnList columnList = null; |
502 | + SubqueryNode subquery = null; |
503 | + String filename = null; |
504 | +} |
505 | +{ |
506 | +( |
507 | + LOOKAHEAD( { getToken(1).kind == LEFT_PAREN && getToken(2).kind == SELECT } ) |
508 | + subquery = derivedTable() |
509 | + <TO> ( filename = string() | <STDOUT> ) |
510 | + { mode = CopyStatementNode.Mode.FROM_SUBQUERY; } |
511 | +| |
512 | + tableName = qualifiedName() |
513 | + [ <LEFT_PAREN> columnList = insertColumnList() <RIGHT_PAREN> ] |
514 | + ( <TO> ( filename = string() | <STDOUT> ) |
515 | + { mode = CopyStatementNode.Mode.FROM_TABLE; } |
516 | + | <FROM> ( filename = string() | <STDIN> ) |
517 | + { mode = CopyStatementNode.Mode.TO_TABLE; } |
518 | + ) |
519 | +) |
520 | + { |
521 | + if (subquery != null) |
522 | + return (CopyStatementNode)nodeFactory.getNode(NodeTypes.COPY_STATEMENT_NODE, |
523 | + mode, |
524 | + subquery, |
525 | + filename, |
526 | + parserContext); |
527 | + else |
528 | + return (CopyStatementNode)nodeFactory.getNode(NodeTypes.COPY_STATEMENT_NODE, |
529 | + mode, |
530 | + tableName, columnList, |
531 | + filename, |
532 | + parserContext); |
533 | + } |
534 | +} |
535 | + |
536 | +void |
537 | +copyOption(CopyStatementNode stmt) throws StandardException : |
538 | +{ |
539 | + String value; |
540 | + long lvalue; |
541 | + CopyStatementNode.Format format; |
542 | +} |
543 | +{ |
544 | + <FORMAT> format = copyFormat() |
545 | + { |
546 | + stmt.setFormat(format); |
547 | + } |
548 | +| |
549 | + <DELIMITER> value = string() |
550 | + { |
551 | + stmt.setDelimiter(value); |
552 | + } |
553 | +| |
554 | + <NULL> value = string() |
555 | + { |
556 | + stmt.setNullString(value); |
557 | + } |
558 | +| |
559 | + <HEADER> token = booleanLiteral() |
560 | + { |
561 | + stmt.setHeader(token.kind == TRUE); |
562 | + } |
563 | +| |
564 | + <_QUOTE> value = string() |
565 | + { |
566 | + stmt.setQuote(value); |
567 | + } |
568 | +| |
569 | + <ESCAPE> value = string() |
570 | + { |
571 | + stmt.setEscape(value); |
572 | + } |
573 | +| |
574 | + <ENCODING> value = string() |
575 | + { |
576 | + stmt.setEncoding(value); |
577 | + } |
578 | +| |
579 | + <COMMIT> lvalue = exactNumber() [<ROWS>] |
580 | + { |
581 | + stmt.setCommitFrequency(lvalue); |
582 | + } |
583 | +} |
584 | + |
585 | +CopyStatementNode.Format |
586 | +copyFormat() throws StandardException : |
587 | +{ |
588 | +} |
589 | +{ |
590 | + <CSV> { return CopyStatementNode.Format.CSV; } |
591 | +} |
592 | + |
593 | String |
594 | internalIdentifier() throws StandardException : |
595 | { |
596 | @@ -14586,8 +14709,10 @@ |
597 | | tok = <CONCAT> |
598 | | tok = <CONTAINS> |
599 | | tok = <CONTENT> |
600 | +| tok = <COPY> |
601 | | tok = <COUNT> |
602 | | tok = <CS> |
603 | +| tok = <CSV> |
604 | | tok = <CURDATE> |
605 | | tok = <CURTIME> |
606 | | tok = <D> |
607 | @@ -14600,6 +14725,7 @@ |
608 | | tok = <DAY_MINUTE> |
609 | | tok = <DAY_SECOND> |
610 | | tok = <DEFRAGMENT> |
611 | +| tok = <DELIMITER> |
612 | | tok = <DIRTY> |
613 | | tok = <DIV> |
614 | | tok = <DUMMY> |
615 | @@ -14609,12 +14735,15 @@ |
616 | | tok = <DOCUMENT> |
617 | | tok = <EACH> |
618 | | tok = <EMPTY> |
619 | +| tok = <ENCODING> |
620 | | tok = <EXCLUSIVE> |
621 | | tok = <EXTRACT> |
622 | | tok = <FN> |
623 | | tok = <FORCE> |
624 | +| tok = <FORMAT> |
625 | | tok = <FORTRAN> |
626 | | tok = <GENERATED> |
627 | +| tok = <HEADER> |
628 | | tok = <HOUR_MICROSECOND> |
629 | | tok = <HOUR_MINUTE> |
630 | | tok = <HOUR_SECOND> |
631 | @@ -14676,6 +14805,7 @@ |
632 | | tok = <PROPERTIES> |
633 | | tok = <PURGE> |
634 | | tok = <QUARTER> |
635 | +| tok = <_QUOTE> |
636 | | tok = <READS> |
637 | | tok = <REF> |
638 | // SQL92 says RELEASE is reserved, but we want it to be non-reserved. |
639 | @@ -14723,6 +14853,8 @@ |
640 | | tok = <START> |
641 | | tok = <STATEMENT> |
642 | | tok = <STATISTICS> |
643 | +| tok = <STDIN> |
644 | +| tok = <STDOUT> |
645 | | tok = <STRIP> |
646 | | tok = <SYNONYM> |
647 | | tok = <STYLE> |
648 | |
649 | === added file 'src/test/resources/com/akiban/sql/parser/copy-1.expected' |
650 | --- src/test/resources/com/akiban/sql/parser/copy-1.expected 1970-01-01 00:00:00 +0000 |
651 | +++ src/test/resources/com/akiban/sql/parser/copy-1.expected 2012-12-30 01:41:22 +0000 |
652 | @@ -0,0 +1,12 @@ |
653 | +com.akiban.sql.parser.CopyStatementNode@5bbf3d87 |
654 | +mode: FROM_TABLE |
655 | +tableName: t1 |
656 | +filename: null |
657 | +format: null |
658 | +delimiter: null |
659 | +nullString: null |
660 | +quote: null |
661 | +escape: null |
662 | +encoding: null |
663 | +commitFrequency: 0 |
664 | +statementType: COPY |
665 | \ No newline at end of file |
666 | |
667 | === added file 'src/test/resources/com/akiban/sql/parser/copy-1.sql' |
668 | --- src/test/resources/com/akiban/sql/parser/copy-1.sql 1970-01-01 00:00:00 +0000 |
669 | +++ src/test/resources/com/akiban/sql/parser/copy-1.sql 2012-12-30 01:41:22 +0000 |
670 | @@ -0,0 +1,1 @@ |
671 | +COPY t1 TO STDOUT |
672 | \ No newline at end of file |
673 | |
674 | === added file 'src/test/resources/com/akiban/sql/parser/copy-2.expected' |
675 | --- src/test/resources/com/akiban/sql/parser/copy-2.expected 1970-01-01 00:00:00 +0000 |
676 | +++ src/test/resources/com/akiban/sql/parser/copy-2.expected 2012-12-30 01:41:22 +0000 |
677 | @@ -0,0 +1,39 @@ |
678 | +com.akiban.sql.parser.CopyStatementNode@44c9d92c |
679 | +mode: FROM_TABLE |
680 | +tableName: t2 |
681 | +filename: /tmp/t2.csv |
682 | +format: null |
683 | +delimiter: null |
684 | +nullString: null |
685 | +quote: null |
686 | +escape: null |
687 | +encoding: null |
688 | +commitFrequency: 0 |
689 | +statementType: COPY |
690 | +columnList: |
691 | + com.akiban.sql.parser.ResultColumnList@1fd0fafc |
692 | + |
693 | + [0]: |
694 | + com.akiban.sql.parser.ResultColumn@510dc6b5 |
695 | + exposedName: c1 |
696 | + name: c1 |
697 | + tableName: null |
698 | + isDefaultColumn: false |
699 | + type: null |
700 | + reference: |
701 | + com.akiban.sql.parser.ColumnReference@5f70bea5 |
702 | + columnName: c1 |
703 | + tableName: null |
704 | + type: null |
705 | + [1]: |
706 | + com.akiban.sql.parser.ResultColumn@62f47396 |
707 | + exposedName: c2 |
708 | + name: c2 |
709 | + tableName: null |
710 | + isDefaultColumn: false |
711 | + type: null |
712 | + reference: |
713 | + com.akiban.sql.parser.ColumnReference@1ed0af9b |
714 | + columnName: c2 |
715 | + tableName: null |
716 | + type: null |
717 | \ No newline at end of file |
718 | |
719 | === added file 'src/test/resources/com/akiban/sql/parser/copy-2.sql' |
720 | --- src/test/resources/com/akiban/sql/parser/copy-2.sql 1970-01-01 00:00:00 +0000 |
721 | +++ src/test/resources/com/akiban/sql/parser/copy-2.sql 2012-12-30 01:41:22 +0000 |
722 | @@ -0,0 +1,1 @@ |
723 | +COPY t2(c1,c2) TO '/tmp/t2.csv' |
724 | \ No newline at end of file |
725 | |
726 | === added file 'src/test/resources/com/akiban/sql/parser/copy-3.expected' |
727 | --- src/test/resources/com/akiban/sql/parser/copy-3.expected 1970-01-01 00:00:00 +0000 |
728 | +++ src/test/resources/com/akiban/sql/parser/copy-3.expected 2012-12-30 01:41:22 +0000 |
729 | @@ -0,0 +1,12 @@ |
730 | +com.akiban.sql.parser.CopyStatementNode@16b8f8eb |
731 | +mode: TO_TABLE |
732 | +tableName: t1 |
733 | +filename: /tmp/t1.csv |
734 | +format: null |
735 | +delimiter: null |
736 | +nullString: null |
737 | +quote: null |
738 | +escape: null |
739 | +encoding: null |
740 | +commitFrequency: 0 |
741 | +statementType: COPY |
742 | \ No newline at end of file |
743 | |
744 | === added file 'src/test/resources/com/akiban/sql/parser/copy-3.sql' |
745 | --- src/test/resources/com/akiban/sql/parser/copy-3.sql 1970-01-01 00:00:00 +0000 |
746 | +++ src/test/resources/com/akiban/sql/parser/copy-3.sql 2012-12-30 01:41:22 +0000 |
747 | @@ -0,0 +1,1 @@ |
748 | +COPY t1 FROM '/tmp/t1.csv' |
749 | \ No newline at end of file |
750 | |
751 | === added file 'src/test/resources/com/akiban/sql/parser/copy-4.expected' |
752 | --- src/test/resources/com/akiban/sql/parser/copy-4.expected 1970-01-01 00:00:00 +0000 |
753 | +++ src/test/resources/com/akiban/sql/parser/copy-4.expected 2012-12-30 01:41:22 +0000 |
754 | @@ -0,0 +1,47 @@ |
755 | +com.akiban.sql.parser.CopyStatementNode@49de17f4 |
756 | +mode: FROM_SUBQUERY |
757 | +tableName: null |
758 | +filename: /tmp/t12.txt |
759 | +format: null |
760 | +delimiter: null |
761 | +nullString: null |
762 | +quote: null |
763 | +escape: null |
764 | +encoding: null |
765 | +commitFrequency: 0 |
766 | +statementType: COPY |
767 | +subquery: |
768 | + com.akiban.sql.parser.SubqueryNode@13f6ba0f |
769 | + subqueryType: FROM |
770 | + type: null |
771 | + resultSet: |
772 | + com.akiban.sql.parser.SelectNode@2b313906 |
773 | + isDistinct: false |
774 | + resultColumns: |
775 | + com.akiban.sql.parser.ResultColumnList@2c96cf11 |
776 | + |
777 | + [0]: |
778 | + com.akiban.sql.parser.AllResultColumn@60f47bf5 |
779 | + tableName: null |
780 | + exposedName: null |
781 | + name: null |
782 | + tableName: null |
783 | + isDefaultColumn: false |
784 | + type: null |
785 | + fromList: |
786 | + com.akiban.sql.parser.FromList@52f6438d |
787 | + |
788 | + [0]: |
789 | + com.akiban.sql.parser.FromBaseTable@25cd0888 |
790 | + tableName: t1 |
791 | + updateOrDelete: null |
792 | + null |
793 | + correlation Name: null |
794 | + null |
795 | + [1]: |
796 | + com.akiban.sql.parser.FromBaseTable@37eb2c1b |
797 | + tableName: t2 |
798 | + updateOrDelete: null |
799 | + null |
800 | + correlation Name: null |
801 | + null |
802 | \ No newline at end of file |
803 | |
804 | === added file 'src/test/resources/com/akiban/sql/parser/copy-4.sql' |
805 | --- src/test/resources/com/akiban/sql/parser/copy-4.sql 1970-01-01 00:00:00 +0000 |
806 | +++ src/test/resources/com/akiban/sql/parser/copy-4.sql 2012-12-30 01:41:22 +0000 |
807 | @@ -0,0 +1,1 @@ |
808 | +COPY (SELECT * FROM t1,t2) TO '/tmp/t12.txt' |
809 | \ No newline at end of file |
810 | |
811 | === added file 'src/test/resources/com/akiban/sql/parser/copy-5.expected' |
812 | --- src/test/resources/com/akiban/sql/parser/copy-5.expected 1970-01-01 00:00:00 +0000 |
813 | +++ src/test/resources/com/akiban/sql/parser/copy-5.expected 2012-12-30 01:41:22 +0000 |
814 | @@ -0,0 +1,12 @@ |
815 | +com.akiban.sql.parser.CopyStatementNode@24f9fdc |
816 | +mode: FROM_TABLE |
817 | +tableName: t1 |
818 | +filename: null |
819 | +format: CSV |
820 | +delimiter: | |
821 | +nullString: null |
822 | +quote: null |
823 | +escape: null |
824 | +encoding: null |
825 | +commitFrequency: 0 |
826 | +statementType: COPY |
827 | \ No newline at end of file |
828 | |
829 | === added file 'src/test/resources/com/akiban/sql/parser/copy-5.sql' |
830 | --- src/test/resources/com/akiban/sql/parser/copy-5.sql 1970-01-01 00:00:00 +0000 |
831 | +++ src/test/resources/com/akiban/sql/parser/copy-5.sql 2012-12-30 01:41:22 +0000 |
832 | @@ -0,0 +1,1 @@ |
833 | +COPY t1 TO STDOUT (FORMAT CSV, DELIMITER '|', NULL 'null') |
834 | \ No newline at end of file |
835 | |
836 | === modified file 'src/test/resources/com/akiban/sql/parser/junk-1.error' |
837 | --- src/test/resources/com/akiban/sql/parser/junk-1.error 2012-12-13 22:38:28 +0000 |
838 | +++ src/test/resources/com/akiban/sql/parser/junk-1.error 2012-12-30 01:41:22 +0000 |
839 | @@ -20,6 +20,7 @@ |
840 | "truncate" ... |
841 | "call" ... |
842 | "explain" ... |
843 | + "copy" ... |
844 | "lock" ... |
845 | "rename" ... |
846 | "{" ... |
847 | |
848 | === added file 'src/test/resources/com/akiban/sql/unparser/copy-3.expected' |
849 | --- src/test/resources/com/akiban/sql/unparser/copy-3.expected 1970-01-01 00:00:00 +0000 |
850 | +++ src/test/resources/com/akiban/sql/unparser/copy-3.expected 2012-12-30 01:41:22 +0000 |
851 | @@ -0,0 +1,1 @@ |
852 | +COPY t1 FROM '/tmp/t1.csv' |
853 | \ No newline at end of file |
854 | |
855 | === added file 'src/test/resources/com/akiban/sql/unparser/copy-3.sql' |
856 | --- src/test/resources/com/akiban/sql/unparser/copy-3.sql 1970-01-01 00:00:00 +0000 |
857 | +++ src/test/resources/com/akiban/sql/unparser/copy-3.sql 2012-12-30 01:41:22 +0000 |
858 | @@ -0,0 +1,1 @@ |
859 | +COPY t1 FROM '/tmp/t1.csv' |
860 | \ No newline at end of file |
861 | |
862 | === added file 'src/test/resources/com/akiban/sql/unparser/copy-5.expected' |
863 | --- src/test/resources/com/akiban/sql/unparser/copy-5.expected 1970-01-01 00:00:00 +0000 |
864 | +++ src/test/resources/com/akiban/sql/unparser/copy-5.expected 2012-12-30 01:41:22 +0000 |
865 | @@ -0,0 +1,1 @@ |
866 | +COPY t1(c1, c2) TO 'file' WITH (FORMAT CSV, DELIMITER '|', NULL 'null', HEADER TRUE) |
867 | \ No newline at end of file |
868 | |
869 | === added file 'src/test/resources/com/akiban/sql/unparser/copy-5.sql' |
870 | --- src/test/resources/com/akiban/sql/unparser/copy-5.sql 1970-01-01 00:00:00 +0000 |
871 | +++ src/test/resources/com/akiban/sql/unparser/copy-5.sql 2012-12-30 01:41:22 +0000 |
872 | @@ -0,0 +1,1 @@ |
873 | +COPY t1(c1,c2) TO 'file' (FORMAT csv, null 'null', delimiter '|', HEADER true) |
874 | \ No newline at end of file |
875 | |
876 | === added file 'src/test/resources/com/akiban/sql/unparser/copy-6.expected' |
877 | --- src/test/resources/com/akiban/sql/unparser/copy-6.expected 1970-01-01 00:00:00 +0000 |
878 | +++ src/test/resources/com/akiban/sql/unparser/copy-6.expected 2012-12-30 01:41:22 +0000 |
879 | @@ -0,0 +1,1 @@ |
880 | +COPY t1 FROM 't1.csv' WITH (COMMIT 10000 ROWS) |
881 | \ No newline at end of file |
882 | |
883 | === added file 'src/test/resources/com/akiban/sql/unparser/copy-6.sql' |
884 | --- src/test/resources/com/akiban/sql/unparser/copy-6.sql 1970-01-01 00:00:00 +0000 |
885 | +++ src/test/resources/com/akiban/sql/unparser/copy-6.sql 2012-12-30 01:41:22 +0000 |
886 | @@ -0,0 +1,1 @@ |
887 | +COPY t1 FROM 't1.csv' WITH (HEADER false, COMMIT 10000) |
888 | \ No newline at end of file |
Should there be a junk-1.sql?
Otherwise looks fine. Feel free to big-A after.