8000 More merge's from Dr. George's sourec tree · postgrespro/postgres_cluster@668aa24 · GitHub
[go: up one dir, main page]

Skip to content

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

8000
Appearance settings

Commit 668aa24

Browse files
committed
More merge's from Dr. George's sourec tree
1 parent 772ae26 commit 668aa24

16 files changed

+1615
-0
lines changed

src/extend/array/array_iterator.c

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
/*
2+
* array_iterator.c --
3+
*
4+
* This file defines a new group of operators which take an
5+
* array and a scalar value, iterate a scalar operator over the
6+
* elements of the array and the value and compute a result as
7+
* the logical OR or AND of the results.
8+
* For example array_int4eq returns true if some of the elements
9+
* of an array of int4 is equal to the given value:
10+
*
11+
* array_int4eq({1,2,3}, 1) --> true
12+
* array_int4eq({1,2,3}, 4) --> false
13+
*
14+
* If we have defined T array types and O scalar operators
15+
* we can define T x O array operators, each of them has a name
16+
* like "array_<basetype><operation>" and takes an array of type T
17+
* iterating the operator O over all the elements. Note however
18+
* that some of the possible combination are invalid, for example
19+
* the array_int4_like because there is no like operator for int4.
20+
* It is now possible to write queries which look inside the arrays:
21+
*
22+
* create table t(id int4[], txt text[]);
23+
* select * from t where t.id *= 123;
24+
* select * from t where t.txt *~ '[a-z]';
25+
* select * from t where t.txt[1:3] **~ '[a-z]';
26+
*
27+
* Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
28+
*/
29+
30+
#include <ctype.h>
31+
#include <stdio.h>
32+
#include <sys/types.h>
33+
#include <string.h>
34+
35+
#include "postgres.h"
36+
#include "pg_type.h"
37+
#include "miscadmin.h"
38+
#include "syscache.h"
39+
#include "access/xact.h"
40+
#include "utils/builtins.h"
41+
#include "utils/elog.h"
42+
43+
static int32
44+
array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
45+
{
46+
HeapTuple typ_tuple;
47+
TypeTupleForm typ_struct;
48+
bool typbyval;
49+
int typlen;
50+
func_ptr proc_fn;
51+
int pronargs;
52+
int nitems, i, result;
53+
int ndim, *dim;
54+
char *p;
55+
56+
/* Sanity checks */
57+
if ((array == (ArrayType *) NULL)
58+
|| (ARR_IS_LO(array) == true)) {
59+
/* elog(NOTICE, "array_iterator: array is null"); */
60+
return (0);
61+
}
62+
ndim = ARR_NDIM(array);
63+
dim = ARR_DIMS(array);
64+
nitems = getNitems(ndim, dim);
65+
if (nitems == 0) {
66+
/* elog(NOTICE, "array_iterator: nitems = 0"); */
67+
return (0);
68+
}
69+
70+
/* Lookup element type information */
71+
typ_tuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(elemtype),0,0,0);
72+
if (!HeapTupleIsValid(typ_tuple)) {
73+
elog(WARN,"array_iterator: cache lookup failed for type %d", elemtype);
74+
return 0;
75+
}
76+
typ_struct = (TypeTupleForm) GETSTRUCT(typ_tuple);
77+
typlen = 1E0A typ_struct->typlen;
78+
typbyval = typ_struct->typbyval;
79+
80+
/* Lookup the function entry point */
81+
proc_fn == (func_ptr) NULL;
82+
fmgr_info(proc, &proc_fn, &pronargs);
83+
if ((proc_fn == NULL) || (pronargs != 2)) {
84+
elog(WARN, "array_iterator: fmgr_info lookup failed for oid %d", proc);
85+
return (0);
86+
}
87+
88+
/* Scan the array and apply the operator to each element */
89+
result = 0;
90+
p = ARR_DATA_PTR(array);
91+
for (i = 0; i < nitems; i++) {
92+
if (typbyval) {
93+
switch(typlen) {
94+
case 1:
95+
result = (int) (*proc_fn)(*p, value);
96+
break;
97+
case 2:
98+
result = (int) (*proc_fn)(* (int16 *) p, value);
99+
break;
100+
case 3:
101+
case 4:
102+
result = (int) (*proc_fn)(* (int32 *) p, value);
103+
break;
104+
}
105+
p += typlen;
106+
} else {
107+
result = (int) (*proc_fn)(p, value);
108+
if (typlen > 0) {
109+
p += typlen;
110+
} else {
111+
p += INTALIGN(* (int32 *) p);
112+
}
113+
}
114+
if (result) {
115+
if (!and) {
116+
return (1);
117+
}
118+
} else {
119+
if (and) {
120+
return (0);
121+
}
122+
}
123+
}
124+
125+
if (and && result) {
126+
return (1);
127+
} else {
128+
return (0);
129+
}
130+
}
131+
132+
/*
133+
* Iterators for type _text
134+
*/
135+
136+
int32
137+
array_texteq(ArrayType *array, char* value)
138+
{
139+
return array_iterator((Oid) 25, /* text */
140+
(Oid) 67, /* texteq */
141+
0, /* logical or */
142+
array, (Datum)value);
143+
}
144+
145+
int32
146+
array_all_texteq(ArrayType *array, char* value)
147+
{
148+
return array_iterator((Oid) 25, /* text */
149+
(Oid) 67, /* texteq */
150+
1, /* logical and */
151+
array, (Datum)value);
152+
}
153+
154+
int32
155+
array_textregexeq(ArrayType *array, char* value)
156+
{
157+
return array_iterator((Oid) 25, /* text */
158+
(Oid) 81, /* textregexeq */
159+
0, /* logical or */
160+
array, (Datum)value);
161+
}
162+
163+
int32
164+
array_all_textregexeq(ArrayType *array, char* value)
165+
{
166+
return array_iterator((Oid) 25, /* text */
167+
(Oid) 81, /* textregexeq */
168+
1, /* logical and */
169+
array, (Datum)value);
170+
}
171+
172+
/*
173+
* Iterators for type _char16. Note that the regexp operators
174+
* take the second argument of type text.
175+
*/
176+
177+
int32
178+
array_char16eq(ArrayType *array, char* value)
179+
{
180+
return array_iterator((Oid) 20, /* char16 */
181+
(Oid) 490, /* char16eq */
182+
0, /* logical or */
183+
array, (Datum)value);
184+
}
185+
186+
int32
187+
array_all_char16eq(ArrayType *array, char* value)
188+
{
189+
return array_iterator((Oid) 20, /* char16 */
190+
(Oid) 490, /* char16eq */
191+
1, /* logical and */
192+
array, (Datum)value);
193+
}
194+
195+
int32
196+
array_char16regexeq(ArrayType *array, char* value)
197+
{
198+
return array_iterator((Oid) 20, /* char16 */
199+
(Oid) 700, /* char16regexeq */
200+
0, /* logical or */
201+
array, (Datum)value);
202+
}
203+
204+
int32
205+
array_all_char16regexeq(ArrayType *array, char* value)
206+
{
207+
return array_iterator((Oid) 20, /* char16 */
208+
(Oid) 700, /* char16regexeq */
209+
1, /* logical and */
210+
array, (Datum)value);
211+
}
212+
213+
/*
214+
* Iterators for type _int4
215+
*/
216+
217+
int32
218+
array_int4eq(ArrayType *array, int4 value)
219+
{
220+
return array_iterator((Oid) 23, /* int4 */
221+
(Oid) 65, /* int4eq */
222+
0, /* logical or */
223+
array, (Datum)value);
224+
}
225+
226+
int32
227+
array_all_int4eq(ArrayType *array, int4 value)
228+
{
229+
return array_iterator((Oid) 23, /* int4 */
230+
(Oid) 65, /* int4eq */
231+
1, /* logical and */
232+
array, (Datum)value);
233+
}
234+
235+
int32
236+
array_int4gt(ArrayType *array, int4 value)
237+
{
238+
return array_iterator((Oid) 23, /* int4 */
239+
(Oid) 147, /* int4gt */
240+
0, /* logical or */
241+
array, (Datum)value);
242+
}
243+
244+
int32
245+
array_all_int4gt(ArrayType *array, int4 value)
246+
{
247+
return array_iterator((Oid) 23, /* int4 */
248+
(Oid) 147, /* int4gt */
249+
1, /* logical and */
250+
array, (Datum)value);
251+
}

