Skip to content

Commit f7d7b9f

Browse files
committed
Use single CSV option, simplify parsing and add more test cases
1 parent 062a6ec commit f7d7b9f

10 files changed

Lines changed: 709 additions & 700 deletions

src/parser/bison_parser.cpp

Lines changed: 627 additions & 622 deletions
Large diffs are not rendered by default.

src/parser/bison_parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ union HSQL_STYPE
344344
hsql::RowLockWaitPolicy lock_wait_policy_t;
345345

346346
hsql::ImportExportOptions* import_export_option_t;
347-
hsql::CsvImportExportOptions* csv_import_export_option_t;
347+
std::pair<hsql::CsvOptionType, char*>* csv_option_t;
348348

349349
// clang-format off
350350

src/parser/bison_parser.y

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
hsql::RowLockWaitPolicy lock_wait_policy_t;
169169

170170
hsql::ImportExportOptions* import_export_option_t;
171-
hsql::CsvImportExportOptions* csv_import_export_option_t;
171+
std::pair<hsql::CsvOptionType, char*>* csv_option_t;
172172

173173
// clang-format off
174174
}
@@ -293,7 +293,7 @@
293293
// ImportType is used for compatibility reasons
294294
%type <import_type_t> file_type
295295
%type <import_export_option_t> opt_import_export_options import_export_options
296-
%type <csv_import_export_option_t> csv_import_export_options
296+
%type <csv_option_t> csv_option
297297

