8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.75 2000/07/22 03:34:27 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.76 2000/07/23 01:35:58 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -64,18 +64,30 @@ static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
64
64
static Datum ExecMakeFunctionResult (Node * node ,List * arguments ,
65
65
ExprContext * econtext ,bool * isNull ,bool * isDone );
66
66
67
- /*
67
+ /*----------
68
68
* ExecEvalArrayRef
69
69
*
70
70
* This function takes an ArrayRef and returns the extracted Datum
71
71
* if it's a simple reference, or the modified array value if it's
72
- * an array assignment (read array element insertion).
72
+ * an array assignment (i.e., array element or slice insertion).
73
+ *
74
+ * NOTE: if we get a NULL result from a subexpression, we return NULL when
75
+ * it's an array reference, or the unmodified source array when it's an
76
+ * array assignment. This may seem peculiar, but if we return NULL (as was
77
+ * done in versions up through 7.0) then an assignment like
78
+ *UPDATE table SET arrayfield[4] = NULL
79
+ * will result in setting the whole array to NULL, which is certainly not
80
+ * very desirable. By returning the source array we make the assignment
81
+ * into a no-op, instead. (Eventually we need to redesign arrays so that
82
+ * individual elements can be NULL, but for now, let's try to protect users
83
+ * from shooting themselves in the foot.)
73
84
*
74
85
* NOTE: we deliberately refrain from applying DatumGetArrayTypeP() here,
75
86
* even though that might seem natural, because this code needs to support
76
87
* both varlena arrays and fixed-length array types. DatumGetArrayTypeP()
77
88
* only works for the varlena kind. The routines we call in arrayfuncs.c
78
89
* have to know the difference (that's what they need refattrlength for).
90
+ *----------
79
91
*/
80
92
static Datum
81
93
ExecEvalArrayRef (ArrayRef * arrayRef ,
@@ -85,6 +97,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
85
97
{
86
98
ArrayType * array_source ;
87
99
ArrayType * resultArray ;
100
+ bool isAssignment = (arrayRef -> refassgnexpr != NULL );
88
101
List * elt ;
89
102
int i = 0 ,
90
103
j = 0 ;
@@ -102,15 +115,19 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
102
115
econtext ,
103
116
isNull ,
104
117
isDone ));
105
- /* If refexpr yields NULL, result is always NULL, for now anyway */
118
+ /*
119
+ * If refexpr yields NULL, result is always NULL, for now anyway.
120
+ * (This means you cannot assign to an element or slice of an array
121
+ * that's NULL; it'll just stay NULL.)
122
+ */
106
123
if (* isNull )
107
124
return (Datum )NULL ;
108
125
}
109
126
else
110
127
{
111
128
112
129
/*
113
- *Null refexpr indicates we are doing an INSERT into an array
130
+ *Empty refexpr indicates we are doing an INSERT into an array
114
131
* column. For now, we just take the refassgnexpr (which the
115
132
* parser will have ensured is an array value) and return it
116
133
* as-is, ignoring any subscripts that may have been supplied in
@@ -130,9 +147,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
130
147
econtext ,
131
148
isNull ,
132
149
& dummy ));
133
- /* If any index expr yields NULL, result is NULL */
150
+ /* If any index expr yields NULL, result is NULLor source array */
134
151
if (* isNull )
135
- return (Datum )NULL ;
152
+ {
153
+ if (!isAssignment || array_source == NULL )
154
+ return (Datum )NULL ;
155
+ * isNull = false;
156
+ return PointerGetDatum (array_source );
157
+ }
136
158
}
137
159
138
160
if (arrayRef -> reflowerindexpr != NIL )
@@ -147,9 +169,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
147
169
econtext ,
148
170
isNull ,
149
171
& dummy ));
150
- /* If any index expr yields NULL, result is NULL */
172
+ /* If any index expr yields NULL, result is NULLor source array */
151
173
if (* isNull )
152
- return (Datum )NULL ;
174
+ {
175
+ if (!isAssignment || array_source == NULL )
176
+ return (Datum )NULL ;
177
+ * isNull = false;
178
+ return PointerGetDatum (array_source );
179
+ }
153
180
}
154
181
if (i != j )
155
182
elog (ERROR ,
@@ -159,18 +186,26 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
159
186
else
160
187
lIndex = NULL ;
161
188
162
- if (arrayRef -> refassgnexpr != NULL )
189
+ if (isAssignment )
163
190
{
164
191
Datum sourceData = ExecEvalExpr (arrayRef -> refassgnexpr ,
165
192
econtext ,
166
193
isNull ,
167
194
& dummy );
168
- /* For now, can't cope with inserting NULL into an array */
195
+ /*
196
+ * For now, can't cope with inserting NULL into an array,
197
+ * so make it a no-op per discussion above...
198
+ */
169
199
if (* isNull )
170
- return (Datum )NULL ;
200
+ {
201
+ if (array_source == NULL )
202
+ return (Datum )NULL ;
203
+ * isNull = false;
204
+ return PointerGetDatum (array_source );
205
+ }
171
206
172
207
if (array_source == NULL )
173
- return sourceData ;/* XXX do something else? */
208
+ return sourceData ;/* XXX do something else? */
174
209
175
210
if (lIndex == NULL )
176
211
resultArray = array_set (array_source ,i ,