summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Deolasee2017-01-05 14:04:36 +0000
committerPavan Deolasee2017-05-05 04:59:33 +0000
commit1e1f85b67f577cd86b4aa0b5387dfaba7272a28e (patch)
tree551a6262bea9eecb056ba0ac71e2331fcbd80890
parentcad751b23b2ed7a2371b3bb9074cd93d38c7bfb7 (diff)
Ensure variable values are quoted when necessary while sending down SET
comamnds to the remote nodes Earlier we'd special cased a few GUCs such as those using memory or time units or transaction isolation levels. But clearly that wasn't enough as we noticed with "application_name" recently. So fix this problem in a more comprehensive manner. Added a few more test cases to cover these scenarios.
-rw-r--r--src/backend/pgxc/pool/execRemote.c2
-rw-r--r--src/backend/pgxc/pool/pgxcnode.c25
-rw-r--r--src/backend/utils/misc/guc.c59
-rw-r--r--src/include/pgxc/pgxcnode.h3
-rw-r--r--src/include/utils/guc.h1
-rw-r--r--src/test/regress/sql/guc.sql96
6 files changed, 139 insertions, 47 deletions
diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c
index 321fa1fee2..d6e842301e 100644
--- a/src/backend/pgxc/pool/execRemote.c
+++ b/src/backend/pgxc/pool/execRemote.c
@@ -1912,7 +1912,7 @@ pgxc_node_begin(int conn_count, PGXCNodeHandle **connections,
/* Send virtualXID to the remote nodes using SET command */
sprintf(lxid, "%d", MyProc->lxid);
- PGXCNodeSetParam(true, "coordinator_lxid", lxid);
+ PGXCNodeSetParam(true, "coordinator_lxid", lxid, 0);
/* after transactions are started send down local set commands */
init_str = PGXCNodeGetTransactionParamStr();
diff --git a/src/backend/pgxc/pool/pgxcnode.c b/src/backend/pgxc/pool/pgxcnode.c
index 28a5bbb4c6..4375e8813a 100644
--- a/src/backend/pgxc/pool/pgxcnode.c
+++ b/src/backend/pgxc/pool/pgxcnode.c
@@ -107,6 +107,7 @@ typedef struct
{
NameData name;
NameData value;
+ int flags;
} ParamEntry;
@@ -2568,7 +2569,7 @@ paramlist_delete_param(List *param_list, const char *name)
* values on newly connected remote nodes.
*/
void
-PGXCNodeSetParam(bool local, const char *name, const char *value)
+PGXCNodeSetParam(bool local, const char *name, const char *value, int flags)
{
List *param_list;
MemoryContext oldcontext;
@@ -2596,6 +2597,7 @@ PGXCNodeSetParam(bool local, const char *name, const char *value)
entry = (ParamEntry *) palloc(sizeof (ParamEntry));
strlcpy((char *) (&entry->name), name, NAMEDATALEN);
strlcpy((char *) (&entry->value), value, NAMEDATALEN);
+ entry->flags = flags;
param_list = lappend(param_list, entry);
}
@@ -2647,25 +2649,6 @@ PGXCNodeResetParams(bool only_local)
local_params = NULL;
}
-
-#ifdef NOT_USED
-static char *
-quote_ident_cstr(char *rawstr)
-{
- text *rawstr_text;
- text *result_text;
- char *result;
-
- rawstr_text = cstring_to_text(rawstr);
- result_text = DatumGetTextP(DirectFunctionCall1(quote_ident,
- PointerGetDatum(rawstr_text)));
- result = text_to_cstring(result_text);
-
- return result;
-}
-#endif
-
-
static void
get_set_command(List *param_list, StringInfo command, bool local)
{
@@ -2682,6 +2665,8 @@ get_set_command(List *param_list, StringInfo command, bool local)
if (strlen(value) == 0)
value = "''";
+ value = quote_guc_value(value, entry->flags);
+
appendStringInfo(command, "SET %s %s TO %s;", local ? "LOCAL" : "",
NameStr(entry->name), value);
}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index eaeaadb9cd..ff26c2e2c7 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -5650,13 +5650,9 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
/* XXX perhaps this should use is_missing=false, not sure */
newvalStr = GetConfigOptionByName(gconf->name, NULL, true);
- /*
- * Quote value if it is including memory or time units
- */
- if (newvalStr && (gconf->flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME)))
- newvalStr = quote_identifier(newvalStr);
if (newvalStr)
- PGXCNodeSetParam((stack->state == GUC_LOCAL), gconf->name, newvalStr);
+ PGXCNodeSetParam((stack->state == GUC_LOCAL), gconf->name,
+ newvalStr, gconf->flags);
}
/* Finish popping the state stack */
@@ -6981,38 +6977,24 @@ set_config_option(const char *name, const char *value,
initStringInfo(&poolcmd);
/*
- * We are getting parse error when sending down
- * SET transaction_isolation TO read committed;
- * XXX generic solution?
- */
- if (value && strcmp("transaction_isolation", name) == 0)
- value = quote_identifier(value);
-
- if (value && strcmp("default_transaction_isolation", name) == 0)
- value = quote_identifier(value);
-
- /*
- * Quote value if it is including memory or time units
- */
- if (value && (record->flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME)))
- value = quote_identifier(value);
-
- /*
* Save new parameter value with the node manager.
* XXX here we may check: if value equals to configuration default
* just reset parameter instead. Minus one table entry, shorter SET
* command sent downn... Sounds like optimization.
*/
+
if (action == GUC_ACTION_LOCAL)
{
if (IsTransactionBlock())
- PGXCNodeSetParam(true, name, value);
+ PGXCNodeSetParam(true, name, value, record->flags);
+ value = quote_guc_value(value, record->flags);
appendStringInfo(&poolcmd, "SET LOCAL %s TO %s", name,
(value ? value : "DEFAULT"));
}
else
{
- PGXCNodeSetParam(false, name, value);
+ PGXCNodeSetParam(false, name, value, record->flags);
+ value = quote_guc_value(value, record->flags);
appendStringInfo(&poolcmd, "SET %s TO %s", name,
(value ? value : "DEFAULT"));
}
@@ -10940,4 +10922,31 @@ check_storm_catalog_remap_string(char **newval, void **extra, GucSource source)
return true;
}
#endif
+
+#ifdef XCP
+/*
+ * Return a quoted GUC value, when necessary
+ */
+char *
+quote_guc_value(const char *value, int flags)
+{
+ if (value == NULL)
+ return value;
+
+ /*
+ * If the GUC rceives list input, then the individual elements in the list
+ * must be already quoted correctly by flatten_set_variable_args(). We must
+ * not quote the entire value again
+ */
+ if (flags & GUC_LIST_INPUT)
+ return value;
+
+ /*
+ * Otherwise quote the value. quote_identifier() takes care of correctly
+ * quoting the value when needed, including GUC_UNIT_MEMORY and
+ * GUC_UNIT_TIME values.
+ */
+ return quote_identifier(value);
+}
+#endif
#include "guc-file.c"
diff --git a/src/include/pgxc/pgxcnode.h b/src/include/pgxc/pgxcnode.h
index f40120671f..7ad15c7c6a 100644
--- a/src/include/pgxc/pgxcnode.h
+++ b/src/include/pgxc/pgxcnode.h
@@ -187,7 +187,8 @@ extern void add_error_message(PGXCNodeHandle * handle, const char *message);
extern Datum pgxc_execute_on_nodes(int numnodes, Oid *nodelist, char *query);
-extern void PGXCNodeSetParam(bool local, const char *name, const char *value);
+extern void PGXCNodeSetParam(bool local, const char *name, const char *value,
+ int flags);
extern void PGXCNodeResetParams(bool only_local);
extern char *PGXCNodeGetSessionParamStr(void);
extern char *PGXCNodeGetTransactionParamStr(void);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index a831fa2777..9fb76be629 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -446,5 +446,6 @@ extern void assign_search_path(const char *newval, void *extra);
/* in access/transam/xlog.c */
extern bool check_wal_buffers(int *newval, void **extra, GucSource source);
extern void assign_xlog_sync_method(int new_sync_method, void *extra);
+extern char *quote_guc_value(const char *value, int flags);
#endif /* GUC_H */
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index 95ac9cb43b..60133f1891 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -209,3 +209,99 @@ set default_text_search_config = no_such_config;
select func_with_bad_set();
reset check_function_bodies;
+
+SET application_name TO "special name";
+CREATE TABLE testtab (a int);
+INSERT INTO testtab VALUES (1), (2), (3);
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+SET default_transaction_isolation TO "read committed";
+CREATE TABLE testtab (a int);
+INSERT INTO testtab VALUES (1), (2), (3);
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+SET work_mem TO '64kB';
+CREATE TABLE testtab (a int);
+INSERT INTO testtab VALUES (1), (2), (3);
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+SET work_mem TO "64kB";
+CREATE TABLE testtab (a int);
+INSERT INTO testtab VALUES (1), (2), (3);
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+SET log_min_duration_statement = '1s';
+CREATE TABLE testtab (a int);
+INSERT INTO testtab VALUES (1), (2), (3);
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+CREATE SCHEMA testschema;
+CREATE SCHEMA "testschema 2";
+CREATE SCHEMA "testschema 3";
+CREATE SCHEMA READ;
+CREATE SCHEMA "READ";
+
+-- ERROR
+CREATE SCHEMA SELECT;
+
+-- Ok
+CREATE SCHEMA "SELECT";
+
+SET search_path TO testschema;
+CREATE TABLE testtab (a int);
+\d+ testtab
+INSERT INTO testtab VALUES (1), (2), (3);
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+SET search_path TO "testschema";
+CREATE TABLE testtab (a int);
+\d+ testtab
+INSERT INTO testtab VALUES (1), (2), (3);
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+SET search_path TO testschema, "testschema 2";
+CREATE TABLE testtab (a int);
+\d+ testtab
+INSERT INTO testtab VALUES (1), (2), (3);
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+SET search_path TO "testschema 3", "testschema 2";
+CREATE TABLE testtab (a int);
+\d+ testtab
+INSERT INTO testtab VALUES (1), (2), (3);
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+-- ERROR
+SET search_path TO "testschema 3", SELECT;
+
+SET search_path TO "SELECT", "testschema 3";
+CREATE TABLE testtab (a int);
+\d+ testtab
+CREATE TABLE "testschema 3".testtab (a int);
+\d+ testtab
+INSERT INTO "testschema 3".testtab VALUES (1), (2), (3);
+INSERT INTO "SELECT".testtab VALUES (4);
+SELECT * FROM "testschema 3".testtab;
+INSERT INTO testtab SELECT * FROM "testschema 3".testtab;
+SELECT * FROM "testschema 3".testtab;
+\d+ testtab
+SELECT * FROM testtab;
+INSERT INTO testtab SELECT * FROM testtab;
+SELECT * FROM testtab;
+DROP TABLE testtab;
+
+DROP SCHEMA testschema CASCADE;
+DROP SCHEMA "testschema 2" CASCADE;
+DROP SCHEMA "testschema 3" CASCADE;
+DROP SCHEMA "READ" CASCADE;
+DROP SCHEMA SELECT CASCADE;
+DROP SCHEMA "SELECT" CASCADE;