Mop-up for nulls-in-arrays patch: fix some places that access array
contents directly.
This commit is contained in:
parent
3201b7f3d0
commit
1d0d8d3c38
@ -73,6 +73,7 @@ static HTAB *createConnHash(void);
|
||||
static void createNewConnection(const char *name, remoteConn * rconn);
|
||||
static void deleteConnection(const char *name);
|
||||
static char **get_pkey_attnames(Oid relid, int16 *numatts);
|
||||
static char **get_text_array_contents(ArrayType *array, int *numitems);
|
||||
static char *get_sql_insert(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals);
|
||||
static char *get_sql_delete(Oid relid, int2vector *pkattnums, int16 pknumatts, char **tgt_pkattvals);
|
||||
static char *get_sql_update(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals);
|
||||
@ -1120,29 +1121,18 @@ PG_FUNCTION_INFO_V1(dblink_build_sql_insert);
|
||||
Datum
|
||||
dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *relname_text = PG_GETARG_TEXT_P(0);
|
||||
int2vector *pkattnums = (int2vector *) PG_GETARG_POINTER(1);
|
||||
int32 pknumatts_tmp = PG_GETARG_INT32(2);
|
||||
ArrayType *src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
||||
Oid relid;
|
||||
text *relname_text;
|
||||
int2vector *pkattnums;
|
||||
int pknumatts_tmp;
|
||||
int16 pknumatts = 0;
|
||||
char **src_pkattvals;
|
||||
char **tgt_pkattvals;
|
||||
ArrayType *src_pkattvals_arry;
|
||||
ArrayType *tgt_pkattvals_arry;
|
||||
int src_ndim;
|
||||
int *src_dim;
|
||||
int src_nitems;
|
||||
int tgt_ndim;
|
||||
int *tgt_dim;
|
||||
int tgt_nitems;
|
||||
int i;
|
||||
char *ptr;
|
||||
char *sql;
|
||||
int16 typlen;
|
||||
bool typbyval;
|
||||
char typalign;
|
||||
|
||||
relname_text = PG_GETARG_TEXT_P(0);
|
||||
|
||||
/*
|
||||
* Convert relname to rel OID.
|
||||
@ -1154,8 +1144,14 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
||||
errmsg("relation \"%s\" does not exist",
|
||||
GET_STR(relname_text))));
|
||||
|
||||
pkattnums = (int2vector *) PG_GETARG_POINTER(1);
|
||||
pknumatts_tmp = PG_GETARG_INT32(2);
|
||||
/*
|
||||
* There should be at least one key attribute
|
||||
*/
|
||||
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
|
||||
@ -1164,24 +1160,11 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
||||
errmsg("input for number of primary key " \
|
||||
"attributes too large")));
|
||||
|
||||
/*
|
||||
* There should be at least one key attribute
|
||||
*/
|
||||
if (pknumatts == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("number of key attributes must be > 0")));
|
||||
|
||||
src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
||||
|
||||
/*
|
||||
* Source array is made up of key values that will be used to locate the
|
||||
* tuple of interest from the local system.
|
||||
*/
|
||||
src_ndim = ARR_NDIM(src_pkattvals_arry);
|
||||
src_dim = ARR_DIMS(src_pkattvals_arry);
|
||||
src_nitems = ArrayGetNItems(src_ndim, src_dim);
|
||||
src_pkattvals = get_text_array_contents(src_pkattvals_arry, &src_nitems);
|
||||
|
||||
/*
|
||||
* There should be one source array key value for each key attnum
|
||||
@ -1192,29 +1175,11 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
||||
errmsg("source key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* get array of pointers to c-strings from the input source array
|
||||
*/
|
||||
Assert(ARR_ELEMTYPE(src_pkattvals_arry) == TEXTOID);
|
||||
get_typlenbyvalalign(ARR_ELEMTYPE(src_pkattvals_arry),
|
||||
&typlen, &typbyval, &typalign);
|
||||
|
||||
src_pkattvals = (char **) palloc(src_nitems * sizeof(char *));
|
||||
ptr = ARR_DATA_PTR(src_pkattvals_arry);
|
||||
for (i = 0; i < src_nitems; i++)
|
||||
{
|
||||
src_pkattvals[i] = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(ptr)));
|
||||
ptr = att_addlength(ptr, typlen, PointerGetDatum(ptr));
|
||||
ptr = (char *) att_align(ptr, typalign);
|
||||
}
|
||||
|
||||
/*
|
||||
* Target array is made up of key values that will be used to build the
|
||||
* SQL string for use on the remote system.
|
||||
*/
|
||||
tgt_ndim = ARR_NDIM(tgt_pkattvals_arry);
|
||||
tgt_dim = ARR_DIMS(tgt_pkattvals_arry);
|
||||
tgt_nitems = ArrayGetNItems(tgt_ndim, tgt_dim);
|
||||
tgt_pkattvals = get_text_array_contents(tgt_pkattvals_arry, &tgt_nitems);
|
||||
|
||||
/*
|
||||
* There should be one target array key value for each key attnum
|
||||
@ -1225,22 +1190,6 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
||||
errmsg("target key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* get array of pointers to c-strings from the input target array
|
||||
*/
|
||||
Assert(ARR_ELEMTYPE(tgt_pkattvals_arry) == TEXTOID);
|
||||
get_typlenbyvalalign(ARR_ELEMTYPE(tgt_pkattvals_arry),
|
||||
&typlen, &typbyval, &typalign);
|
||||
|
||||
tgt_pkattvals = (char **) palloc(tgt_nitems * sizeof(char *));
|
||||
ptr = ARR_DATA_PTR(tgt_pkattvals_arry);
|
||||
for (i = 0; i < tgt_nitems; i++)
|
||||
{
|
||||
tgt_pkattvals[i] = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(ptr)));
|
||||
ptr = att_addlength(ptr, typlen, PointerGetDatum(ptr));
|
||||
ptr = (char *) att_align(ptr, typalign);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prep work is finally done. Go get the SQL string.
|
||||
*/
|
||||
@ -1272,24 +1221,15 @@ PG_FUNCTION_INFO_V1(dblink_build_sql_delete);
|
||||
Datum
|
||||
dblink_build_sql_delete(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *relname_text = PG_GETARG_TEXT_P(0);
|
||||
int2vector *pkattnums = (int2vector *) PG_GETARG_POINTER(1);
|
||||
int32 pknumatts_tmp = PG_GETARG_INT32(2);
|
||||
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||
Oid relid;
|
||||
text *relname_text;
|
||||
int2vector *pkattnums;
|
||||
int pknumatts_tmp;
|
||||
int16 pknumatts = 0;
|
||||
char **tgt_pkattvals;
|
||||
ArrayType *tgt_pkattvals_arry;
|
||||
int tgt_ndim;
|
||||
int *tgt_dim;
|
||||
int tgt_nitems;
|
||||
int i;
|
||||
char *ptr;
|
||||
char *sql;
|
||||
int16 typlen;
|
||||
bool typbyval;
|
||||
char typalign;
|
||||
|
||||
relname_text = PG_GETARG_TEXT_P(0);
|
||||
|
||||
/*
|
||||
* Convert relname to rel OID.
|
||||
@ -1301,8 +1241,14 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
|
||||
errmsg("relation \"%s\" does not exist",
|
||||
GET_STR(relname_text))));
|
||||
|
||||
pkattnums = (int2vector *) PG_GETARG_POINTER(1);
|
||||
pknumatts_tmp = PG_GETARG_INT32(2);
|
||||
/*
|
||||
* There should be at least one key attribute
|
||||
*/
|
||||
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
|
||||
@ -1311,23 +1257,11 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
|
||||
errmsg("input for number of primary key " \
|
||||
"attributes too large")));
|
||||
|
||||
/*
|
||||
* There should be at least one key attribute
|
||||
*/
|
||||
if (pknumatts == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("number of key attributes must be > 0")));
|
||||
|
||||
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||
|
||||
/*
|
||||
* Target array is made up of key values that will be used to build the
|
||||
* SQL string for use on the remote system.
|
||||
*/
|
||||
tgt_ndim = ARR_NDIM(tgt_pkattvals_arry);
|
||||
tgt_dim = ARR_DIMS(tgt_pkattvals_arry);
|
||||
tgt_nitems = ArrayGetNItems(tgt_ndim, tgt_dim);
|
||||
tgt_pkattvals = get_text_array_contents(tgt_pkattvals_arry, &tgt_nitems);
|
||||
|
||||
/*
|
||||
* There should be one target array key value for each key attnum
|
||||
@ -1338,22 +1272,6 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
|
||||
errmsg("target key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* get array of pointers to c-strings from the input target array
|
||||
*/
|
||||
Assert(ARR_ELEMTYPE(tgt_pkattvals_arry) == TEXTOID);
|
||||
get_typlenbyvalalign(ARR_ELEMTYPE(tgt_pkattvals_arry),
|
||||
&typlen, &typbyval, &typalign);
|
||||
|
||||
tgt_pkattvals = (char **) palloc(tgt_nitems * sizeof(char *));
|
||||
ptr = ARR_DATA_PTR(tgt_pkattvals_arry);
|
||||
for (i = 0; i < tgt_nitems; i++)
|
||||
{
|
||||
tgt_pkattvals[i] = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(ptr)));
|
||||
ptr = att_addlength(ptr, typlen, PointerGetDatum(ptr));
|
||||
ptr = (char *) att_align(ptr, typalign);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prep work is finally done. Go get the SQL string.
|
||||
*/
|
||||
@ -1389,29 +1307,18 @@ PG_FUNCTION_INFO_V1(dblink_build_sql_update);
|
||||
Datum
|
||||
dblink_build_sql_update(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *relname_text = PG_GETARG_TEXT_P(0);
|
||||
int2vector *pkattnums = (int2vector *) PG_GETARG_POINTER(1);
|
||||
int32 pknumatts_tmp = PG_GETARG_INT32(2);
|
||||
ArrayType *src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
||||
Oid relid;
|
||||
text *relname_text;
|
||||
int2vector *pkattnums;
|
||||
int pknumatts_tmp;
|
||||
int16 pknumatts = 0;
|
||||
char **src_pkattvals;
|
||||
char **tgt_pkattvals;
|
||||
ArrayType *src_pkattvals_arry;
|
||||
ArrayType *tgt_pkattvals_arry;
|
||||
int src_ndim;
|
||||
int *src_dim;
|
||||
int src_nitems;
|
||||
int tgt_ndim;
|
||||
int *tgt_dim;
|
||||
int tgt_nitems;
|
||||
int i;
|
||||
char *ptr;
|
||||
char *sql;
|
||||
int16 typlen;
|
||||
bool typbyval;
|
||||
char typalign;
|
||||
|
||||
relname_text = PG_GETARG_TEXT_P(0);
|
||||
|
||||
/*
|
||||
* Convert relname to rel OID.
|
||||
@ -1423,8 +1330,14 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
|
||||
errmsg("relation \"%s\" does not exist",
|
||||
GET_STR(relname_text))));
|
||||
|
||||
pkattnums = (int2vector *) PG_GETARG_POINTER(1);
|
||||
pknumatts_tmp = PG_GETARG_INT32(2);
|
||||
/*
|
||||
* There should be one source array key values for each key attnum
|
||||
*/
|
||||
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
|
||||
@ -1433,24 +1346,11 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
|
||||
errmsg("input for number of primary key " \
|
||||
"attributes too large")));
|
||||
|
||||
/*
|
||||
* There should be one source array key values for each key attnum
|
||||
*/
|
||||
if (pknumatts == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("number of key attributes must be > 0")));
|
||||
|
||||
src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
||||
|
||||
/*
|
||||
* Source array is made up of key values that will be used to locate the
|
||||
* tuple of interest from the local system.
|
||||
*/
|
||||
src_ndim = ARR_NDIM(src_pkattvals_arry);
|
||||
src_dim = ARR_DIMS(src_pkattvals_arry);
|
||||
src_nitems = ArrayGetNItems(src_ndim, src_dim);
|
||||
src_pkattvals = get_text_array_contents(src_pkattvals_arry, &src_nitems);
|
||||
|
||||
/*
|
||||
* There should be one source array key value for each key attnum
|
||||
@ -1461,29 +1361,11 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
|
||||
errmsg("source key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* get array of pointers to c-strings from the input source array
|
||||
*/
|
||||
Assert(ARR_ELEMTYPE(src_pkattvals_arry) == TEXTOID);
|
||||
get_typlenbyvalalign(ARR_ELEMTYPE(src_pkattvals_arry),
|
||||
&typlen, &typbyval, &typalign);
|
||||
|
||||
src_pkattvals = (char **) palloc(src_nitems * sizeof(char *));
|
||||
ptr = ARR_DATA_PTR(src_pkattvals_arry);
|
||||
for (i = 0; i < src_nitems; i++)
|
||||
{
|
||||
src_pkattvals[i] = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(ptr)));
|
||||
ptr = att_addlength(ptr, typlen, PointerGetDatum(ptr));
|
||||
ptr = (char *) att_align(ptr, typalign);
|
||||
}
|
||||
|
||||
/*
|
||||
* Target array is made up of key values that will be used to build the
|
||||
* SQL string for use on the remote system.
|
||||
*/
|
||||
tgt_ndim = ARR_NDIM(tgt_pkattvals_arry);
|
||||
tgt_dim = ARR_DIMS(tgt_pkattvals_arry);
|
||||
tgt_nitems = ArrayGetNItems(tgt_ndim, tgt_dim);
|
||||
tgt_pkattvals = get_text_array_contents(tgt_pkattvals_arry, &tgt_nitems);
|
||||
|
||||
/*
|
||||
* There should be one target array key value for each key attnum
|
||||
@ -1494,22 +1376,6 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
|
||||
errmsg("target key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* get array of pointers to c-strings from the input target array
|
||||
*/
|
||||
Assert(ARR_ELEMTYPE(tgt_pkattvals_arry) == TEXTOID);
|
||||
get_typlenbyvalalign(ARR_ELEMTYPE(tgt_pkattvals_arry),
|
||||
&typlen, &typbyval, &typalign);
|
||||
|
||||
tgt_pkattvals = (char **) palloc(tgt_nitems * sizeof(char *));
|
||||
ptr = ARR_DATA_PTR(tgt_pkattvals_arry);
|
||||
for (i = 0; i < tgt_nitems; i++)
|
||||
{
|
||||
tgt_pkattvals[i] = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(ptr)));
|
||||
ptr = att_addlength(ptr, typlen, PointerGetDatum(ptr));
|
||||
ptr = (char *) att_align(ptr, typalign);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prep work is finally done. Go get the SQL string.
|
||||
*/
|
||||
@ -1598,6 +1464,67 @@ get_pkey_attnames(Oid relid, int16 *numatts)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deconstruct a text[] into C-strings (note any NULL elements will be
|
||||
* returned as NULL pointers)
|
||||
*/
|
||||
static char **
|
||||
get_text_array_contents(ArrayType *array, int *numitems)
|
||||
{
|
||||
int ndim = ARR_NDIM(array);
|
||||
int *dims = ARR_DIMS(array);
|
||||
int nitems;
|
||||
int16 typlen;
|
||||
bool typbyval;
|
||||
char typalign;
|
||||
char **values;
|
||||
char *ptr;
|
||||
bits8 *bitmap;
|
||||
int bitmask;
|
||||
int i;
|
||||
|
||||
Assert(ARR_ELEMTYPE(array) == TEXTOID);
|
||||
|
||||
*numitems = nitems = ArrayGetNItems(ndim, dims);
|
||||
|
||||
get_typlenbyvalalign(ARR_ELEMTYPE(array),
|
||||
&typlen, &typbyval, &typalign);
|
||||
|
||||
values = (char **) palloc(nitems * sizeof(char *));
|
||||
|
||||
ptr = ARR_DATA_PTR(array);
|
||||
bitmap = ARR_NULLBITMAP(array);
|
||||
bitmask = 1;
|
||||
|
||||
for (i = 0; i < nitems; i++)
|
||||
{
|
||||
if (bitmap && (*bitmap & bitmask) == 0)
|
||||
{
|
||||
values[i] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
values[i] = DatumGetCString(DirectFunctionCall1(textout,
|
||||
PointerGetDatum(ptr)));
|
||||
ptr = att_addlength(ptr, typlen, PointerGetDatum(ptr));
|
||||
ptr = (char *) att_align(ptr, typalign);
|
||||
}
|
||||
|
||||
/* advance bitmap pointer if any */
|
||||
if (bitmap)
|
||||
{
|
||||
bitmask <<= 1;
|
||||
if (bitmask == 0x100)
|
||||
{
|
||||
bitmap++;
|
||||
bitmask = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_sql_insert(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals)
|
||||
{
|
||||
@ -1665,7 +1592,7 @@ get_sql_insert(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pka
|
||||
key = -1;
|
||||
|
||||
if (key > -1)
|
||||
val = pstrdup(tgt_pkattvals[key]);
|
||||
val = tgt_pkattvals[key] ? pstrdup(tgt_pkattvals[key]) : NULL;
|
||||
else
|
||||
val = SPI_getvalue(tuple, tupdesc, i + 1);
|
||||
|
||||
@ -1697,7 +1624,6 @@ get_sql_delete(Oid relid, int2vector *pkattnums, int16 pknumatts, char **tgt_pka
|
||||
int natts;
|
||||
StringInfo str = makeStringInfo();
|
||||
char *sql;
|
||||
char *val = NULL;
|
||||
int i;
|
||||
|
||||
/* get relation name including any needed schema prefix and quoting */
|
||||
@ -1721,17 +1647,13 @@ get_sql_delete(Oid relid, int2vector *pkattnums, int16 pknumatts, char **tgt_pka
|
||||
appendStringInfo(str, "%s",
|
||||
quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
|
||||
|
||||
if (tgt_pkattvals != NULL)
|
||||
val = pstrdup(tgt_pkattvals[i]);
|
||||
else
|
||||
if (tgt_pkattvals == NULL)
|
||||
/* internal error */
|
||||
elog(ERROR, "target key array must not be NULL");
|
||||
|
||||
if (val != NULL)
|
||||
{
|
||||
appendStringInfo(str, " = %s", quote_literal_cstr(val));
|
||||
pfree(val);
|
||||
}
|
||||
if (tgt_pkattvals[i] != NULL)
|
||||
appendStringInfo(str, " = %s",
|
||||
quote_literal_cstr(tgt_pkattvals[i]));
|
||||
else
|
||||
appendStringInfo(str, " IS NULL");
|
||||
}
|
||||
@ -1795,7 +1717,7 @@ get_sql_update(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pka
|
||||
key = -1;
|
||||
|
||||
if (key > -1)
|
||||
val = pstrdup(tgt_pkattvals[key]);
|
||||
val = tgt_pkattvals[key] ? pstrdup(tgt_pkattvals[key]) : NULL;
|
||||
else
|
||||
val = SPI_getvalue(tuple, tupdesc, i + 1);
|
||||
|
||||
@ -1822,7 +1744,7 @@ get_sql_update(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pka
|
||||
quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
|
||||
|
||||
if (tgt_pkattvals != NULL)
|
||||
val = pstrdup(tgt_pkattvals[i]);
|
||||
val = tgt_pkattvals[i] ? pstrdup(tgt_pkattvals[i]) : NULL;
|
||||
else
|
||||
val = SPI_getvalue(tuple, tupdesc, pkattnum);
|
||||
|
||||
@ -1905,7 +1827,6 @@ get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 pknumatts, char **
|
||||
int ret;
|
||||
HeapTuple tuple;
|
||||
int i;
|
||||
char *val = NULL;
|
||||
|
||||
/* get relation name including any needed schema prefix and quoting */
|
||||
relname = generate_relation_name(relid);
|
||||
@ -1940,12 +1861,9 @@ get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 pknumatts, char **
|
||||
appendStringInfo(str, "%s",
|
||||
quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
|
||||
|
||||
val = pstrdup(src_pkattvals[i]);
|
||||
if (val != NULL)
|
||||
{
|
||||
appendStringInfo(str, " = %s", quote_literal_cstr(val));
|
||||
pfree(val);
|
||||
}
|
||||
if (src_pkattvals[i] != NULL)
|
||||
appendStringInfo(str, " = %s",
|
||||
quote_literal_cstr(src_pkattvals[i]));
|
||||
else
|
||||
appendStringInfo(str, " IS NULL");
|
||||
}
|
||||
|
@ -3,20 +3,20 @@
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "access/gist.h"
|
||||
#include "access/itup.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "commands/trigger.h"
|
||||
#include "executor/spi.h"
|
||||
#include "fmgr.h"
|
||||
#include "funcapi.h"
|
||||
#include "storage/bufpage.h"
|
||||
#include "executor/spi.h"
|
||||
#include "commands/trigger.h"
|
||||
#include "nodes/pg_list.h"
|
||||
#include "catalog/namespace.h"
|
||||
|
||||
#include "storage/bufpage.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
|
||||
#include "tsvector.h"
|
||||
#include "query.h"
|
||||
@ -354,6 +354,7 @@ rank(PG_FUNCTION_ARGS)
|
||||
int method = DEF_NORM_METHOD;
|
||||
float res = 0.0;
|
||||
float ws[lengthof(weights)];
|
||||
float4 *arrdata;
|
||||
int i;
|
||||
|
||||
if (ARR_NDIM(win) != 1)
|
||||
@ -366,9 +367,15 @@ rank(PG_FUNCTION_ARGS)
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("array of weight is too short")));
|
||||
|
||||
if (ARR_HASNULL(win))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
errmsg("array of weight must not contain nulls")));
|
||||
|
||||
arrdata = (float4 *) ARR_DATA_PTR(win);
|
||||
for (i = 0; i < lengthof(weights); i++)
|
||||
{
|
||||
ws[i] = (((float4 *) ARR_DATA_PTR(win))[i] >= 0) ? ((float4 *) ARR_DATA_PTR(win))[i] : weights[i];
|
||||
ws[i] = (arrdata[i] >= 0) ? arrdata[i] : weights[i];
|
||||
if (ws[i] > 1.0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
#include "api.h"
|
||||
|
||||
#define MAXINT INT_MAX
|
||||
#define MININT INT_MIN
|
||||
|
||||
#define HEAD 2*sizeof(int)
|
||||
|
||||
#define SIZE(p) ((int *)(p))[-1]
|
||||
|
@ -113,6 +113,8 @@ init_cfg(Oid id, TSCfgInfo * cfg)
|
||||
ts_error(ERROR, "Wrong dimension");
|
||||
if (ARRNELEMS(a) < 1)
|
||||
continue;
|
||||
if (ARR_HASNULL(a))
|
||||
ts_error(ERROR, "Array must not contain nulls");
|
||||
|
||||
cfg->map[lexid].len = ARRNELEMS(a);
|
||||
cfg->map[lexid].dict_id = (Datum *) malloc(sizeof(Datum) * cfg->map[lexid].len);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.128 2005/11/17 22:14:52 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.129 2005/11/18 02:38:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -67,6 +67,7 @@ static List *cached_membership_roles = NIL;
|
||||
static const char *getid(const char *s, char *n);
|
||||
static void putid(char *p, const char *s);
|
||||
static Acl *allocacl(int n);
|
||||
static void check_acl(const Acl *acl);
|
||||
static const char *aclparse(const char *s, AclItem *aip);
|
||||
static bool aclitem_match(const AclItem *a1, const AclItem *a2);
|
||||
static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
|
||||
@ -359,6 +360,26 @@ allocacl(int n)
|
||||
return new_acl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that an ACL array is acceptable (one-dimensional and has no nulls)
|
||||
*/
|
||||
static void
|
||||
check_acl(const Acl *acl)
|
||||
{
|
||||
if (ARR_ELEMTYPE(acl) != ACLITEMOID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("ACL array contains wrong datatype")));
|
||||
if (ARR_NDIM(acl) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("ACL arrays must be one-dimensional")));
|
||||
if (ARR_HASNULL(acl))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
errmsg("ACL arrays must not contain nulls")));
|
||||
}
|
||||
|
||||
/*
|
||||
* aclitemin
|
||||
* Allocates storage for, and fills in, a new AclItem given a string
|
||||
@ -612,15 +633,8 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip,
|
||||
int dst,
|
||||
num;
|
||||
|
||||
/* These checks for null input are probably dead code, but... */
|
||||
if (!old_acl || ACL_NUM(old_acl) < 0)
|
||||
old_acl = allocacl(0);
|
||||
if (!mod_aip)
|
||||
{
|
||||
new_acl = allocacl(ACL_NUM(old_acl));
|
||||
memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
|
||||
return new_acl;
|
||||
}
|
||||
/* Caller probably already checked old_acl, but be safe */
|
||||
check_acl(old_acl);
|
||||
|
||||
/* If granting grant options, check for circularity */
|
||||
if (modechg != ACL_MODECHG_DEL &&
|
||||
@ -740,6 +754,8 @@ aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
|
||||
targ,
|
||||
num;
|
||||
|
||||
check_acl(old_acl);
|
||||
|
||||
/*
|
||||
* Make a copy of the given ACL, substituting new owner ID for old
|
||||
* wherever it appears as either grantor or grantee. Also note if the new
|
||||
@ -836,6 +852,8 @@ check_circularity(const Acl *old_acl, const AclItem *mod_aip,
|
||||
num;
|
||||
AclMode own_privs;
|
||||
|
||||
check_acl(old_acl);
|
||||
|
||||
/*
|
||||
* For now, grant options can only be granted to roles, not PUBLIC.
|
||||
* Otherwise we'd have to work a bit harder here.
|
||||
@ -916,6 +934,8 @@ recursive_revoke(Acl *acl,
|
||||
int i,
|
||||
num;
|
||||
|
||||
check_acl(acl);
|
||||
|
||||
/* The owner can never truly lose grant options, so short-circuit */
|
||||
if (grantee == ownerId)
|
||||
return acl;
|
||||
@ -1005,6 +1025,8 @@ aclmask(const Acl *acl, Oid roleid, Oid ownerId,
|
||||
if (acl == NULL)
|
||||
elog(ERROR, "null ACL");
|
||||
|
||||
check_acl(acl);
|
||||
|
||||
/* Quick exit for mask == 0 */
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
@ -1091,6 +1113,8 @@ aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
|
||||
if (acl == NULL)
|
||||
elog(ERROR, "null ACL");
|
||||
|
||||
check_acl(acl);
|
||||
|
||||
/* Quick exit for mask == 0 */
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
@ -1151,6 +1175,8 @@ aclmembers(const Acl *acl, Oid **roleids)
|
||||
return 0;
|
||||
}
|
||||
|
||||
check_acl(acl);
|
||||
|
||||
/* Allocate the worst-case space requirement */
|
||||
list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
|
||||
acldat = ACL_DAT(acl);
|
||||
@ -1240,6 +1266,7 @@ aclcontains(PG_FUNCTION_ARGS)
|
||||
int i,
|
||||
num;
|
||||
|
||||
check_acl(acl);
|
||||
num = ACL_NUM(acl);
|
||||
aidat = ACL_DAT(acl);
|
||||
for (i = 0; i < num; ++i)
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.139 2005/10/29 00:31:51 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.140 2005/11/18 02:38:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -2491,16 +2491,18 @@ array_to_text(PG_FUNCTION_ARGS)
|
||||
int nitems,
|
||||
*dims,
|
||||
ndims;
|
||||
char *p;
|
||||
Oid element_type;
|
||||
int typlen;
|
||||
bool typbyval;
|
||||
char typalign;
|
||||
StringInfo result_str = makeStringInfo();
|
||||
bool printed = false;
|
||||
char *p;
|
||||
bits8 *bitmap;
|
||||
int bitmask;
|
||||
int i;
|
||||
ArrayMetaState *my_extra;
|
||||
|
||||
p = ARR_DATA_PTR(v);
|
||||
ndims = ARR_NDIM(v);
|
||||
dims = ARR_DIMS(v);
|
||||
nitems = ArrayGetNItems(ndims, dims);
|
||||
@ -2522,7 +2524,7 @@ array_to_text(PG_FUNCTION_ARGS)
|
||||
fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
|
||||
sizeof(ArrayMetaState));
|
||||
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
|
||||
my_extra->element_type = InvalidOid;
|
||||
my_extra->element_type = ~element_type;
|
||||
}
|
||||
|
||||
if (my_extra->element_type != element_type)
|
||||
@ -2542,23 +2544,47 @@ array_to_text(PG_FUNCTION_ARGS)
|
||||
typbyval = my_extra->typbyval;
|
||||
typalign = my_extra->typalign;
|
||||
|
||||
p = ARR_DATA_PTR(v);
|
||||
bitmap = ARR_NULLBITMAP(v);
|
||||
bitmask = 1;
|
||||
|
||||
for (i = 0; i < nitems; i++)
|
||||
{
|
||||
Datum itemvalue;
|
||||
char *value;
|
||||
|
||||
itemvalue = fetch_att(p, typbyval, typlen);
|
||||
|
||||
value = DatumGetCString(FunctionCall1(&my_extra->proc,
|
||||
itemvalue));
|
||||
|
||||
if (i > 0)
|
||||
appendStringInfo(result_str, "%s%s", fldsep, value);
|
||||
/* Get source element, checking for NULL */
|
||||
if (bitmap && (*bitmap & bitmask) == 0)
|
||||
{
|
||||
/* we ignore nulls */
|
||||
}
|
||||
else
|
||||
appendStringInfoString(result_str, value);
|
||||
{
|
||||
itemvalue = fetch_att(p, typbyval, typlen);
|
||||
|
||||
p = att_addlength(p, typlen, PointerGetDatum(p));
|
||||
p = (char *) att_align(p, typalign);
|
||||
value = DatumGetCString(FunctionCall1(&my_extra->proc,
|
||||
itemvalue));
|
||||
|
||||
if (printed)
|
||||
appendStringInfo(result_str, "%s%s", fldsep, value);
|
||||
else
|
||||
appendStringInfoString(result_str, value);
|
||||
printed = true;
|
||||
|
||||
p = att_addlength(p, typlen, PointerGetDatum(p));
|
||||
p = (char *) att_align(p, typalign);
|
||||
}
|
||||
|
||||
/* advance bitmap pointer if any */
|
||||
if (bitmap)
|
||||
{
|
||||
bitmask <<= 1;
|
||||
if (bitmask == 0x100)
|
||||
{
|
||||
bitmap++;
|
||||
bitmask = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PG_RETURN_TEXT_P(PG_STR_GET_TEXT(result_str->data));
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.87 2005/11/17 22:14:55 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.88 2005/11/18 02:38:24 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* An ACL array is simply an array of AclItems, representing the union
|
||||
@ -78,9 +78,9 @@ typedef struct AclItem
|
||||
#define ACLITEM_ALL_GOPTION_BITS ((AclMode) 0xFFFF << 16)
|
||||
|
||||
/*
|
||||
* Definitions for convenient access to Acl (array of AclItem) and IdList
|
||||
* (array of Oid). These are standard PostgreSQL arrays, but are restricted
|
||||
* to have one dimension. We also ignore the lower bound when reading,
|
||||
* Definitions for convenient access to Acl (array of AclItem).
|
||||
* These are standard PostgreSQL arrays, but are restricted to have one
|
||||
* dimension and no nulls. We also ignore the lower bound when reading,
|
||||
* and set it to one when writing.
|
||||
*
|
||||
* CAUTION: as of PostgreSQL 7.1, these arrays are toastable (just like all
|
||||
@ -100,16 +100,6 @@ typedef ArrayType Acl;
|
||||
#define ACL_N_SIZE(N) (ARR_OVERHEAD_NONULLS(1) + ((N) * sizeof(AclItem)))
|
||||
#define ACL_SIZE(ACL) ARR_SIZE(ACL)
|
||||
|
||||
/*
|
||||
* IdList a one-dimensional array of Oid
|
||||
*/
|
||||
typedef ArrayType IdList;
|
||||
|
||||
#define IDLIST_NUM(IDL) (ARR_DIMS(IDL)[0])
|
||||
#define IDLIST_DAT(IDL) ((Oid *) ARR_DATA_PTR(IDL))
|
||||
#define IDLIST_N_SIZE(N) (ARR_OVERHEAD_NONULLS(1) + ((N) * sizeof(Oid)))
|
||||
#define IDLIST_SIZE(IDL) ARR_SIZE(IDL)
|
||||
|
||||
/*
|
||||
* fmgr macros for these types
|
||||
*/
|
||||
@ -123,13 +113,6 @@ typedef ArrayType IdList;
|
||||
#define PG_GETARG_ACL_P_COPY(n) DatumGetAclPCopy(PG_GETARG_DATUM(n))
|
||||
#define PG_RETURN_ACL_P(x) PG_RETURN_POINTER(x)
|
||||
|
||||
#define DatumGetIdListP(X) ((IdList *) PG_DETOAST_DATUM(X))
|
||||
#define DatumGetIdListPCopy(X) ((IdList *) PG_DETOAST_DATUM_COPY(X))
|
||||
#define PG_GETARG_IDLIST_P(n) DatumGetIdListP(PG_GETARG_DATUM(n))
|
||||
#define PG_GETARG_IDLIST_P_COPY(n) DatumGetIdListPCopy(PG_GETARG_DATUM(n))
|
||||
#define PG_RETURN_IDLIST_P(x) PG_RETURN_POINTER(x)
|
||||
|
||||
|
||||
/*
|
||||
* ACL modification opcodes for aclupdate
|
||||
*/
|
||||
|
@ -3,7 +3,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.155 2005/11/17 22:14:55 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.156 2005/11/18 02:38:24 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@ -3241,8 +3241,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
|
||||
int i;
|
||||
PLpgSQL_expr *subscripts[MAXDIM];
|
||||
int subscriptvals[MAXDIM];
|
||||
bool havenullsubscript,
|
||||
oldarrayisnull;
|
||||
bool oldarrayisnull;
|
||||
Oid arraytypeid,
|
||||
arrayelemtypeid;
|
||||
int16 arraytyplen,
|
||||
@ -3295,9 +3294,9 @@ exec_assign_value(PLpgSQL_execstate * estate,
|
||||
arraytyplen = get_typlen(arraytypeid);
|
||||
|
||||
/*
|
||||
* Evaluate the subscripts, switch into left-to-right order
|
||||
* Evaluate the subscripts, switch into left-to-right order.
|
||||
* Like ExecEvalArrayRef(), complain if any subscript is null.
|
||||
*/
|
||||
havenullsubscript = false;
|
||||
for (i = 0; i < nsubscripts; i++)
|
||||
{
|
||||
bool subisnull;
|
||||
@ -3306,36 +3305,12 @@ exec_assign_value(PLpgSQL_execstate * estate,
|
||||
exec_eval_integer(estate,
|
||||
subscripts[nsubscripts - 1 - i],
|
||||
&subisnull);
|
||||
havenullsubscript |= subisnull;
|
||||
if (subisnull)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
errmsg("array subscript in assignment must not be NULL")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip the assignment if we have any nulls in the subscripts
|
||||
* or the righthand side. This is pretty bogus but it
|
||||
* corresponds to the current behavior of ExecEvalArrayRef().
|
||||
*/
|
||||
if (havenullsubscript || *isNull)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If the original array is null, cons up an empty array so
|
||||
* that the assignment can proceed; we'll end with a
|
||||
* one-element array containing just the assigned-to
|
||||
* subscript. This only works for varlena arrays, though; for
|
||||
* fixed-length array types we skip the assignment. Again,
|
||||
* this corresponds to the current behavior of
|
||||
* ExecEvalArrayRef().
|
||||
*/
|
||||
if (oldarrayisnull)
|
||||
{
|
||||
if (arraytyplen > 0) /* fixed-length array? */
|
||||
return;
|
||||
|
||||
oldarrayval = construct_empty_array(arrayelemtypeid);
|
||||
}
|
||||
else
|
||||
oldarrayval = (ArrayType *) DatumGetPointer(oldarraydatum);
|
||||
|
||||
/* Coerce source value to match array element type. */
|
||||
coerced_value = exec_simple_cast_value(value,
|
||||
valtype,
|
||||
@ -3343,6 +3318,26 @@ exec_assign_value(PLpgSQL_execstate * estate,
|
||||
-1,
|
||||
*isNull);
|
||||
|
||||
/*
|
||||
* If the original array is null, cons up an empty array so
|
||||
* that the assignment can proceed; we'll end with a
|
||||
* one-element array containing just the assigned-to
|
||||
* subscript. This only works for varlena arrays, though; for
|
||||
* fixed-length array types we skip the assignment. We can't
|
||||
* support assignment of a null entry into a fixed-length
|
||||
* array, either, so that's a no-op too. This is all ugly
|
||||
* but corresponds to the current behavior of
|
||||
* ExecEvalArrayRef().
|
||||
*/
|
||||
if (arraytyplen > 0 && /* fixed-length array? */
|
||||
(oldarrayisnull || *isNull))
|
||||
return;
|
||||
|
||||
if (oldarrayisnull)
|
||||
oldarrayval = construct_empty_array(arrayelemtypeid);
|
||||
else
|
||||
oldarrayval = (ArrayType *) DatumGetPointer(oldarraydatum);
|
||||
|
||||
/*
|
||||
* Build the modified array value.
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user