1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Update of contrib stuff from massimo.

This commit is contained in:
Bruce Momjian
1997-11-05 21:38:25 +00:00
parent 5aaf00f3f3
commit 951986c550
33 changed files with 2547 additions and 578 deletions

62
contrib/array/Makefile Normal file
View File

@ -0,0 +1,62 @@
#-------------------------------------------------------------------------
#
# Makefile--
# Makefile for array iterator functions.
#
#-------------------------------------------------------------------------
PGDIR = ../..
SRCDIR = $(PGDIR)/src
include $(SRCDIR)/Makefile.global
INCLUDE_OPT = -I ./ \
-I $(SRCDIR)/ \
-I $(SRCDIR)/include \
-I $(SRCDIR)/port/$(PORTNAME)
CFLAGS += $(INCLUDE_OPT)
ifeq ($(PORTNAME), linux)
ifdef LINUX_ELF
ifeq ($(CC), gcc)
CFLAGS += -fPIC
endif
endif
endif
ifeq ($(PORTNAME), i386_solaris)
CFLAGS+= -fPIC
endif
MODNAME = array_iterator
MODULE = $(MODNAME)$(DLSUFFIX)
all: module sql
module: $(MODULE)
sql: $(MODNAME).sql
install: $(MODULE)
cp -p $(MODULE) $(LIBDIR)
cd $(LIBDIR); strip $(MODULE)
%.sql: %.sql.in
sed "s|MODULE_PATHNAME|$(LIBDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX)
%$(DLSUFFIX): %.c
cc $(CFLAGS) -shared -o $@ $<
depend dep:
$(CC) -MM $(INCLUDE_OPT) *.c >depend
clean:
rm -f $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend))
include depend
endif

View File