298298
%type <str_vec> ident_commalist opt_column_list
299299
%type <expr_vec> expr_list select_list opt_extended_literal_list extended_literal_list hint_list opt_hints opt_partition
@@ -505,7 +505,7 @@ import_export_options : import_export_options ',' FORMAT file_type {
505505
}
506506
if ($1->csv_options && $4 != kImportCSV && $4 != kImportAuto) {
507507
delete $1;
508-
yyerror(&yyloc, result, scanner, "Cannot have CSV options (DELIMITER, NULL, QUOTE) without CSV import type.");
508+
yyerror(&yyloc, result, scanner, "CSV options (DELIMITER, NULL, QUOTE) are only allowed for CSV files.");
509509
YYERROR;
510510
}
511511
$1->format = $4;
@@ -529,78 +529,83 @@ import_export_options : import_export_options ',' FORMAT file_type {
529529
$$ = new ImportExportOptions{};
530530
$$->encoding = $2;
531531
}
532-
| import_export_options ',' csv_import_export_options {
532+
| import_export_options ',' csv_option {
533533
if ($1->format != kImportAuto && $1->format != kImportCSV) {
534534
delete $1;
535+
free($3->second);
535536
delete $3;
536-
yyerror(&yyloc, result, scanner, "Cannot have CSV options (DELIMITER, NULL, QUOTE) without CSV import type.");
537+
yyerror(&yyloc, result, scanner, "CSV options (DELIMITER, NULL, QUOTE) are only allowed for CSV files.");
537538
YYERROR;
538539
}
539540

540-
if ($1->csv_options) {
541-
if ($1->csv_options->delimiter && $3->delimiter) {
542-
delete $1;
543-
delete $3;
544-
yyerror(&yyloc, result, scanner, "Delimiter must only be provided once.");
545-
YYERROR;
546-
}
547-
if ($1->csv_options->null && $3->null) {
548-
delete $1;
549-
delete $3;
550-
yyerror(&yyloc, result, scanner, "Null string must only be provided once.");
551-
YYERROR;
552-
}
553-
if ($1->csv_options->quote && $3->quote) {
554-
delete $1;
555-
delete $3;
556-
yyerror(&yyloc, result, scanner, "Quote must only be provided once.");
557-
YYERROR;
558-
}
541+
if ($1->csv_options == nullptr) {
542+
$1->csv_options = new CsvOptions{};
543+
}
559544

560-
if ($3->delimiter) {
561-
$1->csv_options->delimiter = $3->delimiter;
562-
$3->delimiter = nullptr;
563-
}
564-
if ($3->null) {
565-
$1->csv_options->null = $3->null;
566-
$3->null = nullptr;
545+
#define ASSERT_IS_NULLPTR(ptr) \
546+
if ((ptr) != nullptr) { \
547+
delete $1; \
548+
free($3->second); \
549+
delete $3; \
550+
yyerror(&yyloc, result, scanner, "CSV options (DELIMITER, NULL, QUOTE) cannot be provided more than once."); \
551+
YYERROR; \
552+
}
567553

568-
}
569-
if ($3->quote) {
570-
$1->csv_options->quote = $3->quote;
571-
$3->quote = nullptr;
572-
}
573-
delete $3;
554+
if ($3->first == hsql::CsvOptionType::Delimiter) {
555+
ASSERT_IS_NULLPTR($1->csv_options->delimiter);
556+
$$->csv_options->delimiter = $3->second;
557+
} else if ($3->first == hsql::CsvOptionType::Null) {
558+
ASSERT_IS_NULLPTR($1->csv_options->null);
559+
$$->csv_options->null = $3->second;
560+
} else if ($3->first == hsql::CsvOptionType::Quote) {
561+
ASSERT_IS_NULLPTR($1->csv_options->quote);
562+
$$->csv_options->quote = $3->second;
574563
} else {
575-
$1->csv_options = $3;
564+
delete $1;
565+
free($3->second);
566+
delete $3;
567+
yyerror(&yyloc, result, scanner, "Unknown CSV option.");
568+
YYERROR;
576569
}
577570

571+
delete $3;
578572
$$ = $1;
579573
}
580-
| csv_import_export_options {
574+
| csv_option {
581575
$$ = new ImportExportOptions{};
582-
$$->csv_options = $1;
576+
$$->csv_options = new CsvOptions{};
577+
578+
if ($1->first == hsql::CsvOptionType::Delimiter) {
579+
$$->csv_options->delimiter = $1->second;
580+
} else if ($1->first == hsql::CsvOptionType::Null) {
581+
$$->csv_options->null = $1->second;
582+
} else if ($1->first == hsql::CsvOptionType::Quote) {
583+
$$->csv_options->quote = $1->second;
584+
} else {
585+
free($1->second);
586+
delete $1;
587+
delete $$;
588+
yyerror(&yyloc, result, scanner, "Unknown CSV option.");
589+
YYERROR;
590+
}
591+
592+
delete $1;
583593
}
584594

585-
csv_import_export_options : IDENTIFIER STRING {
586-
$$ = new CsvImportExportOptions{};
595+
csv_option : IDENTIFIER STRING {
587596
if (strcasecmp($1, "DELIMITER") == 0) {
588-
$$->delimiter = $2;
597+
$$ = new std::pair(hsql::CsvOptionType::Delimiter, $2);
589598
} else if (strcasecmp($1, "QUOTE") == 0) {
590-
$$->quote = $2;
599+
$$ = new std::pair(hsql::CsvOptionType::Quote, $2);
591600
} else {
592-
delete $$;
593601
free($1);
594602
free($2);
595-
yyerror(&yyloc, result, scanner, "Unknown identifier when parsing CSV options.");
603+
yyerror(&yyloc, result, scanner, "Unknown CSV option.");
596604
YYERROR;
597605
}
598606
free($1);
599607
}
600-
| NULL STRING {
601-
$$ = new CsvImportExportOptions{};
602-
$$->null = $2;
603-
}
608+
| NULL STRING { $$ = new std::pair(hsql::CsvOptionType::Null, $2); }
604609

605610
/******************************
606611
* Export Statement

src/sql/CsvImportExportOptions.h

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/sql/ExportStatement.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#ifndef SQLPARSER_EXPORT_STATEMENT_H
22
#define SQLPARSER_EXPORT_STATEMENT_H
33

4-
#include "CsvImportExportOptions.h"
54
#include "ImportExportOptions.h"
65
#include "SQLStatement.h"
76
#include "SelectStatement.h"
@@ -19,7 +18,7 @@ struct ExportStatement : SQLStatement {
1918
char* tableName;
2019
SelectStatement* select;
2120
char* encoding;
22-
CsvImportExportOptions* csv_options;
21+
CsvOptions* csv_options;
2322
};
2423

2524
} // namespace hsql

src/sql/ImportExportOptions.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#ifndef SQLPARSER_IMPORT_EXPORT_OPTIONS_H
22
#define SQLPARSER_IMPORT_EXPORT_OPTIONS_H
33

4-
#include "CsvImportExportOptions.h"
5-
64
namespace hsql {
75

86
// Name unchanged for compatibility. Historically, this was only used for import statements before we introduced export
@@ -15,13 +13,28 @@ enum ImportType {
1513
kImportAuto
1614
};
1715

16+
enum CsvOptionType {
17+
Delimiter,
18+
Null,
19+
Quote,
20+
};
21+
22+
struct CsvOptions {
23+
CsvOptions();
24+
~CsvOptions();
25+
26+
char* delimiter;
27+
char* null;
28+
char* quote;
29+
};
30+
1831
struct ImportExportOptions {
1932
ImportExportOptions();
2033
~ImportExportOptions();
2134

2235
ImportType format;
2336
char* encoding;
24-
CsvImportExportOptions* csv_options;
37+
CsvOptions* csv_options;
2538
};
2639

2740
} // namespace hsql

src/sql/ImportStatement.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#ifndef SQLPARSER_IMPORT_STATEMENT_H
22
#define SQLPARSER_IMPORT_STATEMENT_H
33

4-
#include "CsvImportExportOptions.h"
54
#include "ImportExportOptions.h"
65
#include "SQLStatement.h"
76

@@ -18,7 +17,7 @@ struct ImportStatement : SQLStatement {
1817
char* tableName;
1918
Expr* whereClause;
2019
char* encoding;
21-
CsvImportExportOptions* csv_options;
20+
CsvOptions* csv_options;
2221
};
2322

2423
} // namespace hsql

src/sql/statements.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ ExportStatement::~ExportStatement() {
152152
delete csv_options;
153153
}
154154

155-
CsvImportExportOptions::CsvImportExportOptions() : delimiter(nullptr), null(nullptr), quote(nullptr) {}
156-
CsvImportExportOptions::~CsvImportExportOptions() {
155+
CsvOptions::CsvOptions() : delimiter(nullptr), null(nullptr), quote(nullptr) {}
156+
CsvOptions::~CsvOptions() {
157157
free(delimiter);
158158
free(null);
159159
free(quote);

test/queries/queries-bad.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
!SELECT * FROM t WHERE a = DATE '2000-01-01' + x DAYS;
5454
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 'x' DAY;
5555
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '3.3 DAYS';
56-
!COPY students FROM 'file_path' WITH (FORMAT TBL, DELIMITER '|', NULL '', QUOTE '"'); # Cannot have CSV options with non-CSV format
5756
# ON is not supported by postgres. We follow postgres here since the sql-92 standard does not specify index
5857
# implementation details.
5958
!DROP INDEX myindex ON mytable;
@@ -94,3 +93,8 @@
9493
!SELECT * FROM foo WITH HINT (?);
9594
!SELECT * FROM foo WITH HINT (CAST(column_a AS INT));
9695
!SELECT * FROM foo WITH HINT (AVG(another_column));
96+
# CSV options
97+
!COPY students FROM 'file_path' WITH (FORMAT TBL, DELIMITER '|', NULL '', QUOTE '"');
98+
!COPY students FROM 'file_path' WITH (DELIMITER '|', NULL '', QUOTE '"', FORMAT TBL);
99+
!COPY students FROM 'file_path' WITH (DELIMITER '|', NULL '', QUOTE '"', NULL 'a');
100+
!COPY students FROM 'file_path' WITH (FORMAT CSV, QUOTE '"', DELIMINIMITER '|');

test/queries/queries-good.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ COPY students FROM 'file_path' WITH (FORMAT CSV);
7575
COPY students FROM 'file_path' WITH (FORMAT BIN);
7676
COPY students FROM 'file_path' WITH (FORMAT BINARY);
7777
COPY students FROM 'file_path' WITH (FORMAT CSV, DELIMITER '|', NULL '', QUOTE '"');
78+
COPY students FROM 'file_path' WITH (DELIMITER '|', NULL '', FORMAT CSV, QUOTE '"');
7879
COPY students FROM 'file_path' (FORMAT TBL);
7980
COPY good_students FROM 'file_path' WHERE grade > (SELECT AVG(grade) from alumni);
8081
COPY students TO 'student.tbl';

0 commit comments

Comments
 (0)