mirror of
https://github.com/postgres/postgres.git
synced 2025-06-05 23:56:58 +03:00
Consolidate and improve checking of key-column-attnum arguments for
dblink_build_sql_insert() and related functions. In particular, be sure to reject references to dropped and out-of-range column numbers. The numbers are still interpreted as physical column numbers, though, for backward compatibility. This patch replaces Joe's patch of 2010-02-03, which handled only some aspects of the problem.
This commit is contained in:
parent
fa66d0e2da
commit
93ad259139
@ -8,7 +8,7 @@
|
|||||||
* Darko Prenosil <Darko.Prenosil@finteh.hr>
|
* Darko Prenosil <Darko.Prenosil@finteh.hr>
|
||||||
* Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
|
* Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.69.2.6 2010/06/14 20:49:46 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.69.2.7 2010/06/15 16:22:33 tgl Exp $
|
||||||
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
|
||||||
* ALL RIGHTS RESERVED;
|
* ALL RIGHTS RESERVED;
|
||||||
*
|
*
|
||||||
@ -85,17 +85,19 @@ static void createNewConnection(const char *name, remoteConn * rconn);
|
|||||||
static void deleteConnection(const char *name);
|
static void deleteConnection(const char *name);
|
||||||
static char **get_pkey_attnames(Relation rel, int16 *numatts);
|
static char **get_pkey_attnames(Relation rel, int16 *numatts);
|
||||||
static char **get_text_array_contents(ArrayType *array, int *numitems);
|
static char **get_text_array_contents(ArrayType *array, int *numitems);
|
||||||
static char *get_sql_insert(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals);
|
static char *get_sql_insert(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals);
|
||||||
static char *get_sql_delete(Relation rel, int2vector *pkattnums, int16 pknumatts, char **tgt_pkattvals);
|
static char *get_sql_delete(Relation rel, int *pkattnums, int pknumatts, char **tgt_pkattvals);
|
||||||
static char *get_sql_update(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals);
|
static char *get_sql_update(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals);
|
||||||
static char *quote_literal_cstr(char *rawstr);
|
static char *quote_literal_cstr(char *rawstr);
|
||||||
static char *quote_ident_cstr(char *rawstr);
|
static char *quote_ident_cstr(char *rawstr);
|
||||||
static int16 get_attnum_pk_pos(int2vector *pkattnums, int16 pknumatts, int16 key);
|
static int get_attnum_pk_pos(int *pkattnums, int pknumatts, int key);
|
||||||
static HeapTuple get_tuple_of_interest(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals);
|
static HeapTuple get_tuple_of_interest(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals);
|
||||||
static Relation get_rel_from_relname(text *relname_text, LOCKMODE lockmode, AclMode aclmode);
|
static Relation get_rel_from_relname(text *relname_text, LOCKMODE lockmode, AclMode aclmode);
|
||||||
static char *generate_relation_name(Relation rel);
|
static char *generate_relation_name(Relation rel);
|
||||||
static void dblink_security_check(PGconn *conn, remoteConn *rconn);
|
static void dblink_security_check(PGconn *conn, remoteConn *rconn);
|
||||||
static int get_nondropped_natts(Relation rel);
|
static void validate_pkattnums(Relation rel,
|
||||||
|
int2vector *pkattnums_arg, int32 pknumatts_arg,
|
||||||
|
int **pkattnums, int *pknumatts);
|
||||||
|
|
||||||
/* Global */
|
/* Global */
|
||||||
static remoteConn *pconn = NULL;
|
static remoteConn *pconn = NULL;
|
||||||
@ -1379,18 +1381,18 @@ Datum
|
|||||||
dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
text *relname_text = PG_GETARG_TEXT_P(0);
|
text *relname_text = PG_GETARG_TEXT_P(0);
|
||||||
int2vector *pkattnums = (int2vector *) PG_GETARG_POINTER(1);
|
int2vector *pkattnums_arg = (int2vector *) PG_GETARG_POINTER(1);
|
||||||
int32 pknumatts_tmp = PG_GETARG_INT32(2);
|
int32 pknumatts_arg = PG_GETARG_INT32(2);
|
||||||
ArrayType *src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
ArrayType *src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||||
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
||||||
Relation rel;
|
Relation rel;
|
||||||
int16 pknumatts = 0;
|
int *pkattnums;
|
||||||
|
int pknumatts;
|
||||||
char **src_pkattvals;
|
char **src_pkattvals;
|
||||||
char **tgt_pkattvals;
|
char **tgt_pkattvals;
|
||||||
int src_nitems;
|
int src_nitems;
|
||||||
int tgt_nitems;
|
int tgt_nitems;
|
||||||
char *sql;
|
char *sql;
|
||||||
int nondropped_natts;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open target relation.
|
* Open target relation.
|
||||||
@ -1398,29 +1400,10 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
|||||||
rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT);
|
rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There should be at least one key attribute
|
* Process pkattnums argument.
|
||||||
*/
|
*/
|
||||||
if (pknumatts_tmp <= 0)
|
validate_pkattnums(rel, pkattnums_arg, pknumatts_arg,
|
||||||
ereport(ERROR,
|
&pkattnums, &pknumatts);
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("number of key attributes must be > 0")));
|
|
||||||
|
|
||||||
if (pknumatts_tmp <= SHRT_MAX)
|
|
||||||
pknumatts = pknumatts_tmp;
|
|
||||||
else
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("input for number of primary key " \
|
|
||||||
"attributes too large")));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ensure we don't ask for more pk attributes than we have
|
|
||||||
* non-dropped columns
|
|
||||||
*/
|
|
||||||
nondropped_natts = get_nondropped_natts(rel);
|
|
||||||
if (pknumatts > nondropped_natts)
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
|
|
||||||
errmsg("number of primary key fields exceeds number of specified relation attributes")));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Source array is made up of key values that will be used to locate the
|
* Source array is made up of key values that will be used to locate the
|
||||||
@ -1489,12 +1472,12 @@ Datum
|
|||||||
dblink_build_sql_delete(PG_FUNCTION_ARGS)
|
dblink_build_sql_delete(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
text *relname_text = PG_GETARG_TEXT_P(0);
|
text *relname_text = PG_GETARG_TEXT_P(0);
|
||||||
int2vector *pkattnums = (int2vector *) PG_GETARG_POINTER(1);
|
int2vector *pkattnums_arg = (int2vector *) PG_GETARG_POINTER(1);
|
||||||
int32 pknumatts_tmp = PG_GETARG_INT32(2);
|
int32 pknumatts_arg = PG_GETARG_INT32(2);
|
||||||
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||||
int nondropped_natts;
|
|
||||||
Relation rel;
|
Relation rel;
|
||||||
int16 pknumatts = 0;
|
int *pkattnums;
|
||||||
|
int pknumatts;
|
||||||
char **tgt_pkattvals;
|
char **tgt_pkattvals;
|
||||||
int tgt_nitems;
|
int tgt_nitems;
|
||||||
char *sql;
|
char *sql;
|
||||||
@ -1505,29 +1488,10 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
|
|||||||
rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT);
|
rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There should be at least one key attribute
|
* Process pkattnums argument.
|
||||||
*/
|
*/
|
||||||
if (pknumatts_tmp <= 0)
|
validate_pkattnums(rel, pkattnums_arg, pknumatts_arg,
|
||||||
ereport(ERROR,
|
&pkattnums, &pknumatts);
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("number of key attributes must be > 0")));
|
|
||||||
|
|
||||||
if (pknumatts_tmp <= SHRT_MAX)
|
|
||||||
pknumatts = pknumatts_tmp;
|
|
||||||
else
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("input for number of primary key " \
|
|
||||||
"attributes too large")));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ensure we don't ask for more pk attributes than we have
|
|
||||||
* non-dropped columns
|
|
||||||
*/
|
|
||||||
nondropped_natts = get_nondropped_natts(rel);
|
|
||||||
if (pknumatts > nondropped_natts)
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
|
|
||||||
errmsg("number of primary key fields exceeds number of specified relation attributes")));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Target array is made up of key values that will be used to build the
|
* Target array is made up of key values that will be used to build the
|
||||||
@ -1585,13 +1549,13 @@ Datum
|
|||||||
dblink_build_sql_update(PG_FUNCTION_ARGS)
|
dblink_build_sql_update(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
text *relname_text = PG_GETARG_TEXT_P(0);
|
text *relname_text = PG_GETARG_TEXT_P(0);
|
||||||
int2vector *pkattnums = (int2vector *) PG_GETARG_POINTER(1);
|
int2vector *pkattnums_arg = (int2vector *) PG_GETARG_POINTER(1);
|
||||||
int32 pknumatts_tmp = PG_GETARG_INT32(2);
|
int32 pknumatts_arg = PG_GETARG_INT32(2);
|
||||||
ArrayType *src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
ArrayType *src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||||
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
||||||
int nondropped_natts;
|
|
||||||
Relation rel;
|
Relation rel;
|
||||||
int16 pknumatts = 0;
|
int *pkattnums;
|
||||||
|
int pknumatts;
|
||||||
char **src_pkattvals;
|
char **src_pkattvals;
|
||||||
char **tgt_pkattvals;
|
char **tgt_pkattvals;
|
||||||
int src_nitems;
|
int src_nitems;
|
||||||
@ -1604,29 +1568,10 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
|
|||||||
rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT);
|
rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There should be one source array key values for each key attnum
|
* Process pkattnums argument.
|
||||||
*/
|
*/
|
||||||
if (pknumatts_tmp <= 0)
|
validate_pkattnums(rel, pkattnums_arg, pknumatts_arg,
|
||||||
ereport(ERROR,
|
&pkattnums, &pknumatts);
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("number of key attributes must be > 0")));
|
|
||||||
|
|
||||||
if (pknumatts_tmp <= SHRT_MAX)
|
|
||||||
pknumatts = pknumatts_tmp;
|
|
||||||
else
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("input for number of primary key " \
|
|
||||||
"attributes too large")));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ensure we don't ask for more pk attributes than we have
|
|
||||||
* non-dropped columns
|
|
||||||
*/
|
|
||||||
nondropped_natts = get_nondropped_natts(rel);
|
|
||||||
if (pknumatts > nondropped_natts)
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
|
|
||||||
errmsg("number of primary key fields exceeds number of specified relation attributes")));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Source array is made up of key values that will be used to locate the
|
* Source array is made up of key values that will be used to locate the
|
||||||
@ -1815,7 +1760,7 @@ get_text_array_contents(ArrayType *array, int *numitems)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_sql_insert(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals)
|
get_sql_insert(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals)
|
||||||
{
|
{
|
||||||
char *relname;
|
char *relname;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
@ -1823,7 +1768,7 @@ get_sql_insert(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_
|
|||||||
int natts;
|
int natts;
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
char *val;
|
char *val;
|
||||||
int16 key;
|
int key;
|
||||||
int i;
|
int i;
|
||||||
bool needComma;
|
bool needComma;
|
||||||
|
|
||||||
@ -1872,7 +1817,7 @@ get_sql_insert(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_
|
|||||||
appendStringInfo(&buf, ",");
|
appendStringInfo(&buf, ",");
|
||||||
|
|
||||||
if (tgt_pkattvals != NULL)
|
if (tgt_pkattvals != NULL)
|
||||||
key = get_attnum_pk_pos(pkattnums, pknumatts, i + 1);
|
key = get_attnum_pk_pos(pkattnums, pknumatts, i);
|
||||||
else
|
else
|
||||||
key = -1;
|
key = -1;
|
||||||
|
|
||||||
@ -1896,11 +1841,10 @@ get_sql_insert(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_sql_delete(Relation rel, int2vector *pkattnums, int16 pknumatts, char **tgt_pkattvals)
|
get_sql_delete(Relation rel, int *pkattnums, int pknumatts, char **tgt_pkattvals)
|
||||||
{
|
{
|
||||||
char *relname;
|
char *relname;
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
int natts;
|
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -1910,18 +1854,17 @@ get_sql_delete(Relation rel, int2vector *pkattnums, int16 pknumatts, char **tgt_
|
|||||||
relname = generate_relation_name(rel);
|
relname = generate_relation_name(rel);
|
||||||
|
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
natts = tupdesc->natts;
|
|
||||||
|
|
||||||
appendStringInfo(&buf, "DELETE FROM %s WHERE ", relname);
|
appendStringInfo(&buf, "DELETE FROM %s WHERE ", relname);
|
||||||
for (i = 0; i < pknumatts; i++)
|
for (i = 0; i < pknumatts; i++)
|
||||||
{
|
{
|
||||||
int16 pkattnum = pkattnums->values[i];
|
int pkattnum = pkattnums[i];
|
||||||
|
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
appendStringInfo(&buf, " AND ");
|
appendStringInfo(&buf, " AND ");
|
||||||
|
|
||||||
appendStringInfoString(&buf,
|
appendStringInfoString(&buf,
|
||||||
quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
|
quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum]->attname)));
|
||||||
|
|
||||||
if (tgt_pkattvals == NULL)
|
if (tgt_pkattvals == NULL)
|
||||||
/* internal error */
|
/* internal error */
|
||||||
@ -1938,7 +1881,7 @@ get_sql_delete(Relation rel, int2vector *pkattnums, int16 pknumatts, char **tgt_
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_sql_update(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals)
|
get_sql_update(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals)
|
||||||
{
|
{
|
||||||
char *relname;
|
char *relname;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
@ -1946,7 +1889,7 @@ get_sql_update(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_
|
|||||||
int natts;
|
int natts;
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
char *val;
|
char *val;
|
||||||
int16 key;
|
int key;
|
||||||
int i;
|
int i;
|
||||||
bool needComma;
|
bool needComma;
|
||||||
|
|
||||||
@ -1979,7 +1922,7 @@ get_sql_update(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_
|
|||||||
quote_ident_cstr(NameStr(tupdesc->attrs[i]->attname)));
|
quote_ident_cstr(NameStr(tupdesc->attrs[i]->attname)));
|
||||||
|
|
||||||
if (tgt_pkattvals != NULL)
|
if (tgt_pkattvals != NULL)
|
||||||
key = get_attnum_pk_pos(pkattnums, pknumatts, i + 1);
|
key = get_attnum_pk_pos(pkattnums, pknumatts, i);
|
||||||
else
|
else
|
||||||
key = -1;
|
key = -1;
|
||||||
|
|
||||||
@ -2002,18 +1945,18 @@ get_sql_update(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_
|
|||||||
|
|
||||||
for (i = 0; i < pknumatts; i++)
|
for (i = 0; i < pknumatts; i++)
|
||||||
{
|
{
|
||||||
int16 pkattnum = pkattnums->values[i];
|
int pkattnum = pkattnums[i];
|
||||||
|
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
appendStringInfo(&buf, " AND ");
|
appendStringInfo(&buf, " AND ");
|
||||||
|
|
||||||
appendStringInfo(&buf, "%s",
|
appendStringInfo(&buf, "%s",
|
||||||
quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
|
quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum]->attname)));
|
||||||
|
|
||||||
if (tgt_pkattvals != NULL)
|
if (tgt_pkattvals != NULL)
|
||||||
val = tgt_pkattvals[i] ? pstrdup(tgt_pkattvals[i]) : NULL;
|
val = tgt_pkattvals[i] ? pstrdup(tgt_pkattvals[i]) : NULL;
|
||||||
else
|
else
|
||||||
val = SPI_getvalue(tuple, tupdesc, pkattnum);
|
val = SPI_getvalue(tuple, tupdesc, pkattnum + 1);
|
||||||
|
|
||||||
if (val != NULL)
|
if (val != NULL)
|
||||||
{
|
{
|
||||||
@ -2063,8 +2006,8 @@ quote_ident_cstr(char *rawstr)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16
|
static int
|
||||||
get_attnum_pk_pos(int2vector *pkattnums, int16 pknumatts, int16 key)
|
get_attnum_pk_pos(int *pkattnums, int pknumatts, int key)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -2072,14 +2015,14 @@ get_attnum_pk_pos(int2vector *pkattnums, int16 pknumatts, int16 key)
|
|||||||
* Not likely a long list anyway, so just scan for the value
|
* Not likely a long list anyway, so just scan for the value
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < pknumatts; i++)
|
for (i = 0; i < pknumatts; i++)
|
||||||
if (key == pkattnums->values[i])
|
if (key == pkattnums[i])
|
||||||
return i;
|
return i;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HeapTuple
|
static HeapTuple
|
||||||
get_tuple_of_interest(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals)
|
get_tuple_of_interest(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals)
|
||||||
{
|
{
|
||||||
char *relname;
|
char *relname;
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
@ -2110,13 +2053,13 @@ get_tuple_of_interest(Relation rel, int2vector *pkattnums, int16 pknumatts, char
|
|||||||
|
|
||||||
for (i = 0; i < pknumatts; i++)
|
for (i = 0; i < pknumatts; i++)
|
||||||
{
|
{
|
||||||
int16 pkattnum = pkattnums->values[i];
|
int pkattnum = pkattnums[i];
|
||||||
|
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
appendStringInfo(&buf, " AND ");
|
appendStringInfo(&buf, " AND ");
|
||||||
|
|
||||||
appendStringInfoString(&buf,
|
appendStringInfoString(&buf,
|
||||||
quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
|
quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum]->attname)));
|
||||||
|
|
||||||
if (src_pkattvals[i] != NULL)
|
if (src_pkattvals[i] != NULL)
|
||||||
appendStringInfo(&buf, " = %s",
|
appendStringInfo(&buf, " = %s",
|
||||||
@ -2314,24 +2257,52 @@ dblink_security_check(PGconn *conn, remoteConn *rconn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/*
|
||||||
get_nondropped_natts(Relation rel)
|
* Validate the PK-attnums argument for dblink_build_sql_insert() and related
|
||||||
|
* functions, and translate to the internal representation.
|
||||||
|
*
|
||||||
|
* The user supplies an int2vector of 1-based physical attnums, plus a count
|
||||||
|
* argument (the need for the separate count argument is historical, but we
|
||||||
|
* still check it). We check that each attnum corresponds to a valid,
|
||||||
|
* non-dropped attribute of the rel. We do *not* prevent attnums from being
|
||||||
|
* listed twice, though the actual use-case for such things is dubious.
|
||||||
|
*
|
||||||
|
* The internal representation is a palloc'd int array of 0-based physical
|
||||||
|
* attnums.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
validate_pkattnums(Relation rel,
|
||||||
|
int2vector *pkattnums_arg, int32 pknumatts_arg,
|
||||||
|
int **pkattnums, int *pknumatts)
|
||||||
{
|
{
|
||||||
int nondropped_natts = 0;
|
TupleDesc tupdesc = rel->rd_att;
|
||||||
TupleDesc tupdesc;
|
int natts = tupdesc->natts;
|
||||||
int natts;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
tupdesc = rel->rd_att;
|
/* Don't take more array elements than there are */
|
||||||
natts = tupdesc->natts;
|
pknumatts_arg = Min(pknumatts_arg, pkattnums_arg->dim1);
|
||||||
|
|
||||||
for (i = 0; i < natts; i++)
|
/* Must have at least one pk attnum selected */
|
||||||
|
if (pknumatts_arg <= 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("number of key attributes must be > 0")));
|
||||||
|
|
||||||
|
/* Allocate output array */
|
||||||
|
*pkattnums = (int *) palloc(pknumatts_arg * sizeof(int));
|
||||||
|
*pknumatts = pknumatts_arg;
|
||||||
|
|
||||||
|
/* Validate attnums and convert to internal form */
|
||||||
|
for (i = 0; i < pknumatts_arg; i++)
|
||||||
{
|
{
|
||||||
if (tupdesc->attrs[i]->attisdropped)
|
int pkattnum = pkattnums_arg->values[i];
|
||||||
continue;
|
|
||||||
nondropped_natts++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nondropped_natts;
|
if (pkattnum <= 0 || pkattnum > natts ||
|
||||||
|
tupdesc->attrs[pkattnum - 1]->attisdropped)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("invalid attribute number %d", pkattnum)));
|
||||||
|
(*pkattnums)[i] = pkattnum - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ SELECT dblink_build_sql_insert('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
|
|||||||
|
|
||||||
-- too many pk fields, should fail
|
-- too many pk fields, should fail
|
||||||
SELECT dblink_build_sql_insert('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
|
SELECT dblink_build_sql_insert('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
|
||||||
ERROR: number of primary key fields exceeds number of specified relation attributes
|
ERROR: invalid attribute number 4
|
||||||
-- build an update statement based on a local tuple,
|
-- build an update statement based on a local tuple,
|
||||||
-- replacing the primary key values with new ones
|
-- replacing the primary key values with new ones
|
||||||
SELECT dblink_build_sql_update('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
|
SELECT dblink_build_sql_update('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
|
||||||
@ -59,7 +59,7 @@ SELECT dblink_build_sql_update('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
|
|||||||
|
|
||||||
-- too many pk fields, should fail
|
-- too many pk fields, should fail
|
||||||
SELECT dblink_build_sql_update('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
|
SELECT dblink_build_sql_update('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
|
||||||
ERROR: number of primary key fields exceeds number of specified relation attributes
|
ERROR: invalid attribute number 4
|
||||||
-- 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"}');
|
||||||
dblink_build_sql_delete
|
dblink_build_sql_delete
|
||||||
@ -69,7 +69,7 @@ SELECT dblink_build_sql_delete('foo','1 2',2,'{"0", "a"}');
|
|||||||
|
|
||||||
-- too many pk fields, should fail
|
-- too many pk fields, should fail
|
||||||
SELECT dblink_build_sql_delete('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}');
|
SELECT dblink_build_sql_delete('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}');
|
||||||
ERROR: number of primary key fields exceeds number of specified relation attributes
|
ERROR: invalid attribute number 4
|
||||||
-- retest using a quoted and schema qualified table
|
-- retest using a quoted and schema qualified table
|
||||||
CREATE SCHEMA "MySchema";
|
CREATE SCHEMA "MySchema";
|
||||||
CREATE TABLE "MySchema"."Foo"(f1 int, f2 text, f3 text[], primary key (f1,f2));
|
CREATE TABLE "MySchema"."Foo"(f1 int, f2 text, f3 text[], primary key (f1,f2));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user