@ -1,30 +1,12 @@
/*
* array_iterator.c --
*
* This file defines a new group of operators which take an
* This file defines a new class of operators which take an
* array and a scalar value, iterate a scalar operator over the
* elements of the array and the value and compute a result as
* the logical OR or AND of the results.
* For example array_int4eq returns true if some of the elements
* of an array of int4 is equal to the given value:
* the logical OR or AND of the iteration results.
*
* array_int4eq({1,2,3}, 1) --> true
* array_int4eq({1,2,3}, 4) --> false
*
* If we have defined T array types and O scalar operators
* we can define T x O array operators, each of them has a name
* like "array_<basetype><operation>" and takes an array of type T
* iterating the operator O over all the elements. Note however
* that some of the possible combination are invalid, for example
* the array_int4_like because there is no like operator for int4.
* It is now possible to write queries which look inside the arrays:
*
* create table t(id int4[], txt text[]);
* select * from t where t.id *= 123;
* select * from t where t.txt *~ '[a-z]';
* select * from t where t.txt[1:3] **~ '[a-z]';
*
* Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
* Copyright (c) 1997, Massimo Dal Zotto <dz@cs.unitn.it>
*/
#include <ctype.h>
@ -33,242 +15,297 @@
#include <string.h>
#include "postgres.h"
#include "pg_type.h"
#include "miscadmin.h"
#include "syscache.h"
#include "access/xact.h"
#include "backend/fmgr.h"
#include "catalog/pg_type.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/elog.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "array_iterator.h"
static int32
array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
{
HeapTuple typ_tuple;
TypeTupleForm typ_struct;
bool typbyval;
int typlen;
func_ptr proc_fn;
int pronargs;
int nitems,
i,
result;
int ndim,
*dim;
char *p;
HeapTuple typ_tuple;
TypeTupleForm typ_struct;
bool typbyval;
int typlen;
func_ptr proc_fn;
int pronargs;
int nitems, i, result;
int ndim, *dim;
char *p;
/* Sanity checks */
if ((array == (ArrayType *) NULL)
|| (ARR_IS_LO(array) == true))
{
/* elog(NOTICE, "array_iterator: array is null"); */
return (0);
}
ndim = ARR_NDIM(array);
dim = ARR_DIMS(array);
nitems = getNitems(ndim, dim);
if (nitems == 0)
{
/* elog(NOTICE, "array_iterator: nitems = 0"); */
return (0);
}
/* Sanity checks */
if ((array == (ArrayType *) NULL)
|| (ARR_IS_LO(array) == true)) {
/* elog(NOTICE, "array_iterator: array is null"); */
return (0);
}
ndim = ARR_NDIM(array);
dim = ARR_DIMS(array);
nitems = getNitems(ndim, dim);
if (nitems == 0) {
/* elog(NOTICE, "array_iterator: nitems = 0"); */
return (0);
}
/* Lookup element type information */
typ_tuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(elemtype), 0, 0, 0);
if (!HeapTupleIsValid(typ_tuple))
{
elog(WARN, "array_iterator: cache lookup failed for type %d", elemtype);
return 0;
}
typ_struct = (TypeTupleForm) GETSTRUCT(typ_tuple);
typlen = typ_struct->typlen;
typbyval = typ_struct->typbyval;
/* Lookup element type information */
typ_tuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(elemtype),0,0,0);
if (!HeapTupleIsValid(typ_tuple)) {
elog(WARN,"array_iterator: cache lookup failed for type %d", elemtype);
return 0;
}
typ_struct = (TypeTupleForm) GETSTRUCT(typ_tuple);
typlen = typ_struct->typlen;
typbyval = typ_struct->typbyval;
/* Lookup the function entry point */
proc_fn == (func_ptr) NULL;
fmgr_info(proc, &proc_fn, &pronargs);
if ((proc_fn == NULL) || (pronargs != 2))
{
elog(WARN, "array_iterator: fmgr_info lookup failed for oid %d", proc);
return (0);
}
/* Lookup the function entry point */
proc_fn = (func_ptr) NULL;
fmgr_info(proc, &proc_fn, &pronargs);
if ((proc_fn == NULL) || (pronargs != 2)) {
elog(WARN, "array_iterator: fmgr_info lookup failed for oid %d", proc);
return (0);
}
/* Scan the array and apply the operator to each element */
result = 0;
p = ARR_DATA_PTR(array);
for (i = 0; i < nitems; i++)
{
if (typbyval)
{
switch (typlen)
{
case 1:
result = (int) (*proc_fn) (*p, value);
break;
case 2:
result = (int) (*proc_fn) (*(int16 *) p, value);
break;
case 3:
case 4:
result = (int) (*proc_fn) (*(int32 *) p, value);
break;
}
p += typlen;
}
else
{
result = (int) (*proc_fn) (p, value);
if (typlen > 0)
{
p += typlen;
}
else
{
p += INTALIGN(*(int32 *) p);
}
}
if (result)
{
if (!and)
{
return (1);
}
}
else
{
if (and)
{
return (0);
}
}
}
if (and && result)
{
/* Scan the array and apply the operator to each element */
result = 0;
p = ARR_DATA_PTR(array);
for (i = 0; i < nitems; i++) {
if (typbyval) {
switch(typlen) {
case 1:
result = (int) (*proc_fn)(*p, value);
break;
case 2:
result = (int) (*proc_fn)(* (int16 *) p, value);
break;
case 3:
case 4:
result = (int) (*proc_fn)(* (int32 *) p, value);
break;
}
p += typlen;
} else {
result = (int) (*proc_fn)(p, value);
if (typlen > 0) {
p += typlen;
} else {
p += INTALIGN(* (int32 *) p);
}
}
if (result) {
if (!and) {
return (1);
}
else
{
}
} else {
if (and) {
return (0);
}
}
}
if (and && result) {
return (1);
} else {
return (0);
}
}
/*
* Iterators for type _text
* Iterator functions for type _text
*/
int32
array_texteq(ArrayType *array, char *value)
array_texteq(ArrayType *array, char* value)
{
return array_iterator((Oid) 25, /* text */
(Oid) 67, /* texteq */
0, /* logical or */
array, (Datum) value);
return array_iterator((Oid) 25, /* text */
(Oid) 67, /* texteq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_texteq(ArrayType *array, char *value)
array_all_texteq(ArrayType *array, char* value)
{
return array_iterator((Oid) 25, /* text */
(Oid) 67, /* texteq */
1, /* logical and */
array, (Datum) value);
return array_iterator((Oid) 25, /* text */
(Oid) 67, /* texteq */
1, /* logical and */
array, (Datum)value);
}
int32
array_textregexeq(ArrayType *array, char *value)
array_textregexeq(ArrayType *array, char* value)
{
return array_iterator((Oid) 25, /* text */
(Oid) 81, /* textregexeq */
0, /* logical or */
array, (Datum) value);
return array_iterator((Oid) 25, /* text */
(Oid) 1254, /* textregexeq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_textregexeq(ArrayType *array, char *value)
array_all_textregexeq(ArrayType *array, char* value)
{
return array_iterator((Oid) 25, /* text */
(Oid) 81, /* textregexeq */
1, /* logical and */
array, (Datum) value);
return array_iterator((Oid) 25, /* text */
(Oid) 1254, /* textregexeq */
1, /* logical and */
array, (Datum)value);
}
/*
* Iterators for type _char16. Note that the regexp operators
* take the second argument of type text.
* Iterator functions for type _char16. Note that the regexp
* operators take the second argument of type text.
*/
int32
array_char16eq(ArrayType *array, char *value)
array_char16eq(ArrayType *array, char* value)
{
return array_iterator((Oid) 20, /* char16 */
(Oid) 490, /* char16eq */
0, /* logical or */
array, (Datum) value);
return array_iterator((Oid) 20, /* char16 */
(Oid) 1275, /* char16eq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_char16eq(ArrayType *array, char *value)
array_all_char16eq(ArrayType *array, char* value)
{
return array_iterator((Oid) 20, /* char16 */
(Oid) 490, /* char16eq */
1, /* logical and */
array, (Datum) value);
return array_iterator((Oid) 20, /* char16 */
(Oid) 1275, /* char16eq */
1, /* logical and */
array, (Datum)value);
}
int32
array_char16regexeq(ArrayType *array, char *value)
array_char16regexeq(ArrayType *array, char* value)
{
return array_iterator((Oid) 20, /* char16 */
(Oid) 700, /* char16regexeq */
0, /* logical or */
array, (Datum) value);
return array_iterator((Oid) 20, /* char16 */
(Oid) 1288, /* char16regexeq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_char16regexeq(ArrayType *array, char *value)
array_all_char16regexeq(ArrayType *array, char* value)
{
return array_iterator((Oid) 20, /* char16 */
(Oid) 700, /* char16regexeq */
1, /* logical and */
array, (Datum) value);
return array_iterator((Oid) 20, /* char16 */
(Oid) 1288, /* char16regexeq */
1, /* logical and */
array, (Datum)value);
}
/*
* Iterators for type _int4
* Iterator functions for type _int4
*/
int32
array_int4eq(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 65, /* int4eq */
0, /* logical or */
array, (Datum) value);
return array_iterator((Oid) 23, /* int4 */
(Oid) 65, /* int4eq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_int4eq(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 65, /* int4eq */
1, /* logical and */
array, (Datum) value);
return array_iterator((Oid) 23, /* int4 */
(Oid) 65, /* int4eq */
1, /* logical and */
array, (Datum)value);
}
int32
array_int4ne(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 144, /* int4ne */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_int4ne(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 144, /* int4ne */
1, /* logical and */
array, (Datum)value);
}
int32
array_int4gt(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 147, /* int4gt */
0, /* logical or */
array, (Datum) value);
return array_iterator((Oid) 23, /* int4 */
(Oid) 147, /* int4gt */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_int4gt(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 147, /* int4gt */
1, /* logical and */
array, (Datum) value);
return array_iterator((Oid) 23, /* int4 */
(Oid) 147, /* int4gt */
1, /* logical and */
array, (Datum)value);
}
int32
array_int4ge(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 150, /* int4ge */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_int4ge(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 150, /* int4ge */
1, /* logical and */
array, (Datum)value);
}
int32
array_int4lt(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 66, /* int4lt */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_int4lt(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 66, /* int4lt */
1, /* logical and */
array, (Datum)value);
}
int32
array_int4le(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 149, /* int4le */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_int4le(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 149, /* int4le */
1, /* logical and */
array, (Datum)value);
}
/* end of file */

