aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2005-11-18 02:38:24 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2005-11-18 02:38:24 +0000
commit1d0d8d3c38e4c5611769c0cd9dd9c0faeee57b84 (patch)
tree373157511529770d2581ad615f5432bf6cc70e7f
parent3201b7f3d0657db9d5c29c3155eeae0f2066bf56 (diff)
downloadpostgresql-1d0d8d3c38e4c5611769c0cd9dd9c0faeee57b84.tar.gz
postgresql-1d0d8d3c38e4c5611769c0cd9dd9c0faeee57b84.zip
Mop-up for nulls-in-arrays patch: fix some places that access array
contents directly.
-rw-r--r--contrib/dblink/dblink.c312
-rw-r--r--contrib/tsearch2/rank.c21
-rw-r--r--contrib/tsearch2/snowball/header.h3
-rw-r--r--contrib/tsearch2/ts_cfg.c2
-rw-r--r--src/backend/utils/adt/acl.c47
-rw-r--r--src/backend/utils/adt/varlena.c52
-rw-r--r--src/include/utils/acl.h25
-rw-r--r--src/pl/plpgsql/src/pl_exec.c49
8 files changed, 233 insertions, 278 deletions
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 54e787bb206..bb646807c57 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -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,34 +1144,27 @@ 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);
- 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
*/
- if (pknumatts == 0)
+ if (pknumatts_tmp <= 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);
+ 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")));
/*
* 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
@@ -1193,28 +1176,10 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
"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
@@ -1226,22 +1191,6 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
"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.
*/
sql = get_sql_insert(relid, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals);
@@ -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,33 +1241,27 @@ 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);
- 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
*/
- if (pknumatts == 0)
+ if (pknumatts_tmp <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("number of key attributes must be > 0")));
- tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
+ 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")));
/*
* 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
@@ -1339,22 +1273,6 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
"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.
*/
sql = get_sql_delete(relid, pkattnums, pknumatts, tgt_pkattvals);
@@ -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,34 +1330,27 @@ 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);
- 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
*/
- if (pknumatts == 0)
+ if (pknumatts_tmp <= 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);
+ 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")));
/*
* 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
@@ -1462,28 +1362,10 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
"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
@@ -1495,22 +1377,6 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
"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.
*/
sql = get_sql_update(relid, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals);
@@ -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");
}
diff --git a/contrib/tsearch2/rank.c b/contrib/tsearch2/rank.c
index e678b205d62..d5cb7774017 100644
--- a/contrib/tsearch2/rank.c
+++ b/contrib/tsearch2/rank.c
@@ -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),
diff --git a/contrib/tsearch2/snowball/header.h b/contrib/tsearch2/snowball/header.h
index ad07388154c..3889ede53e6 100644
--- a/contrib/tsearch2/snowball/header.h
+++ b/contrib/tsearch2/snowball/header.h
@@ -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]
diff --git a/contrib/tsearch2/ts_cfg.c b/contrib/tsearch2/ts_cfg.c
index a1fcf0b4f27..50a355e464a 100644
--- a/contrib/tsearch2/ts_cfg.c
+++ b/contrib/tsearch2/ts_cfg.c
@@ -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);
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index a1080b59f60..9282c417d01 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -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,
@@ -360,6 +361,26 @@ allocacl(int n)
}
/*
+ * 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
* 's' that contains an ACL specification. See aclparse for details.
@@ -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)
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 1f6c176f640..dd877c7d3f0 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -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);
+ /* Get source element, checking for NULL */
+ if (bitmap && (*bitmap & bitmask) == 0)
+ {
+ /* we ignore nulls */
+ }
+ else
+ {
+ itemvalue = fetch_att(p, typbyval, typlen);
- value = DatumGetCString(FunctionCall1(&my_extra->proc,
- itemvalue));
+ value = DatumGetCString(FunctionCall1(&my_extra->proc,
+ itemvalue));
- if (i > 0)
- appendStringInfo(result_str, "%s%s", fldsep, value);
- else
- appendStringInfoString(result_str, value);
+ 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);
+ }
- 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));
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index c668382ba31..8699913eb95 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -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
@@ -101,16 +101,6 @@ typedef ArrayType Acl;
#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
*/
#define DatumGetAclItemP(X) ((AclItem *) DatumGetPointer(X))
@@ -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
*/
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 608854cbb5f..58f6d814b8f 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -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,43 +3305,39 @@ 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;
+ /* Coerce source value to match array element type. */
+ coerced_value = exec_simple_cast_value(value,
+ valtype,
+ arrayelemtypeid,
+ -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. Again,
- * this corresponds to the current behavior of
+ * 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 (oldarrayisnull)
- {
- if (arraytyplen > 0) /* fixed-length array? */
- return;
+ if (arraytyplen > 0 && /* fixed-length array? */
+ (oldarrayisnull || *isNull))
+ return;
+ if (oldarrayisnull)
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,
- arrayelemtypeid,
- -1,
- *isNull);
-
/*
* Build the modified array value.
*/