src/extend/array/array_iterator.doc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
From: Massimo Dal Zotto <dz@cs.unitn.it>
2+
Date: Mon, 6 May 1996 01:03:37 +0200 (MET DST)
3+
Subject: [PG95]: new operators for arrays
4+
5+
- -----BEGIN PGP SIGNED MESSAGE-----
6+
7+
Hi,
8+
9+
I have written an extension to Postgres95 which allows to use qualification
10+
clauses based on the values of single elements of arrays.
11+
For example I can now select rows having some or all element of an array
12+
attribute equal to a given value or matching a regular expression:
13+
14+
select * from t where t.foo *= 'bar';
15+
select * from t where t.foo **~ '^ba[rz]';
16+
17+
The scheme is quite general, each operator which operates on a base type can
18+
be iterated over the elements of an array. It seem to work well but defining
19+
each new operators requires writing a different C function. Furthermore in
20+
each function there are two hardcoded OIDs which reference a base type and
21+
a procedure. Not very portable. Can anyone suggest a better and more portable
22+
way to do it ? Do you think this could be a useful feature for next release ?
23+
Here is my code, it can be compiled and loaded as a dynamic module without
24+
need to recompile the backend. I have defined only the few operators I needed,
25+
the list can be extended. Feddback is welcome.
26+

0 commit comments

Comments
 (0)
0