version 1.38.4.8, 2010/06/14 20:50:04
|
version 1.38.4.9, 2010/06/15 16:22:51
|
Line 77 static HTAB *createConnHash(void);
|
Line 77 static HTAB *createConnHash(void);
|
static void createNewConnection(const char *name, remoteConn * con); |
static void createNewConnection(const char *name, remoteConn * con); |
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_sql_insert(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, int16 *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, int16 *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(int16 *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, int16 *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 char *connstr_strip_password(const char *connstr); |
static char *connstr_strip_password(const char *connstr); |
static void dblink_security_check(PGconn *conn, remoteConn *rcon, 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 */ |
/* Global */ |
List *res_id = NIL; |
List *res_id = NIL; |
Line 1087 dblink_get_pkey(PG_FUNCTION_ARGS)
|
Line 1089 dblink_get_pkey(PG_FUNCTION_ARGS)
|
} |
} |
|
|
|
|
#ifndef SHRT_MAX |
|
#define SHRT_MAX (0x7FFF) |
|
#endif |
|
/* |
/* |
* dblink_build_sql_insert |
* dblink_build_sql_insert |
* |
* |
Line 1115 dblink_build_sql_insert(PG_FUNCTION_ARGS
|
Line 1114 dblink_build_sql_insert(PG_FUNCTION_ARGS
|
{ |
{ |
Relation rel; |
Relation rel; |
text *relname_text; |
text *relname_text; |
int16 *pkattnums; |
int16 *pkattnums_arg; |
int pknumatts_tmp; |
int32 pknumatts_arg; |
int16 pknumatts = 0; |
int *pkattnums; |
|
int pknumatts; |
char **src_pkattvals; |
char **src_pkattvals; |
char **tgt_pkattvals; |
char **tgt_pkattvals; |
ArrayType *src_pkattvals_arry; |
ArrayType *src_pkattvals_arry; |
Line 1134 dblink_build_sql_insert(PG_FUNCTION_ARGS
|
Line 1134 dblink_build_sql_insert(PG_FUNCTION_ARGS
|
int16 typlen; |
int16 typlen; |
bool typbyval; |
bool typbyval; |
char typalign; |
char typalign; |
int nondropped_natts; |
|
|
|
relname_text = PG_GETARG_TEXT_P(0); |
relname_text = PG_GETARG_TEXT_P(0); |
|
|
Line 1143 dblink_build_sql_insert(PG_FUNCTION_ARGS
|
Line 1142 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); |
|
|
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) |
pkattnums_arg = (int16 *) PG_GETARG_POINTER(1); |
ereport(ERROR, |
pknumatts_arg = PG_GETARG_INT32(2); |
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
validate_pkattnums(rel, pkattnums_arg, pknumatts_arg, |
errmsg("number of key attributes must be > 0"))); |
&pkattnums, &pknumatts); |
|
|
src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3); |
src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3); |
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4); |
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 |
* Source array is made up of key values that will be used to locate |
* the tuple of interest from the local system. |
* the tuple of interest from the local system. |
*/ |
*/ |
Line 1277 dblink_build_sql_delete(PG_FUNCTION_ARGS
|
Line 1257 dblink_build_sql_delete(PG_FUNCTION_ARGS
|
{ |
{ |
Relation rel; |
Relation rel; |
text *relname_text; |
text *relname_text; |
int16 *pkattnums; |
int16 *pkattnums_arg; |
int pknumatts_tmp; |
int32 pknumatts_arg; |
int16 pknumatts = 0; |
int *pkattnums; |
|
int pknumatts; |
char **tgt_pkattvals; |
char **tgt_pkattvals; |
ArrayType *tgt_pkattvals_arry; |
ArrayType *tgt_pkattvals_arry; |
int tgt_ndim; |
int tgt_ndim; |
Line 1291 dblink_build_sql_delete(PG_FUNCTION_ARGS
|
Line 1272 dblink_build_sql_delete(PG_FUNCTION_ARGS
|
int16 typlen; |
int16 typlen; |
bool typbyval; |
bool typbyval; |
char typalign; |
char typalign; |
int nondropped_natts; |
|
|
|
relname_text = PG_GETARG_TEXT_P(0); |
relname_text = PG_GETARG_TEXT_P(0); |
|
|
Line 1300 dblink_build_sql_delete(PG_FUNCTION_ARGS
|
Line 1280 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); |
|
|
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) |
pkattnums_arg = (int16 *) PG_GETARG_POINTER(1); |
ereport(ERROR, |
pknumatts_arg = PG_GETARG_INT32(2); |
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
validate_pkattnums(rel, pkattnums_arg, pknumatts_arg, |
errmsg("number of key attributes must be > 0"))); |
&pkattnums, &pknumatts); |
|
|
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3); |
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 |
* Target array is made up of key values that will be used to build |
* the SQL string for use on the remote system. |
* the SQL string for use on the remote system. |
*/ |
*/ |
Line 1404 dblink_build_sql_update(PG_FUNCTION_ARGS
|
Line 1365 dblink_build_sql_update(PG_FUNCTION_ARGS
|
{ |
{ |
Relation rel; |
Relation rel; |
text *relname_text; |
text *relname_text; |
int16 *pkattnums; |
int16 *pkattnums_arg; |
int pknumatts_tmp; |
int32 pknumatts_arg; |
int16 pknumatts = 0; |
int *pkattnums; |
|
int pknumatts; |
char **src_pkattvals; |
char **src_pkattvals; |
char **tgt_pkattvals; |
char **tgt_pkattvals; |
ArrayType *src_pkattvals_arry; |
ArrayType *src_pkattvals_arry; |
Line 1423 dblink_build_sql_update(PG_FUNCTION_ARGS
|
Line 1385 dblink_build_sql_update(PG_FUNCTION_ARGS
|
int16 typlen; |
int16 typlen; |
bool typbyval; |
bool typbyval; |
char typalign; |
char typalign; |
int nondropped_natts; |
|
|
|
relname_text = PG_GETARG_TEXT_P(0); |
relname_text = PG_GETARG_TEXT_P(0); |
|
|
Line 1432 dblink_build_sql_update(PG_FUNCTION_ARGS
|
Line 1393 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); |
|
|
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) |
pkattnums_arg = (int16 *) PG_GETARG_POINTER(1); |
ereport(ERROR, |
pknumatts_arg = PG_GETARG_INT32(2); |
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
validate_pkattnums(rel, pkattnums_arg, pknumatts_arg, |
errmsg("number of key attributes must be > 0"))); |
&pkattnums, &pknumatts); |
|
|
src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3); |
src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3); |
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4); |
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 |
* Source array is made up of key values that will be used to locate |
* the tuple of interest from the local system. |
* the tuple of interest from the local system. |
*/ |
*/ |
Line 1621 get_pkey_attnames(Relation rel, int16 *n
|
Line 1563 get_pkey_attnames(Relation rel, int16 *n
|
} |
} |
|
|
static char * |
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; |
char *relname; |
HeapTuple tuple; |
HeapTuple tuple; |
Line 1630 get_sql_insert(Relation rel, int16 *pkat
|
Line 1572 get_sql_insert(Relation rel, int16 *pkat
|
StringInfo str = makeStringInfo(); |
StringInfo str = makeStringInfo(); |
char *sql; |
char *sql; |
char *val; |
char *val; |
int16 key; |
int key; |
int i; |
int i; |
bool needComma; |
bool needComma; |
|
|
Line 1677 get_sql_insert(Relation rel, int16 *pkat
|
Line 1619 get_sql_insert(Relation rel, int16 *pkat
|
appendStringInfo(str, ","); |
appendStringInfo(str, ","); |
|
|
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 1705 get_sql_insert(Relation rel, int16 *pkat
|
Line 1647 get_sql_insert(Relation rel, int16 *pkat
|
} |
} |
|
|
static char * |
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; |
char *relname; |
TupleDesc tupdesc; |
TupleDesc tupdesc; |
Line 1724 get_sql_delete(Relation rel, int16 *pkat
|
Line 1666 get_sql_delete(Relation rel, int16 *pkat
|
appendStringInfo(str, "DELETE FROM %s WHERE ", relname); |
appendStringInfo(str, "DELETE FROM %s WHERE ", relname); |
for (i = 0; i < pknumatts; i++) |
for (i = 0; i < pknumatts; i++) |
{ |
{ |
int16 pkattnum = pkattnums[i]; |
int pkattnum = pkattnums[i]; |
|
|
if (i > 0) |
if (i > 0) |
appendStringInfo(str, " AND "); |
appendStringInfo(str, " AND "); |
|
|
appendStringInfo(str, "%s", |
appendStringInfo(str, "%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 = pstrdup(tgt_pkattvals[i]); |
val = pstrdup(tgt_pkattvals[i]); |
Line 1755 get_sql_delete(Relation rel, int16 *pkat
|
Line 1697 get_sql_delete(Relation rel, int16 *pkat
|
} |
} |
|
|
static char * |
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; |
char *relname; |
HeapTuple tuple; |
HeapTuple tuple; |
Line 1764 get_sql_update(Relation rel, int16 *pkat
|
Line 1706 get_sql_update(Relation rel, int16 *pkat
|
StringInfo str = makeStringInfo(); |
StringInfo str = makeStringInfo(); |
char *sql; |
char *sql; |
char *val; |
char *val; |
int16 key; |
int key; |
int i; |
int i; |
bool needComma; |
bool needComma; |
|
|
Line 1795 get_sql_update(Relation rel, int16 *pkat
|
Line 1737 get_sql_update(Relation rel, int16 *pkat
|
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 1818 get_sql_update(Relation rel, int16 *pkat
|
Line 1760 get_sql_update(Relation rel, int16 *pkat
|
|
|
for (i = 0; i < pknumatts; i++) |
for (i = 0; i < pknumatts; i++) |
{ |
{ |
int16 pkattnum = pkattnums[i]; |
int pkattnum = pkattnums[i]; |
|
|
if (i > 0) |
if (i > 0) |
appendStringInfo(str, " AND "); |
appendStringInfo(str, " AND "); |
|
|
appendStringInfo(str, "%s", |
appendStringInfo(str, "%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 = pstrdup(tgt_pkattvals[i]); |
val = pstrdup(tgt_pkattvals[i]); |
else |
else |
val = SPI_getvalue(tuple, tupdesc, pkattnum); |
val = SPI_getvalue(tuple, tupdesc, pkattnum + 1); |
|
|
if (val != NULL) |
if (val != NULL) |
{ |
{ |
Line 1883 quote_ident_cstr(char *rawstr)
|
Line 1825 quote_ident_cstr(char *rawstr)
|
return result; |
return result; |
} |
} |
|
|
static int16 |
static int |
get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key) |
get_attnum_pk_pos(int *pkattnums, int pknumatts, int key) |
{ |
{ |
int i; |
int i; |
|
|
Line 1899 get_attnum_pk_pos(int16 *pkattnums, int1
|
Line 1841 get_attnum_pk_pos(int16 *pkattnums, int1
|
} |
} |
|
|
static HeapTuple |
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; |
char *relname; |
TupleDesc tupdesc; |
TupleDesc tupdesc; |
Line 1930 get_tuple_of_interest(Relation rel, int1
|
Line 1872 get_tuple_of_interest(Relation rel, int1
|
|
|
for (i = 0; i < pknumatts; i++) |
for (i = 0; i < pknumatts; i++) |
{ |
{ |
int16 pkattnum = pkattnums[i]; |
int pkattnum = pkattnums[i]; |
|
|
if (i > 0) |
if (i > 0) |
appendStringInfo(str, " AND "); |
appendStringInfo(str, " AND "); |
|
|
appendStringInfo(str, "%s", |
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]); |
val = pstrdup(src_pkattvals[i]); |
if (val != NULL) |
if (val != NULL) |
Line 2281 dblink_security_check(PGconn *conn, remo
|
Line 2223 dblink_security_check(PGconn *conn, remo
|
} |
} |
} |
} |
|
|
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 = rel->rd_att; |
TupleDesc tupdesc; |
int natts = tupdesc->natts; |
int natts; |
|
int i; |
int i; |
|
|
tupdesc = rel->rd_att; |
/* Must have at least one pk attnum selected */ |
natts = tupdesc->natts; |
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) |
int pkattnum = pkattnums_arg[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; |
|
} |
} |
} |