mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-28 00:41:52 +02:00
Fix inappropriate quoting in dblink. From Joe Conway.
This commit is contained in:
parent
c3637205b2
commit
11d337185d
@ -151,6 +151,10 @@ Installation:
|
|||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
|
|
||||||
|
Note: Parameters representing relation names must include double
|
||||||
|
quotes if the names are mixed-case or contain special characters. They
|
||||||
|
must also be appropriately qualified with schema name if applicable.
|
||||||
|
|
||||||
See the following files:
|
See the following files:
|
||||||
doc/connection
|
doc/connection
|
||||||
doc/cursor
|
doc/cursor
|
||||||
|
@ -71,6 +71,7 @@ static dblink_results *get_res_ptr(int32 res_id_index);
|
|||||||
static void append_res_ptr(dblink_results * results);
|
static void append_res_ptr(dblink_results * results);
|
||||||
static void remove_res_ptr(dblink_results * results);
|
static void remove_res_ptr(dblink_results * results);
|
||||||
static TupleDesc pgresultGetTupleDesc(PGresult *res);
|
static TupleDesc pgresultGetTupleDesc(PGresult *res);
|
||||||
|
static char *generate_relation_name(Oid relid);
|
||||||
|
|
||||||
/* Global */
|
/* Global */
|
||||||
List *res_id = NIL;
|
List *res_id = NIL;
|
||||||
@ -171,7 +172,7 @@ dblink_open(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
appendStringInfo(str, "DECLARE %s CURSOR FOR %s", quote_ident_cstr(curname), sql);
|
appendStringInfo(str, "DECLARE %s CURSOR FOR %s", curname, sql);
|
||||||
res = PQexec(conn, str->data);
|
res = PQexec(conn, str->data);
|
||||||
if (!res ||
|
if (!res ||
|
||||||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
||||||
@ -210,7 +211,7 @@ dblink_close(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
elog(ERROR, "dblink_close: no connection available");
|
elog(ERROR, "dblink_close: no connection available");
|
||||||
|
|
||||||
appendStringInfo(str, "CLOSE %s", quote_ident_cstr(curname));
|
appendStringInfo(str, "CLOSE %s", curname);
|
||||||
|
|
||||||
/* close the cursor */
|
/* close the cursor */
|
||||||
res = PQexec(conn, str->data);
|
res = PQexec(conn, str->data);
|
||||||
@ -287,7 +288,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
elog(ERROR, "dblink_fetch: no connection available");
|
elog(ERROR, "dblink_fetch: no connection available");
|
||||||
|
|
||||||
appendStringInfo(str, "FETCH %d FROM %s", howmany, quote_ident_cstr(curname));
|
appendStringInfo(str, "FETCH %d FROM %s", howmany, curname);
|
||||||
|
|
||||||
res = PQexec(conn, str->data);
|
res = PQexec(conn, str->data);
|
||||||
if (!res ||
|
if (!res ||
|
||||||
@ -306,7 +307,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
/* cursor does not exist - closed already or bad name */
|
/* cursor does not exist - closed already or bad name */
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
elog(ERROR, "dblink_fetch: cursor %s does not exist", quote_ident_cstr(curname));
|
elog(ERROR, "dblink_fetch: cursor %s does not exist", curname);
|
||||||
}
|
}
|
||||||
|
|
||||||
funcctx->max_calls = PQntuples(res);
|
funcctx->max_calls = PQntuples(res);
|
||||||
@ -1527,11 +1528,13 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
|
|||||||
int i;
|
int i;
|
||||||
bool needComma;
|
bool needComma;
|
||||||
|
|
||||||
|
/* get relation name including any needed schema prefix and quoting */
|
||||||
|
relname = generate_relation_name(relid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open relation using relid
|
* Open relation using relid
|
||||||
*/
|
*/
|
||||||
rel = relation_open(relid, AccessShareLock);
|
rel = relation_open(relid, AccessShareLock);
|
||||||
relname = RelationGetRelationName(rel);
|
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
natts = tupdesc->natts;
|
natts = tupdesc->natts;
|
||||||
|
|
||||||
@ -1539,7 +1542,7 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
|
|||||||
if (!tuple)
|
if (!tuple)
|
||||||
elog(ERROR, "dblink_build_sql_insert: row not found");
|
elog(ERROR, "dblink_build_sql_insert: row not found");
|
||||||
|
|
||||||
appendStringInfo(str, "INSERT INTO %s(", quote_ident_cstr(relname));
|
appendStringInfo(str, "INSERT INTO %s(", relname);
|
||||||
|
|
||||||
needComma = false;
|
needComma = false;
|
||||||
for (i = 0; i < natts; i++)
|
for (i = 0; i < natts; i++)
|
||||||
@ -1610,15 +1613,17 @@ get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattval
|
|||||||
char *val;
|
char *val;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* get relation name including any needed schema prefix and quoting */
|
||||||
|
relname = generate_relation_name(relid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open relation using relid
|
* Open relation using relid
|
||||||
*/
|
*/
|
||||||
rel = relation_open(relid, AccessShareLock);
|
rel = relation_open(relid, AccessShareLock);
|
||||||
relname = RelationGetRelationName(rel);
|
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
natts = tupdesc->natts;
|
natts = tupdesc->natts;
|
||||||
|
|
||||||
appendStringInfo(str, "DELETE FROM %s WHERE ", quote_ident_cstr(relname));
|
appendStringInfo(str, "DELETE FROM %s WHERE ", relname);
|
||||||
for (i = 0; i < pknumatts; i++)
|
for (i = 0; i < pknumatts; i++)
|
||||||
{
|
{
|
||||||
int16 pkattnum = pkattnums[i];
|
int16 pkattnum = pkattnums[i];
|
||||||
@ -1669,11 +1674,13 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
|
|||||||
int i;
|
int i;
|
||||||
bool needComma;
|
bool needComma;
|
||||||
|
|
||||||
|
/* get relation name including any needed schema prefix and quoting */
|
||||||
|
relname = generate_relation_name(relid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open relation using relid
|
* Open relation using relid
|
||||||
*/
|
*/
|
||||||
rel = relation_open(relid, AccessShareLock);
|
rel = relation_open(relid, AccessShareLock);
|
||||||
relname = RelationGetRelationName(rel);
|
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
natts = tupdesc->natts;
|
natts = tupdesc->natts;
|
||||||
|
|
||||||
@ -1681,7 +1688,7 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
|
|||||||
if (!tuple)
|
if (!tuple)
|
||||||
elog(ERROR, "dblink_build_sql_update: row not found");
|
elog(ERROR, "dblink_build_sql_update: row not found");
|
||||||
|
|
||||||
appendStringInfo(str, "UPDATE %s SET ", quote_ident_cstr(relname));
|
appendStringInfo(str, "UPDATE %s SET ", relname);
|
||||||
|
|
||||||
needComma = false;
|
needComma = false;
|
||||||
for (i = 0; i < natts; i++)
|
for (i = 0; i < natts; i++)
|
||||||
@ -1813,11 +1820,13 @@ get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_p
|
|||||||
int i;
|
int i;
|
||||||
char *val = NULL;
|
char *val = NULL;
|
||||||
|
|
||||||
|
/* get relation name including any needed schema prefix and quoting */
|
||||||
|
relname = generate_relation_name(relid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open relation using relid
|
* Open relation using relid
|
||||||
*/
|
*/
|
||||||
rel = relation_open(relid, AccessShareLock);
|
rel = relation_open(relid, AccessShareLock);
|
||||||
relname = RelationGetRelationName(rel);
|
|
||||||
tupdesc = CreateTupleDescCopy(rel->rd_att);
|
tupdesc = CreateTupleDescCopy(rel->rd_att);
|
||||||
relation_close(rel, AccessShareLock);
|
relation_close(rel, AccessShareLock);
|
||||||
|
|
||||||
@ -1831,7 +1840,7 @@ get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_p
|
|||||||
* Build sql statement to look up tuple of interest Use src_pkattvals
|
* Build sql statement to look up tuple of interest Use src_pkattvals
|
||||||
* as the criteria.
|
* as the criteria.
|
||||||
*/
|
*/
|
||||||
appendStringInfo(str, "SELECT * FROM %s WHERE ", quote_ident_cstr(relname));
|
appendStringInfo(str, "SELECT * FROM %s WHERE ", relname);
|
||||||
|
|
||||||
for (i = 0; i < pknumatts; i++)
|
for (i = 0; i < pknumatts; i++)
|
||||||
{
|
{
|
||||||
@ -2003,3 +2012,37 @@ pgresultGetTupleDesc(PGresult *res)
|
|||||||
|
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generate_relation_name - copied from ruleutils.c
|
||||||
|
* Compute the name to display for a relation specified by OID
|
||||||
|
*
|
||||||
|
* The result includes all necessary quoting and schema-prefixing.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
generate_relation_name(Oid relid)
|
||||||
|
{
|
||||||
|
HeapTuple tp;
|
||||||
|
Form_pg_class reltup;
|
||||||
|
char *nspname;
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
tp = SearchSysCache(RELOID,
|
||||||
|
ObjectIdGetDatum(relid),
|
||||||
|
0, 0, 0);
|
||||||
|
if (!HeapTupleIsValid(tp))
|
||||||
|
elog(ERROR, "cache lookup of relation %u failed", relid);
|
||||||
|
reltup = (Form_pg_class) GETSTRUCT(tp);
|
||||||
|
|
||||||
|
/* Qualify the name if not visible in search path */
|
||||||
|
if (RelationIsVisible(relid))
|
||||||
|
nspname = NULL;
|
||||||
|
else
|
||||||
|
nspname = get_namespace_name(reltup->relnamespace);
|
||||||
|
|
||||||
|
result = quote_qualified_identifier(nspname, NameStr(reltup->relname));
|
||||||
|
|
||||||
|
ReleaseSysCache(tp);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -59,6 +59,43 @@ SELECT dblink_build_sql_delete('foo','1 2',2,'{"0", "a"}');
|
|||||||
DELETE FROM foo WHERE f1 = '0' AND f2 = 'a'
|
DELETE FROM foo WHERE f1 = '0' AND f2 = 'a'
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- retest using a quoted and schema qualified table
|
||||||
|
CREATE SCHEMA "MySchema";
|
||||||
|
CREATE TABLE "MySchema"."Foo"(f1 int, f2 text, f3 text[], primary key (f1,f2));
|
||||||
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'Foo_pkey' for table 'Foo'
|
||||||
|
INSERT INTO "MySchema"."Foo" VALUES (0,'a','{"a0","b0","c0"}');
|
||||||
|
-- list the primary key fields
|
||||||
|
SELECT *
|
||||||
|
FROM dblink_get_pkey('"MySchema"."Foo"');
|
||||||
|
position | colname
|
||||||
|
----------+---------
|
||||||
|
1 | f1
|
||||||
|
2 | f2
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- build an insert statement based on a local tuple,
|
||||||
|
-- replacing the primary key values with new ones
|
||||||
|
SELECT dblink_build_sql_insert('"MySchema"."Foo"','1 2',2,'{"0", "a"}','{"99", "xyz"}');
|
||||||
|
dblink_build_sql_insert
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
INSERT INTO "MySchema"."Foo"(f1,f2,f3) VALUES('99','xyz','{a0,b0,c0}')
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- build an update statement based on a local tuple,
|
||||||
|
-- replacing the primary key values with new ones
|
||||||
|
SELECT dblink_build_sql_update('"MySchema"."Foo"','1 2',2,'{"0", "a"}','{"99", "xyz"}');
|
||||||
|
dblink_build_sql_update
|
||||||
|
-----------------------------------------------------------------------------------------------------
|
||||||
|
UPDATE "MySchema"."Foo" SET f1 = '99', f2 = 'xyz', f3 = '{a0,b0,c0}' WHERE f1 = '99' AND f2 = 'xyz'
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- build a delete statement based on a local tuple,
|
||||||
|
SELECT dblink_build_sql_delete('"MySchema"."Foo"','1 2',2,'{"0", "a"}');
|
||||||
|
dblink_build_sql_delete
|
||||||
|
----------------------------------------------------------
|
||||||
|
DELETE FROM "MySchema"."Foo" WHERE f1 = '0' AND f2 = 'a'
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- regular old dblink
|
-- regular old dblink
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM dblink('dbname=regression','SELECT * FROM foo') AS t(a int, b text, c text[])
|
FROM dblink('dbname=regression','SELECT * FROM foo') AS t(a int, b text, c text[])
|
||||||
|
@ -44,6 +44,26 @@ SELECT dblink_build_sql_update('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
|
|||||||
-- build a delete statement based on a local tuple,
|
-- build a delete statement based on a local tuple,
|
||||||
SELECT dblink_build_sql_delete('foo','1 2',2,'{"0", "a"}');
|
SELECT dblink_build_sql_delete('foo','1 2',2,'{"0", "a"}');
|
||||||
|
|
||||||
|
-- retest using a quoted and schema qualified table
|
||||||
|
CREATE SCHEMA "MySchema";
|
||||||
|
CREATE TABLE "MySchema"."Foo"(f1 int, f2 text, f3 text[], primary key (f1,f2));
|
||||||
|
INSERT INTO "MySchema"."Foo" VALUES (0,'a','{"a0","b0","c0"}');
|
||||||
|
|
||||||
|
-- list the primary key fields
|
||||||
|
SELECT *
|
||||||
|
FROM dblink_get_pkey('"MySchema"."Foo"');
|
||||||
|
|
||||||
|
-- build an insert statement based on a local tuple,
|
||||||
|
-- replacing the primary key values with new ones
|
||||||
|
SELECT dblink_build_sql_insert('"MySchema"."Foo"','1 2',2,'{"0", "a"}','{"99", "xyz"}');
|
||||||
|
|
||||||
|
-- build an update statement based on a local tuple,
|
||||||
|
-- replacing the primary key values with new ones
|
||||||
|
SELECT dblink_build_sql_update('"MySchema"."Foo"','1 2',2,'{"0", "a"}','{"99", "xyz"}');
|
||||||
|
|
||||||
|
-- build a delete statement based on a local tuple,
|
||||||
|
SELECT dblink_build_sql_delete('"MySchema"."Foo"','1 2',2,'{"0", "a"}');
|
||||||
|
|
||||||
-- regular old dblink
|
-- regular old dblink
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM dblink('dbname=regression','SELECT * FROM foo') AS t(a int, b text, c text[])
|
FROM dblink('dbname=regression','SELECT * FROM foo') AS t(a int, b text, c text[])
|
||||||
|
Loading…
Reference in New Issue
Block a user