summaryrefslogtreecommitdiff
path: root/contrib/dblink/dblink.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/dblink/dblink.c')
-rw-r--r--contrib/dblink/dblink.c213
1 files changed, 90 insertions, 123 deletions
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 15d00d888c..ca77509546 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -77,18 +77,20 @@ static HTAB *createConnHash(void);
static void createNewConnection(const char *name, remoteConn * con);
static void deleteConnection(const char *name);
static char **get_pkey_attnames(Relation rel, int16 *numatts);
-static char *get_sql_insert(Relation rel, int16 *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals);
-static char *get_sql_delete(Relation rel, int16 *pkattnums, int16 pknumatts, char **tgt_pkattvals);
-static char *get_sql_update(Relation rel, int16 *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, int *pkattnums, int pknumatts, 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_ident_cstr(char *rawstr);
-static int16 get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key);
-static HeapTuple get_tuple_of_interest(Relation rel, int16 *pkattnums, int16 pknumatts, char **src_pkattvals);
+static int get_attnum_pk_pos(int *pkattnums, int pknumatts, int key);
+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 char *generate_relation_name(Relation rel);
static char *connstr_strip_password(const char *connstr);
static void dblink_security_check(PGconn *conn, remoteConn *rcon, const char *connstr);
-static int get_nondropped_natts(Relation rel);
+static void validate_pkattnums(Relation rel,
+ int16 *pkattnums_arg, int32 pknumatts_arg,
+ int **pkattnums, int *pknumatts);
/* Global */
List *res_id = NIL;
@@ -1087,9 +1089,6 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
}
-#ifndef SHRT_MAX
-#define SHRT_MAX (0x7FFF)
-#endif
/*
* dblink_build_sql_insert
*
@@ -1115,9 +1114,10 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
{
Relation rel;
text *relname_text;
- int16 *pkattnums;
- int pknumatts_tmp;
- int16 pknumatts = 0;
+ int16 *pkattnums_arg;
+ int32 pknumatts_arg;
+ int *pkattnums;
+ int pknumatts;
char **src_pkattvals;
char **tgt_pkattvals;
ArrayType *src_pkattvals_arry;
@@ -1134,7 +1134,6 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
int16 typlen;
bool typbyval;
char typalign;
- int nondropped_natts;
relname_text = PG_GETARG_TEXT_P(0);
@@ -1143,37 +1142,18 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
*/
rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT);
- pkattnums = (int16 *) PG_GETARG_POINTER(1);
- pknumatts_tmp = PG_GETARG_INT32(2);
- 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")));
-
/*
- * There should be at least one key attribute
+ * Process pkattnums argument.
*/
- if (pknumatts == 0)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("number of key attributes must be > 0")));
+ pkattnums_arg = (int16 *) PG_GETARG_POINTER(1);
+ pknumatts_arg = PG_GETARG_INT32(2);
+ validate_pkattnums(rel, pkattnums_arg, pknumatts_arg,
+ &pkattnums, &pknumatts);
src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
/*
- * 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 tuple of interest from the local system.
*/
@@ -1277,9 +1257,10 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
{
Relation rel;
text *relname_text;
- int16 *pkattnums;
- int pknumatts_tmp;
- int16 pknumatts = 0;
+ int16 *pkattnums_arg;
+ int32 pknumatts_arg;
+ int *pkattnums;
+ int pknumatts;
char **tgt_pkattvals;
ArrayType *tgt_pkattvals_arry;
int tgt_ndim;
@@ -1291,7 +1272,6 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
int16 typlen;
bool typbyval;
char typalign;
- int nondropped_natts;
relname_text = PG_GETARG_TEXT_P(0);
@@ -1300,36 +1280,17 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
*/
rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT);
- pkattnums = (int16 *) PG_GETARG_POINTER(1);
- pknumatts_tmp = PG_GETARG_INT32(2);
- 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")));
-
/*
- * There should be at least one key attribute
+ * Process pkattnums argument.
*/
- if (pknumatts == 0)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("number of key attributes must be > 0")));
+ pkattnums_arg = (int16 *) PG_GETARG_POINTER(1);
+ pknumatts_arg = PG_GETARG_INT32(2);
+ validate_pkattnums(rel, pkattnums_arg, pknumatts_arg,
+ &pkattnums, &pknumatts);
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
/*
- * 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 SQL string for use on the remote system.
*/
@@ -1404,9 +1365,10 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
{
Relation rel;
text *relname_text;
- int16 *pkattnums;
- int pknumatts_tmp;
- int16 pknumatts = 0;
+ int16 *pkattnums_arg;
+ int32 pknumatts_arg;
+ int *pkattnums;
+ int pknumatts;
char **src_pkattvals;
char **tgt_pkattvals;
ArrayType *src_pkattvals_arry;
@@ -1423,7 +1385,6 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
int16 typlen;
bool typbyval;
char typalign;
- int nondropped_natts;
relname_text = PG_GETARG_TEXT_P(0);
@@ -1432,37 +1393,18 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
*/
rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT);
- pkattnums = (int16 *) PG_GETARG_POINTER(1);
- pknumatts_tmp = PG_GETARG_INT32(2);
- 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")));
-
/*
- * There should be one source array key values for each key attnum
+ * Process pkattnums argument.
*/
- if (pknumatts == 0)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("number of key attributes must be > 0")));
+ pkattnums_arg = (int16 *) PG_GETARG_POINTER(1);
+ pknumatts_arg = PG_GETARG_INT32(2);
+ validate_pkattnums(rel, pkattnums_arg, pknumatts_arg,
+ &pkattnums, &pknumatts);
src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
/*
- * 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 tuple of interest from the local system.
*/
@@ -1621,7 +1563,7 @@ get_pkey_attnames(Relation rel, int16 *numatts)
}
static char *
-get_sql_insert(Relation rel, int16 *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;
HeapTuple tuple;
@@ -1630,7 +1572,7 @@ get_sql_insert(Relation rel, int16 *pkattnums, int16 pknumatts, char **src_pkatt
StringInfo str = makeStringInfo();
char *sql;
char *val;
- int16 key;
+ int key;
int i;
bool needComma;
@@ -1677,7 +1619,7 @@ get_sql_insert(Relation rel, int16 *pkattnums, int16 pknumatts, char **src_pkatt
appendStringInfo(str, ",");
if (tgt_pkattvals != NULL)
- key = get_attnum_pk_pos(pkattnums, pknumatts, i + 1);
+ key = get_attnum_pk_pos(pkattnums, pknumatts, i);
else
key = -1;
@@ -1705,7 +1647,7 @@ get_sql_insert(Relation rel, int16 *pkattnums, int16 pknumatts, char **src_pkatt
}
static char *
-get_sql_delete(Relation rel, int16 *pkattnums, int16 pknumatts, char **tgt_pkattvals)
+get_sql_delete(Relation rel, int *pkattnums, int pknumatts, char **tgt_pkattvals)
{
char *relname;
TupleDesc tupdesc;
@@ -1724,13 +1666,13 @@ get_sql_delete(Relation rel, int16 *pkattnums, int16 pknumatts, char **tgt_pkatt
appendStringInfo(str, "DELETE FROM %s WHERE ", relname);
for (i = 0; i < pknumatts; i++)
{
- int16 pkattnum = pkattnums[i];
+ int pkattnum = pkattnums[i];
if (i > 0)
appendStringInfo(str, " AND ");
appendStringInfo(str, "%s",
- quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
+ quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum]->attname)));
if (tgt_pkattvals != NULL)
val = pstrdup(tgt_pkattvals[i]);
@@ -1755,7 +1697,7 @@ get_sql_delete(Relation rel, int16 *pkattnums, int16 pknumatts, char **tgt_pkatt
}
static char *
-get_sql_update(Relation rel, int16 *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;
HeapTuple tuple;
@@ -1764,7 +1706,7 @@ get_sql_update(Relation rel, int16 *pkattnums, int16 pknumatts, char **src_pkatt
StringInfo str = makeStringInfo();
char *sql;
char *val;
- int16 key;
+ int key;
int i;
bool needComma;
@@ -1795,7 +1737,7 @@ get_sql_update(Relation rel, int16 *pkattnums, int16 pknumatts, char **src_pkatt
quote_ident_cstr(NameStr(tupdesc->attrs[i]->attname)));
if (tgt_pkattvals != NULL)
- key = get_attnum_pk_pos(pkattnums, pknumatts, i + 1);
+ key = get_attnum_pk_pos(pkattnums, pknumatts, i);
else
key = -1;
@@ -1818,18 +1760,18 @@ get_sql_update(Relation rel, int16 *pkattnums, int16 pknumatts, char **src_pkatt
for (i = 0; i < pknumatts; i++)
{
- int16 pkattnum = pkattnums[i];
+ int pkattnum = pkattnums[i];
if (i > 0)
appendStringInfo(str, " AND ");
appendStringInfo(str, "%s",
- quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
+ quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum]->attname)));
if (tgt_pkattvals != NULL)
val = pstrdup(tgt_pkattvals[i]);
else
- val = SPI_getvalue(tuple, tupdesc, pkattnum);
+ val = SPI_getvalue(tuple, tupdesc, pkattnum + 1);
if (val != NULL)
{
@@ -1883,8 +1825,8 @@ quote_ident_cstr(char *rawstr)
return result;
}
-static int16
-get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key)
+static int
+get_attnum_pk_pos(int *pkattnums, int pknumatts, int key)
{
int i;
@@ -1899,7 +1841,7 @@ get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key)
}
static HeapTuple
-get_tuple_of_interest(Relation rel, int16 *pkattnums, int16 pknumatts, char **src_pkattvals)
+get_tuple_of_interest(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals)
{
char *relname;
TupleDesc tupdesc;
@@ -1930,13 +1872,13 @@ get_tuple_of_interest(Relation rel, int16 *pkattnums, int16 pknumatts, char **sr
for (i = 0; i < pknumatts; i++)
{
- int16 pkattnum = pkattnums[i];
+ int pkattnum = pkattnums[i];
if (i > 0)
appendStringInfo(str, " AND ");
appendStringInfo(str, "%s",
- quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
+ quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum]->attname)));
val = pstrdup(src_pkattvals[i]);
if (val != NULL)
@@ -2281,23 +2223,48 @@ dblink_security_check(PGconn *conn, remoteConn *rcon, const char *connstr)
}
}
-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,
+ int16 *pkattnums_arg, int32 pknumatts_arg,
+ int **pkattnums, int *pknumatts)
{
- int nondropped_natts = 0;
- TupleDesc tupdesc;
- int natts;
+ TupleDesc tupdesc = rel->rd_att;
+ int natts = tupdesc->natts;
int i;
- tupdesc = rel->rd_att;
- natts = tupdesc->natts;
+ /* 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")));
- for (i = 0; i < natts; i++)
+ /* 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)
- continue;
- nondropped_natts++;
- }
+ int pkattnum = pkattnums_arg[i];
- 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;
+ }
}