version 1.82.2.6, 2010/06/14 20:49:39
|
version 1.82.2.7, 2010/06/15 16:22:26
|
Line 8
|
Line 8
|
* Darko Prenosil <[email protected]> |
* Darko Prenosil <[email protected]> |
* Shridhar Daithankar <[email protected]> |
* Shridhar Daithankar <[email protected]> |
* |
* |
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.82.2.5 2010/06/09 03:40:16 itagaki Exp $ |
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.82.2.6 2010/06/14 20:49:39 tgl Exp $ |
* Copyright (c) 2001-2009, PostgreSQL Global Development Group |
* Copyright (c) 2001-2009, PostgreSQL Global Development Group |
* ALL RIGHTS RESERVED; |
* ALL RIGHTS RESERVED; |
* |
* |
Line 87 static void createNewConnection(const ch
|
Line 87 static void createNewConnection(const ch
|
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_connstr_check(const char *connstr); |
static void dblink_connstr_check(const char *connstr); |
Line 101 static void dblink_security_check(PGconn
|
Line 101 static void dblink_security_check(PGconn
|
static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail); |
static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail); |
static char *get_connect_string(const char *servername); |
static char *get_connect_string(const char *servername); |
static char *escape_param_str(const char *from); |
static char *escape_param_str(const char *from); |
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; |
Line 1355 Datum
|
Line 1357 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. |
Line 1374 dblink_build_sql_insert(PG_FUNCTION_ARGS
|
Line 1376 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 |
Line 1465 Datum
|
Line 1448 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; |
Line 1481 dblink_build_sql_delete(PG_FUNCTION_ARGS
|
Line 1464 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 |
Line 1561 Datum
|
Line 1525 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; |
Line 1580 dblink_build_sql_update(PG_FUNCTION_ARGS
|
Line 1544 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) |
|
ereport(ERROR, |
|
(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); |
validate_pkattnums(rel, pkattnums_arg, pknumatts_arg, |
if (pknumatts > nondropped_natts) |
&pkattnums, &pknumatts); |
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 |
Line 1787 get_text_array_contents(ArrayType *array
|
Line 1732 get_text_array_contents(ArrayType *array
|
} |
} |
|
|
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; |
Line 1795 get_sql_insert(Relation rel, int2vector
|
Line 1740 get_sql_insert(Relation rel, int2vector
|
int natts; |
int natts; |
StringInfoData buf; |
StringInfoData buf; |
char *val; |
char *val; |
int16 key; |
int key; |
int i; |
int i; |
bool needComma; |
bool needComma; |
|
|
Line 1844 get_sql_insert(Relation rel, int2vector
|
Line 1789 get_sql_insert(Relation rel, int2vector
|
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; |
|
|
Line 1868 get_sql_insert(Relation rel, int2vector
|
Line 1813 get_sql_insert(Relation rel, int2vector
|
} |
} |
|
|
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; |
|
|
Line 1882 get_sql_delete(Relation rel, int2vector
|
Line 1826 get_sql_delete(Relation rel, int2vector
|
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 */ |
Line 1910 get_sql_delete(Relation rel, int2vector
|
Line 1853 get_sql_delete(Relation rel, int2vector
|
} |
} |
|
|
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; |
Line 1918 get_sql_update(Relation rel, int2vector
|
Line 1861 get_sql_update(Relation rel, int2vector
|
int natts; |
int natts; |
StringInfoData buf; |
StringInfoData buf; |
char *val; |
char *val; |
int16 key; |
int key; |
int i; |
int i; |
bool needComma; |
bool needComma; |
|
|
Line 1951 get_sql_update(Relation rel, int2vector
|
Line 1894 get_sql_update(Relation rel, int2vector
|
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; |
|
|
Line 1974 get_sql_update(Relation rel, int2vector
|
Line 1917 get_sql_update(Relation rel, int2vector
|
|
|
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) |
{ |
{ |
Line 2037 quote_ident_cstr(char *rawstr)
|
Line 1980 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; |
|
|
Line 2046 get_attnum_pk_pos(int2vector *pkattnums,
|
Line 1989 get_attnum_pk_pos(int2vector *pkattnums,
|
* 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; |
Line 2084 get_tuple_of_interest(Relation rel, int2
|
Line 2027 get_tuple_of_interest(Relation rel, int2
|
|
|
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", |
Line 2464 escape_param_str(const char *str)
|
Line 2407 escape_param_str(const char *str)
|
return buf->data; |
return buf->data; |
} |
} |
|
|
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; |
|
} |
} |
} |
|
|