View File

@ -1,26 +1,44 @@
From: Massimo Dal Zotto <dz@cs.unitn.it>
Date: Mon, 6 May 1996 01:03:37 +0200 (MET DST)
Subject: [PG95]: new operators for arrays
Array iterator functions, by Massimo Dal Zotto <dz@cs.unitn.it>
- -----BEGIN PGP SIGNED MESSAGE-----
This loadable module defines a new class of functions which take
an array and a scalar value, iterate a scalar operator over the
elements of the array and the value, and compute a result as
the logical OR or AND of the iteration results.
For example array_int4eq returns true if some of the elements
of an array of int4 is equal to the given value:
Hi,
array_int4eq({1,2,3}, 1) --> true
array_int4eq({1,2,3}, 4) --> false
I have written an extension to Postgres95 which allows to use qualification
clauses based on the values of single elements of arrays.
For example I can now select rows having some or all element of an array
If we have defined T array types and O scalar operators we can
define T x O x 2 array functions, each of them has a name like
"array_[all_]<basetype><operation>" and takes an array of type T
iterating the operator O over all the elements. Note however
that some of the possible combination are invalid, for example
the array_int4_like because there is no like operator for int4.
We can then define new operators based on these functions and use
them to write queries with qualification clauses based on the
values of some of the elements of an array.
For example to select rows having some or all element of an array
attribute equal to a given value or matching a regular expression:
select * from t where t.foo *= 'bar';
select * from t where t.foo **~ '^ba[rz]';
create table t(id int4[], txt text[]);
The scheme is quite general, each operator which operates on a base type can
be iterated over the elements of an array. It seem to work well but defining
each new operators requires writing a different C function. Furthermore in
each function there are two hardcoded OIDs which reference a base type and
a procedure. Not very portable. Can anyone suggest a better and more portable
way to do it ? Do you think this could be a useful feature for next release ?
Here is my code, it can be compiled and loaded as a dynamic module without
need to recompile the backend. I have defined only the few operators I needed,
the list can be extended. Feddback is welcome.
-- select tuples with some id element equal to 123
select * from t where t.id *= 123;
-- select tuples with some txt element matching '[a-z]'
select * from t where t.txt *~ '[a-z]';
-- select tuples with all txt elements matching '^[A-Z]'
select * from t where t.txt[1:3] **~ '^[A-Z]';
The scheme is quite general, each operator which operates on a base type
can be iterated over the elements of an array. It seem to work well but
defining each new operators requires writing a different C function.
Furthermore in each function there are two hardcoded OIDs which reference
a base type and a procedure. Not very portable. Can anyone suggest a
better and more portable way to do it ?
See also array_iterator.sql for an example on how to use this module.

