提交 1d15b9bc 编写于 作者: D Daniel Gustafsson

Support FORCE QUOTE * in external tables

FORCE QUOTE * was added in PostgreSQL 9.0 as a shorthand for FORCE
QUOTE <column_1 .. column_n> in the COPY comamnd, where all columns
of a relation are added for forced quoting. External tables use copy
and copy options under the hood, so they too should support '*' to
quote all columns. This resolves a FIXME added during the 9.0 merge.
上级 cdd5699a
......@@ -85,7 +85,7 @@ CREATE WRITABLE EXTERNAL [TEMPORARY | TEMP] TABLE <varname>table_name</varname>
               [([QUOTE [AS] '<varname>quote</varname>']
               [DELIMITER [AS] '<varname>delimiter</varname>']
               [NULL [AS] '<varname>null string</varname>']
               [FORCE QUOTE <varname>column</varname> [, ...]] ]
               [FORCE QUOTE <varname>column</varname> [, ...]] | * ]
               [ESCAPE [AS] '<varname>escape</varname>'] )]
           | 'AVRO'
| 'PARQUET'
......@@ -106,7 +106,7 @@ CREATE WRITABLE EXTERNAL [TEMPORARY | TEMP] TABLE <varname>table_name</varname>
               [([QUOTE [AS] '<varname>quote</varname>']
               [DELIMITER [AS] '<varname>delimiter</varname>']
               [NULL [AS] '<varname>null string</varname>']
               [FORCE QUOTE <varname>column</varname> [, ...]] ]
               [FORCE QUOTE <varname>column</varname> [, ...]] | * ]
               [ESCAPE [AS] '<varname>escape</varname>'] )]
CREATE WRITABLE EXTERNAL WEB [TEMPORARY | TEMP] TABLE <varname>table_name</varname>
......@@ -120,7 +120,7 @@ CREATE WRITABLE EXTERNAL WEB [TEMPORARY | TEMP] TABLE <varname>table_name</varna
               [([QUOTE [AS] '<varname>quote</varname>']
               [DELIMITER [AS] '<varname>delimiter</varname>']
               [NULL [AS] '<varname>null string</varname>']
               [FORCE QUOTE <varname>column</varname> [, ...]] ]
               [FORCE QUOTE <varname>column</varname> [, ...]] | * ]
               [ESCAPE [AS] '<varname>escape</varname>'] )]
           | 'CUSTOM' (Formatter=<varname>&lt;formatter specifications&gt;</varname>)
    [ ENCODING '<varname>write_encoding</varname>' ]
