diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index ef9ddd4adcd80648a25614acc4d7d97b667e2e1a..89701467c49586eb32c3940cf557a1cd0879a39d 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -1232,13 +1232,13 @@ ProcessCopyOptions(CopyState cstate, { bool format_specified = false; ListCell *option; - bool delim_off = false; /* Support external use for option sanity checking */ if (cstate == NULL) cstate = (CopyStateData *) palloc0(sizeof(CopyStateData)); cstate->escape_off = false; + cstate->delim_off = false; cstate->file_encoding = -1; /* Extract options from the statement node tree */ @@ -1291,7 +1291,7 @@ ProcessCopyOptions(CopyState cstate, cstate->delim = defGetString(defel); if (cstate->delim && pg_strcasecmp(cstate->delim, "off") == 0) - delim_off = true; + cstate->delim_off = true; } else if (strcmp(defel->defname, "null") == 0) { @@ -1506,7 +1506,7 @@ ProcessCopyOptions(CopyState cstate, * future-proofing. Likewise we disallow all digits though only octal * digits are actually dangerous. */ - if (!cstate->csv_mode && !delim_off && + if (!cstate->csv_mode && !cstate->delim_off && strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789", cstate->delim[0]) != NULL) ereport(ERROR, @@ -1534,7 +1534,7 @@ ProcessCopyOptions(CopyState cstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("COPY quote must be a single one-byte character"))); - if (cstate->csv_mode && cstate->delim[0] == cstate->quote[0] && !delim_off) + if (cstate->csv_mode && cstate->delim[0] == cstate->quote[0] && !cstate->delim_off) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("COPY delimiter and quote must be different"))); @@ -1609,7 +1609,7 @@ ProcessCopyOptions(CopyState cstate, if (pg_database_encoding_max_length() == 1) { /* single byte encoding such as ascii, latinx and other */ - if (strlen(cstate->delim) != 1 && !delim_off) + if (strlen(cstate->delim) != 1 && !cstate->delim_off) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("COPY delimiter must be a single one-byte character, or \'off\'"))); @@ -1617,7 +1617,7 @@ ProcessCopyOptions(CopyState cstate, else { /* multi byte encoding such as utf8 */ - if ((strlen(cstate->delim) != 1 || IS_HIGHBIT_SET(cstate->delim[0])) && !delim_off ) + if ((strlen(cstate->delim) != 1 || IS_HIGHBIT_SET(cstate->delim[0])) && !cstate->delim_off ) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("COPY delimiter must be a single one-byte character, or \'off\'"))); @@ -1635,12 +1635,12 @@ ProcessCopyOptions(CopyState cstate, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("COPY delimiter cannot be backslash"))); - if (strchr(cstate->null_print, cstate->delim[0]) != NULL && !delim_off) + if (strchr(cstate->null_print, cstate->delim[0]) != NULL && !cstate->delim_off) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("COPY delimiter must not appear in the NULL specification"))); - if (delim_off) + if (cstate->delim_off) { /* @@ -6509,6 +6509,7 @@ CopyReadAttributesText(CopyState cstate, int stop_processing_at_field) { char delimc = cstate->delim[0]; char escapec = cstate->escape_off ? delimc : cstate->escape[0]; + bool delim_off = cstate->delim_off; int fieldno; char *output_ptr; char *cur_ptr; @@ -6594,7 +6595,7 @@ CopyReadAttributesText(CopyState cstate, int stop_processing_at_field) if (cur_ptr >= line_end_ptr) break; c = *cur_ptr++; - if (c == delimc) + if (c == delimc && !delim_off) { found_delim = true; break; @@ -6755,6 +6756,7 @@ static int CopyReadAttributesCSV(CopyState cstate, int stop_processing_at_field) { char delimc = cstate->delim[0]; + bool delim_off = cstate->delim_off; char quotec = cstate->quote[0]; char escapec = cstate->escape[0]; int fieldno; @@ -6842,7 +6844,7 @@ CopyReadAttributesCSV(CopyState cstate, int stop_processing_at_field) goto endfield; c = *cur_ptr++; /* unquoted field delimiter */ - if (c == delimc) + if (c == delimc && !delim_off) { found_delim = true; goto endfield; diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h index b9389eebe073222e2f7d8fe70063515d23a065c0..d54806109c5c99a03d6da83c481b2c4e64ae8fa9 100644 --- a/src/include/commands/copy.h +++ b/src/include/commands/copy.h @@ -256,6 +256,8 @@ typedef struct CopyStateData /* Information on the connections to QEs. */ CdbCopy *cdbCopy; + bool delim_off; /* delimiter is set to OFF? */ + /* end Greenplum Database specific variables */ } CopyStateData; diff --git a/src/test/isolation2/input/external_table.source b/src/test/isolation2/input/external_table.source index a0caf654a64b8e2d0e7c020db18aee7b7db70c53..f558073252f507d96b62e985f154d19095d8a9cf 100644 --- a/src/test/isolation2/input/external_table.source +++ b/src/test/isolation2/input/external_table.source @@ -124,3 +124,24 @@ CREATE EXTERNAL WEB TABLE ext_delim_off ( junk text) execute 'echo hi' on master -- Query the ext_delim_off table SELECT * FROM ext_delim_off; + +-- start_ignore +DROP EXTERNAL TABLE IF EXISTS ext_delimiter_off_text; +-- end_ignore + +-- Create external table(format text) with delimiter off, and a row with 'O' +CREATE EXTERNAL WEB TABLE ext_delimiter_off_text +(a text) EXECUTE E'echo O' ON MASTER FORMAT 'text' (delimiter 'OFF') ENCODING 'UTF8'; + +SELECT * FROM ext_delimiter_off_text; + +-- start_ignore +DROP EXTERNAL TABLE IF EXISTS ext_delimiter_off_csv; +-- end_ignore + +-- Create external table(format csv) with delimiter off, and a row with 'O' +CREATE EXTERNAL WEB TABLE ext_delimiter_off_csv +(a text) EXECUTE E'echo O' ON MASTER FORMAT 'csv' (delimiter 'OFF') ENCODING 'UTF8'; + +SELECT * FROM ext_delimiter_off_csv; + diff --git a/src/test/isolation2/output/external_table.source b/src/test/isolation2/output/external_table.source index 78fde5de58f115260e49b72b3ee1e04240c2c09f..ea399b2ce935e29794be1e21a467dce2595c4417 100644 --- a/src/test/isolation2/output/external_table.source +++ b/src/test/isolation2/output/external_table.source @@ -204,3 +204,34 @@ SELECT * FROM ext_delim_off; ------ hi (1 row) + +GP_IGNORE:-- start_ignore +GP_IGNORE:DROP EXTERNAL TABLE IF EXISTS ext_delimiter_off_text; +GP_IGNORE:DROP +GP_IGNORE:-- end_ignore + +-- Create external table(format text) with delimiter off, and a row with 'O' +CREATE EXTERNAL WEB TABLE ext_delimiter_off_text (a text) EXECUTE E'echo O' ON MASTER FORMAT 'text' (delimiter 'OFF') ENCODING 'UTF8'; +CREATE + +SELECT * FROM ext_delimiter_off_text; + a +--- + O +(1 row) + +GP_IGNORE:-- start_ignore +GP_IGNORE:DROP EXTERNAL TABLE IF EXISTS ext_delimiter_off_csv; +GP_IGNORE:DROP +GP_IGNORE:-- end_ignore + +-- Create external table(format csv) with delimiter off, and a row with 'O' +CREATE EXTERNAL WEB TABLE ext_delimiter_off_csv (a text) EXECUTE E'echo O' ON MASTER FORMAT 'csv' (delimiter 'OFF') ENCODING 'UTF8'; +CREATE + +SELECT * FROM ext_delimiter_off_csv; + a +--- + O +(1 row) +