View File

@ -0,0 +1,27 @@
#ifndef ARRAY_ITERATOR_H
#define ARRAY_ITERATOR_H
static int32 array_iterator(Oid elemtype, Oid proc, int and,
ArrayType *array, Datum value);
int32 array_texteq(ArrayType *array, char* value);
int32 array_all_texteq(ArrayType *array, char* value);
int32 array_textregexeq(ArrayType *array, char* value);
int32 array_all_textregexeq(ArrayType *array, char* value);
int32 array_char16eq(ArrayType *array, char* value);
int32 array_all_char16eq(ArrayType *array, char* value);
int32 array_char16regexeq(ArrayType *array, char* value);
int32 array_all_char16regexeq(ArrayType *array, char* value);
int32 array_int4eq(ArrayType *array, int4 value);
int32 array_all_int4eq(ArrayType *array, int4 value);
int32 array_int4ne(ArrayType *array, int4 value);
int32 array_all_int4ne(ArrayType *array, int4 value);
int32 array_int4gt(ArrayType *array, int4 value);
int32 array_all_int4gt(ArrayType *array, int4 value);
int32 array_int4ge(ArrayType *array, int4 value);
int32 array_all_int4ge(ArrayType *array, int4 value);
int32 array_int4lt(ArrayType *array, int4 value);
int32 array_all_int4lt(ArrayType *array, int4 value);
int32 array_int4le(ArrayType *array, int4 value);
int32 array_all_int4le(ArrayType *array, int4 value);
#endif

View File

@ -0,0 +1,191 @@
-- SQL code to define the new array iterator functions and operators
-- define the array operators *=, **=, *~ and **~ for type _text
--
create function array_texteq(_text, text) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_texteq(_text, text) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_textregexeq(_text, text) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_textregexeq(_text, text) returns bool
as 'MODULE_PATHNAME'
language 'c';
create operator *= (
leftarg=_text,
rightarg=text,
procedure=array_texteq);
create operator **= (
leftarg=_text,
rightarg=text,
procedure=array_all_texteq);
create operator *~ (
leftarg=_text,
rightarg=text,
procedure=array_textregexeq);
create operator **~ (
leftarg=_text,
rightarg=text,
procedure=array_all_textregexeq);
-- define the array operators *=, **=, *~ and **~ for type _char16
--
create function array_char16eq(_char16, char16) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_char16eq(_char16, char16) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_char16regexeq(_char16, text) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_char16regexeq(_char16, text) returns bool
as 'MODULE_PATHNAME'
language 'c';
create operator *= (
leftarg=_char16,
rightarg=char16,
procedure=array_char16eq);
create operator **= (
leftarg=_char16,
rightarg=char16,
procedure=array_all_char16eq);
create operator *~ (
leftarg=_char16,
rightarg=text,
procedure=array_char16regexeq);
create operator **~ (
leftarg=_char16,
rightarg=text,
procedure=array_all_char16regexeq);
-- define the array operators *=, **=, *> and **> for type _int4
--
create function array_int4eq(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_int4eq(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_int4ne(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_int4ne(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_int4gt(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_int4gt(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_int4ge(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_int4ge(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_int4lt(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_int4lt(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_int4le(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create function array_all_int4le(_int4, int4) returns bool
as 'MODULE_PATHNAME'
language 'c';
create operator *= (
leftarg=_int4,
rightarg=int4,
procedure=array_int4eq);
create operator **= (
leftarg=_int4,
rightarg=int4,
procedure=array_all_int4eq);
create operator *<> (
leftarg=_int4,
rightarg=int4,
procedure=array_int4ne);
create operator **<> (
leftarg=_int4,
rightarg=int4,
procedure=array_all_int4ne);
create operator *> (
leftarg=_int4,
rightarg=int4,
procedure=array_int4gt);
create operator **> (
leftarg=_int4,
rightarg=int4,
procedure=array_all_int4gt);
create operator *>= (
leftarg=_int4,
rightarg=int4,
procedure=array_int4ge);
create operator **>= (
leftarg=_int4,
rightarg=int4,
procedure=array_all_int4ge);
create operator *< (
leftarg=_int4,
rightarg=int4,
procedure=array_int4lt);
create operator **< (
leftarg=_int4,
rightarg=int4,
procedure=array_all_int4lt);
create operator *<= (
leftarg=_int4,
rightarg=int4,
procedure=array_int4le);
create operator **<= (
leftarg=_int4,
rightarg=int4,
procedure=array_all_int4le);
-- end of file