......@@ -422,8 +422,9 @@ CREATE WRITABLE EXTERNAL WEB [TEMPORARY | TEMP] TABLE <varname>table_name</varna
<plentry>
<pt>FORCE QUOTE</pt>
<pd>In <codeph>CSV</codeph> mode for writable external tables, forces quoting to be used
for all non-<codeph>NULL</codeph> values in each specified column. <codeph>NULL</codeph>
output is never quoted.</pd>
for all non-<codeph>NULL</codeph> values in each specified column. If <codeph>*</codeph>
is specified then non-<codeph>NULL</codeph> values will be quoted in all columns.
<codeph>NULL</codeph> output is never quoted.</pd>
</plentry>
<plentry>
<pt>FILL MISSING FIELDS</pt>
......
......@@ -87,7 +87,7 @@ static int external_getdata_callback(void *outbuf, int datasize, void *extra);
static int external_getdata(URL_FILE *extfile, CopyState pstate, void *outbuf, int maxread);
static void external_senddata(URL_FILE *extfile, CopyState pstate);
static void external_scan_error_callback(void *arg);
static List *parseCopyFormatString(char *fmtstr, char fmttype);
static List *parseCopyFormatString(Relation rel, char *fmtstr, char fmttype);
static void parseCustomFormatString(char *fmtstr, char **formatter_name, List **formatter_params);
static Oid lookupCustomFormatter(char *formatter_name, bool iswritable);
static void justifyDatabuf(StringInfo buf);
......@@ -283,7 +283,7 @@ external_beginscan(Relation relation, uint32 scancounter,
&custom_formatter_params);
}
else
copyFmtOpts = parseCopyFormatString(fmtOptString, fmtType);
copyFmtOpts = parseCopyFormatString(relation, fmtOptString, fmtType);
/* pass external table's encoding to copy's options */
copyFmtOpts = appendCopyEncodingOption(copyFmtOpts, encoding);
......@@ -618,7 +618,7 @@ external_insert_init(Relation rel)
&custom_formatter_params);
}
else
copyFmtOpts = parseCopyFormatString(extentry->fmtopts, extentry->fmtcode);
copyFmtOpts = parseCopyFormatString(rel, extentry->fmtopts, extentry->fmtcode);
/* pass external table's encoding to copy's options */
copyFmtOpts = appendCopyEncodingOption(copyFmtOpts, extentry->encoding);
......@@ -1919,7 +1919,7 @@ strtokx2(const char *s,
}
static List *
parseCopyFormatString(char *fmtstr, char fmttype)
parseCopyFormatString(Relation rel, char *fmtstr, char fmttype)
{
char *token;
const char *whitespace = " \t\n\r";
......@@ -2019,6 +2019,32 @@ parseCopyFormatString(char *fmtstr, char fmttype)
if (!token || strchr(",", token[0]))
goto error;
/*
* For a '*' token the format option is force_quote_all
* and we need to recreate the column list for the entire
* relation.
*/
if (strcmp(token, "*") == 0)
{
int i;
TupleDesc tupdesc = RelationGetDescr(rel);
for (i = 0; i < tupdesc->natts; i++)
{
Form_pg_attribute att = tupdesc->attrs[i];
if (att->attisdropped)
continue;
cols = lappend(cols, makeString(NameStr(att->attname)));
}
/* consume the comma if any */
token = strtokx2(NULL, whitespace, ",", "\"",
0, false, false, encoding);
break;
}
cols = lappend(cols, makeString(pstrdup(token)));
/* consume the comma if any */
......
......@@ -812,7 +812,6 @@ transformFormatOpts(char formattype, List *formatOpts, int numcols, bool iswrita
strcmp(defel->defname, "escape") == 0 ||
strcmp(defel->defname, "force_not_null") == 0 ||
strcmp(defel->defname, "force_quote") == 0 ||
/* GPDB_90_MERGE_FIXME: add 'force_quote_all' here */
strcmp(defel->defname, "fill_missing_fields") == 0 ||
strcmp(defel->defname, "newline") == 0)
{
......@@ -908,6 +907,9 @@ transformFormatOpts(char formattype, List *formatOpts, int numcols, bool iswrita
}
}
if (cstate->force_quote_all)
appendStringInfo(&cfbuf, " force quote *");
if (cstate->eol_str)
appendStringInfo(&cfbuf, " newline '%s'", cstate->eol_str);
......
......@@ -5282,6 +5282,10 @@ format_opt_item:
{
$$ = makeDefElem("force_quote", (Node *)$3);
}
| FORCE QUOTE '*'
{
$$ = makeDefElem("force_quote", (Node *)makeNode(A_Star));
}
| FILL MISSING FIELDS
{
$$ = makeDefElem("fill_missing_fields", (Node *)makeInteger(TRUE));
......
......@@ -1464,17 +1464,21 @@ CREATE WRITABLE EXTERNAL WEB TABLE tbl_wet_csv4 (a int, b text) EXECUTE 'cat > @
-- Create writable external table with force quote
CREATE WRITABLE EXTERNAL WEB TABLE tbl_wet_csv5 (a int, b text) EXECUTE 'cat > @abs_srcdir@/data/wet_csv5.tbl' FORMAT 'CSV' (DELIMITER AS '|' NULL AS 'null' ESCAPE AS ' ' QUOTE AS '"' FORCE QUOTE b);
CREATE WRITABLE EXTERNAL WEB TABLE tbl_wet_csv6 (a int, b text, c text) EXECUTE 'cat > @abs_srcdir@/data/wet_csv6.tbl' FORMAT 'CSV' (DELIMITER AS '|' NULL AS 'null' ESCAPE AS ' ' QUOTE AS '"' FORCE QUOTE *);
INSERT INTO tbl_wet_csv1 VALUES (generate_series(1,256), 'test_1');
INSERT INTO tbl_wet_csv2 VALUES (generate_series(1,256), 'test_2');
INSERT INTO tbl_wet_csv3 VALUES (generate_series(1,256), 'test_3');
INSERT INTO tbl_wet_csv4 VALUES (generate_series(1,256), 'test_4');
INSERT INTO tbl_wet_csv5 VALUES (generate_series(1,256), 'test_5');
INSERT INTO tbl_wet_csv6 VALUES (generate_series(1,256), 'test_6', 'test_6_1');
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv1;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv2;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv3;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv4;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv5;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv6;
-- start_ignore
DROP EXTERNAL TABLE IF EXISTS tbl_wet_text1;
......
......@@ -2816,16 +2816,19 @@ CREATE WRITABLE EXTERNAL WEB TABLE tbl_wet_csv3 (a int, b text) EXECUTE 'cat > @
CREATE WRITABLE EXTERNAL WEB TABLE tbl_wet_csv4 (a int, b text) EXECUTE 'cat > @abs_srcdir@/data/wet_csv4.tbl' FORMAT 'CSV' (DELIMITER AS '|' NULL AS 'null' ESCAPE AS ' ' QUOTE AS '''');
-- Create writable external table with force quote
CREATE WRITABLE EXTERNAL WEB TABLE tbl_wet_csv5 (a int, b text) EXECUTE 'cat > @abs_srcdir@/data/wet_csv5.tbl' FORMAT 'CSV' (DELIMITER AS '|' NULL AS 'null' ESCAPE AS ' ' QUOTE AS '"' FORCE QUOTE b);
CREATE WRITABLE EXTERNAL WEB TABLE tbl_wet_csv6 (a int, b text, c text) EXECUTE 'cat > @abs_srcdir@/data/wet_csv6.tbl' FORMAT 'CSV' (DELIMITER AS '|' NULL AS 'null' ESCAPE AS ' ' QUOTE AS '"' FORCE QUOTE *);
INSERT INTO tbl_wet_csv1 VALUES (generate_series(1,256), 'test_1');
INSERT INTO tbl_wet_csv2 VALUES (generate_series(1,256), 'test_2');
INSERT INTO tbl_wet_csv3 VALUES (generate_series(1,256), 'test_3');
INSERT INTO tbl_wet_csv4 VALUES (generate_series(1,256), 'test_4');
INSERT INTO tbl_wet_csv5 VALUES (generate_series(1,256), 'test_5');
INSERT INTO tbl_wet_csv6 VALUES (generate_series(1,256), 'test_6', 'test_6_1');
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv1;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv2;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv3;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv4;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv5;
DROP EXTERNAL TABLE IF EXISTS tbl_wet_csv6;
-- start_ignore
DROP EXTERNAL TABLE IF EXISTS tbl_wet_text1;
NOTICE: table "tbl_wet_text1" does not exist, skipping
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册