Commit 1d0d8d3c authored by Tom Lane's avatar Tom Lane

Mop-up for nulls-in-arrays patch: fix some places that access array

contents directly.
parent 3201b7f3
This diff is collapsed.
...@@ -3,20 +3,20 @@ ...@@ -3,20 +3,20 @@
* Teodor Sigaev <teodor@sigaev.ru> * Teodor Sigaev <teodor@sigaev.ru>
*/ */
#include "postgres.h" #include "postgres.h"
#include <math.h> #include <math.h>
#include "access/gist.h" #include "access/gist.h"
#include "access/itup.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 "fmgr.h"
#include "funcapi.h" #include "funcapi.h"
#include "storage/bufpage.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "catalog/namespace.h" #include "storage/bufpage.h"
#include "utils/array.h" #include "utils/array.h"
#include "utils/builtins.h"
#include "tsvector.h" #include "tsvector.h"
#include "query.h" #include "query.h"
...@@ -354,6 +354,7 @@ rank(PG_FUNCTION_ARGS) ...@@ -354,6 +354,7 @@ rank(PG_FUNCTION_ARGS)
int method = DEF_NORM_METHOD; int method = DEF_NORM_METHOD;
float res = 0.0; float res = 0.0;
float ws[lengthof(weights)]; float ws[lengthof(weights)];
float4 *arrdata;
int i; int i;
if (ARR_NDIM(win) != 1) if (ARR_NDIM(win) != 1)
...@@ -366,9 +367,15 @@ rank(PG_FUNCTION_ARGS) ...@@ -366,9 +367,15 @@ rank(PG_FUNCTION_ARGS)
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("array of weight is too short"))); 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++) 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) if (ws[i] > 1.0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
......
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
#include "api.h" #include "api.h"
#define MAXINT INT_MAX
#define MININT INT_MIN
#define HEAD 2*sizeof(int) #define HEAD 2*sizeof(int)
#define SIZE(p) ((int *)(p))[-1] #define SIZE(p) ((int *)(p))[-1]
......
...@@ -113,6 +113,8 @@ init_cfg(Oid id, TSCfgInfo * cfg) ...@@ -113,6 +113,8 @@ init_cfg(Oid id, TSCfgInfo * cfg)
ts_error(ERROR, "Wrong dimension"); ts_error(ERROR, "Wrong dimension");
if (ARRNELEMS(a) < 1) if (ARRNELEMS(a) < 1)
continue; continue;
if (ARR_HASNULL(a))
ts_error(ERROR, "Array must not contain nulls");
cfg->map[lexid].len = ARRNELEMS(a); cfg->map[lexid].len = ARRNELEMS(a);
cfg->map[lexid].dict_id = (Datum *) malloc(sizeof(Datum) * cfg->map[lexid].len); cfg->map[lexid].dict_id = (Datum *) malloc(sizeof(Datum) * cfg->map[lexid].len);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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; ...@@ -67,6 +67,7 @@ static List *cached_membership_roles = NIL;
static const char *getid(const char *s, char *n); static const char *getid(const char *s, char *n);
static void putid(char *p, const char *s); static void putid(char *p, const char *s);
static Acl *allocacl(int n); static Acl *allocacl(int n);
static void check_acl(const Acl *acl);
static const char *aclparse(const char *s, AclItem *aip); static const char *aclparse(const char *s, AclItem *aip);
static bool aclitem_match(const AclItem *a1, const AclItem *a2); static bool aclitem_match(const AclItem *a1, const AclItem *a2);
static void check_circularity(const Acl *old_acl, const AclItem *mod_aip, static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
...@@ -359,6 +360,26 @@ allocacl(int n) ...@@ -359,6 +360,26 @@ allocacl(int n)
return new_acl; 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 * aclitemin
* Allocates storage for, and fills in, a new AclItem given a string * 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, ...@@ -612,15 +633,8 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip,
int dst, int dst,
num; num;
/* These checks for null input are probably dead code, but... */ /* Caller probably already checked old_acl, but be safe */
if (!old_acl || ACL_NUM(old_acl) < 0) check_acl(old_acl);
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;
}
/* If granting grant options, check for circularity */ /* If granting grant options, check for circularity */
if (modechg != ACL_MODECHG_DEL && if (modechg != ACL_MODECHG_DEL &&
...@@ -740,6 +754,8 @@ aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId) ...@@ -740,6 +754,8 @@ aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
targ, targ,
num; num;
check_acl(old_acl);
/* /*
* Make a copy of the given ACL, substituting new owner ID for old * 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 * 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, ...@@ -836,6 +852,8 @@ check_circularity(const Acl *old_acl, const AclItem *mod_aip,
num; num;
AclMode own_privs; AclMode own_privs;
check_acl(old_acl);
/* /*
* For now, grant options can only be granted to roles, not PUBLIC. * For now, grant options can only be granted to roles, not PUBLIC.
* Otherwise we'd have to work a bit harder here. * Otherwise we'd have to work a bit harder here.
...@@ -916,6 +934,8 @@ recursive_revoke(Acl *acl, ...@@ -916,6 +934,8 @@ recursive_revoke(Acl *acl,
int i, int i,
num; num;
check_acl(acl);
/* The owner can never truly lose grant options, so short-circuit */ /* The owner can never truly lose grant options, so short-circuit */
if (grantee == ownerId) if (grantee == ownerId)
return acl; return acl;
...@@ -1005,6 +1025,8 @@ aclmask(const Acl *acl, Oid roleid, Oid ownerId, ...@@ -1005,6 +1025,8 @@ aclmask(const Acl *acl, Oid roleid, Oid ownerId,
if (acl == NULL) if (acl == NULL)
elog(ERROR, "null ACL"); elog(ERROR, "null ACL");
check_acl(acl);
/* Quick exit for mask == 0 */ /* Quick exit for mask == 0 */
if (mask == 0) if (mask == 0)
return 0; return 0;
...@@ -1091,6 +1113,8 @@ aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId, ...@@ -1091,6 +1113,8 @@ aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
if (acl == NULL) if (acl == NULL)
elog(ERROR, "null ACL"); elog(ERROR, "null ACL");
check_acl(acl);
/* Quick exit for mask == 0 */ /* Quick exit for mask == 0 */
if (mask == 0) if (mask == 0)
return 0; return 0;
...@@ -1151,6 +1175,8 @@ aclmembers(const Acl *acl, Oid **roleids) ...@@ -1151,6 +1175,8 @@ aclmembers(const Acl *acl, Oid **roleids)
return 0; return 0;
} }
check_acl(acl);
/* Allocate the worst-case space requirement */ /* Allocate the worst-case space requirement */
list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid)); list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
acldat = ACL_DAT(acl); acldat = ACL_DAT(acl);
...@@ -1240,6 +1266,7 @@ aclcontains(PG_FUNCTION_ARGS) ...@@ -1240,6 +1266,7 @@ aclcontains(PG_FUNCTION_ARGS)
int i, int i,
num; num;
check_acl(acl);
num = ACL_NUM(acl); num = ACL_NUM(acl);
aidat = ACL_DAT(acl); aidat = ACL_DAT(acl);
for (i = 0; i < num; ++i) for (i = 0; i < num; ++i)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -2491,16 +2491,18 @@ array_to_text(PG_FUNCTION_ARGS)
int nitems, int nitems,
*dims, *dims,
ndims; ndims;
char *p;
Oid element_type; Oid element_type;
int typlen; int typlen;
bool typbyval; bool typbyval;
char typalign; char typalign;
StringInfo result_str = makeStringInfo(); StringInfo result_str = makeStringInfo();
bool printed = false;
char *p;
bits8 *bitmap;
int bitmask;
int i; int i;
ArrayMetaState *my_extra; ArrayMetaState *my_extra;
p = ARR_DATA_PTR(v);
ndims = ARR_NDIM(v); ndims = ARR_NDIM(v);
dims = ARR_DIMS(v); dims = ARR_DIMS(v);
nitems = ArrayGetNItems(ndims, dims); nitems = ArrayGetNItems(ndims, dims);
...@@ -2522,7 +2524,7 @@ array_to_text(PG_FUNCTION_ARGS) ...@@ -2522,7 +2524,7 @@ array_to_text(PG_FUNCTION_ARGS)
fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
sizeof(ArrayMetaState)); sizeof(ArrayMetaState));
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; 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) if (my_extra->element_type != element_type)
...@@ -2542,25 +2544,49 @@ array_to_text(PG_FUNCTION_ARGS) ...@@ -2542,25 +2544,49 @@ array_to_text(PG_FUNCTION_ARGS)
typbyval = my_extra->typbyval; typbyval = my_extra->typbyval;
typalign = my_extra->typalign; typalign = my_extra->typalign;
p = ARR_DATA_PTR(v);
bitmap = ARR_NULLBITMAP(v);
bitmask = 1;
for (i = 0; i < nitems; i++) for (i = 0; i < nitems; i++)
{ {
Datum itemvalue; Datum itemvalue;
char *value; char *value;
/* Get source element, checking for NULL */
if (bitmap && (*bitmap & bitmask) == 0)
{
/* we ignore nulls */
}
else
{
itemvalue = fetch_att(p, typbyval, typlen); itemvalue = fetch_att(p, typbyval, typlen);
value = DatumGetCString(FunctionCall1(&my_extra->proc, value = DatumGetCString(FunctionCall1(&my_extra->proc,
itemvalue)); itemvalue));
if (i > 0) if (printed)
appendStringInfo(result_str, "%s%s", fldsep, value); appendStringInfo(result_str, "%s%s", fldsep, value);
else else
appendStringInfoString(result_str, value); appendStringInfoString(result_str, value);
printed = true;
p = att_addlength(p, typlen, PointerGetDatum(p)); p = att_addlength(p, typlen, PointerGetDatum(p));
p = (char *) att_align(p, typalign); 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)); PG_RETURN_TEXT_P(PG_STR_GET_TEXT(result_str->data));
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* An ACL array is simply an array of AclItems, representing the union * An ACL array is simply an array of AclItems, representing the union
...@@ -78,9 +78,9 @@ typedef struct AclItem ...@@ -78,9 +78,9 @@ typedef struct AclItem
#define ACLITEM_ALL_GOPTION_BITS ((AclMode) 0xFFFF << 16) #define ACLITEM_ALL_GOPTION_BITS ((AclMode) 0xFFFF << 16)
/* /*
* Definitions for convenient access to Acl (array of AclItem) and IdList * Definitions for convenient access to Acl (array of AclItem).
* (array of Oid). These are standard PostgreSQL arrays, but are restricted * These are standard PostgreSQL arrays, but are restricted to have one
* to have one dimension. We also ignore the lower bound when reading, * dimension and no nulls. We also ignore the lower bound when reading,
* and set it to one when writing. * and set it to one when writing.
* *
* CAUTION: as of PostgreSQL 7.1, these arrays are toastable (just like all * CAUTION: as of PostgreSQL 7.1, these arrays are toastable (just like all
...@@ -100,16 +100,6 @@ typedef ArrayType Acl; ...@@ -100,16 +100,6 @@ typedef ArrayType Acl;
#define ACL_N_SIZE(N) (ARR_OVERHEAD_NONULLS(1) + ((N) * sizeof(AclItem))) #define ACL_N_SIZE(N) (ARR_OVERHEAD_NONULLS(1) + ((N) * sizeof(AclItem)))
#define ACL_SIZE(ACL) ARR_SIZE(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 * fmgr macros for these types
*/ */
...@@ -123,13 +113,6 @@ typedef ArrayType IdList; ...@@ -123,13 +113,6 @@ typedef ArrayType IdList;
#define PG_GETARG_ACL_P_COPY(n) DatumGetAclPCopy(PG_GETARG_DATUM(n)) #define PG_GETARG_ACL_P_COPY(n) DatumGetAclPCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_ACL_P(x) PG_RETURN_POINTER(x) #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 * ACL modification opcodes for aclupdate
*/ */
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -3241,8 +3241,7 @@ exec_assign_value(PLpgSQL_execstate * estate, ...@@ -3241,8 +3241,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
int i; int i;
PLpgSQL_expr *subscripts[MAXDIM]; PLpgSQL_expr *subscripts[MAXDIM];
int subscriptvals[MAXDIM]; int subscriptvals[MAXDIM];
bool havenullsubscript, bool oldarrayisnull;
oldarrayisnull;
Oid arraytypeid, Oid arraytypeid,
arrayelemtypeid; arrayelemtypeid;
int16 arraytyplen, int16 arraytyplen,
...@@ -3295,9 +3294,9 @@ exec_assign_value(PLpgSQL_execstate * estate, ...@@ -3295,9 +3294,9 @@ exec_assign_value(PLpgSQL_execstate * estate,
arraytyplen = get_typlen(arraytypeid); 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++) for (i = 0; i < nsubscripts; i++)
{ {
bool subisnull; bool subisnull;
...@@ -3306,43 +3305,39 @@ exec_assign_value(PLpgSQL_execstate * estate, ...@@ -3306,43 +3305,39 @@ exec_assign_value(PLpgSQL_execstate * estate,
exec_eval_integer(estate, exec_eval_integer(estate,
subscripts[nsubscripts - 1 - i], subscripts[nsubscripts - 1 - i],
&subisnull); &subisnull);
havenullsubscript |= subisnull; if (subisnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("array subscript in assignment must not be NULL")));
} }
/* /* Coerce source value to match array element type. */
* Skip the assignment if we have any nulls in the subscripts coerced_value = exec_simple_cast_value(value,
* or the righthand side. This is pretty bogus but it valtype,
* corresponds to the current behavior of ExecEvalArrayRef(). arrayelemtypeid,
*/ -1,
if (havenullsubscript || *isNull) *isNull);
return;
/* /*
* If the original array is null, cons up an empty array so * If the original array is null, cons up an empty array so
* that the assignment can proceed; we'll end with a * that the assignment can proceed; we'll end with a
* one-element array containing just the assigned-to * one-element array containing just the assigned-to
* subscript. This only works for varlena arrays, though; for * subscript. This only works for varlena arrays, though; for
* fixed-length array types we skip the assignment. Again, * fixed-length array types we skip the assignment. We can't
* this corresponds to the current behavior of * 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(). * ExecEvalArrayRef().
*/ */
if (oldarrayisnull) if (arraytyplen > 0 && /* fixed-length array? */
{ (oldarrayisnull || *isNull))
if (arraytyplen > 0) /* fixed-length array? */
return; return;
if (oldarrayisnull)
oldarrayval = construct_empty_array(arrayelemtypeid); oldarrayval = construct_empty_array(arrayelemtypeid);
}
else else
oldarrayval = (ArrayType *) DatumGetPointer(oldarraydatum); 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. * Build the modified array value.
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment