mirror of https://github.com/postgres/postgres
parent
c6cf21825a
commit
5eb17f53b6
@ -1,251 +0,0 @@ |
||||
/*
|
||||
* array_iterator.c -- |
||||
* |
||||
* This file defines a new group 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: |
||||
* |
||||
* 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> |
||||
*/ |
||||
|
||||
#include <ctype.h> |
||||
#include <stdio.h> |
||||
#include <sys/types.h> |
||||
#include <string.h> |
||||
|
||||
#include "postgres.h" |
||||
#include "pg_type.h" |
||||
#include "miscadmin.h" |
||||
#include "syscache.h" |
||||
#include "access/xact.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/elog.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; |
||||
|
||||
/* 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 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) { |
||||
return (1); |
||||
} else { |
||||
return (0); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Iterators for type _text |
||||
*/ |
||||
|
||||
int32 |
||||
array_texteq(ArrayType *array, char* value) |
||||
{ |
||||
return array_iterator((Oid) 25, /* text */ |
||||
(Oid) 67, /* texteq */ |
||||
0, /* logical or */ |
||||
array, (Datum)value); |
||||
} |
||||
|
||||
int32 |
||||
array_all_texteq(ArrayType *array, char* value) |
||||
{ |
||||
return array_iterator((Oid) 25, /* text */ |
||||
(Oid) 67, /* texteq */ |
||||
1, /* logical and */ |
||||
array, (Datum)value); |
||||
} |
||||
|
||||
int32 |
||||
array_textregexeq(ArrayType *array, char* value) |
||||
{ |
||||
return array_iterator((Oid) 25, /* text */ |
||||
(Oid) 81, /* textregexeq */ |
||||
0, /* logical or */ |
||||
array, (Datum)value); |
||||
} |
||||
|
||||
int32 |
||||
array_all_textregexeq(ArrayType *array, char* value) |
||||
{ |
||||
return array_iterator((Oid) 25, /* text */ |
||||
(Oid) 81, /* textregexeq */ |
||||
1, /* logical and */ |
||||
array, (Datum)value); |
||||
} |
||||
|
||||
/*
|
||||
* Iterators for type _char16. Note that the regexp operators |
||||
* take the second argument of type text. |
||||
*/ |
||||
|
||||
int32 |
||||
array_char16eq(ArrayType *array, char* value) |
||||
{ |
||||
return array_iterator((Oid) 20, /* char16 */ |
||||
(Oid) 490, /* char16eq */ |
||||
0, /* logical or */ |
||||
array, (Datum)value); |
||||
} |
||||
|
||||
int32 |
||||
array_all_char16eq(ArrayType *array, char* value) |
||||
{ |
||||
return array_iterator((Oid) 20, /* char16 */ |
||||
(Oid) 490, /* char16eq */ |
||||
1, /* logical and */ |
||||
array, (Datum)value); |
||||
} |
||||
|
||||
int32 |
||||
array_char16regexeq(ArrayType *array, char* value) |
||||
{ |
||||
return array_iterator((Oid) 20, /* char16 */ |
||||
(Oid) 700, /* char16regexeq */ |
||||
0, /* logical or */ |
||||
array, (Datum)value); |
||||
} |
||||
|
||||
int32 |
||||
array_all_char16regexeq(ArrayType *array, char* value) |
||||
{ |
||||
return array_iterator((Oid) 20, /* char16 */ |
||||
(Oid) 700, /* char16regexeq */ |
||||
1, /* logical and */ |
||||
array, (Datum)value); |
||||
} |
||||
|
||||
/*
|
||||
* Iterators 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); |
||||
} |
||||
|
||||
int32 |
||||
array_all_int4eq(ArrayType *array, int4 value) |
||||
{ |
||||
return array_iterator((Oid) 23, /* int4 */ |
||||
(Oid) 65, /* int4eq */ |
||||
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); |
||||
} |
||||
|
||||
int32 |
||||
array_all_int4gt(ArrayType *array, int4 value) |
||||
{ |
||||
return array_iterator((Oid) 23, /* int4 */ |
||||
(Oid) 147, /* int4gt */ |
||||
1, /* logical and */ |
||||
array, (Datum)value); |
||||
} |
@ -1,26 +0,0 @@ |
||||
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 |
||||
|
||||
- -----BEGIN PGP SIGNED MESSAGE----- |
||||
|
||||
Hi, |
||||
|
||||
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 |
||||
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]'; |
||||
|
||||
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. |
||||
|
@ -1,137 +0,0 @@ |
||||
/* |
||||
* SQL code |
||||
|
||||
- - -- load the new functions |
||||
- - -- |
||||
load '/home/dz/lib/postgres/array_iterator.so'; |
||||
|
||||
- - -- define the array operators *=, **=, *~ and **~ for type _text |
||||
- - -- |
||||
create function array_texteq(_text, text) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
language 'c'; |
||||
|
||||
create function array_all_texteq(_text, text) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
language 'c'; |
||||
|
||||
create function array_textregexeq(_text, text) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
language 'c'; |
||||
|
||||
create function array_all_textregexeq(_text, text) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
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 '/home/dz/lib/postgres/array_iterator.so' |
||||
language 'c'; |
||||
|
||||
create function array_all_char16eq(_char16, char16) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
language 'c'; |
||||
|
||||
create function array_char16regexeq(_char16, text) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
language 'c'; |
||||
|
||||
create function array_all_char16regexeq(_char16, text) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
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 '/home/dz/lib/postgres/array_iterator.so' |
||||
language 'c'; |
||||
|
||||
create function array_all_int4eq(_int4, int4) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
language 'c'; |
||||
|
||||
create function array_int4gt(_int4, int4) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
language 'c'; |
||||
|
||||
create function array_all_int4gt(_int4, int4) |
||||
returns bool |
||||
as '/home/dz/lib/postgres/array_iterator.so' |
||||
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_int4gt); |
||||
|
||||
create operator **> ( |
||||
leftarg=_int4, |
||||
rightarg=int4, |
||||
procedure=array_all_int4gt); |
||||
|
||||
*/ |
||||
|
||||
/* end of file */ |
||||
|
@ -1,147 +0,0 @@ |
||||
/*
|
||||
* datetime_functions.c -- |
||||
* |
||||
* This file defines new functions for the time and date data types. |
||||
* |
||||
* Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it> |
||||
*/ |
||||
|
||||
#include <time.h> |
||||
|
||||
#include "postgres.h" |
||||
#include "pg_type.h" |
||||
#include "utils/palloc.h" |
||||
|
||||
typedef struct DateADT { |
||||
char day; |
||||
char month; |
||||
short year; |
||||
} DateADT; |
||||
|
||||
typedef struct TimeADT { |
||||
short hr; |
||||
short min; |
||||
float sec; |
||||
} TimeADT; |
||||
|
||||
TimeADT * |
||||
time_difference(TimeADT *time1, TimeADT *time2) |
||||
{ |
||||
TimeADT *time = (TimeADT*)palloc(sizeof(TimeADT)); |
||||
|
||||
time->sec = time1->sec - time2->sec; |
||||
time->min = time1->min - time2->min; |
||||
time->hr = time1->hr - time2->hr; |
||||
|
||||
if (time->sec < 0) { |
||||
time->sec += 60.0; |
||||
time->min--; |
||||
} else if (time->sec >= 60.0) { |
||||
time->sec -= 60.0; |
||||
time->min++; |
||||
} |
||||
|
||||
if (time->min < 0) { |
||||
time->min += 60; |
||||
time->hr--; |
||||
} else if (time->min >= 60) { |
||||
time->min -= 60; |
||||
time->hr++; |
||||
} |
||||
|
||||
if (time->hr < 0) { |
||||
time->hr += 24; |
||||
} else if (time->hr >= 24) { |
||||
time->hr -= 24; |
||||
} |
||||
|
||||
return (time); |
||||
} |
||||
|
||||
TimeADT * |
||||
currentTime() |
||||
{ |
||||
time_t current_time; |
||||
struct tm *tm; |
||||
TimeADT *result = (TimeADT*)palloc(sizeof(TimeADT)); |
||||
|
||||
current_time = time(NULL); |
||||
tm = localtime(¤t_time); |
||||
result->sec = tm->tm_sec; |
||||
result->min = tm->tm_min; |
||||
result->hr = tm->tm_hour; |
||||
|
||||
return (result); |
||||
} |
||||
|
||||
int4 |
||||
currentDate() |
||||
{ |
||||
time_t current_time; |
||||
struct tm *tm; |
||||
int4 result; |
||||
DateADT *date = (DateADT*)&result; |
||||
|
||||
current_time = time(NULL); |
||||
tm = localtime(¤t_time); |
||||
date->day = tm->tm_mday; |
||||
date->month = tm->tm_mon+1; |
||||
date->year = tm->tm_year+1900; |
||||
|
||||
return (result); |
||||
} |
||||
|
||||
int4 |
||||
hours(TimeADT *time) |
||||
{ |
||||
return (time->hr); |
||||
} |
||||
|
||||
int4 |
||||
minutes(TimeADT *time) |
||||
{ |
||||
return (time->min); |
||||
} |
||||
|
||||
int4 |
||||
seconds(TimeADT *time) |
||||
{ |
||||
int seconds = (int)time->sec; |
||||
return (seconds); |
||||
} |
||||
|
||||
int4 |
||||
day(int4 val) |
||||
{ |
||||
DateADT *date = (DateADT*)&val; |
||||
return (date->day); |
||||
} |
||||
|
||||
int4 |
||||
month(int4 val) |
||||
{ |
||||
DateADT *date = (DateADT*)&val; |
||||
return (date->month); |
||||
} |
||||
|
||||
int4 |
||||
year(int4 val) |
||||
{ |
||||
DateADT *date = (DateADT*)&val; |
||||
return (date->year); |
||||
} |
||||
|
||||
int4 |
||||
asMinutes(TimeADT *time) |
||||
{ |
||||
int seconds = (int)time->sec; |
||||
return (time->min + 60*time->hr); |
||||
} |
||||
|
||||
int4 |
||||
asSeconds(TimeADT *time) |
||||
{ |
||||
int seconds = (int)time->sec; |
||||
return (seconds + 60*time->min + 3600*time->hr); |
||||
} |
||||
|
@ -1,25 +0,0 @@ |
||||
From: Massimo Dal Zotto <dz@cs.unitn.it> |
||||
Date: Tue, 14 May 1996 14:31:18 +0200 (MET DST) |
||||
Subject: [PG95]: new postgres functions |
||||
|
||||
- -----BEGIN PGP SIGNED MESSAGE----- |
||||
|
||||
Some time ago I read in the mailing list requests of people looking |
||||
for more time and date functions. I have now written some of them: |
||||
|
||||
time_difference(time1, time2) ,also defined as operator '-' |
||||
hour(time) |
||||
minutes(time) |
||||
seconds(time) |
||||
asMinutes(time) |
||||
asSeconds(time) |
||||
currentTime() |
||||
currentDate() |
||||
|
||||
The file can be compiled as shared library and loaded as dynamic module |
||||
without need to recompile the backend. This can also be taken as an example |
||||
of the extensibility of postgres (user-defined functions, operators, etc). |
||||
I would be nice to see more of these user contributed modules posted to this |
||||
list and hopefully accessible from the Postgres home page. |
||||
|
||||
|
@ -1,69 +0,0 @@ |
||||
|
||||
-- SQL code to load and define 'datetime' functions |
||||
|
||||
-- load the new functions |
||||
|
||||
load '/home/dz/lib/postgres/datetime_functions.so'; |
||||
|
||||
-- define the new functions in postgres |
||||
|
||||
create function time_difference(time,time) |
||||
returns time |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function currentDate() |
||||
returns date |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function currentTime() |
||||
returns time |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function hours(time) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function minutes(time) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function seconds(time) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function day(date) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function month(date) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function year(date) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function asMinutes(time) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create function asSeconds(time) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/datetime_functions.so' |
||||
language 'c'; |
||||
|
||||
create operator - ( |
||||
leftarg=time, |
||||
rightarg=time, |
||||
procedure=time_difference); |
||||
|
@ -1,83 +0,0 @@ |
||||
/*****************************************************************************/ |
||||
/* soundex.c */ |
||||
/*****************************************************************************/ |
||||
|
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include "postgres.h" /* for char16, etc. */ |
||||
#include "utils/palloc.h" /* for palloc */ |
||||
#include "libpq-fe.h" /* for TUPLE */ |
||||
#include <stdio.h> |
||||
#include <ctype.h> |
||||
|
||||
/* prototype for soundex function */ |
||||
char *soundex(char *instr, char *outstr); |
||||
|
||||
text *text_soundex(text *t) |
||||
{ |
||||
/* ABCDEFGHIJKLMNOPQRSTUVWXYZ */ |
||||
char *table = "01230120022455012623010202"; |
||||
int count = 0; |
||||
text *new_t; |
||||
|
||||
char outstr[6+1]; /* max length of soundex is 6 */ |
||||
char *instr; |
||||
|
||||
/* make a null-terminated string */ |
||||
instr=palloc(VARSIZE(t)+1); |
||||
memcpy(instr,VARDATA(t),VARSIZE(t)-VARHDRSZ); |
||||
instr[VARSIZE(t)-VARHDRSZ] = (char)0; |
||||
|
||||
/* load soundex into outstr */ |
||||
soundex(instr, outstr); |
||||
|
||||
/* Now the outstr contains the soundex of instr */ |
||||
/* copy outstr to new_t */ |
||||
new_t = (text *) palloc(strlen(outstr)+VARHDRSZ); |
||||
memset(new_t, 0, strlen(outstr)+1); |
||||
VARSIZE(new_t) = strlen(outstr)+VARHDRSZ; |
||||
memcpy((void *) VARDATA(new_t), |
||||
(void *) outstr, |
||||
strlen(outstr)); |
||||
|
||||
/* free instr */ |
||||
pfree(instr); |
||||
|
||||
return(new_t); |
||||
} |
||||
|
||||
char *soundex(char *instr, char *outstr) |
||||
{ /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */ |
||||
char *table = "01230120022455012623010202"; |
||||
int count = 0; |
||||
|
||||
while(!isalpha(instr[0]) && instr[0]) |
||||
++instr; |
||||
|
||||
if(!instr[0]) { /* Hey! Where'd the string go? */ |
||||
outstr[0]=(char)0; |
||||
return outstr; |
||||
} |
||||
|
||||
if(toupper(instr[0]) == 'P' && toupper(instr[1]) == 'H') { |
||||
instr[0] = 'F'; |
||||
instr[1] = 'A'; |
||||
} |
||||
|
||||
*outstr++ = (char)toupper(*instr++); |
||||
|
||||
while(*instr && count < 5) { |
||||
if(isalpha(*instr) && *instr != *(instr-1)) { |
||||
*outstr = table[toupper(instr[0]) - 'A']; |
||||
if(*outstr != '0') { |
||||
++outstr; |
||||
++count; |
||||
} |
||||
} |
||||
++instr; |
||||
} |
||||
|
||||
*outstr = '\0'; |
||||
return(outstr); |
||||
} |
||||
|
@ -1,57 +0,0 @@ |
||||
--------------- soundex.sql: |
||||
|
||||
CREATE FUNCTION text_soundex(text) RETURNS text |
||||
AS '/usr/local/postgres/postgres95/src/funcs/soundex.so' LANGUAGE 'c'; |
||||
|
||||
SELECT text_soundex('hello world!'); |
||||
|
||||
CREATE TABLE s (nm text)\g |
||||
|
||||
insert into s values ('john')\g |
||||
insert into s values ('joan')\g |
||||
insert into s values ('wobbly')\g |
||||
|
||||
select * from s |
||||
where text_soundex(nm) = text_soundex('john')\g |
||||
|
||||
select nm from s a, s b |
||||
where text_soundex(a.nm) = text_soundex(b.nm) |
||||
and a.oid <> b.oid\g |
||||
|
||||
CREATE FUNCTION text_sx_eq(text, text) RETURNS bool AS |
||||
'select text_soundex($1) = text_soundex($2)' |
||||
LANGUAGE 'sql'\g |
||||
|
||||
CREATE FUNCTION text_sx_lt(text,text) RETURNS bool AS |
||||
'select text_soundex($1) < text_soundex($2)' |
||||
LANGUAGE 'sql'\g |
||||
|
||||
CREATE FUNCTION text_sx_gt(text,text) RETURNS bool AS |
||||
'select text_soundex($1) > text_soundex($2)' |
||||
LANGUAGE 'sql'; |
||||
|
||||
CREATE FUNCTION text_sx_le(text,text) RETURNS bool AS |
||||
'select text_soundex($1) <= text_soundex($2)' |
||||
LANGUAGE 'sql'; |
||||
|
||||
CREATE FUNCTION text_sx_ge(text,text) RETURNS bool AS |
||||
'select text_soundex($1) >= text_soundex($2)' |
||||
LANGUAGE 'sql'; |
||||
|
||||
CREATE FUNCTION text_sx_ne(text,text) RETURNS bool AS |
||||
'select text_soundex($1) <> text_soundex($2)' |
||||
LANGUAGE 'sql'; |
||||
|
||||
DROP OPERATOR #= (text,text)\g |
||||
|
||||
CREATE OPERATOR #= (leftarg=text, rightarg=text, procedure=text_sx_eq, |
||||
commutator=text_sx_eq)\g |
||||
|
||||
SELECT * |
||||
FROM s |
||||
WHERE text_sx_eq(nm,'john')\g |
||||
|
||||
SELECT * |
||||
from s |
||||
where s.nm #= 'john'; |
||||
|
@ -1,361 +0,0 @@ |
||||
/*
|
||||
* string_io.c -- |
||||
* |
||||
* This file defines new input/output conversion routines for strings. |
||||
* |
||||
* Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it> |
||||
*/ |
||||
|
||||
#include <ctype.h> |
||||
#include <string.h> |
||||
|
||||
#include "postgres.h" |
||||
#include "utils/elog.h" |
||||
#include "utils/palloc.h" |
||||
#include "utils/builtins.h" |
||||
|
||||
/* define this if you want to see iso-8859 characters */ |
||||
#define ISO8859 |
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y)) |
||||
#define VALUE(char) ((char) - '0') |
||||
#define DIGIT(val) ((val) + '0') |
||||
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7')) |
||||
#ifndef ISO8859 |
||||
#define NOTPRINTABLE(c) (!isprint(c)) |
||||
#else |
||||
#define NOTPRINTABLE(c) (!isprint(c) && ((c) < 0xa0)) |
||||
#endif |
||||
|
||||
/*
|
||||
* string_output() -- |
||||
* |
||||
* This function takes a pointer to a string data and an optional |
||||
* data size and returns a printable representation of the data |
||||
* translating all escape sequences to C-like \nnn or \c escapes. |
||||
* The function is used by output methods of various string types. |
||||
* |
||||
* Arguments: |
||||
* data - input data (can be NULL) |
||||
* size - optional size of data. A negative value indicates |
||||
* that data is a null terminated string. |
||||
* |
||||
* Returns: |
||||
* a pointer to a new string containing the printable |
||||
* representation of data. |
||||
*/ |
||||
|
||||
char * |
||||
string_output(char *data, int size) |
||||
{ |
||||
register unsigned char c, *p, *r, *result; |
||||
register int l, len; |
||||
|
||||
if (data == NULL) { |
||||
result = (char *) palloc(2); |
||||
result[0] = '-'; |
||||
result[1] = '\0'; |
||||
return (result); |
||||
} |
||||
|
||||
if (size < 0) { |
||||
size = strlen(data); |
||||
} |
||||
|
||||
/* adjust string length for escapes */ |
||||
len = size; |
||||
for (p=data,l=size; l>0; p++,l--) { |
||||
switch (*p) { |
||||
case '\\': |
||||
case '"' : |
||||
case '{': |
||||
case '}': |
||||
case '\b': |
||||
case '\f': |
||||
case '\n': |
||||
case '\r': |
||||
case '\t': |
||||
case '\v': |
||||
len++; |
||||
break; |
||||
default: |
||||
if (NOTPRINTABLE(c)) { |
||||
len += 3; |
||||
} |
||||
} |
||||
} |
||||
len++; |
||||
|
||||
result = (char *) palloc(len); |
||||
|
||||
for (p=data,r=result,l=size; (l > 0) && (c = *p); p++,l--) { |
||||
switch (c) { |
||||
case '\\': |
||||
case '"' : |
||||
case '{': |
||||
case '}': |
||||
*r++ = '\\'; |
||||
*r++ = c; |
||||
break; |
||||
case '\b': |
||||
*r++ = '\\'; |
||||
*r++ = 'b'; |
||||
break; |
||||
case '\f': |
||||
*r++ = '\\'; |
||||
*r++ = 'f'; |
||||
break; |
||||
case '\n': |
||||
*r++ = '\\'; |
||||
*r++ = 'n'; |
||||
break; |
||||
case '\r': |
||||
*r++ = '\\'; |
||||
*r++ = 'r'; |
||||
break; |
||||
case '\t': |
||||
*r++ = '\\'; |
||||
*r++ = 't'; |
||||
break; |
||||
case '\v': |
||||
*r++ = '\\'; |
||||
*r++ = 'v'; |
||||
break; |
||||
default: |
||||
if (NOTPRINTABLE(c)) { |
||||
*r = '\\'; |
||||
r += 3; |
||||
*r-- = DIGIT(c & 07); |
||||
c >>= 3; |
||||
*r-- = DIGIT(c & 07); |
||||
c >>= 3; |
||||
*r = DIGIT(c & 03); |
||||
r += 3; |
||||
} else { |
||||
*r++ = c; |
||||
} |
||||
} |
||||
} |
||||
*r = '\0'; |
||||
|
||||
return((char *) result); |
||||
} |
||||
|
||||
/*
|
||||
* string_input() -- |
||||
* |
||||
* This function accepts a C string in input and copies it into a new
|
||||
* object allocated with palloc() translating all escape sequences. |
||||
* An optional header can be allocatd before the string, for example |
||||
* to hold the length of a varlena object. |
||||
* This function is not necessary for input from sql commands because |
||||
* the parser already does escape translation, all data input routines |
||||
* receive strings in internal form. |
||||
* |
||||
* Arguments: |
||||
* str - input string possibly with escapes |
||||
* size - the required size of new data. A value of 0 |
||||
* indicates a variable size string, while a |
||||
* negative value indicates a variable size string |
||||
* of size not greater than this absolute value. |
||||
* hdrsize - size of an optional header to be allocated before |
||||
* the data. It must then be filled by the caller. |
||||
* rtn_size - an optional pointer to an int variable where the |
||||
* size of the new string is stored back. |
||||
* |
||||
* Returns: |
||||
* a pointer to the new string or the header. |
||||
*/ |
||||
|
||||
char * |
||||
string_input(char *str, int size, int hdrsize, int *rtn_size) |
||||
{ |
||||
register unsigned char *p, *r; |
||||
unsigned char *result; |
||||
int len; |
||||
|
||||
if ((str == NULL) || (hdrsize < 0)) { |
||||
return (char *) NULL; |
||||
} |
||||
|
||||
/* Compute result size */ |
||||
len = strlen(str); |
||||
for (p=str; *p; ) { |
||||
if (*p++ == '\\') { |
||||
if (ISOCTAL(*p)) { |
||||
if (ISOCTAL(*(p+1))) { |
||||
p++; |
||||
len--; |
||||
} |
||||
if (ISOCTAL(*(p+1))) { |
||||
p++; |
||||
len--; |
||||
} |
||||
} |
||||
if (*p) p++; |
||||
len--; |
||||
} |
||||
} |
||||
|
||||
/* result has variable length */ |
||||
if (size == 0) { |
||||
size = len+1; |
||||
} else |
||||
|
||||
/* result has variable length with maximum size */ |
||||
if (size < 0) { |
||||
size = MIN(len, - size)+1; |
||||
} |
||||
|
||||
result = (char *) palloc(hdrsize+size); |
||||
memset(result, 0, hdrsize+size); |
||||
if (rtn_size) { |
||||
*rtn_size = size; |
||||
} |
||||
|
||||
r = result + hdrsize; |
||||
for (p=str; *p; ) { |
||||
register unsigned char c; |
||||
if ((c = *p++) == '\\') { |
||||
switch (c = *p++) { |
||||
case '\0': |
||||
p--; |
||||
break; |
||||
case '0': |
||||
case '1': |
||||
case '2': |
||||
case '3': |
||||
case '4': |
||||
case '5': |
||||
case '6': |
||||
case '7': |
||||
c = VALUE(c); |
||||
if (isdigit(*p)) { |
||||
c = (c<<3) + VALUE(*p++); |
||||
} |
||||
if (isdigit(*p)) { |
||||
c = (c<<3) + VALUE(*p++); |
||||
} |
||||
*r++ = c; |
||||
break; |
||||
case 'b': |
||||
*r++ = '\b'; |
||||
break; |
||||
case 'f': |
||||
*r++ = '\f'; |
||||
break; |
||||
case 'n': |
||||
*r++ = '\n'; |
||||
break; |
||||
case 'r': |
||||
*r++ = '\r'; |
||||
break; |
||||
case 't': |
||||
*r++ = '\t'; |
||||
break; |
||||
case 'v': |
||||
*r++ = '\v'; |
||||
break; |
||||
default: |
||||
*r++ = c; |
||||
} |
||||
} else { |
||||
*r++ = c; |
||||
} |
||||
} |
||||
|
||||
return((char *) result); |
||||
} |
||||
|
||||
char * |
||||
c_charout(int32 c) |
||||
{ |
||||
char str[2]; |
||||
|
||||
str[0] = (char) c; |
||||
str[1] = '\0'; |
||||
|
||||
return (string_output(str, 1)); |
||||
} |
||||
|
||||
char * |
||||
c_char2out(uint16 s) |
||||
{ |
||||
return (string_output((char *) &s, 2)); |
||||
} |
||||
|
||||
char * |
||||
c_char4out(uint32 s) |
||||
{ |
||||
return (string_output((char *) &s, 4)); |
||||
} |
||||
|
||||
char * |
||||
c_char8out(char *s) |
||||
{ |
||||
return (string_output(s, 8)); |
||||
} |
||||
|
||||
char * |
||||
c_char16out(char *s) |
||||
{ |
||||
return (string_output(s, 16)); |
||||
} |
||||
|
||||
/*
|
||||
* This can be used for text, bytea, SET and unknown data types |
||||
*/ |
||||
|
||||
char * |
||||
c_textout(struct varlena *vlena) |
||||
{ |
||||
int len = 0; |
||||
char *s = NULL; |
||||
|
||||
if (vlena) { |
||||
len = VARSIZE(vlena) - VARHDRSZ; |
||||
s = VARDATA(vlena); |
||||
} |
||||
return (string_output(s, len)); |
||||
} |
||||
|
||||
/*
|
||||
* This can be used for varchar and bpchar strings |
||||
*/ |
||||
|
||||
char * |
||||
c_varcharout(char *s) |
||||
{ |
||||
int len; |
||||
|
||||
if (s) { |
||||
len = *(int32*)s - 4; |
||||
s += 4; |
||||
} |
||||
return (string_output(s, len)); |
||||
} |
||||
|
||||
#ifdef 0 |
||||
struct varlena * |
||||
c_textin(char *str) |
||||
{ |
||||
struct varlena *result; |
||||
int len; |
||||
|
||||
if (str == NULL) { |
||||
return ((struct varlena *) NULL); |
||||
} |
||||
|
||||
result = (struct varlena *) string_input(str, 0, VARHDRSZ, &len); |
||||
VARSIZE(result) = len; |
||||
|
||||
return (result); |
||||
} |
||||
|
||||
char * |
||||
c_char16in(char *str) |
||||
{ |
||||
return (string_input(str, 16, 0, NULL)); |
||||
} |
||||
#endif |
||||
|
@ -1,111 +0,0 @@ |
||||
|
||||
- - -- load the new functions |
||||
- - -- |
||||
load '/home/dz/lib/postgres/string_output.so'; |
||||
|
||||
- - -- create function c_textin(opaque) |
||||
- - -- returns text |
||||
- - -- as '/home/dz/lib/postgres/string_output.so' |
||||
- - -- language 'c'; |
||||
|
||||
create function c_charout(opaque) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/string_output.so' |
||||
language 'c'; |
||||
|
||||
create function c_char2out(opaque) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/string_output.so' |
||||
language 'c'; |
||||
|
||||
create function c_char4out(opaque) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/string_output.so' |
||||
language 'c'; |
||||
|
||||
create function c_char8out(opaque) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/string_output.so' |
||||
language 'c'; |
||||
|
||||
create function c_char16out(opaque) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/string_output.so' |
||||
language 'c'; |
||||
|
||||
create function c_textout(opaque) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/string_output.so' |
||||
language 'c'; |
||||
|
||||
create function c_varcharout(opaque) |
||||
returns int4 |
||||
as '/home/dz/lib/postgres/string_output.so' |
||||
language 'c'; |
||||
|
||||
- - -- define a function which sets the new output routines for char types |
||||
- - -- |
||||
- - -- select c_mode(); |
||||
- - -- |
||||
create function c_mode() |
||||
returns text |
||||
as 'update pg_type set typoutput=''c_charout'' where typname=''char''\; |
||||
update pg_type set typoutput=''c_char2out'' where typname=''char2''\; |
||||
update pg_type set typoutput=''c_char4out'' where typname=''char4''\; |
||||
update pg_type set typoutput=''c_char8out'' where typname=''char8''\; |
||||
update pg_type set typoutput=''c_char16out'' where typname=''char16''\; |
||||
update pg_type set typoutput=''c_textout'' where typname=''text''\; |
||||
update pg_type set typoutput=''c_textout'' where typname=''bytea''\; |
||||
update pg_type set typoutput=''c_textout'' where typname=''unknown''\; |
||||
update pg_type set typoutput=''c_textout'' where typname=''SET''\; |
||||
update pg_type set typoutput=''c_varcharout'' where typname=''varchar''\; |
||||
update pg_type set typoutput=''c_varcharout'' where typname=''bpchar''\; |
||||
select ''c_mode''::text' |
||||
language 'sql'; |
||||
|
||||
- - -- define a function which restores the original routines for char types |
||||
- - -- |
||||
- - -- select pg_mode(); |
||||
- - -- |
||||
create function pg_mode() |
||||
returns text |
||||
as 'update pg_type set typoutput=''charout'' where typname=''char''\; |
||||
update pg_type set typoutput=''char2out'' where typname=''char2''\; |
||||
update pg_type set typoutput=''char4out'' where typname=''char4''\; |
||||
update pg_type set typoutput=''char8out'' where typname=''char8''\; |
||||
update pg_type set typoutput=''char16out'' where typname=''char16''\; |
||||
update pg_type set typoutput=''textout'' where typname=''text''\; |
||||
update pg_type set typoutput=''textout'' where typname=''bytea''\; |
||||
update pg_type set typoutput=''textout'' where typname=''unknown''\; |
||||
update pg_type set typoutput=''textout'' where typname=''SET''\; |
||||
update pg_type set typoutput=''varcharout'' where typname=''varchar''\; |
||||
update pg_type set typoutput=''varcharout'' where typname=''bpchar''\; |
||||
select ''pg_mode''::text' |
||||
language 'sql'; |
||||
|
||||
- - -- or do the changes manually |
||||
- - -- |
||||
- - -- update pg_type set typoutput='charout' where typname='char'; |
||||
- - -- update pg_type set typoutput='char2out' where typname='char2'; |
||||
- - -- update pg_type set typoutput='char4out' where typname='char4'; |
||||
- - -- update pg_type set typoutput='char8out' where typname='char8'; |
||||
- - -- update pg_type set typoutput='char16out' where typname='char16'; |
||||
- - -- update pg_type set typoutput='textout' where typname='text'; |
||||
- - -- update pg_type set typoutput='textout' where typname='bytea'; |
||||
- - -- update pg_type set typoutput='textout' where typname='unknown'; |
||||
- - -- update pg_type set typoutput='textout' where typname='SET'; |
||||
- - -- update pg_type set typoutput='varcharout' where typname='varchar'; |
||||
- - -- update pg_type set typoutput='varcharout' where typname='bpchar'; |
||||
- - -- |
||||
- - -- update pg_type set typoutput='c_charout' where typname='char'; |
||||
- - -- update pg_type set typoutput='c_char2out' where typname='char2'; |
||||
- - -- update pg_type set typoutput='c_char4out' where typname='char4'; |
||||
- - -- update pg_type set typoutput='c_char8out' where typname='char8'; |
||||
- - -- update pg_type set typoutput='c_char16out' where typname='char16'; |
||||
- - -- update pg_type set typoutput='c_textout' where typname='text'; |
||||
- - -- update pg_type set typoutput='c_textout' where typname='bytea'; |
||||
- - -- update pg_type set typoutput='c_textout' where typname='unknown'; |
||||
- - -- update pg_type set typoutput='c_textout' where typname='SET'; |
||||
- - -- update pg_type set typoutput='c_varcharout' where typname='varchar'; |
||||
- - -- update pg_type set typoutput='c_varcharout' where typname='bpchar'; |
||||
|
Loading…
Reference in new issue