mirror of https://github.com/postgres/postgres
parent
82c4733116
commit
f7f177d372
@ -1,94 +1,81 @@ |
||||
This directory contains the contribution functions or tools. |
||||
|
||||
--------------------------------------------------------------------------- |
||||
The PostgreSQL contrib tree |
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
||||
apache_logging - |
||||
Getting Apache to log to PostgreSQL |
||||
by Terry Mackintosh <terry@terrym.com> |
||||
FIXME: |
||||
os2client |
||||
odbc |
||||
spi/preprocessor |
||||
tools |
||||
|
||||
|
||||
array - |
||||
Array iterator functions |
||||
by Massimo Dal Zotto <dz@cs.unitn.it> |
||||
- in each directory must be Makefile, possible Makefile template |
||||
is below this text, |
||||
|
||||
bit - |
||||
Bit type |
||||
by Adriaan Joubert <a.joubert@albourne.com> |
||||
-------- |
||||
# |
||||
# $Header: /cvsroot/pgsql/contrib/README,v 1.18 2000/06/15 18:54:29 momjian Exp $ |
||||
# |
||||
|
||||
datetime - |
||||
Date & time functions |
||||
by Massimo Dal Zotto <dz@cs.unitn.it> |
||||
TOPDIR=../.. |
||||
|
||||
earthdistance - |
||||
Operator for computing earth distance for two points |
||||
by Hal Snyder <hal@vailsys.com> |
||||
include ../Makefile.global |
||||
|
||||
findoidjoins - |
||||
Finds the joins used by oid columns by examining the actual |
||||
values in the oid columns and row oids. |
||||
by Bruce Momjian <root@candle.pha.pa.us> |
||||
NAME = some_name |
||||
|
||||
fulltextindex - |
||||
Full text indexing using triggers |
||||
by Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl> |
||||
PROGRAM = |
||||
OBJS = $(NAME).o |
||||
DOCS = $(NAME).doc |
||||
SQLS = $(NAME).sql |
||||
BINS = |
||||
EXAMPLES= |
||||
MODS = $(NAME)$(DLSUFFIX) |
||||
|
||||
isbn_issn - |
||||
PostgreSQL type extensions for ISBN (books) and ISSN (serials) |
||||
by Garrett A. Wollman <wollman@khavrinen.lcs.mit.edu> |
||||
CFLAGS += -I. $(CFLAGS_SL) |
||||
|
||||
likeplanning - |
||||
Scripts to enable/disable new planning code for LIKE and regexp |
||||
pattern match operators. These will go away again once the code |
||||
is mature enough to enable by default. |
||||
by Tom Lane <tgl@sss.pgh.pa.us> |
||||
OTHER_CLEAN = $(SQLS) |
||||
|
||||
linux - |
||||
Start postgres back end system |
||||
by Thomas Lockhart <lockhart@alumni.caltech.edu> |
||||
all: $(MODS) $(SQLS) |
||||
|
||||
lo - |
||||
Large Object maintenance |
||||
by Peter Mount <peter@retep.org.uk> |
||||
%.sql: %.sql.in |
||||
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@ |
||||
|
||||
miscutil - |
||||
Postgres assert checking and various utility functions |
||||
by Dal Zotto <dz@cs.unitn.it> |
||||
|
||||
mSQL-interface - |
||||
mSQL API translation library |
||||
by Aldrin Leal <aldrin@americasnet.com> |
||||
install: install_doc install_sql install_mod install_bin install_example |
||||
|
||||
noupdate - |
||||
trigger to prevent updates on single columns |
||||
install_doc: |
||||
for inst_file in $(DOCS); do \ |
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \ |
||||
done |
||||
|
||||
pg_dumplo - |
||||
Dump large objects |
||||
install_sql: |
||||
for inst_file in $(SQLS); do \ |
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \ |
||||
done |
||||
|
||||
soundex - |
||||
Prototype for soundex function |
||||
install_mod: |
||||
for inst_file in $(MODS); do \ |
||||
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \ |
||||
done |
||||
|
||||
spi - |
||||
A general trigger function autoinc() and so on. |
||||
install_bin: |
||||
for inst_file in $(BINS); do \ |
||||
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \ |
||||
done |
||||
|
||||
string - |
||||
C-like input/output conversion routines for strings |
||||
by Massimo Dal Zotto <dz@cs.unitn.it> |
||||
install_example: |
||||
for inst_file in $(EXAMPLES); do \ |
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_EXAMPLESDIR); \ |
||||
done |
||||
|
||||
tools - |
||||
Assorted developer tools |
||||
by Massimo Dal Zotto <dz@cs.unitn.it> |
||||
depend dep: |
||||
$(CC) -MM -MG $(CFLAGS) *.c > depend |
||||
|
||||
unixdate - |
||||
Conversions from integer to datetime |
||||
by Thomas Lockhart <lockhart@alumni.caltech.edu> |
||||
clean: |
||||
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log |
||||
|
||||
userlock - |
||||
User locks |
||||
by Massimo Dal Zotto <dz@cs.unitn.it> |
||||
|
||||
vacuumlo - |
||||
Remove orphaned large objects |
||||
by Peter T Mount <peter@retep.org.uk> |
||||
|
||||
pgbench - |
||||
TPC-B like benchmarking tool |
||||
by Tatsuo Ishii <t-ishii@sra.co.jp> |
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
||||
----------- |
||||
|
@ -1,3 +0,0 @@ |
||||
drop table access; |
||||
CREATE TABLE access (host char(200), ident char(200), authuser char(200), accdate datetime, request char(500), ttime int2, status int2, bytes int4) archive = none; |
||||
grant all on access to nobody; |
@ -1,12 +0,0 @@ |
||||
# This is mostly the same as the default, except for no square brakets around |
||||
# the time or the extra timezone info, also added the download time, 3rd from |
||||
# the end, number of seconds. |
||||
|
||||
LogFormat "insert into access values ( '%h', '%l', '%u', '%{%d/%b/%Y:%H:%M:%S}t', '%r', %T, %s, %b );" |
||||
|
||||
|
||||
# The above format ALMOST eleminates the need to use sed, except that I noticed |
||||
# that when a frameset page is called, then the bytes transfered is '-', which |
||||
# will choke the insert, so replaced it with '-1'. |
||||
|
||||
TransferLog '| su -c "sed \"s/, - );$/, -1 );/\" | /usr/local/pgsql/bin/psql www_log" nobody' |
@ -0,0 +1,49 @@ |
||||
Array iterator functions, by Massimo Dal Zotto <dz@cs.unitn.it> |
||||
Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it> |
||||
|
||||
This software is distributed under the GNU General Public License |
||||
either version 2, or (at your option) any later version. |
||||
|
||||
|
||||
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: |
||||
|
||||
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 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: |
||||
|
||||
create table t(id int4[], txt text[]); |
||||
|
||||
-- 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. |
@ -1,45 +0,0 @@ |
||||
# Makefile
|
||||
# For the bit/varbit data types
|
||||
|
||||
SRCDIR= ../../src
|
||||
|
||||
include $(SRCDIR)/Makefile.global |
||||
|
||||
INSTALLDIR= $(LIBDIR)
|
||||
MODDIR= $(INSTALLDIR)/modules
|
||||
SQLDIR= $(INSTALLDIR)/sql
|
||||
|
||||
TARGETS= varbit.sql varbit$(DLSUFFIX)
|
||||
# vartest
|
||||
SOURCE= varbit.c varbit_glue.c
|
||||
OBJ= $(SOURCE:.c=.o)
|
||||
CFLAGS += -g
|
||||
|
||||
all: $(TARGETS) |
||||
|
||||
vartest: varbit.o vartest.o |
||||
$(CC) -o $@ varbit.o vartest.o
|
||||
|
||||
install: |
||||
$(MAKE) all
|
||||
-test -d $(INSTALLDIR) || $(INSTALL) -d $(INSTALLDIR)
|
||||
-test -d ${MODDIR} || $(INSTALL) -d ${MODDIR}
|
||||
-test -d ${SQLDIR} || $(INSTALL) -d ${SQLDIR}
|
||||
$(INSTALL) -m 555 $(filter %$(DLSUFFIX), $(TARGETS)) $(MODDIR)
|
||||
$(INSTALL) -m 664 $(filter %.sql, $(TARGETS)) $(SQLDIR)
|
||||
|
||||
%.sql: %.source |
||||
if [ -z "$$USER" ]; then USER=$$LOGNAME; fi; \
|
||||
if [ -z "$$USER" ]; then USER=`whoami`; fi; \
|
||||
if [ -z "$$USER" ]; then echo 'Cannot deduce $$USER.'; exit 1; fi; \
|
||||
rm -f $@; \
|
||||
C=`pwd`; \
|
||||
O=${MODDIR}; \
|
||||
sed -e "s:_CWD_:$$C:g" \
|
||||
-e "s:_OBJWD_:$$O:g" \
|
||||
-e "s:_DLSUFFIX_:$(DLSUFFIX):g" \
|
||||
-e "s/_USER_/$$USER/g" < $< > $@
|
||||
|
||||
clean: |
||||
rm -f $(TARGETS) varbit.o
|
||||
|
@ -1,891 +0,0 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* varbit.c |
||||
* Functions for the built-in type bit() and varying bit(). |
||||
* |
||||
* IDENTIFICATION |
||||
* $Header: /cvsroot/pgsql/contrib/bit/Attic/varbit.c,v 1.3 2000/04/12 17:14:21 momjian Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "varbit.h" |
||||
#include "access/htup.h" |
||||
/*#include "catalog/pg_type.h" */ |
||||
/*#include "utils/builtins.h" */ |
||||
|
||||
|
||||
/*
|
||||
Prefixes: |
||||
zp -- zero-padded fixed length bit string |
||||
var -- varying bit string |
||||
|
||||
attypmod -- contains the length of the bit string in bits, or for |
||||
varying bits the maximum length. |
||||
|
||||
The data structure contains the following elements: |
||||
header -- length of the whole data structure (incl header) |
||||
in bytes. (as with all varying length datatypes) |
||||
data section -- private data section for the bits data structures |
||||
bitlength -- lenght of the bit string in bits |
||||
bitdata -- least significant byte first string |
||||
*/ |
||||
|
||||
/*
|
||||
* zpbitin - |
||||
|
||||
* converts a string to the internal representation of a bitstring. |
||||
* The length is determined by the number of bits required plus |
||||
* VARHDRSZ bytes or from atttypmod. |
||||
* (XXX dummy is here because we pass typelem as the second argument |
||||
* for array_in. copied this, no idea what it means??) |
||||
*/ |
||||
bits8 * |
||||
zpbitin(char *s, int dummy, int32 atttypmod) |
||||
{ |
||||
bits8 *result; /* the bits string that was read in */ |
||||
char *sp; /* pointer into the character string */ |
||||
bits8 *r; |
||||
int len, /* Length of the whole data structure */ |
||||
bitlen, /* Number of bits in the bit string */ |
||||
slen; /* Length of the input string */ |
||||
int bit_not_hex = 0;/* 0 = hex string 1=bit string */ |
||||
int bc, |
||||
ipad; |
||||
bits8 x = 0; |
||||
|
||||
|
||||
if (s == NULL) |
||||
return (bits8 *) NULL; |
||||
|
||||
/* Check that the first character is a b or an x */ |
||||
if (s[0] == 'b' || s[0] == 'B') |
||||
bit_not_hex = 1; |
||||
else if (s[0] == 'x' || s[0] == 'X') |
||||
bit_not_hex = 0; |
||||
else |
||||
elog(ERROR, "zpbitin: %s is not a valid bitstring", s); |
||||
|
||||
slen = strlen(s) - 1; |
||||
/* Determine bitlength from input string */ |
||||
bitlen = slen; |
||||
if (!bit_not_hex) |
||||
bitlen *= 4; |
||||
|
||||
/*
|
||||
* Sometimes atttypmod is not supplied. If it is supplied we need to |
||||
* make sure that the bitstring fits. Note that the number of infered |
||||
* bits can be larger than the number of actual bits needed, but only |
||||
* if we are reading a hex string and not by more than 3 bits, as a |
||||
* hex string gives and accurate length upto 4 bits |
||||
*/ |
||||
if (atttypmod == -1) |
||||
atttypmod = bitlen; |
||||
else if ((bitlen > atttypmod && bit_not_hex) || |
||||
(bitlen > atttypmod + 3 && !bit_not_hex)) |
||||
elog(ERROR, "zpbitin: bit string of size %d cannot be written into bits(%d)", |
||||
bitlen, atttypmod); |
||||
|
||||
|
||||
len = VARBITDATALEN(atttypmod); |
||||
|
||||
if (len > MaxAttrSize) |
||||
elog(ERROR, "zpbitin: length of bit() must be less than %ld", |
||||
(MaxAttrSize - VARHDRSZ - VARBITHDRSZ) * BITSPERBYTE); |
||||
|
||||
result = (bits8 *) palloc(len); |
||||
/* set to 0 so that *r is always initialised and strin is zero-padded */ |
||||
memset(result, 0, len); |
||||
VARSIZE(result) = len; |
||||
VARBITLEN(result) = atttypmod; |
||||
|
||||
/*
|
||||
* We need to read the bitstring from the end, as we store it least |
||||
* significant byte first. s points to the byte before the beginning |
||||
* of the bitstring |
||||
*/ |
||||
sp = s + 1; |
||||
r = VARBITS(result); |
||||
if (bit_not_hex) |
||||
{ |
||||
/* Parse the bit representation of the string */ |
||||
/* We know it fits, as bitlen was compared to atttypmod */ |
||||
x = BITHIGH; |
||||
for (bc = 0; sp != s + slen + 1; sp++, bc++) |
||||
{ |
||||
if (*sp == '1') |
||||
*r |= x; |
||||
if (bc == 7) |
||||
{ |
||||
bc = 0; |
||||
x = BITHIGH; |
||||
r++; |
||||
} |
||||
else |
||||
x >>= 1; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
/* Parse the hex representation of the string */ |
||||
for (bc = 0; sp != s + slen + 1; sp++) |
||||
{ |
||||
if (*sp >= '0' && *sp <= '9') |
||||
x = (bits8) (*sp - '0'); |
||||
else if (*sp >= 'A' && *sp <= 'F') |
||||
x = (bits8) (*sp - 'A') + 10; |
||||
else if (*sp >= 'a' && *sp <= 'f') |
||||
x = (bits8) (*sp - 'a') + 10; |
||||
else |
||||
elog(ERROR, "Cannot parse %c as a hex digit", *sp); |
||||
if (bc) |
||||
{ |
||||
bc = 0; |
||||
*r++ |= x; |
||||
} |
||||
else |
||||
{ |
||||
bc++; |
||||
*r = x << 4; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (bitlen > atttypmod) |
||||
{ |
||||
/* Check that this fitted */ |
||||
r = (bits8 *) (result + len - 1); |
||||
ipad = VARBITPAD(result); |
||||
|
||||
/*
|
||||
* The bottom ipad bits of the byte pointed to by r need to be |
||||
* zero |
||||
*/ |
||||
|
||||
/*
|
||||
* printf("Byte %X shift %X %d\n",*r,(*r << (8-ipad)) & BITMASK, |
||||
* (*r << (8-ipad)) & BITMASK > 0); |
||||
*/ |
||||
if (((*r << (BITSPERBYTE - ipad)) & BITMASK) > 0) |
||||
elog(ERROR, "zpbitin: bit string too large for bit(%d) data type", |
||||
atttypmod); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* zpbitout -
|
||||
* for the time being we print everything as hex strings, as this is likely |
||||
* to be more compact than bit strings, and consequently much more efficient |
||||
* for long strings |
||||
*/ |
||||
char * |
||||
zpbitout(bits8 *s) |
||||
{ |
||||
char *result, |
||||
*r; |
||||
bits8 *sp; |
||||
int i, |
||||
len, |
||||
bitlen; |
||||
|
||||
if (s == NULL) |
||||
{ |
||||
result = (char *) palloc(2); |
||||
result[0] = '-'; |
||||
result[1] = '\0'; |
||||
} |
||||
else |
||||
{ |
||||
bitlen = VARBITLEN(s); |
||||
len = bitlen / 4 + (bitlen % 4 > 0 ? 1 : 0); |
||||
result = (char *) palloc(len + 4); |
||||
sp = VARBITS(s); |
||||
r = result; |
||||
*r++ = 'X'; |
||||
*r++ = '\''; |
||||
/* we cheat by knowing that we store full bytes zero padded */ |
||||
for (i = 0; i < len; i += 2, sp++) |
||||
{ |
||||
*r++ = HEXDIG((*sp) >> 4); |
||||
*r++ = HEXDIG((*sp) & 0xF); |
||||
} |
||||
|
||||
/*
|
||||
* Go back one step if we printed a hex number that was not part |
||||
* of the bitstring anymore |
||||
*/ |
||||
if (i == len + 1) |
||||
r--; |
||||
*r++ = '\''; |
||||
*r = '\0'; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/* zpbitsout -
|
||||
* Prints the string a bits |
||||
*/ |
||||
char * |
||||
zpbitsout(bits8 *s) |
||||
{ |
||||
char *result, |
||||
*r; |
||||
bits8 *sp; |
||||
bits8 x; |
||||
int i, |
||||
k, |
||||
len; |
||||
|
||||
if (s == NULL) |
||||
{ |
||||
result = (char *) palloc(2); |
||||
result[0] = '-'; |
||||
result[1] = '\0'; |
||||
} |
||||
else |
||||
{ |
||||
len = VARBITLEN(s); |
||||
result = (char *) palloc(len + 4); |
||||
sp = VARBITS(s); |
||||
r = result; |
||||
*r++ = 'B'; |
||||
*r++ = '\''; |
||||
for (i = 0; i < len - BITSPERBYTE; i += BITSPERBYTE, sp++) |
||||
{ |
||||
x = *sp; |
||||
for (k = 0; k < BITSPERBYTE; k++) |
||||
{ |
||||
*r++ = (x & BITHIGH) ? '1' : '0'; |
||||
x <<= 1; |
||||
} |
||||
} |
||||
x = *sp; |
||||
for (k = i; k < len; k++) |
||||
{ |
||||
*r++ = (x & BITHIGH) ? '1' : '0'; |
||||
x <<= 1; |
||||
} |
||||
*r++ = '\''; |
||||
*r = '\0'; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* varbitin - |
||||
* converts a string to the internal representation of a bitstring. |
||||
*/ |
||||
bits8 * |
||||
varbitin(char *s, int dummy, int32 atttypmod) |
||||
{ |
||||
bits8 *result; /* The resulting bit string */ |
||||
char *sp; /* pointer into the character string */ |
||||
bits8 *r; |
||||
int len, /* Length of the whole data structure */ |
||||
bitlen, /* Number of bits in the bit string */ |
||||
slen; /* Length of the input string */ |
||||
int bit_not_hex = 0; |
||||
int bc, |
||||
ipad; |
||||
bits8 x = 0; |
||||
|
||||
|
||||
if (s == NULL) |
||||
return (bits8 *) NULL; |
||||
|
||||
/* Check that the first character is a b or an x */ |
||||
if (s[0] == 'b' || s[0] == 'B') |
||||
bit_not_hex = 1; |
||||
else if (s[0] == 'x' || s[0] == 'X') |
||||
bit_not_hex = 0; |
||||
else |
||||
elog(ERROR, "zpbitin: %s is not a valid bitstring", s); |
||||
|
||||
slen = strlen(s) - 1; |
||||
/* Determine bitlength from input string */ |
||||
bitlen = slen; |
||||
if (!bit_not_hex) |
||||
bitlen *= 4; |
||||
|
||||
/*
|
||||
* Sometimes atttypmod is not supplied. If it is supplied we need to |
||||
* make sure that the bitstring fits. Note that the number of infered |
||||
* bits can be larger than the number of actual bits needed, but only |
||||
* if we are reading a hex string and not by more than 3 bits, as a |
||||
* hex string gives and accurate length upto 4 bits |
||||
*/ |
||||
if (atttypmod > -1) |
||||
if ((bitlen > atttypmod && bit_not_hex) || |
||||
(bitlen > atttypmod + 3 && !bit_not_hex)) |
||||
elog(ERROR, "varbitin: bit string of size %d cannot be written into varying bits(%d)", |
||||
bitlen, atttypmod); |
||||
|
||||
|
||||
len = VARBITDATALEN(bitlen); |
||||
|
||||
if (len > MaxAttrSize) |
||||
elog(ERROR, "varbitin: length of bit() must be less than %ld", |
||||
(MaxAttrSize - VARHDRSZ - VARBITHDRSZ) * BITSPERBYTE); |
||||
|
||||
result = (bits8 *) palloc(len); |
||||
/* set to 0 so that *r is always initialised and strin is zero-padded */ |
||||
memset(result, 0, len); |
||||
VARSIZE(result) = len; |
||||
VARBITLEN(result) = bitlen; |
||||
|
||||
/*
|
||||
* We need to read the bitstring from the end, as we store it least |
||||
* significant byte first. s points to the byte before the beginning |
||||
* of the bitstring |
||||
*/ |
||||
sp = s + 1; |
||||
r = VARBITS(result); |
||||
if (bit_not_hex) |
||||
{ |
||||
/* Parse the bit representation of the string */ |
||||
x = BITHIGH; |
||||
for (bc = 0; sp != s + slen + 1; sp++, bc++) |
||||
{ |
||||
if (*sp == '1') |
||||
*r |= x; |
||||
if (bc == 7) |
||||
{ |
||||
bc = 0; |
||||
x = BITHIGH; |
||||
r++; |
||||
} |
||||
else |
||||
x >>= 1; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
for (bc = 0; sp != s + slen + 1; sp++) |
||||
{ |
||||
if (*sp >= '0' && *sp <= '9') |
||||
x = (bits8) (*sp - '0'); |
||||
else if (*sp >= 'A' && *sp <= 'F') |
||||
x = (bits8) (*sp - 'A') + 10; |
||||
else if (*sp >= 'a' && *sp <= 'f') |
||||
x = (bits8) (*sp - 'a') + 10; |
||||
else |
||||
elog(ERROR, "Cannot parse %c as a hex digit", *sp); |
||||
if (bc) |
||||
{ |
||||
bc = 0; |
||||
*r++ |= x; |
||||
} |
||||
else |
||||
{ |
||||
bc++; |
||||
*r = x << 4; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (bitlen > atttypmod) |
||||
{ |
||||
/* Check that this fitted */ |
||||
r = (bits8 *) (result + len - 1); |
||||
ipad = VARBITPAD(result); |
||||
|
||||
/*
|
||||
* The bottom ipad bits of the byte pointed to by r need to be |
||||
* zero |
||||
*/ |
||||
if (((*r << (BITSPERBYTE - ipad)) & BITMASK) > 0) |
||||
elog(ERROR, "varbitin: bit string too large for varying bit(%d) data type", |
||||
atttypmod); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
the zpbitout routines are fine for varying bits as well |
||||
*/ |
||||
|
||||
|
||||
/*
|
||||
* Comparison operators |
||||
* |
||||
* We only need one set of comparison operators for bitstrings, as the lengths |
||||
* are stored in the same way for zero-padded and varying bit strings. |
||||
* |
||||
* Note that the standard is not unambiguous about the comparison between |
||||
* zero-padded bit strings and varying bitstrings. If the same value is written |
||||
* into a zero padded bitstring as into a varying bitstring, but the zero |
||||
* padded bitstring has greater length, it will be bigger. |
||||
* |
||||
* Zeros from the beginning of a bitstring cannot simply be ignored, as they |
||||
* may be part of a bit string and may be significant. |
||||
*/ |
||||
|
||||
bool |
||||
biteq(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
int bitlen1, |
||||
bitlen2; |
||||
|
||||
if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) |
||||
return (bool) 0; |
||||
bitlen1 = VARBITLEN(arg1); |
||||
bitlen2 = VARBITLEN(arg2); |
||||
if (bitlen1 != bitlen2) |
||||
return (bool) 0; |
||||
|
||||
/* bit strings are always stored in a full number of bytes */ |
||||
return memcmp((void *) VARBITS(arg1), (void *) VARBITS(arg2), |
||||
VARBITBYTES(arg1)) == 0; |
||||
} |
||||
|
||||
bool |
||||
bitne(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
int bitlen1, |
||||
bitlen2; |
||||
|
||||
if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) |
||||
return (bool) 0; |
||||
bitlen1 = VARBITLEN(arg1); |
||||
bitlen2 = VARBITLEN(arg2); |
||||
if (bitlen1 != bitlen2) |
||||
return (bool) 1; |
||||
|
||||
/* bit strings are always stored in a full number of bytes */ |
||||
return memcmp((void *) VARBITS(arg1), (void *) VARBITS(arg2), |
||||
VARBITBYTES(arg1)) != 0; |
||||
} |
||||
|
||||
/* bitcmp
|
||||
* |
||||
* Compares two bitstrings and returns -1, 0, 1 depending on whether the first |
||||
* string is smaller, equal, or bigger than the second. All bits are considered |
||||
* and additional zero bits may make one string smaller/larger than the other, |
||||
* even if their zero-padded values would be the same. |
||||
* Anything is equal to undefined. |
||||
*/ |
||||
int |
||||
bitcmp(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
int bitlen1, |
||||
bytelen1, |
||||
bitlen2, |
||||
bytelen2; |
||||
int cmp; |
||||
|
||||
if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) |
||||
return (bool) 0; |
||||
bytelen1 = VARBITBYTES(arg1); |
||||
bytelen2 = VARBITBYTES(arg2); |
||||
|
||||
cmp = memcmp(VARBITS(arg1), VARBITS(arg2), Min(bytelen1, bytelen2)); |
||||
if (cmp == 0) |
||||
{ |
||||
bitlen1 = VARBITLEN(arg1); |
||||
bitlen2 = VARBITLEN(arg2); |
||||
if (bitlen1 != bitlen2) |
||||
return bitlen1 < bitlen2 ? -1 : 1; |
||||
} |
||||
return cmp; |
||||
} |
||||
|
||||
bool |
||||
bitlt(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
return (bool) (bitcmp(arg1, arg2) == -1); |
||||
} |
||||
|
||||
bool |
||||
bitle(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
return (bool) (bitcmp(arg1, arg2) <= 0); |
||||
} |
||||
|
||||
bool |
||||
bitge(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
return (bool) (bitcmp(arg1, arg2) >= 0); |
||||
} |
||||
|
||||
bool |
||||
bitgt(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
return (bool) (bitcmp(arg1, arg2) == 1); |
||||
} |
||||
|
||||
/* bitcat
|
||||
* Concatenation of bit strings |
||||
*/ |
||||
bits8 * |
||||
bitcat(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
int bitlen1, |
||||
bitlen2, |
||||
bytelen, |
||||
bit1pad, |
||||
bit2shift; |
||||
bits8 *result; |
||||
bits8 *pr, |
||||
*pa; |
||||
|
||||
if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) |
||||
return NULL; |
||||
|
||||
bitlen1 = VARBITLEN(arg1); |
||||
bitlen2 = VARBITLEN(arg2); |
||||
|
||||
bytelen = VARBITDATALEN(bitlen1 + bitlen2); |
||||
|
||||
result = (bits8 *) palloc(bytelen * sizeof(bits8)); |
||||
VARSIZE(result) = bytelen; |
||||
VARBITLEN(result) = bitlen1 + bitlen2; |
||||
printf("%d %d %d \n", VARBITBYTES(arg1), VARBITLEN(arg1), VARBITPAD(arg1)); |
||||
/* Copy the first bitstring in */ |
||||
memcpy(VARBITS(result), VARBITS(arg1), VARBITBYTES(arg1)); |
||||
/* Copy the second bit string */ |
||||
bit1pad = VARBITPAD(arg1); |
||||
if (bit1pad == 0) |
||||
{ |
||||
memcpy(VARBITS(result) + VARBITBYTES(arg1), VARBITS(arg2), |
||||
VARBITBYTES(arg2)); |
||||
} |
||||
else if (bitlen2 > 0) |
||||
{ |
||||
/* We need to shift all the results to fit */ |
||||
bit2shift = BITSPERBYTE - bit1pad; |
||||
pa = VARBITS(arg2); |
||||
pr = VARBITS(result) + VARBITBYTES(arg1) - 1; |
||||
for (; pa < VARBITEND(arg2); pa++) |
||||
{ |
||||
*pr |= ((*pa >> bit2shift) & BITMASK); |
||||
pr++; |
||||
if (pr < VARBITEND(result)) |
||||
*pr = (*pa << bit1pad) & BITMASK; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* bitsubstr
|
||||
* retrieve a substring from the bit string. |
||||
* Note, s is 1-based. |
||||
* SQL draft 6.10 9) |
||||
*/ |
||||
bits8 * |
||||
bitsubstr(bits8 *arg, int32 s, int32 l) |
||||
{ |
||||
int bitlen, |
||||
rbitlen, |
||||
len, |
||||
ipad = 0, |
||||
ishift, |
||||
i; |
||||
int e, |
||||
s1, |
||||
e1; |
||||
bits8 *result; |
||||
bits8 mask, |
||||
*r, |
||||
*ps; |
||||
|
||||
if (!PointerIsValid(arg)) |
||||
return NULL; |
||||
|
||||
bitlen = VARBITLEN(arg); |
||||
e = s + l; |
||||
s1 = Max(s, 1); |
||||
e1 = Min(e, bitlen + 1); |
||||
if (s1 > bitlen || e1 < 1) |
||||
{ |
||||
/* Need to return a null string */ |
||||
len = VARBITDATALEN(0); |
||||
result = (bits8 *) palloc(len); |
||||
VARBITLEN(result) = 0; |
||||
VARSIZE(result) = len; |
||||
} |
||||
else |
||||
{ |
||||
|
||||
/*
|
||||
* OK, we've got a true substring starting at position s1-1 and |
||||
* ending at position e1-1 |
||||
*/ |
||||
rbitlen = e1 - s1; |
||||
len = VARBITDATALEN(rbitlen); |
||||
result = (bits8 *) palloc(len); |
||||
VARBITLEN(result) = rbitlen; |
||||
VARSIZE(result) = len; |
||||
len -= VARHDRSZ + VARBITHDRSZ; |
||||
/* Are we copying from a byte boundary? */ |
||||
if ((s1 - 1) % BITSPERBYTE == 0) |
||||
{ |
||||
/* Yep, we are copying bytes */ |
||||
memcpy(VARBITS(result), VARBITS(arg) + (s1 - 1) / BITSPERBYTE, len); |
||||
} |
||||
else |
||||
{ |
||||
/* Figure out how much we need to shift the sequence by */ |
||||
ishift = (s1 - 1) % BITSPERBYTE; |
||||
r = VARBITS(result); |
||||
ps = VARBITS(arg) + (s1 - 1) / BITSPERBYTE; |
||||
for (i = 0; i < len; i++) |
||||
{ |
||||
*r = (*ps << ishift) & BITMASK; |
||||
if ((++ps) < VARBITEND(arg)) |
||||
*r |= *ps >> (BITSPERBYTE - ishift); |
||||
r++; |
||||
} |
||||
} |
||||
/* Do we need to pad at the end? */ |
||||
ipad = VARBITPAD(result); |
||||
if (ipad > 0) |
||||
{ |
||||
mask = BITMASK << ipad; |
||||
*(VARBITS(result) + len - 1) &= mask; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* bitand
|
||||
* perform a logical AND on two bit strings. The result is automatically |
||||
* truncated to the shorter bit string |
||||
*/ |
||||
bits8 * |
||||
bitand(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
int len, |
||||
i; |
||||
bits8 *result; |
||||
bits8 *p1, |
||||
*p2, |
||||
*r; |
||||
|
||||
if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) |
||||
return (bool) 0; |
||||
|
||||
len = Min(VARSIZE(arg1), VARSIZE(arg2)); |
||||
result = (bits8 *) palloc(len); |
||||
VARSIZE(result) = len; |
||||
VARBITLEN(result) = Min(VARBITLEN(arg1), VARBITLEN(arg2)); |
||||
|
||||
p1 = (bits8 *) VARBITS(arg1); |
||||
p2 = (bits8 *) VARBITS(arg2); |
||||
r = (bits8 *) VARBITS(result); |
||||
for (i = 0; i < Min(VARBITBYTES(arg1), VARBITBYTES(arg2)); i++) |
||||
*r++ = *p1++ & *p2++; |
||||
|
||||
/* Padding is not needed as & of 0 pad is 0 */ |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* bitor
|
||||
* perform a logical OR on two bit strings. The result is automatically |
||||
* truncated to the shorter bit string. |
||||
*/ |
||||
bits8 * |
||||
bitor(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
int len, |
||||
i; |
||||
bits8 *result; |
||||
bits8 *p1, |
||||
*p2, |
||||
*r; |
||||
bits8 mask; |
||||
|
||||
if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) |
||||
return (bool) 0; |
||||
|
||||
len = Min(VARSIZE(arg1), VARSIZE(arg2)); |
||||
result = (bits8 *) palloc(len); |
||||
VARSIZE(result) = len; |
||||
VARBITLEN(result) = Min(VARBITLEN(arg1), VARBITLEN(arg2)); |
||||
|
||||
p1 = (bits8 *) VARBITS(arg1); |
||||
p2 = (bits8 *) VARBITS(arg2); |
||||
r = (bits8 *) VARBITS(result); |
||||
for (i = 0; i < Min(VARBITBYTES(arg1), VARBITBYTES(arg2)); i++) |
||||
*r++ = *p1++ | *p2++; |
||||
|
||||
/* Pad the result */ |
||||
mask = BITMASK << VARBITPAD(result); |
||||
*r &= mask; |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* bitxor
|
||||
* perform a logical XOR on two bit strings. The result is automatically |
||||
* truncated to the shorter bit string. |
||||
*/ |
||||
bits8 * |
||||
bitxor(bits8 *arg1, bits8 *arg2) |
||||
{ |
||||
int len, |
||||
i; |
||||
bits8 *result; |
||||
bits8 *p1, |
||||
*p2, |
||||
*r; |
||||
bits8 mask; |
||||
|
||||
if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) |
||||
return (bool) 0; |
||||
|
||||
len = Min(VARSIZE(arg1), VARSIZE(arg2)); |
||||
result = (bits8 *) palloc(len); |
||||
VARSIZE(result) = len; |
||||
VARBITLEN(result) = Min(VARBITLEN(arg1), VARBITLEN(arg2)); |
||||
|
||||
p1 = (bits8 *) VARBITS(arg1); |
||||
p2 = (bits8 *) VARBITS(arg2); |
||||
r = (bits8 *) VARBITS(result); |
||||
for (i = 0; i < Min(VARBITBYTES(arg1), VARBITBYTES(arg2)); i++) |
||||
*r++ = *p1++ ^ *p2++; |
||||
|
||||
/* Pad the result */ |
||||
mask = BITMASK << VARBITPAD(result); |
||||
*r &= mask; |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* bitnot
|
||||
* perform a logical NOT on a bit strings. |
||||
*/ |
||||
bits8 * |
||||
bitnot(bits8 *arg) |
||||
{ |
||||
bits8 *result; |
||||
bits8 *p, |
||||
*r; |
||||
bits8 mask; |
||||
|
||||
if (!PointerIsValid(arg)) |
||||
return (bool) 0; |
||||
|
||||
result = (bits8 *) palloc(VARSIZE(arg)); |
||||
VARSIZE(result) = VARSIZE(arg); |
||||
VARBITLEN(result) = VARBITLEN(arg); |
||||
|
||||
p = (bits8 *) VARBITS(arg); |
||||
r = (bits8 *) VARBITS(result); |
||||
for (; p < VARBITEND(arg); p++, r++) |
||||
*r = ~*p; |
||||
|
||||
/* Pad the result */ |
||||
mask = BITMASK << VARBITPAD(result); |
||||
*r &= mask; |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* bitshiftleft
|
||||
* do a left shift (i.e. to the beginning of the string) of the bit string |
||||
*/ |
||||
bits8 * |
||||
bitshiftleft(bits8 *arg, int shft) |
||||
{ |
||||
int byte_shift, |
||||
ishift, |
||||
len; |
||||
bits8 *result; |
||||
bits8 *p, |
||||
*r; |
||||
|
||||
if (!PointerIsValid(arg)) |
||||
return (bool) 0; |
||||
|
||||
/* Negative shift is a shift to the right */ |
||||
if (shft < 0) |
||||
return bitshiftright(arg, -shft); |
||||
|
||||
result = (bits8 *) palloc(VARSIZE(arg)); |
||||
VARSIZE(result) = VARSIZE(arg); |
||||
VARBITLEN(result) = VARBITLEN(arg); |
||||
r = (bits8 *) VARBITS(result); |
||||
|
||||
byte_shift = shft / BITSPERBYTE; |
||||
ishift = shft % BITSPERBYTE; |
||||
p = ((bits8 *) VARBITS(arg)) + byte_shift; |
||||
|
||||
if (ishift == 0) |
||||
{ |
||||
/* Special case: we can do a memcpy */ |
||||
len = VARBITBYTES(arg) - byte_shift; |
||||
memcpy(r, p, len); |
||||
memset(r + len, 0, byte_shift); |
||||
} |
||||
else |
||||
{ |
||||
for (; p < VARBITEND(arg); r++) |
||||
{ |
||||
*r = *p << ishift; |
||||
if ((++p) < VARBITEND(arg)) |
||||
*r |= *p >> (BITSPERBYTE - ishift); |
||||
} |
||||
for (; r < VARBITEND(result); r++) |
||||
*r = (bits8) 0; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* bitshiftright
|
||||
* do a right shift (i.e. to the beginning of the string) of the bit string |
||||
*/ |
||||
bits8 * |
||||
bitshiftright(bits8 *arg, int shft) |
||||
{ |
||||
int byte_shift, |
||||
ishift, |
||||
len; |
||||
bits8 *result; |
||||
bits8 *p, |
||||
*r; |
||||
|
||||
if (!PointerIsValid(arg)) |
||||
return (bits8 *) 0; |
||||
|
||||
/* Negative shift is a shift to the left */ |
||||
if (shft < 0) |
||||
return bitshiftleft(arg, -shft); |
||||
|
||||
result = (bits8 *) palloc(VARSIZE(arg)); |
||||
VARSIZE(result) = VARSIZE(arg); |
||||
VARBITLEN(result) = VARBITLEN(arg); |
||||
r = (bits8 *) VARBITS(result); |
||||
|
||||
byte_shift = shft / BITSPERBYTE; |
||||
ishift = shft % BITSPERBYTE; |
||||
p = (bits8 *) VARBITS(arg); |
||||
|
||||
/* Set the first part of the result to 0 */ |
||||
memset(r, 0, byte_shift); |
||||
|
||||
if (ishift == 0) |
||||
{ |
||||
/* Special case: we can do a memcpy */ |
||||
len = VARBITBYTES(arg) - byte_shift; |
||||
memcpy(r + byte_shift, p, len); |
||||
} |
||||
else |
||||
{ |
||||
r += byte_shift; |
||||
*r = 0; /* Initialise first byte */ |
||||
for (; r < VARBITEND(result); p++) |
||||
{ |
||||
*r |= *p >> ishift; |
||||
if ((++r) < VARBITEND(result)) |
||||
*r = (*p << (BITSPERBYTE - ishift)) & BITMASK; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
@ -1,29 +0,0 @@ |
||||
create table bit_example (a bit, b bit); |
||||
copy bit_example from stdin; |
||||
X0F X10 |
||||
X1F X11 |
||||
X2F X12 |
||||
X3F X13 |
||||
X8F X04 |
||||
X000F X0010 |
||||
X0123 XFFFF |
||||
X2468 X2468 |
||||
XFA50 X05AF |
||||
X12345 XFFF |
||||
\. |
||||
|
||||
select a,b,a||b as "a||b", bitsubstr(a,4,4) as "sub(a,4,4)", |
||||
bitsubstr(b,2,4) as "sub(b,2,4)", |
||||
bitsubstr(b,5,5) as "sub(b,5,5)" |
||||
from bit_example; |
||||
select a,b,~a as "~ a",~b as "~ b",a & b as "a & b", |
||||
a|b as "a | b", a^b as "a ^ b" from bit_example; |
||||
select a,b,a<b as "a<b",a<=b as "a<=b",a=b as "a=b", |
||||
a>=b as "a>=b",a>b as "a>b",a<=>b as "a<=>b" from bit_example; |
||||
select a,a<<4 as "a<<4",b,b>>2 as "b>>2" from bit_example; |
||||
select a,b,a||b as "a||b", bitsubstr(a,4,4) as "sub(a,4,4)", |
||||
bitsubstr(b,2,4) as "sub(b,2,4)", |
||||
bitsubstr(b,5,5) as "sub(b,5,5)" |
||||
from bit_example; |
||||
|
||||
drop table bit_example; |
@ -1,36 +0,0 @@ |
||||
DROP FUNCTION biteq(bits,bits); |
||||
DROP OPERATOR = (bits,bits); |
||||
DROP FUNCTION bitne(bits,bits); |
||||
DROP OPERATOR <> (bits,bits); |
||||
DROP FUNCTION bitlt(bits,bits); |
||||
DROP OPERATOR < (bits,bits); |
||||
DROP FUNCTION bitle(bits,bits); |
||||
DROP OPERATOR <= (bits,bits); |
||||
DROP FUNCTION bitgt(bits,bits); |
||||
DROP OPERATOR > (bits,bits); |
||||
DROP FUNCTION bitge(bits,bits); |
||||
DROP OPERATOR >= (bits,bits); |
||||
DROP FUNCTION bitcmp(bits,bits); |
||||
DROP OPERATOR <=> (bits,bits); |
||||
|
||||
DROP FUNCTION bitor(bits,bits); |
||||
DROP OPERATOR | (bits,bits); |
||||
DROP FUNCTION bitand(bits,bits); |
||||
DROP OPERATOR & (bits,bits); |
||||
DROP FUNCTION bitxor(bits,bits); |
||||
DROP OPERATOR ^ (bits,bits); |
||||
DROP FUNCTION bitnot(bits); |
||||
DROP OPERATOR ~ (none,bits); |
||||
|
||||
DROP FUNCTION bitshiftleft(bits,int4); |
||||
DROP OPERATOR << (bits,int4); |
||||
DROP FUNCTION bitshiftright(bits,int4); |
||||
DROP OPERATOR >> (bits,int4); |
||||
|
||||
DROP FUNCTION bitsubstr(bits,integer,integer); |
||||
DROP OPERATOR || (bits,bits); |
||||
DROP FUNCTION bitcat(bits,bits); |
||||
|
||||
DROP FUNCTION varbit_in(opaque); |
||||
DROP FUNCTION varbit_out(opaque); |
||||
DROP TYPE bits; |
@ -1,73 +0,0 @@ |
||||
#include <stdlib.h> |
||||
#include <ctype.h> |
||||
#include <errno.h> |
||||
|
||||
#include <float.h> /* faked on sunos4 */ |
||||
|
||||
#include <math.h> |
||||
|
||||
#include "postgres.h" |
||||
#ifdef HAVE_LIMITS_H |
||||
#include <limits.h> |
||||
#ifndef MAXINT |
||||
#define MAXINT INT_MAX |
||||
#endif |
||||
#else |
||||
#ifdef HAVE_VALUES_H |
||||
#include <values.h> |
||||
#endif |
||||
#endif |
||||
#include "fmgr.h" |
||||
#include "utils/timestamp.h" |
||||
#include "utils/builtins.h" |
||||
|
||||
|
||||
#define HEXDIG(z) (z)<10 ? ((z)+'0') : ((z)-10+'A') |
||||
|
||||
/* Modeled on struct varlena from postgres.h, bu data type is bits8 */ |
||||
struct varbita |
||||
{ |
||||
int32 vl_len; |
||||
bits8 vl_dat[1]; |
||||
}; |
||||
|
||||
#define BITSPERBYTE 8 |
||||
#define VARBITHDRSZ sizeof(int32) |
||||
/* Number of bits in this bit string */ |
||||
#define VARBITLEN(PTR) (((struct varbita *)VARDATA(PTR))->vl_len) |
||||
/* Pointer tp the first byte containing bit string data */ |
||||
#define VARBITS(PTR) (((struct varbita *)VARDATA(PTR))->vl_dat) |
||||
/* Number of bytes in the data section of a bit string */ |
||||
#define VARBITBYTES(PTR) (VARSIZE(PTR) - VARHDRSZ - VARBITHDRSZ) |
||||
/* Padding of the bit string at the end */ |
||||
#define VARBITPAD(PTR) (VARBITBYTES(PTR)*BITSPERBYTE - VARBITLEN(PTR)) |
||||
/* Number of bytes needed to store a bit string of a given length */ |
||||
#define VARBITDATALEN(BITLEN) (BITLEN/BITSPERBYTE + \ |
||||
(BITLEN%BITSPERBYTE > 0 ? 1 : 0) + \
|
||||
VARHDRSZ + VARBITHDRSZ) |
||||
/* pointer beyond the end of the bit string (like end() in STL containers) */ |
||||
#define VARBITEND(PTR) ((bits8 *) (PTR + VARSIZE(PTR))) |
||||
/* Mask that will cover exactly one byte, i.e. BITSPERBYTE bits */ |
||||
#define BITMASK 0xFF |
||||
#define BITHIGH 0x80 |
||||
|
||||
|
||||
bits8 *zpbitin(char *s, int dummy, int32 atttypmod); |
||||
char *zpbitout(bits8 *s); |
||||
char *zpbitsout(bits8 *s); |
||||
bits8 *varbitin(char *s, int dummy, int32 atttypmod); |
||||
bool biteq(bits8 *arg1, bits8 *arg2); |
||||
bool bitne(bits8 *arg1, bits8 *arg2); |
||||
bool bitge(bits8 *arg1, bits8 *arg2); |
||||
bool bitgt(bits8 *arg1, bits8 *arg2); |
||||
bool bitle(bits8 *arg1, bits8 *arg2); |
||||
bool bitlt(bits8 *arg1, bits8 *arg2); |
||||
int bitcmp(bits8 *arg1, bits8 *arg2); |
||||
bits8 *bitand(bits8 *arg1, bits8 *arg2); |
||||
bits8 *bitor(bits8 *arg1, bits8 *arg2); |
||||
bits8 *bitxor(bits8 *arg1, bits8 *arg2); |
||||
bits8 *bitnot(bits8 *arg); |
||||
bits8 *bitshiftright(bits8 *arg, int shft); |
||||
bits8 *bitshiftleft(bits8 *arg, int shft); |
||||
bits8 *bitcat(bits8 *arg1, bits8 *arg2); |
||||
bits8 *bitsubstr(bits8 *arg, int32 s, int32 l); |
@ -1,171 +0,0 @@ |
||||
LOAD '_OBJWD_/varbit.so'; |
||||
|
||||
CREATE FUNCTION varbitin(opaque) |
||||
RETURNS bit |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION zpbitout(opaque) |
||||
RETURNS opaque |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'c'; |
||||
|
||||
CREATE TYPE bit ( |
||||
internallength = -1, |
||||
input = varbitin, |
||||
output = zpbitout |
||||
); |
||||
|
||||
CREATE FUNCTION bitcat(bit,bit) RETURNS bit |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR || ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitcat |
||||
); |
||||
|
||||
CREATE FUNCTION bitsubstr(bit,integer,integer) RETURNS bit |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE FUNCTION biteq(bit,bit) RETURNS bool |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR = ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = biteq, |
||||
negator = <>, |
||||
commutator = = |
||||
); |
||||
|
||||
CREATE FUNCTION bitne(bit,bit) RETURNS bool |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR <> ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitne, |
||||
negator = =, |
||||
commutator = <> |
||||
); |
||||
|
||||
CREATE FUNCTION bitlt(bit,bit) RETURNS bool |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR < ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitlt |
||||
); |
||||
|
||||
CREATE FUNCTION bitle(bit,bit) RETURNS bool |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR <= ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitle |
||||
); |
||||
|
||||
CREATE FUNCTION bitgt(bit,bit) RETURNS bool |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR > ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitgt, |
||||
negator = <=, |
||||
commutator = < |
||||
); |
||||
|
||||
CREATE FUNCTION bitge(bit,bit) RETURNS bool |
||||
as '_OBJWD_/varbit.so' |
||||
language 'C'; |
||||
|
||||
CREATE OPERATOR >= ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitge, |
||||
negator = <, |
||||
commutator = <= |
||||
); |
||||
|
||||
CREATE FUNCTION bitcmp(bit,bit) RETURNS integer |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR <=> ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitcmp |
||||
); |
||||
|
||||
CREATE FUNCTION bitor(bit,bit) RETURNS bit |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR | ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitor, |
||||
commutator = | |
||||
); |
||||
|
||||
CREATE FUNCTION bitand(bit,bit) RETURNS bit |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR & ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitand, |
||||
commutator = & |
||||
); |
||||
|
||||
|
||||
CREATE FUNCTION bitxor(bit,bit) RETURNS bit |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR ^ ( |
||||
leftarg = bit, |
||||
rightarg = bit, |
||||
procedure = bitxor |
||||
); |
||||
|
||||
CREATE FUNCTION bitnot(bit) RETURNS bit |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR ~ ( |
||||
rightarg = bit, |
||||
procedure = bitnot |
||||
); |
||||
|
||||
CREATE FUNCTION bitshiftleft(bit,integer) RETURNS bit |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR << ( |
||||
leftarg = bit, |
||||
rightarg = integer, |
||||
procedure = bitshiftleft |
||||
); |
||||
|
||||
CREATE FUNCTION bitshiftright(bit,integer) RETURNS bit |
||||
AS '_OBJWD_/varbit.so' |
||||
LANGUAGE 'C'; |
||||
|
||||
CREATE OPERATOR >> ( |
||||
leftarg = bit, |
||||
rightarg = integer, |
||||
procedure = bitshiftright |
||||
); |
@ -1,24 +0,0 @@ |
||||
/* Glue file to use varbit before it is properly integrated with postgres */ |
||||
|
||||
#include "varbit.h" |
||||
|
||||
bits8 *varbit_in(char *s); |
||||
char *varbit_out(bits8 *s); |
||||
|
||||
bits8 * |
||||
varbit_in(char *s) |
||||
{ |
||||
return varbitin(s, 0, -1); |
||||
} |
||||
|
||||
/*char *
|
||||
varbit_out (bits8 *s) { |
||||
return zpbitout(s); |
||||
} |
||||
*/ |
||||
|
||||
char * |
||||
varbit_out(bits8 *s) |
||||
{ |
||||
return zpbitsout(s); |
||||
} |
@ -1,184 +0,0 @@ |
||||
#include "postgres.h" |
||||
#include "varbit.h" |
||||
#include <stdio.h> |
||||
|
||||
void print_details(unsigned char *s); |
||||
|
||||
const int numb = 8; |
||||
|
||||
/*
|
||||
const char *b[] = { "B0010", "B11011011", "B0001", "X3F12", "X27", "B", |
||||
"X11", "B100111"}; |
||||
int atttypmod[] = {-1, -1, -1,-1,-1,-1,-1,-1 }; |
||||
*/ |
||||
const char *b[] = {"B0010", "B11011011", "B10001", "X3D12", "X27", "B", |
||||
"X11", "B100111"}; |
||||
int atttypmod[] = {7, 9, 6, 18, 11, 6, -1, -1}; |
||||
|
||||
|
||||
void |
||||
print_details(unsigned char *s) |
||||
{ |
||||
int i; |
||||
|
||||
printf("Length in bytes : %d\n", VARSIZE(s)); |
||||
printf("Length of bitstring: %d\n", VARBITLEN(s)); |
||||
for (i = 8; i < VARSIZE(s); i++) |
||||
printf("%X%X ", s[i] >> 4, s[i] & 0xF); |
||||
printf("\n"); |
||||
} |
||||
|
||||
int |
||||
main() |
||||
{ |
||||
int i, |
||||
j; |
||||
char *s[numb]; |
||||
|
||||
for (i = 0; i < numb; i++) |
||||
{ |
||||
printf("Input: %s\n", b[i]); |
||||
s[i] = zpbitin(b[i], 0, atttypmod[i]); |
||||
//print_details(s[i]);
|
||||
printf("%s = %s\n", zpbitout(s[i]), zpbitsout(s[i])); |
||||
} |
||||
|
||||
printf("\nCOMPARISONS:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s <=> %s = %d\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
bitcmp(s[i], s[j])); |
||||
|
||||
printf("\nCONCATENATION:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s || %s = %s\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
zpbitsout(bitcat(s[i], s[j]))); |
||||
|
||||
printf("\nSUBSTR:\n"); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 1, 8, |
||||
zpbitsout(bitsubstr(s[3], 1, 8))); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 9, 8, |
||||
zpbitsout(bitsubstr(s[3], 9, 8))); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 1, 9, |
||||
zpbitsout(bitsubstr(s[3], 1, 9))); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 3, 5, |
||||
zpbitsout(bitsubstr(s[3], 3, 5))); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 3, 9, |
||||
zpbitsout(bitsubstr(s[3], 3, 9))); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 3, 17, |
||||
zpbitsout(bitsubstr(s[3], 3, 17))); |
||||
printf("\nLOGICAL AND:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s & %s = %s\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
zpbitsout(bitand(s[i], s[j]))); |
||||
|
||||
printf("\nLOGICAL OR:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s | %s = %s\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
zpbitsout(bitor(s[i], s[j]))); |
||||
|
||||
printf("\nLOGICAL XOR:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s ^ %s = %s\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
zpbitsout(bitxor(s[i], s[j]))); |
||||
|
||||
printf("\nLOGICAL NOT:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
printf("~%s = %s\n", zpbitsout(s[i]), zpbitsout(bitnot(s[i]))); |
||||
|
||||
|
||||
printf("\nSHIFT LEFT:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
{ |
||||
printf("%s\n", zpbitsout(s[i])); |
||||
for (j = 0; j <= VARBITLEN(s[i]); j++) |
||||
printf("\t%3d\t%s\n", j, zpbitsout(bitshiftleft(s[i], j))); |
||||
} |
||||
|
||||
printf("\nSHIFT RIGHT:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
{ |
||||
printf("%s\n", zpbitsout(s[i])); |
||||
for (j = 0; j <= VARBITLEN(s[i]); j++) |
||||
printf("\t%3d\t%s\n", j, zpbitsout(bitshiftright(s[i], j))); |
||||
} |
||||
|
||||
printf("\n\n ********** VARYING **********\n"); |
||||
for (i = 0; i < numb; i++) |
||||
{ |
||||
printf("Input: %s\n", b[i]); |
||||
s[i] = varbitin(b[i], 0, atttypmod[i]); |
||||
/* print_details(s); */ |
||||
printf("%s\n", zpbitout(s[i])); |
||||
printf("%s\n", zpbitsout(s[i])); |
||||
} |
||||
|
||||
printf("\nCOMPARISONS:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s <=> %s = %d\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
bitcmp(s[i], s[j])); |
||||
|
||||
printf("\nCONCATENATION:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s || %s = %s\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
zpbitsout(bitcat(s[i], s[j]))); |
||||
|
||||
printf("\nSUBSTR:\n"); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 1, 8, |
||||
zpbitsout(bitsubstr(s[3], 1, 8))); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 9, 8, |
||||
zpbitsout(bitsubstr(s[3], 9, 8))); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 1, 9, |
||||
zpbitsout(bitsubstr(s[3], 1, 9))); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 3, 5, |
||||
zpbitsout(bitsubstr(s[3], 3, 5))); |
||||
printf("%s (%d,%d) => %s\n", zpbitsout(s[3]), 3, 9, |
||||
zpbitsout(bitsubstr(s[3], 3, 9))); |
||||
printf("%s (%d,%d) => %s (%s)\n", zpbitsout(s[3]), 3, 17, |
||||
zpbitsout(bitsubstr(s[3], 3, 17)), zpbitsout(bitsubstr(s[3], 3, 17))); |
||||
printf("\nLOGICAL AND:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s & %s = %s\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
zpbitsout(bitand(s[i], s[j]))); |
||||
|
||||
printf("\nLOGICAL OR:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s | %s = %s\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
zpbitsout(bitor(s[i], s[j]))); |
||||
|
||||
printf("\nLOGICAL XOR:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
for (j = i + 1; j < numb; j++) |
||||
printf("%s ^ %s = %s\n", zpbitsout(s[i]), zpbitsout(s[j]), |
||||
zpbitsout(bitxor(s[i], s[j]))); |
||||
|
||||
printf("\nLOGICAL NOT:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
printf("~%s = %s\n", zpbitsout(s[i]), zpbitsout(bitnot(s[i]))); |
||||
|
||||
|
||||
printf("\nSHIFT LEFT:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
{ |
||||
printf("%s\n", zpbitsout(s[i])); |
||||
for (j = 0; j <= VARBITLEN(s[i]); j++) |
||||
printf("\t%3d\t%s\n", j, zpbitsout(bitshiftleft(s[i], j))); |
||||
} |
||||
|
||||
printf("\nSHIFT RIGHT:\n"); |
||||
for (i = 0; i < numb; i++) |
||||
{ |
||||
printf("%s\n", zpbitsout(s[i])); |
||||
for (j = 0; j <= VARBITLEN(s[i]); j++) |
||||
printf("\t%3d\t%s\n", j, zpbitsout(bitshiftright(s[i], j))); |
||||
} |
||||
|
||||
} |
@ -1,66 +0,0 @@ |
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile --
|
||||
#
|
||||
# Makefile for new datetime module.
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
PGDIR = ../..
|
||||
SRCDIR = $(PGDIR)/src
|
||||
|
||||
include $(SRCDIR)/Makefile.global |
||||
|
||||
CFLAGS += -I. $(CFLAGS_SL)
|
||||
|
||||
MODNAME = datetime_functions
|
||||
|
||||
SQLDEFS = $(MODNAME).sql
|
||||
|
||||
MODULE = $(MODNAME)$(DLSUFFIX)
|
||||
|
||||
MODDIR = $(LIBDIR)/modules
|
||||
|
||||
SQLDIR = $(LIBDIR)/sql
|
||||
|
||||
all: module sql |
||||
|
||||
module: $(MODULE) |
||||
|
||||
sql: $(SQLDEFS) |
||||
|
||||
install: $(MODULE) $(SQLDEFS) $(MODDIR) $(SQLDIR) |
||||
cp -p $(MODULE) $(MODDIR)/
|
||||
strip $(MODDIR)/$(MODULE)
|
||||
cp -p $(SQLDEFS) $(SQLDIR)/
|
||||
|
||||
install-doc: |
||||
if [ -d "$(DOCDIR)" ]; then \
|
||||
cp -p *.doc $(DOCDIR); \
|
||||
else \
|
||||
cp -p *.doc $(SQLDIR); \
|
||||
fi
|
||||
|
||||
$(MODDIR): |
||||
mkdir -p $@
|
||||
|
||||
$(SQLDIR): |
||||
mkdir -p $@
|
||||
|
||||
%.sql: %.sql.in |
||||
sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
|
||||
|
||||
.SUFFIXES: $(DLSUFFIX) |
||||
|
||||
%$(DLSUFFIX): %.c |
||||
$(CC) $(CFLAGS) -shared -o $@ $<
|
||||
|
||||
depend dep: |
||||
$(CC) -MM $(CFLAGS) *.c >depend
|
||||
|
||||
clean: |
||||
rm -f *~ $(MODULE) $(MODNAME).sql
|
||||
|
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
@ -1,281 +0,0 @@ |
||||
/*
|
||||
* datetime_functions.c -- |
||||
* |
||||
* This file defines new functions for the time and date data types. |
||||
* |
||||
* Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it> |
||||
* |
||||
* Date2mjd code contributed by Reiner Dassing <dassing@wettzell.ifag.de> |
||||
* |
||||
* This software is distributed under the GNU General Public License |
||||
* either version 2, or (at your option) any later version. |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <limits.h> |
||||
#ifdef HAVE_FLOAT_H |
||||
#include <float.h> |
||||
#endif |
||||
|
||||
#include "postgres.h" |
||||
#include "miscadmin.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/nabstime.h" |
||||
#include "utils/datetime.h" |
||||
#include "access/xact.h" |
||||
|
||||
#include "datetime_functions.h" |
||||
|
||||
/* Constant to replace calls to date2j(2000,1,1) */ |
||||
#define JDATE_2000 2451545 |
||||
|
||||
/*
|
||||
* decode_24h_time() |
||||
* |
||||
* Decode time string 00:00:00 through 24:00:00. |
||||
*/ |
||||
static int |
||||
decode_24h_time(char *str, struct tm * tm, double *fsec) |
||||
{ |
||||
char *cp; |
||||
|
||||
tm->tm_hour = strtol(str, &cp, 10); |
||||
if (*cp != ':') |
||||
return -1; |
||||
str = cp + 1; |
||||
tm->tm_min = strtol(str, &cp, 10); |
||||
if (*cp == '\0') |
||||
{ |
||||
tm->tm_sec = 0; |
||||
*fsec = 0; |
||||
} |
||||
else if (*cp != ':') |
||||
return -1; |
||||
else |
||||
{ |
||||
str = cp + 1; |
||||
tm->tm_sec = strtol(str, &cp, 10); |
||||
if (*cp == '\0') |
||||
*fsec = 0; |
||||
else if (*cp == '.') |
||||
{ |
||||
str = cp; |
||||
*fsec = strtod(str, &cp); |
||||
if (cp == str) |
||||
return -1; |
||||
} |
||||
else |
||||
return -1; |
||||
} |
||||
|
||||
/* do a sanity check */ |
||||
if ((tm->tm_hour < 0) || (tm->tm_hour > 24) |
||||
|| (tm->tm_min < 0) || (tm->tm_min > 59) |
||||
|| (tm->tm_sec < 0) || (tm->tm_sec > 59) |
||||
|| (*fsec < 0)) |
||||
return -1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* A modified version of time_in which allows the value 24:00:00 for |
||||
* time and converts it to TimeADT data type forcing seconds to 0. |
||||
* This can be useful if you need to handle TimeADT values limited |
||||
* to hh:mm like in timetables. |
||||
*/ |
||||
|
||||
TimeADT * |
||||
hhmm_in(char *str) |
||||
{ |
||||
TimeADT *time; |
||||
|
||||
double fsec; |
||||
struct tm tt, |
||||
*tm = &tt; |
||||
|
||||
if (!PointerIsValid(str)) |
||||
elog(ERROR, "Bad (null) time external representation"); |
||||
|
||||
if (decode_24h_time(str, tm, &fsec) != 0) |
||||
elog(ERROR, "Bad time external representation '%s'", str); |
||||
|
||||
if ((tm->tm_hour < 0) || (tm->tm_hour > 24) |
||||
|| ((tm->tm_hour == 24) |
||||
&& ((tm->tm_min != 0) || (tm->tm_sec != 0) || (fsec != 0.0)))) |
||||
{ |
||||
elog(ERROR, |
||||
"Time must be limited to values 00:00:00 through 24:00:00 " |
||||
"in \"%s\"", |
||||
str); |
||||
} |
||||
|
||||
time = palloc(sizeof(TimeADT)); |
||||
*time = ((((tm->tm_hour * 60) + tm->tm_min) * 60)); |
||||
|
||||
return (time); |
||||
} |
||||
|
||||
/*
|
||||
* A modified version of time_out which converts from TimeADT data type |
||||
* omitting the seconds field when it is 0. |
||||
* Useful if you need to handle TimeADT values limited to hh:mm. |
||||
*/ |
||||
|
||||
char * |
||||
hhmm_out(TimeADT *time) |
||||
{ |
||||
char *result; |
||||
struct tm tt, |
||||
*tm = &tt; |
||||
char buf[MAXDATELEN + 1]; |
||||
|
||||
if (!PointerIsValid(time)) |
||||
return NULL; |
||||
|
||||
tm->tm_hour = (*time / (60 * 60)); |
||||
tm->tm_min = (((int) (*time / 60)) % 60); |
||||
tm->tm_sec = (((int) *time) % 60); |
||||
|
||||
if (tm->tm_sec == 0) |
||||
sprintf(buf, "%02d:%02d", tm->tm_hour, tm->tm_min); |
||||
else |
||||
sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); |
||||
|
||||
result = palloc(strlen(buf) + 1); |
||||
strcpy(result, buf); |
||||
|
||||
return (result); |
||||
} |
||||
|
||||
TimeADT * |
||||
hhmm(TimeADT *time) |
||||
{ |
||||
TimeADT *result = palloc(sizeof(TimeADT)); |
||||
|
||||
*result = (((int) *time) / 60 * 60); |
||||
|
||||
return (result); |
||||
} |
||||
|
||||
TimeADT * |
||||
time_difference(TimeADT *time1, TimeADT *time2) |
||||
{ |
||||
TimeADT *time = palloc(sizeof(TimeADT)); |
||||
|
||||
*time = (*time1 - *time2); |
||||
return (time); |
||||
} |
||||
|
||||
int4 |
||||
time_hours(TimeADT *time) |
||||
{ |
||||
return (((int) *time) / 3600); |
||||
} |
||||
|
||||
int4 |
||||
time_minutes(TimeADT *time) |
||||
{ |
||||
return ((((int) *time) / 60) % 60); |
||||
} |
||||
|
||||
int4 |
||||
time_seconds(TimeADT *time) |
||||
{ |
||||
return (((int) *time) % 60); |
||||
} |
||||
|
||||
int4 |
||||
as_minutes(TimeADT *time) |
||||
{ |
||||
return (((int) *time) / 60); |
||||
} |
||||
|
||||
int4 |
||||
as_seconds(TimeADT *time) |
||||
{ |
||||
return ((int) *time); |
||||
} |
||||
|
||||
int4 |
||||
date_day(DateADT val) |
||||
{ |
||||
int year, |
||||
month, |
||||
day; |
||||
|
||||
j2date(val + JDATE_2000, &year, &month, &day); |
||||
|
||||
return (day); |
||||
} |
||||
|
||||
int4 |
||||
date_month(DateADT val) |
||||
{ |
||||
int year, |
||||
month, |
||||
day; |
||||
|
||||
j2date(val + JDATE_2000, &year, &month, &day); |
||||
|
||||
return (month); |
||||
} |
||||
|
||||
int4 |
||||
date_year(DateADT val) |
||||
{ |
||||
int year, |
||||
month, |
||||
day; |
||||
|
||||
j2date(val + JDATE_2000, &year, &month, &day); |
||||
|
||||
return (year); |
||||
} |
||||
|
||||
TimeADT * |
||||
currenttime() |
||||
{ |
||||
TimeADT *result = palloc(sizeof(TimeADT)); |
||||
struct tm *tm; |
||||
time_t current_time; |
||||
|
||||
current_time = time(NULL); |
||||
tm = localtime(¤t_time); |
||||
*result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec); |
||||
|
||||
return (result); |
||||
} |
||||
|
||||
DateADT |
||||
currentdate() |
||||
{ |
||||
DateADT date; |
||||
struct tm tt, |
||||
*tm = &tt; |
||||
|
||||
GetCurrentTime(tm); |
||||
date = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - JDATE_2000); |
||||
return (date); |
||||
} |
||||
|
||||
int4 |
||||
date2mjd(DateADT val) |
||||
{ |
||||
int result; |
||||
|
||||
result = val + JDATE_2000 - 2400000.5; |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* end of file */ |
||||
|
||||
/*
|
||||
* Local Variables: |
||||
* tab-width: 4 |
||||
* c-indent-level: 4 |
||||
* c-basic-offset: 4 |
||||
* End: |
||||
*/ |
@ -1,28 +0,0 @@ |
||||
#ifndef DATETIME_FUNCTIONS_H |
||||
#define DATETIME_FUNCTIONS_H |
||||
|
||||
TimeADT *hhmm_in(char *str); |
||||
char *hhmm_out(TimeADT *time); |
||||
TimeADT *hhmm(TimeADT *time); |
||||
TimeADT *time_difference(TimeADT *time1, TimeADT *time2); |
||||
int4 time_hours(TimeADT *time); |
||||
int4 time_minutes(TimeADT *time); |
||||
int4 time_seconds(TimeADT *time); |
||||
int4 as_minutes(TimeADT *time); |
||||
int4 as_seconds(TimeADT *time); |
||||
int4 date_day(DateADT val); |
||||
int4 date_month(DateADT val); |
||||
int4 date_year(DateADT val); |
||||
TimeADT *currenttime(void); |
||||
DateADT currentdate(void); |
||||
int4 date2mjd(DateADT val); |
||||
|
||||
#endif |
||||
|
||||
/*
|
||||
* Local Variables: |
||||
* tab-width: 4 |
||||
* c-indent-level: 4 |
||||
* c-basic-offset: 4 |
||||
* End: |
||||
*/ |
@ -1,100 +0,0 @@ |
||||
-- datetime_functions.sql -- |
||||
-- |
||||
-- SQL code to define the new date and time functions and operators |
||||
-- |
||||
-- Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it> |
||||
-- |
||||
-- This file is distributed under the GNU General Public License |
||||
-- either version 2, or (at your option) any later version. |
||||
|
||||
-- Define the new time functions. |
||||
-- |
||||
create function hhmm_in(opaque) returns time |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function hhmm_out(opaque) returns int4 |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function hhmm(time) returns time |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function time_difference(time,time) returns time |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function time_hours(time) returns int4 |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function time_minutes(time) returns int4 |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function time_seconds(time) returns int4 |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function as_minutes(time) returns int4 |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function as_seconds(time) returns int4 |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function date_day(date) returns int4 |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function date_month(date) returns int4 |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function date_year(date) returns int4 |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function currenttime() returns time |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
create function currentdate() returns date |
||||
as 'MODULE_PATHNAME' |
||||
language 'c'; |
||||
|
||||
-- Define new operator - for time. |
||||
-- |
||||
create operator - ( |
||||
leftarg=time, |
||||
rightarg=time, |
||||
procedure=time_difference); |
||||
|
||||
-- Define functions to switch from time to hhmm representation. |
||||
-- |
||||
-- select hhmm_mode(); |
||||
-- select time_mode(); |
||||
-- |
||||
create function hhmm_mode() returns text |
||||
as 'update pg_type set typinput =''hhmm_in'' where typname=''time''; |
||||
update pg_type set typoutput=''hhmm_out'' where typname=''time''; |
||||
select ''hhmm_mode''::text;' |
||||
language 'sql'; |
||||
|
||||
create function time_mode() returns text |
||||
as 'update pg_type set typinput =''time_in'' where typname=''time''; |
||||
update pg_type set typoutput=''time_out'' where typname=''time''; |
||||
select ''time_mode''::text;' |
||||
language 'sql'; |
||||
|
||||
-- Use these to do the updates manually |
||||
-- |
||||
-- update pg_type set typinput ='hhmm_in' where typname='time'; |
||||
-- update pg_type set typoutput='hhmm_out' where typname='time'; |
||||
-- |
||||
-- update pg_type set typinput ='time_in' where typname='time'; |
||||
-- update pg_type set typoutput='time_out' where typname='time'; |
||||
|
||||
-- end of file |
@ -1,15 +1,53 @@ |
||||
# PGLIB is probably /usr/local/pgsql/lib
|
||||
#
|
||||
# $Header: /cvsroot/pgsql/contrib/earthdistance/Makefile,v 1.2 2000/06/15 18:54:46 momjian Exp $
|
||||
#
|
||||
|
||||
PGINCLUDE=${PGLIB}/../include
|
||||
CFLAGS+=-I${PGINCLUDE}
|
||||
TOPDIR=../..
|
||||
|
||||
install-earthdistance: ${PGLIB}/earthdistance.so |
||||
include ../Makefile.global |
||||
|
||||
${PGLIB}/earthdistance.so: earthdistance.so |
||||
sudo install -C -g bin -o bin earthdistance.so ${PGLIB}
|
||||
NAME = earthdistance
|
||||
|
||||
earthdistance.so: earthdistance.o |
||||
$(LD) -o $@ -Bshareable $<
|
||||
PROGRAM =
|
||||
OBJS = $(NAME).o
|
||||
DOCS = $(NAME).doc
|
||||
SQLS = $(NAME).sql
|
||||
BINS =
|
||||
EXAMPLES=
|
||||
MODS = $(NAME)$(DLSUFFIX)
|
||||
|
||||
earthdistance.o: earthdistance.c |
||||
$(CC) -o $@ -c $(CFLAGS) $<
|
||||
CFLAGS += -I. $(CFLAGS_SL)
|
||||
|
||||
OTHER_CLEAN = $(SQLS)
|
||||
|
||||
all: $(MODS) $(SQLS) |
||||
|
||||
%.sql: %.sql.in |
||||
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||
|
||||
install: install_doc install_sql install_mod |
||||
|
||||
install_doc: |
||||
for inst_file in $(DOCS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
|
||||
done
|
||||
|
||||
install_sql: |
||||
for inst_file in $(SQLS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
|
||||
done
|
||||
|
||||
install_mod: |
||||
for inst_file in $(MODS); do \
|
||||
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
|
||||
done
|
||||
|
||||
depend dep: |
||||
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||
|
||||
clean: |
||||
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||
|
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
||||
|
@ -1,23 +0,0 @@ |
||||
|
||||
--------------- geo_distance |
||||
|
||||
DROP FUNCTION geo_distance (point, point); |
||||
CREATE FUNCTION geo_distance (point, point) RETURNS float8 |
||||
AS '/usr/local/pgsql/lib/earthdistance.so' LANGUAGE 'c'; |
||||
|
||||
SELECT geo_distance ('(1,2)'::point, '(3,4)'::point); |
||||
|
||||
--------------- geo_distance as operator <@> |
||||
|
||||
DROP OPERATOR <@> (point, point); |
||||
CREATE OPERATOR <@> ( |
||||
leftarg = point, |
||||
rightarg = point, |
||||
procedure = geo_distance, |
||||
commutator = <@> |
||||
); |
||||
|
||||
-- ( 87.6, 41.8) is in Chicago |
||||
-- (106.7, 35.1) is in Albuquerque |
||||
-- The cities are about 1100 miles apart |
||||
SELECT '(87.6,41.8)'::point <@> '(106.7,35.1)'::point; |
@ -1,23 +1,50 @@ |
||||
#
|
||||
# Makefile, requires src/interfaces/libpgeasy
|
||||
# $Header: /cvsroot/pgsql/contrib/findoidjoins/Attic/Makefile,v 1.5 2000/06/15 18:54:49 momjian Exp $
|
||||
#
|
||||
#
|
||||
INSTALLDIR = /usr/local/pgsql
|
||||
|
||||
TARGET = findoidjoins
|
||||
PGEASY = ../../src/interfaces/libpgeasy
|
||||
CFLAGS = -g -Wall -I. -I$(PGEASY) -I$(INSTALLDIR)/include
|
||||
LIBPGEASY = $(PGEASY)/libpgeasy.a
|
||||
LDFLAGS = -L$(INSTALLDIR)/lib -lpq
|
||||
TOPDIR=../..
|
||||
|
||||
all : $(TARGET) |
||||
include ../Makefile.global |
||||
|
||||
findoidjoins: findoidjoins.c $(LIBPGEASY) |
||||
gcc -o $@ $(CFLAGS) $^ $(LDFLAGS)
|
||||
NAME = findoidjoins
|
||||
|
||||
clean: |
||||
rm -f *.o $(TARGET) log core
|
||||
PROGRAM = $(NAME)
|
||||
OBJS = $(NAME).o
|
||||
DOCS = $(NAME).doc
|
||||
SQLS =
|
||||
BINS = $(PROGRAM) make_oidjoins_check
|
||||
EXAMPLES=
|
||||
MODS =
|
||||
|
||||
CFLAGS += -I$(LIBPGEASYDIR) -I$(LIBPQDIR)
|
||||
|
||||
OTHER_CLEAN =
|
||||
|
||||
|
||||
all: $(PROGRAM) |
||||
|
||||
$(PROGRAM): $(OBJS) $(LIBPGEASYDIR)/libpgeasy.a |
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPGEASY)
|
||||
|
||||
install: |
||||
install -s -o bin -g bin $(TARGET) $(INSTALLDIR)/bin
|
||||
|
||||
install: install_doc nstall_bin |
||||
|
||||
install_doc: |
||||
for inst_file in $(DOCS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
|
||||
done
|
||||
|
||||
install_bin: |
||||
for inst_file in $(BINS); do \
|
||||
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
|
||||
done
|
||||
|
||||
depend dep: |
||||
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||
|
||||
clean: |
||||
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||
|
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
||||
|
@ -1,97 +0,0 @@ |
||||
The following data was generated by the 'timings.sh' script included |
||||
in this directory. It uses a very large table with music-related |
||||
articles as a source for the fti-table. The tables used are: |
||||
|
||||
product : contains product information : 540.429 rows |
||||
artist_fti : fti table for product : 4.501.321 rows |
||||
clustered : same as above, only clustered : 4.501.321 rows |
||||
|
||||
A sequential scan of the artist_fti table (and thus also the clustered table) |
||||
takes around 6:16 minutes.... |
||||
|
||||
Unfortunately I cannot probide anybody else with this test-date, since I |
||||
am not allowed to redistribute the data (it's a database being sold by |
||||
a couple of wholesale companies). Anyways, it's megabytes, so you probably |
||||
wouldn't want it in this distribution anyways. |
||||
|
||||
I haven't tested this with less data. |
||||
|
||||
The test-machine is a Pentium 133, 64 MB, Linux 2.0.32 with the database |
||||
on a 'QUANTUM BIGFOOT_CY4320A, 4134MB w/67kB Cache, CHS=8960/15/63'. This |
||||
is a very slow disk. |
||||
|
||||
The postmaster was running with: |
||||
|
||||
postmaster -i -b /usr/local/pgsql/bin/postgres -S 1024 -B 256 \ |
||||
-o -o /usr/local/pgsql/debug-output -F -d 1 |
||||
|
||||
('trashing' means a 'select count(*) from artist_fti' to completely trash |
||||
any disk-caches and buffers....) |
||||
|
||||
TESTING ON UNCLUSTERED FTI |
||||
trashing |
||||
1: ^lapton and ^ric : 0.050u 0.000s 5m37.484s 0.01% |
||||
2: ^lapton and ^ric : 0.050u 0.030s 5m32.447s 0.02% |
||||
3: ^lapton and ^ric : 0.030u 0.020s 5m28.822s 0.01% |
||||
trashing |
||||
1: ^lling and ^tones : 0.020u 0.030s 0m54.313s 0.09% |
||||
2: ^lling and ^tones : 0.040u 0.030s 0m5.057s 1.38% |
||||
3: ^lling and ^tones : 0.010u 0.050s 0m2.072s 2.89% |
||||
trashing |
||||
1: ^aughan and ^evie : 0.020u 0.030s 0m26.241s 0.19% |
||||
2: ^aughan and ^evie : 0.050u 0.010s 0m1.316s 4.55% |
||||
3: ^aughan and ^evie : 0.030u 0.020s 0m1.029s 4.85% |
||||
trashing |
||||
1: ^lling : 0.040u 0.010s 0m55.104s 0.09% |
||||
2: ^lling : 0.030u 0.030s 0m4.716s 1.27% |
||||
3: ^lling : 0.040u 0.010s 0m2.157s 2.31% |
||||
trashing |
||||
1: ^stev and ^ray and ^vaugh : 0.040u 0.000s 1m5.630s 0.06% |
||||
2: ^stev and ^ray and ^vaugh : 0.050u 0.020s 1m3.561s 0.11% |
||||
3: ^stev and ^ray and ^vaugh : 0.050u 0.010s 1m5.923s 0.09% |
||||
trashing |
||||
1: ^lling (no join) : 0.050u 0.020s 0m24.139s 0.28% |
||||
2: ^lling (no join) : 0.040u 0.040s 0m1.087s 7.35% |
||||
3: ^lling (no join) : 0.020u 0.030s 0m0.772s 6.48% |
||||
trashing |
||||
1: ^vaughan (no join) : 0.040u 0.030s 0m9.075s 0.77% |
||||
2: ^vaughan (no join) : 0.030u 0.010s 0m0.609s 6.56% |
||||
3: ^vaughan (no join) : 0.040u 0.010s 0m0.503s 9.94% |
||||
trashing |
||||
1: ^rol (no join) : 0.020u 0.030s 0m49.898s 0.10% |
||||
2: ^rol (no join) : 0.030u 0.020s 0m3.136s 1.59% |
||||
3: ^rol (no join) : 0.030u 0.020s 0m1.231s 4.06% |
||||
|
||||
TESTING ON CLUSTERED FTI |
||||
trashing |
||||
1: ^lapton and ^ric : 0.020u 0.020s 2m17.120s 0.02% |
||||
2: ^lapton and ^ric : 0.030u 0.020s 2m11.767s 0.03% |
||||
3: ^lapton and ^ric : 0.040u 0.010s 2m8.128s 0.03% |
||||
trashing |
||||
1: ^lling and ^tones : 0.020u 0.030s 0m18.179s 0.27% |
||||
2: ^lling and ^tones : 0.030u 0.010s 0m1.897s 2.10% |
||||
3: ^lling and ^tones : 0.040u 0.010s 0m1.619s 3.08% |
||||
trashing |
||||
1: ^aughan and ^evie : 0.070u 0.010s 0m11.765s 0.67% |
||||
2: ^aughan and ^evie : 0.040u 0.010s 0m1.198s 4.17% |
||||
3: ^aughan and ^evie : 0.030u 0.020s 0m0.872s 5.73% |
||||
trashing |
||||
1: ^lling : 0.040u 0.000s 0m28.623s 0.13% |
||||
2: ^lling : 0.030u 0.010s 0m2.339s 1.70% |
||||
3: ^lling : 0.030u 0.010s 0m1.975s 2.02% |
||||
trashing |
||||
1: ^stev and ^ray and ^vaugh : 0.020u 0.010s 0m17.667s 0.16% |
||||
2: ^stev and ^ray and ^vaugh : 0.030u 0.010s 0m3.745s 1.06% |
||||
3: ^stev and ^ray and ^vaugh : 0.030u 0.020s 0m3.439s 1.45% |
||||
trashing |
||||
1: ^lling (no join) : 0.020u 0.040s 0m2.218s 2.70% |
||||
2: ^lling (no join) : 0.020u 0.020s 0m0.506s 7.90% |
||||
3: ^lling (no join) : 0.030u 0.030s 0m0.510s 11.76% |
||||
trashing |
||||
1: ^vaughan (no join) : 0.040u 0.050s 0m2.048s 4.39% |
||||
2: ^vaughan (no join) : 0.030u 0.020s 0m0.332s 15.04% |
||||
3: ^vaughan (no join) : 0.040u 0.010s 0m0.318s 15.72% |
||||
trashing |
||||
1: ^rol (no join) : 0.020u 0.030s 0m2.384s 2.09% |
||||
2: ^rol (no join) : 0.020u 0.030s 0m0.676s 7.39% |
||||
3: ^rol (no join) : 0.020u 0.030s 0m0.697s 7.17% |
@ -1,24 +1,58 @@ |
||||
SRCDIR= ../../src
|
||||
#
|
||||
# $Header: /cvsroot/pgsql/contrib/fulltextindex/Attic/Makefile,v 1.3 2000/06/15 18:54:51 momjian Exp $
|
||||
#
|
||||
|
||||
include $(SRCDIR)/Makefile.global |
||||
TOPDIR=../..
|
||||
|
||||
CONTRIBDIR=$(LIBDIR)/contrib
|
||||
include ../Makefile.global |
||||
|
||||
CFLAGS+= $(CFLAGS_SL)
|
||||
NAME = fti
|
||||
|
||||
TARGETS= fti$(DLSUFFIX)
|
||||
CLEANFILES+= $(TARGETS)
|
||||
CURDIR=`pwd`
|
||||
PROGRAM =
|
||||
OBJS = $(NAME).o
|
||||
DOCS = $(NAME).doc
|
||||
SQLS = $(NAME).sql
|
||||
BINS = fti.pl
|
||||
EXAMPLES=
|
||||
MODS = $(NAME)$(DLSUFFIX)
|
||||
|
||||
all:: $(TARGETS) |
||||
CFLAGS += -I. $(CFLAGS_SL)
|
||||
|
||||
%.sql: %.source |
||||
rm -f $@; \
|
||||
sed -e "s:_CURRENTDIR_:$(CURDIR):g" \
|
||||
-e "s:_DLSUFFIX_:$(DLSUFFIX):g" < $< > $@
|
||||
OTHER_CLEAN = $(SQLS)
|
||||
|
||||
clean: |
||||
rm -f $(TARGETS) *.o
|
||||
all: $(MODS) $(SQLS) |
||||
|
||||
dist: |
||||
tar cf fti.tar README BENCH Makefile fti.c timings.sh
|
||||
%.sql: %.sql.in |
||||
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||
|
||||
install: install_doc install_sql install_mod install_bin |
||||
|
||||
install_doc: |
||||
for inst_file in $(DOCS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
|
||||
done
|
||||
|
||||
install_sql: |
||||
for inst_file in $(SQLS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
|
||||
done
|
||||
|
||||
install_mod: |
||||
for inst_file in $(MODS); do \
|
||||
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
|
||||
done
|
||||
|
||||
install_bin: |
||||
for inst_file in $(BINS); do \
|
||||
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
|
||||
done
|
||||
|
||||
depend dep: |
||||
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||
|
||||
clean: |
||||
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||
|
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
||||
|
@ -1,204 +0,0 @@ |
||||
#!/usr/bin/perl |
||||
# |
||||
# This script substracts all substrings out of a specific column in a table |
||||
# and generates output that can be loaded into a new table with the |
||||
# psql '\copy' command. The new table should have the following structure: |
||||
# |
||||
# create table tab ( |
||||
# string text, |
||||
# id oid |
||||
# ); |
||||
# |
||||
# Note that you cannot use 'copy' (the SQL-command) directly, because |
||||
# there's no '\.' included at the end of the output. |
||||
# |
||||
# The output can be fed through the UNIX commands 'uniq' and 'sort' |
||||
# to generate the smallest and sorted output to populate the fti-table. |
||||
# |
||||
# Example: |
||||
# |
||||
# fti.pl -u -d mydb -t mytable -c mycolumn -f myfile |
||||
# sort -o myoutfile myfile |
||||
# uniq myoutfile sorted-file |
||||
# |
||||
# psql -u mydb |
||||
# |
||||
# \copy my_fti_table from myfile |
||||
# |
||||
# create index fti_idx on my_fti_table (string,id); |
||||
# |
||||
# create function fti() returns opaque as |
||||
# '/path/to/fti/file/fti.so' |
||||
# language 'newC'; |
||||
# |
||||
# create trigger my_fti_trigger after update or insert or delete |
||||
# on mytable |
||||
# for each row execute procedure fti(my_fti_table, mycolumn); |
||||
# |
||||
# Make sure you have an index on mytable(oid) to be able to do somewhat |
||||
# efficient substring searches. |
||||
|
||||
#use lib '/usr/local/pgsql/lib/perl5/'; |
||||
use lib '/mnt/web/guide/postgres/lib/perl5/site_perl'; |
||||
use Pg; |
||||
use Getopt::Std; |
||||
|
||||
$PGRES_EMPTY_QUERY = 0 ; |
||||
$PGRES_COMMAND_OK = 1 ; |
||||
$PGRES_TUPLES_OK = 2 ; |
||||
$PGRES_COPY_OUT = 3 ; |
||||
$PGRES_COPY_IN = 4 ; |
||||
$PGRES_BAD_RESPONSE = 5 ; |
||||
$PGRES_NONFATAL_ERROR = 6 ; |
||||
$PGRES_FATAL_ERROR = 7 ; |
||||
|
||||
$[ = 0; # make sure string offsets start at 0 |
||||
|
||||
sub break_up { |
||||
my $string = pop @_; |
||||
|
||||
@strings = split(/\W+/, $string); |
||||
@subs = (); |
||||
|
||||
foreach $s (@strings) { |
||||
$len = length($s); |
||||
next if ($len < 4); |
||||
|
||||
$lpos = $len-1; |
||||
while ($lpos >= 3) { |
||||
$fpos = $lpos - 3; |
||||
while ($fpos >= 0) { |
||||
$sub = substr($s, $fpos, $lpos - $fpos + 1); |
||||
push(@subs, $sub); |
||||
$fpos = $fpos - 1; |
||||
} |
||||
$lpos = $lpos - 1; |
||||
} |
||||
} |
||||
|
||||
return @subs; |
||||
} |
||||
|
||||
sub connect_db { |
||||
my $dbname = shift @_; |
||||
my $user = shift @_; |
||||
my $passwd = shift @_; |
||||
|
||||
if (!defined($dbname) || $dbname eq "") { |
||||
return 1; |
||||
} |
||||
$connect_string = "dbname=$dbname"; |
||||
|
||||
if ($user ne "") { |
||||
if ($passwd eq "") { |
||||
return 0; |
||||
} |
||||
$connect_string = "$connect_string user=$user password=$passwd ". |
||||
"authtype=password"; |
||||
} |
||||
|
||||
$PG_CONN = PQconnectdb($connect_string); |
||||
|
||||
if (PQstatus($PG_CONN)) { |
||||
print STDERR "Couldn't make connection with database!\n"; |
||||
print STDERR PQerrorMessage($PG_CONN), "\n"; |
||||
return 0; |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
sub quit_prog { |
||||
close(OUT); |
||||
unlink $opt_f; |
||||
if (defined($PG_CONN)) { |
||||
PQfinish($PG_CONN); |
||||
} |
||||
exit 1; |
||||
} |
||||
|
||||
sub get_username { |
||||
print "Username: "; |
||||
chop($n = <STDIN>); |
||||
|
||||
return $n;; |
||||
} |
||||
|
||||
sub get_password { |
||||
print "Password: "; |
||||
|
||||
system("stty -echo < /dev/tty"); |
||||
chop($pwd = <STDIN>); |
||||
print "\n"; |
||||
system("stty echo < /dev/tty"); |
||||
|
||||
return $pwd; |
||||
} |
||||
|
||||
sub main { |
||||
getopts('d:t:c:f:u'); |
||||
|
||||
if (!$opt_d || !$opt_t || !$opt_c || !$opt_f) { |
||||
print STDERR "usage: $0 [-u] -d database -t table -c column ". |
||||
"-f output-file\n"; |
||||
return 1; |
||||
} |
||||
|
||||
if (defined($opt_u)) { |
||||
$uname = get_username(); |
||||
$pwd = get_password(); |
||||
} else { |
||||
$uname = ""; |
||||
$pwd = ""; |
||||
} |
||||
|
||||
$SIG{'INT'} = 'quit_prog'; |
||||
if (!connect_db($opt_d, $uname, $pwd)) { |
||||
print STDERR "Connecting to database failed!\n"; |
||||
return 1; |
||||
} |
||||
|
||||
if (!open(OUT, ">$opt_f")) { |
||||
print STDERR "Couldnt' open file '$opt_f' for output!\n"; |
||||
return 1; |
||||
} |
||||
|
||||
PQexec($PG_CONN, "begin"); |
||||
|
||||
$query = "declare C cursor for select $opt_c, oid from $opt_t"; |
||||
$res = PQexec($PG_CONN, $query); |
||||
if (!$res || (PQresultStatus($res) != $PGRES_COMMAND_OK)) { |
||||
print STDERR "Error declaring cursor!\n"; |
||||
print STDERR PQerrorMessage($PG_CONN), "\n"; |
||||
PQfinish($PG_CONN); |
||||
return 1; |
||||
} |
||||
PQclear($res); |
||||
|
||||
$query = "fetch in C"; |
||||
while (($res = PQexec($PG_CONN, $query)) && |
||||
(PQresultStatus($res) == $PGRES_TUPLES_OK) && |
||||
(PQntuples($res) == 1)) { |
||||
$col = PQgetvalue($res, 0, 0); |
||||
$oid = PQgetvalue($res, 0, 1); |
||||
|
||||
@subs = break_up($col); |
||||
foreach $i (@subs) { |
||||
print OUT "$i\t$oid\n"; |
||||
} |
||||
} |
||||
|
||||
if (!$res || (PQresultStatus($res) != PGRES_TUPLES_OK)) { |
||||
print STDERR "Error retrieving data from backend!\n"; |
||||
print STDERR PQerrorMEssage($PG_CONN), "\n"; |
||||
PQfinish($PG_CONN); |
||||
return 1; |
||||
} |
||||
|
||||
PQclear($res); |
||||
PQfinish($PG_CONN); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
exit main(); |
@ -1,18 +1,54 @@ |
||||
#
|
||||
# PostgreSQL types for ISBN and ISSN identifiers.
|
||||
# $Header: /cvsroot/pgsql/contrib/isbn_issn/Attic/Makefile,v 1.3 2000/06/15 18:54:53 momjian Exp $
|
||||
#
|
||||
# $Id: Makefile,v 1.2 2000/05/29 05:44:26 tgl Exp $
|
||||
|
||||
SRCDIR= ../../src
|
||||
TOPDIR=../..
|
||||
|
||||
include $(SRCDIR)/Makefile.global |
||||
include ../Makefile.global |
||||
|
||||
CFLAGS+= $(CFLAGS_SL)
|
||||
NAME = isbn_issn
|
||||
|
||||
all: isbn$(DLSUFFIX) issn$(DLSUFFIX) |
||||
PROGRAM =
|
||||
OBJS = $(NAME).o
|
||||
DOCS = $(NAME).doc
|
||||
SQLS = $(NAME).sql
|
||||
BINS =
|
||||
EXAMPLES=
|
||||
MODS = $(NAME)$(DLSUFFIX)
|
||||
|
||||
install: isbn$(DLSUFFIX) issn$(DLSUFFIX) |
||||
install -c isbn$(DLSUFFIX) issn$(DLSUFFIX) /usr/local/pgsql/modules
|
||||
CFLAGS += -I. $(CFLAGS_SL)
|
||||
|
||||
OTHER_CLEAN = $(SQLS)
|
||||
|
||||
all: $(MODS) $(SQLS) |
||||
|
||||
|
||||
%.sql: %.sql.in |
||||
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||
|
||||
install: install_doc install_sql install_mod |
||||
|
||||
install_doc: |
||||
for inst_file in $(DOCS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
|
||||
done
|
||||
|
||||
install_sql: |
||||
for inst_file in $(SQLS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
|
||||
done
|
||||
|
||||
install_mod: |
||||
for inst_file in $(MODS); do \
|
||||
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
|
||||
done
|
||||
|
||||
depend dep: |
||||
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||
|
||||
clean: |
||||
rm -f isbn$(DLSUFFIX) issn$(DLSUFFIX) *.o
|
||||
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||
|
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
||||
|
@ -1,199 +0,0 @@ |
||||
/*
|
||||
* PostgreSQL type definitions for ISBNs. |
||||
* |
||||
* $Id: isbn.c,v 1.3 2000/05/29 05:44:26 tgl Exp $ |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <postgres.h> |
||||
#include <utils/palloc.h> |
||||
|
||||
/*
|
||||
* This is the internal storage format for ISBNs. |
||||
* NB: This is an intentional type pun with builtin type `char16'. |
||||
*/ |
||||
|
||||
typedef struct isbn |
||||
{ |
||||
char num[13]; |
||||
char pad[3]; |
||||
} isbn; |
||||
|
||||
/*
|
||||
* Various forward declarations: |
||||
*/ |
||||
|
||||
isbn *isbn_in(char *str); |
||||
char *isbn_out(isbn * addr); |
||||
|
||||
bool isbn_lt(isbn * a1, isbn * a2); |
||||
bool isbn_le(isbn * a1, isbn * a2); |
||||
bool isbn_eq(isbn * a1, isbn * a2); |
||||
bool isbn_ge(isbn * a1, isbn * a2); |
||||
bool isbn_gt(isbn * a1, isbn * a2); |
||||
|
||||
bool isbn_ne(isbn * a1, isbn * a2); |
||||
|
||||
int4 isbn_cmp(isbn * a1, isbn * a2); |
||||
|
||||
int4 isbn_sum(char *str); |
||||
|
||||
/*
|
||||
* ISBN reader. |
||||
*/ |
||||
|
||||
isbn * |
||||
isbn_in(char *str) |
||||
{ |
||||
isbn *result; |
||||
|
||||
if (strlen(str) != 13) |
||||
{ |
||||
elog(ERROR, "isbn_in: invalid ISBN \"%s\"", str); |
||||
return (NULL); |
||||
} |
||||
if (isbn_sum(str) != 0) |
||||
{ |
||||
elog(ERROR, "isbn_in: purported ISBN \"%s\" failed checksum", |
||||
str); |
||||
return (NULL); |
||||
} |
||||
|
||||
result = (isbn *) palloc(sizeof(isbn)); |
||||
|
||||
strncpy(result->num, str, 13); |
||||
memset(result->pad, ' ', 3); |
||||
return (result); |
||||
} |
||||
|
||||
/*
|
||||
* The ISBN checksum is defined as follows: |
||||
* |
||||
* Number the digits from 1 to 9 (call this N). |
||||
* Compute the sum, S, of N * D_N. |
||||
* The check digit, C, is the value which satisfies the equation |
||||
* S + 10*C === 0 (mod 11) |
||||
* The value 10 for C is written as `X'. |
||||
* |
||||
* For our purposes, we want the complete sum including the check |
||||
* digit; if this is zero, then the checksum passed. We also check |
||||
* the syntactic validity if the provided string, and return 12 |
||||
* if any errors are found. |
||||
*/ |
||||
int4 |
||||
isbn_sum(char *str) |
||||
{ |
||||
int4 sum = 0, |
||||
dashes = 0, |
||||
val; |
||||
int i; |
||||
|
||||
for (i = 0; str[i] && i < 13; i++) |
||||
{ |
||||
switch (str[i]) |
||||
{ |
||||
case '-': |
||||
if (++dashes > 3) |
||||
return 12; |
||||
continue; |
||||
|
||||
case '0': |
||||
case '1': |
||||
case '2': |
||||
case '3': |
||||
case '4': |
||||
case '5': |
||||
case '6': |
||||
case '7': |
||||
case '8': |
||||
case '9': |
||||
val = str[i] - '0'; |
||||
break; |
||||
|
||||
case 'X': |
||||
case 'x': |
||||
val = 10; |
||||
break; |
||||
|
||||
default: |
||||
return 12; |
||||
} |
||||
|
||||
sum += val * (i + 1 - dashes); |
||||
} |
||||
return (sum % 11); |
||||
} |
||||
|
||||
/*
|
||||
* ISBN output function. |
||||
*/ |
||||
|
||||
char * |
||||
isbn_out(isbn * num) |
||||
{ |
||||
char *result; |
||||
|
||||
if (num == NULL) |
||||
return (NULL); |
||||
|
||||
result = (char *) palloc(14); |
||||
|
||||
result[0] = '\0'; |
||||
strncat(result, num->num, 13); |
||||
return (result); |
||||
} |
||||
|
||||
/*
|
||||
* Boolean tests for magnitude. |
||||
*/ |
||||
|
||||
bool |
||||
isbn_lt(isbn * a1, isbn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 13) < 0); |
||||
}; |
||||
|
||||
bool |
||||
isbn_le(isbn * a1, isbn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 13) <= 0); |
||||
}; |
||||
|
||||
bool |
||||
isbn_eq(isbn * a1, isbn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 13) == 0); |
||||
}; |
||||
|
||||
bool |
||||
isbn_ge(isbn * a1, isbn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 13) >= 0); |
||||
}; |
||||
|
||||
bool |
||||
isbn_gt(isbn * a1, isbn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 13) > 0); |
||||
}; |
||||
|
||||
bool |
||||
isbn_ne(isbn * a1, isbn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 13) != 0); |
||||
}; |
||||
|
||||
/*
|
||||
* Comparison function for sorting: |
||||
*/ |
||||
|
||||
int4 |
||||
isbn_cmp(isbn * a1, isbn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 13)); |
||||
} |
||||
|
||||
/*
|
||||
* eof |
||||
*/ |
@ -1,116 +0,0 @@ |
||||
-- |
||||
-- PostgreSQL code for ISBNs. |
||||
-- |
||||
-- $Id: isbn.sql,v 1.1 1998/08/17 03:35:05 scrappy Exp $ |
||||
-- |
||||
|
||||
load '/usr/local/pgsql/modules/isbn.so'; |
||||
|
||||
-- |
||||
-- Input and output functions and the type itself: |
||||
-- |
||||
|
||||
create function isbn_in(opaque) |
||||
returns opaque |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_out(opaque) |
||||
returns opaque |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create type isbn ( |
||||
internallength = 16, |
||||
externallength = 13, |
||||
input = isbn_in, |
||||
output = isbn_out |
||||
); |
||||
|
||||
-- |
||||
-- The various boolean tests: |
||||
-- |
||||
|
||||
create function isbn_lt(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_le(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_eq(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_ge(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_gt(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_ne(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
-- |
||||
-- Now the operators. Note how some of the parameters to some |
||||
-- of the 'create operator' commands are commented out. This |
||||
-- is because they reference as yet undefined operators, and |
||||
-- will be implicitly defined when those are, further down. |
||||
-- |
||||
|
||||
create operator < ( |
||||
leftarg = isbn, |
||||
rightarg = isbn, |
||||
-- negator = >=, |
||||
procedure = isbn_lt |
||||
); |
||||
|
||||
create operator <= ( |
||||
leftarg = isbn, |
||||
rightarg = isbn, |
||||
-- negator = >, |
||||
procedure = isbn_le |
||||
); |
||||
|
||||
create operator = ( |
||||
leftarg = isbn, |
||||
rightarg = isbn, |
||||
commutator = =, |
||||
-- negator = <>, |
||||
procedure = isbn_eq |
||||
); |
||||
|
||||
create operator >= ( |
||||
leftarg = isbn, |
||||
rightarg = isbn, |
||||
negator = <, |
||||
procedure = isbn_ge |
||||
); |
||||
|
||||
create operator > ( |
||||
leftarg = isbn, |
||||
rightarg = isbn, |
||||
negator = <=, |
||||
procedure = isbn_gt |
||||
); |
||||
|
||||
create operator <> ( |
||||
leftarg = isbn, |
||||
rightarg = isbn, |
||||
negator = =, |
||||
procedure = isbn_ne |
||||
); |
||||
|
||||
-- |
||||
-- eof |
||||
-- |
@ -1,190 +0,0 @@ |
||||
/*
|
||||
* PostgreSQL type definitions for ISSNs. |
||||
* |
||||
* $Id: issn.c,v 1.3 2000/05/29 05:44:26 tgl Exp $ |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <postgres.h> |
||||
#include <utils/palloc.h> |
||||
|
||||
/*
|
||||
* This is the internal storage format for ISSNs. |
||||
* NB: This is an intentional type pun with builtin type `char16'. |
||||
*/ |
||||
|
||||
typedef struct issn |
||||
{ |
||||
char num[9]; |
||||
char pad[7]; |
||||
} issn; |
||||
|
||||
/*
|
||||
* Various forward declarations: |
||||
*/ |
||||
|
||||
issn *issn_in(char *str); |
||||
char *issn_out(issn * addr); |
||||
|
||||
bool issn_lt(issn * a1, issn * a2); |
||||
bool issn_le(issn * a1, issn * a2); |
||||
bool issn_eq(issn * a1, issn * a2); |
||||
bool issn_ge(issn * a1, issn * a2); |
||||
bool issn_gt(issn * a1, issn * a2); |
||||
|
||||
bool issn_ne(issn * a1, issn * a2); |
||||
|
||||
int4 issn_cmp(issn * a1, issn * a2); |
||||
|
||||
int4 issn_sum(char *str); |
||||
|
||||
/*
|
||||
* ISSN reader. |
||||
*/ |
||||
|
||||
issn * |
||||
issn_in(char *str) |
||||
{ |
||||
issn *result; |
||||
|
||||
if (strlen(str) != 9) |
||||
{ |
||||
elog(ERROR, "issn_in: invalid ISSN \"%s\"", str); |
||||
return (NULL); |
||||
} |
||||
if (issn_sum(str) != 0) |
||||
{ |
||||
elog(ERROR, "issn_in: purported ISSN \"%s\" failed checksum", |
||||
str); |
||||
return (NULL); |
||||
} |
||||
|
||||
result = (issn *) palloc(sizeof(issn)); |
||||
|
||||
strncpy(result->num, str, 9); |
||||
memset(result->pad, ' ', 7); |
||||
return (result); |
||||
} |
||||
|
||||
/*
|
||||
* The ISSN checksum works just like the ISBN sum, only different |
||||
* (of course!). |
||||
* Here, the weights start at 8 and decrease. |
||||
*/ |
||||
int4 |
||||
issn_sum(char *str) |
||||
{ |
||||
int4 sum = 0, |
||||
dashes = 0, |
||||
val; |
||||
int i; |
||||
|
||||
for (i = 0; str[i] && i < 9; i++) |
||||
{ |
||||
switch (str[i]) |
||||
{ |
||||
case '-': |
||||
if (++dashes > 1) |
||||
return 12; |
||||
continue; |
||||
|
||||
case '0': |
||||
case '1': |
||||
case '2': |
||||
case '3': |
||||
case '4': |
||||
case '5': |
||||
case '6': |
||||
case '7': |
||||
case '8': |
||||
case '9': |
||||
val = str[i] - '0'; |
||||
break; |
||||
|
||||
case 'X': |
||||
case 'x': |
||||
val = 10; |
||||
break; |
||||
|
||||
default: |
||||
return 12; |
||||
} |
||||
|
||||
sum += val * (8 - (i - dashes)); |
||||
} |
||||
return (sum % 11); |
||||
} |
||||
|
||||
/*
|
||||
* ISSN output function. |
||||
*/ |
||||
|
||||
char * |
||||
issn_out(issn * num) |
||||
{ |
||||
char *result; |
||||
|
||||
if (num == NULL) |
||||
return (NULL); |
||||
|
||||
result = (char *) palloc(14); |
||||
|
||||
result[0] = '\0'; |
||||
strncat(result, num->num, 9); |
||||
return (result); |
||||
} |
||||
|
||||
/*
|
||||
* Boolean tests for magnitude. |
||||
*/ |
||||
|
||||
bool |
||||
issn_lt(issn * a1, issn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 9) < 0); |
||||
}; |
||||
|
||||
bool |
||||
issn_le(issn * a1, issn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 9) <= 0); |
||||
}; |
||||
|
||||
bool |
||||
issn_eq(issn * a1, issn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 9) == 0); |
||||
}; |
||||
|
||||
bool |
||||
issn_ge(issn * a1, issn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 9) >= 0); |
||||
}; |
||||
|
||||
bool |
||||
issn_gt(issn * a1, issn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 9) > 0); |
||||
}; |
||||
|
||||
bool |
||||
issn_ne(issn * a1, issn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 9) != 0); |
||||
}; |
||||
|
||||
/*
|
||||
* Comparison function for sorting: |
||||
*/ |
||||
|
||||
int4 |
||||
issn_cmp(issn * a1, issn * a2) |
||||
{ |
||||
return (strncmp(a1->num, a2->num, 9)); |
||||
} |
||||
|
||||
/*
|
||||
* eof |
||||
*/ |
@ -1,116 +0,0 @@ |
||||
-- |
||||
-- PostgreSQL code for ISSNs. |
||||
-- |
||||
-- $Id: issn.sql,v 1.1 1998/08/17 03:35:05 scrappy Exp $ |
||||
-- |
||||
|
||||
load '/usr/local/pgsql/modules/issn.so'; |
||||
|
||||
-- |
||||
-- Input and output functions and the type itself: |
||||
-- |
||||
|
||||
create function issn_in(opaque) |
||||
returns opaque |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_out(opaque) |
||||
returns opaque |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create type issn ( |
||||
internallength = 16, |
||||
externallength = 9, |
||||
input = issn_in, |
||||
output = issn_out |
||||
); |
||||
|
||||
-- |
||||
-- The various boolean tests: |
||||
-- |
||||
|
||||
create function issn_lt(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_le(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_eq(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_ge(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_gt(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_ne(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
-- |
||||
-- Now the operators. Note how some of the parameters to some |
||||
-- of the 'create operator' commands are commented out. This |
||||
-- is because they reference as yet undefined operators, and |
||||
-- will be implicitly defined when those are, further down. |
||||
-- |
||||
|
||||
create operator < ( |
||||
leftarg = issn, |
||||
rightarg = issn, |
||||
-- negator = >=, |
||||
procedure = issn_lt |
||||
); |
||||
|
||||
create operator <= ( |
||||
leftarg = issn, |
||||
rightarg = issn, |
||||
-- negator = >, |
||||
procedure = issn_le |
||||
); |
||||
|
||||
create operator = ( |
||||
leftarg = issn, |
||||
rightarg = issn, |
||||
commutator = =, |
||||
-- negator = <>, |
||||
procedure = issn_eq |
||||
); |
||||
|
||||
create operator >= ( |
||||
leftarg = issn, |
||||
rightarg = issn, |
||||
negator = <, |
||||
procedure = issn_ge |
||||
); |
||||
|
||||
create operator > ( |
||||
leftarg = issn, |
||||
rightarg = issn, |
||||
negator = <=, |
||||
procedure = issn_gt |
||||
); |
||||
|
||||
create operator <> ( |
||||
leftarg = issn, |
||||
rightarg = issn, |
||||
negator = =, |
||||
procedure = issn_ne |
||||
); |
||||
|
||||
-- |
||||
-- eof |
||||
-- |
@ -1,21 +0,0 @@ |
||||
-- |
||||
-- This removes the type (and a test table) |
||||
-- It's used just for development |
||||
-- |
||||
|
||||
-- remove our test table |
||||
drop table a; |
||||
|
||||
-- now drop any sql based functions associated with the lo type |
||||
drop function oid(lo); |
||||
|
||||
-- now drop the type |
||||
drop type lo; |
||||
|
||||
-- as the type is gone, remove the C based functions |
||||
drop function lo_in(opaque); |
||||
drop function lo_out(opaque); |
||||
drop function lo(oid); |
||||
drop function lo_manage(); |
||||
|
||||
-- the lo stuff is now removed from the system |
@ -1,57 +0,0 @@ |
||||
-- |
||||
-- This runs some common tests against the type |
||||
-- |
||||
-- It's used just for development |
||||
-- |
||||
|
||||
-- ignore any errors here - simply drop the table if it already exists |
||||
drop table a; |
||||
|
||||
-- create the test table |
||||
create table a (fname name,image lo); |
||||
|
||||
-- insert a null object |
||||
insert into a values ('null'); |
||||
|
||||
-- insert an empty large object |
||||
insert into a values ('empty',''); |
||||
|
||||
-- insert a large object based on a file |
||||
insert into a values ('/etc/group',lo_import('/etc/group')::lo); |
||||
|
||||
-- now select the table |
||||
select * from a; |
||||
|
||||
-- this select also returns an oid based on the lo column |
||||
select *,image::oid from a; |
||||
|
||||
-- now test the trigger |
||||
create trigger t_a before update or delete on a for each row execute procedure lo_manage(image); |
||||
|
||||
-- insert |
||||
insert into a values ('aa',''); |
||||
select * from a where fname like 'aa%'; |
||||
|
||||
-- update |
||||
update a set image=lo_import('/etc/group')::lo where fname='aa'; |
||||
select * from a where fname like 'aa%'; |
||||
|
||||
-- update the 'empty' row which should be null |
||||
update a set image=lo_import('/etc/hosts')::lo where fname='empty'; |
||||
select * from a where fname like 'empty%'; |
||||
update a set image=null where fname='empty'; |
||||
select * from a where fname like 'empty%'; |
||||
|
||||
-- delete the entry |
||||
delete from a where fname='aa'; |
||||
select * from a where fname like 'aa%'; |
||||
|
||||
-- This deletes the table contents. Note, if you comment this out, and |
||||
-- expect the drop table to remove the objects, think again. The trigger |
||||
-- doesn't get thrown by drop table. |
||||
delete from a; |
||||
|
||||
-- finally drop the table |
||||
drop table a; |
||||
|
||||
-- end of tests |
@ -0,0 +1,43 @@ |
||||
Miscellaneous utility functions for PostgreSQL. |
||||
Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it> |
||||
|
||||
This software is distributed under the GNU General Public License |
||||
either version 2, or (at your option) any later version. |
||||
|
||||
query_limit(n) |
||||
|
||||
sets a limit on the maximum numbers of query returned from |
||||
a backend. It can be used to limit the result size retrieved |
||||
by the application for poor input data or to avoid accidental |
||||
table product while playying with sql. |
||||
|
||||
backend_pid() |
||||
|
||||
return the pid of our corresponding backend. |
||||
|
||||
unlisten(relname) |
||||
|
||||
unlisten from a relation or from all relations if the argument |
||||
is null, empty or '*'. |
||||
It is now obsoleted by the new unlisten command but still useful |
||||
if you want unlisten a name computed by the query. |
||||
Note that a listen/notify relname can be any ascii string, not |
||||
just valid relation names. |
||||
|
||||
min(x,y) |
||||
max(x,y) |
||||
|
||||
return the min or max bteween two integers. |
||||
|
||||
assert_enable(bool) |
||||
|
||||
enable/disable assert checkings in the backend, if it has been |
||||
compiled with USE_ASSERT_CHECKING. |
||||
|
||||
assert_test(bool) |
||||
|
||||
test the assert enable/disable code, if the backend has been |
||||
compiled with ASSERT_CHECKING_TEST. |
||||
|
||||
-- |
||||
Massimo Dal Zotto <dz@cs.unitn.it> |
@ -0,0 +1,20 @@ |
||||
|
||||
|
||||
noupdate |
||||
~~~~~~~~ |
||||
|
||||
- trigger to prevent updates on single columns. |
||||
|
||||
|
||||
Example: |
||||
~~~~~~~ |
||||
|
||||
CREATE TABLE TEST ( COL1 INT, COL2 INT, COL3 INT ); |
||||
|
||||
CREATE TRIGGER BT BEFORE UPDATE ON TEST FOR EACH ROW |
||||
EXECUTE PROCEDURE |
||||
noup ('COL1'); |
||||
|
||||
-- Now Try |
||||
INSERT INTO TEST VALUES (10,20,30); |
||||
UPDATE TEST SET COL1 = 5; |
@ -1,9 +0,0 @@ |
||||
CREATE TABLE TEST ( COL1 INT, COL2 INT, COL3 INT ); |
||||
|
||||
CREATE TRIGGER BT BEFORE UPDATE ON TEST FOR EACH ROW |
||||
EXECUTE PROCEDURE |
||||
noup ('COL1'); |
||||
|
||||
-- Now Try |
||||
INSERT INTO TEST VALUES (10,20,30); |
||||
UPDATE TEST SET COL1 = 5; |
@ -1,7 +0,0 @@ |
||||
DROP FUNCTION noup (); |
||||
|
||||
CREATE FUNCTION noup () |
||||
RETURNS opaque |
||||
AS '_OBJWD_/noup_DLSUFFIX_' |
||||
LANGUAGE 'newC' |
||||
; |
@ -1,145 +0,0 @@ |
||||
-- ODBC.sql |
||||
-- |
||||
|
||||
-- |
||||
-- Character string manipulation |
||||
-- |
||||
|
||||
-- |
||||
-- Extensions for ODBC compliance in v7.0. |
||||
-- In the current driver, ODBC functions must map directly into a |
||||
-- Postgres function. So in some cases we must create a compatible |
||||
-- function. |
||||
-- |
||||
|
||||
-- truncate on the left |
||||
CREATE FUNCTION ltrunc(text, integer) |
||||
RETURNS text |
||||
AS 'SELECT substring($1 FROM 1 FOR $2)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
-- truncate on the right |
||||
CREATE FUNCTION rtrunc(text, integer) |
||||
RETURNS text |
||||
AS 'SELECT substring($1 FROM (char_length($1)-($2)+1) FOR $2)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION space(integer) |
||||
RETURNS text |
||||
AS 'SELECT lpad('''', $1, '' '')' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
-- |
||||
-- Mathematical functions |
||||
-- |
||||
|
||||
CREATE FUNCTION truncate(numeric,integer) |
||||
RETURNS numeric |
||||
AS 'SELECT trunc($1, $2)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
-- |
||||
-- Date/time functions for v7.0 |
||||
-- |
||||
|
||||
CREATE FUNCTION curdate() |
||||
RETURNS date |
||||
AS 'SELECT CAST(''now'' AS date)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION curtime() |
||||
RETURNS time |
||||
AS 'SELECT CAST(''now'' AS time)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION dayname(timestamp) |
||||
RETURNS text |
||||
AS 'SELECT to_char($1,''Day'')' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION dayofmonth(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT CAST(date_part(''day'', $1) AS integer)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION dayofweek(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT ( CAST(date_part(''dow'', $1) AS integer) + 1)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION dayofyear(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT CAST(date_part(''doy'', $1) AS integer)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION hour(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT CAST(date_part(''hour'', $1) AS integer)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION minute(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT CAST(date_part(''minute'', $1) AS integer)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION odbc_month(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT CAST(date_part(''month'', $1) AS integer)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION monthname(timestamp) |
||||
RETURNS text |
||||
AS 'SELECT to_char($1, ''Month'')' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION quarter(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT CAST(date_part(''quarter'', $1) AS integer)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION second(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT CAST(date_part(''second'', $1) AS integer)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
/* |
||||
-- The first argument is an integer constant denoting the units |
||||
-- of the second argument. Until we know the actual values, we |
||||
-- cannot implement these. - thomas 2000-04-11 |
||||
CREATE FUNCTION timestampadd(integer,integer,timestamp) |
||||
RETURNS timestamp |
||||
AS 'SELECT CAST(($3 + ($2 * $1)) AS timestamp)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION timestampdiff(integer,integer,timestamp) |
||||
RETURNS timestamp |
||||
AS 'SELECT CAST(($3 + ($2 * $1)) AS timestamp)' |
||||
LANGUAGE 'SQL'; |
||||
*/ |
||||
|
||||
CREATE FUNCTION week(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT CAST(date_part(''week'', $1) AS integer)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
CREATE FUNCTION year(timestamp) |
||||
RETURNS integer |
||||
AS 'SELECT CAST(date_part(''year'', $1) AS integer)' |
||||
LANGUAGE 'SQL'; |
||||
|
||||
-- |
||||
-- System functions. |
||||
-- |
||||
|
||||
/* |
||||
CREATE FUNCTION database() |
||||
RETURNS text |
||||
AS 'SELECT ...' |
||||
LANGUAGE 'SQL'; |
||||
*/ |
||||
|
||||
CREATE FUNCTION odbc_user() |
||||
RETURNS text |
||||
AS 'SELECT CAST(USER AS text)' |
||||
LANGUAGE 'SQL'; |
||||
|
@ -1,86 +0,0 @@ |
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile
|
||||
# Makefile for libpq library
|
||||
#
|
||||
# Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/contrib/os2client/Attic/Makefile,v 1.2 2000/03/19 21:59:30 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
SO_MAJOR_VERSION=1
|
||||
SO_MINOR_VERSION=1
|
||||
|
||||
SRCDIR= ../../src
|
||||
|
||||
INTERFACES= $(SRCDIR)/interfaces/libpq
|
||||
|
||||
PORTNAME=OS2
|
||||
|
||||
CC=gcc
|
||||
CFLAGS=-I. -I$(SRCDIR)/include
|
||||
CFLAGS+=-DFRONTEND -DTCPIPV4 -DHAVE_CRYPT_H
|
||||
|
||||
CP= copy
|
||||
|
||||
AR=ar
|
||||
|
||||
AROPT=rc
|
||||
|
||||
RANLIB= ar s
|
||||
|
||||
LDFLAGS= -L.
|
||||
|
||||
OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-lobj.o fe-print.o \
|
||||
dllist.o pqsignal.o pqcomprim.o
|
||||
|
||||
EXEOBJS= psql.o stringutils.o
|
||||
|
||||
all: libpq.a psql |
||||
|
||||
fe-auth.o: $(INTERFACES)/fe-auth.c |
||||
$(CC) $(CFLAGS) -c $(INTERFACES)/fe-auth.c
|
||||
|
||||
fe-connect.o: $(INTERFACES)/fe-connect.c |
||||
$(CC) $(CFLAGS) -c $(INTERFACES)/fe-connect.c
|
||||
|
||||
fe-exec.o: $(INTERFACES)/fe-exec.c |
||||
$(CC) $(CFLAGS) -c $(INTERFACES)/fe-exec.c
|
||||
|
||||
fe-lobj.o: $(INTERFACES)/fe-lobj.c |
||||
$(CC) $(CFLAGS) -c $(INTERFACES)/fe-lobj.c
|
||||
|
||||
fe-misc.o: $(INTERFACES)/fe-misc.c |
||||
$(CC) $(CFLAGS) -c $(INTERFACES)/fe-misc.c
|
||||
|
||||
fe-print.o: $(INTERFACES)/fe-print.c |
||||
$(CC) $(CFLAGS) -c $(INTERFACES)/fe-print.c
|
||||
|
||||
pqsignal.o: $(INTERFACES)/pqsignal.c |
||||
$(CC) $(CFLAGS) -c $(INTERFACES)/pqsignal.c
|
||||
|
||||
dllist.o: $(SRCDIR)/backend/lib/dllist.c |
||||
$(CC) $(CFLAGS) -c $(SRCDIR)/backend/lib/dllist.c
|
||||
|
||||
pqcomprim.o: $(SRCDIR)/backend/libpq/pqcomprim.c |
||||
$(CC) $(CFLAGS) -c $(SRCDIR)/backend/libpq/pqcomprim.c
|
||||
|
||||
libpq.a: $(OBJS) |
||||
$(AR) $(AROPT) libpq.a $(OBJS)
|
||||
$(RANLIB) libpq.a
|
||||
|
||||
psql: $(EXEOBJS) |
||||
$(CC) -o psql.exe $(EXEOBJS) $(LDFLAGS) -llibpq -lsocket -lufc
|
||||
|
||||
psql.o: $(SRCDIR)/bin/psql/psql.c |
||||
$(CC) $(CFLAGS) -I$(INTERFACES) -c $(SRCDIR)/bin/psql/psql.c
|
||||
|
||||
stringutils.o: $(SRCDIR)/bin/psql/stringutils.c |
||||
$(CC) $(CFLAGS) -I$(INTERFACES) -c $(SRCDIR)/bin/psql/stringutils.c
|
||||
|
||||
clean: |
||||
rm -f libpq.a $(OBJS) $(EXEOBJS) psql.exe dllist.c pqcomprim.c
|
||||
|
@ -1,50 +0,0 @@ |
||||
|
||||
19981029 libpq.a and psql.exe Version 6.4 for OS/2 |
||||
--------------------------------------------------- |
||||
|
||||
|
||||
Requirements: |
||||
|
||||
emx 0.9c or newer under OS/2 |
||||
GNU crypt library for emx+gcc version 2.0.6 (available from |
||||
ftp://ftp.leo.org/pub/comp/os/os2/leo/crypt/gnuufc.zip) |
||||
|
||||
|
||||
Also a patch is needed for sys/socket.h around line 291. The lines |
||||
with the pluses need to be added, the other lines are already there |
||||
and are only for reference: |
||||
|
||||
|
||||
#define MT_IFADDR 13 |
||||
|
||||
+#ifndef MAXSOCKETS |
||||
+#define MAXSOCKETS 2048 |
||||
+#endif |
||||
|
||||
struct mbstat { |
||||
u_short m_mbufs; |
||||
u_short m_clusters; |
||||
|
||||
|
||||
Possible problems: |
||||
|
||||
You will also need to #define TCPIPV4 |
||||
|
||||
Make sure both socket.a and ufc.a are linked in to the executable |
||||
AFTER libpq.a. |
||||
|
||||
The following include files will be needed in order to use the library. |
||||
You only need to include one (libpq-fe.h) but these need to be present: |
||||
|
||||
postgres_ext.h |
||||
libpq/pqcomm.h |
||||
lib/dllist.h" |
||||
c.h |
||||
|
||||
|
||||
Good luck and enjoy!! |
||||
|
||||
Vince Vielhaber <vev@michvhf.com> |
||||
|
||||
|
||||
|
@ -1,26 +0,0 @@ |
||||
|
||||
#ifndef TCPIPV4 |
||||
#define TCPIPV4 |
||||
#endif /*
*/ |
||||
|
||||
#ifndef MAXSOCKETS |
||||
#define MAXSOCKETS 2048 |
||||
#endif /*
*/ |
||||
|
||||
/*
|
||||
* DEF_PGPORT is the TCP port number on which the Postmaster listens by |
||||
* default. This can be overriden by command options, environment variables, |
||||
* and the postconfig hook. (set by build script) |
||||
*/ |
||||
|
||||
#define DEF_PGPORT "5432" |
||||
|
||||
#define HAVE_TERMIOS_H |
||||
#define HAVE_ENDIAN_H |
||||
|
||||
#define SOCKET_SIZE_TYPE size_t |
||||
|
||||
#define strcasecmp(s1, s2) stricmp(s1, s2) |
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
@ -1,26 +1,50 @@ |
||||
#
|
||||
# $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/Makefile,v 1.2 2000/06/15 18:55:10 momjian Exp $
|
||||
#
|
||||
|
||||
PROGRAM = pg_dumplo
|
||||
|
||||
OBJECTS = pg_dumplo.o
|
||||
TOPDIR=../..
|
||||
|
||||
CFLAGS = -Wall -fpic -g
|
||||
CC = gcc
|
||||
RM = rm -f
|
||||
INCLUDE = -I/usr/include/postgresql
|
||||
LIBS =-lpq
|
||||
include ../Makefile.global |
||||
|
||||
COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDE)
|
||||
LINK = $(CC) $(CFLAGS) -o $@ $(LIBS)
|
||||
NAME = pg_dumplo
|
||||
|
||||
PROGRAM = $(NAME)
|
||||
OBJS = main.o lo_export.o lo_import.o utils.o
|
||||
DOCS = $(NAME).doc
|
||||
SQLS =
|
||||
BINS = $(PROGRAM)
|
||||
EXAMPLES=
|
||||
MODS =
|
||||
|
||||
all: $(PROGRAM) |
||||
CFLAGS += -I$(LIBPQDIR)
|
||||
|
||||
$(PROGRAM): $(OBJECTS) |
||||
$(LINK) $(OBJECTS)
|
||||
OTHER_CLEAN =
|
||||
|
||||
.c.o: $< |
||||
$(COMPILE) -c $<
|
||||
all: $(PROGRAM) |
||||
|
||||
$(PROGRAM): $(OBJS) $(LIBPQDIR)/libpq.a |
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPQ)
|
||||
|
||||
install: install_doc install_bin |
||||
|
||||
install_doc: |
||||
for inst_file in $(DOCS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
|
||||
done
|
||||
|
||||
install_bin: |
||||
for inst_file in $(BINS); do \
|
||||
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
|
||||
done
|
||||
|
||||
depend dep: |
||||
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||
|
||||
clean: |
||||
$(RM) -f *~ $(OBJECTS) $(PROGRAM)
|
||||
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||
|
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
||||
|
||||
|
@ -1,18 +1,117 @@ |
||||
|
||||
pg_dumplo - PostgreSQL large object dumper |
||||
|
||||
How to use pg_dumplo? |
||||
===================== |
||||
|
||||
Hmm... documentation is not available. For more information |
||||
see the help ( pg_dumplo -h ) and examples in this help. |
||||
(c) 2000, Pavel Janík ml. <Pavel.Janik@linux.cz> |
||||
|
||||
Compilation: |
||||
- you need the PostgreSQL's devel. libs |
||||
- and type: 'make' |
||||
|
||||
|
||||
Karel Zak <zakkr@zf.jcu.cz> |
||||
|
||||
|
||||
Q: How do you use pg_dumplo? |
||||
============================ |
||||
|
||||
|
||||
A: This is a small demo of backing up the database table with Large Objects: |
||||
|
||||
|
||||
We will create a demo database and a small and useless table `lo' inside |
||||
it: |
||||
|
||||
SnowWhite:$ createdb test |
||||
CREATE DATABASE |
||||
|
||||
Ok, our database with the name 'test' is created. Now we should create demo |
||||
table which will contain only one column with the name 'id' which will hold |
||||
the oid number of Large Object: |
||||
|
||||
SnowWhite:$ psql test |
||||
Welcome to psql, the PostgreSQL interactive terminal. |
||||
|
||||
Type: \copyright for distribution terms |
||||
\h for help with SQL commands |
||||
\? for help on internal slash commands |
||||
\g or terminate with semicolon to execute query |
||||
\q to quit |
||||
|
||||
test=# CREATE TABLE lo (id oid); |
||||
CREATE |
||||
test=# \lo_import /etc/aliases |
||||
lo_import 19338 |
||||
test=# INSERT INTO lo VALUES (19338); |
||||
INSERT 19352 1 |
||||
test=# select * from lo; |
||||
id |
||||
------- |
||||
19338 |
||||
(1 row) |
||||
|
||||
test=# \q |
||||
|
||||
In the above example you can see that we have also imported one "Large |
||||
Object" - the file /etc/aliases. It has an oid of 19338 so we have inserted |
||||
this oid number to the database table lo to the column id. The final SELECT |
||||
shows that we have one record in the table. |
||||
|
||||
Now we can demonstrate the work of pg_dumplo. We will create dump directory |
||||
which will contain the whole dump of large objects (/tmp/dump): |
||||
|
||||
mkdir -p /tmp/dump |
||||
|
||||
Now we can dump all large objects from the database `test' which has an oid |
||||
stored in the column `id' in the table `lo': |
||||
|
||||
SnowWhite:$ pg_dumplo -s /tmp/dump -d test -l lo.id |
||||
pg_dumplo: dump lo.id (1 large obj) |
||||
|
||||
Voila, we have the dump of all Large Objects in our directory: |
||||
|
||||
SnowWhite:$ tree /tmp/dump/ |
||||
/tmp/dump/ |
||||
`-- test |
||||
|-- lo |
||||
| `-- id |
||||
| `-- 19338 |
||||
`-- lo_dump.index |
||||
|
||||
3 directories, 2 files |
||||
SnowWhite:$ |
||||
|
||||
Isn't it nice :-) Yes, it is, but we are on the half of our way. We should |
||||
also be able to recreate the contents of the table lo and the Large Object |
||||
database when something went wrong. It is very easy, we will demonstrate |
||||
this via dropping the database and recreating it from scratch with |
||||
pg_dumplo: |
||||
|
||||
SnowwWite:$ dropdb test |
||||
DROP DATABASE |
||||
|
||||
SnowWhite:$ createdb test |
||||
CREATE DATABASE |
||||
|
||||
Ok, our database with the name `test' is created again. We should also |
||||
create the table `lo' again: |
||||
|
||||
SnowWhite:$ psql test |
||||
Welcome to psql, the PostgreSQL interactive terminal. |
||||
|
||||
Type: \copyright for distribution terms |
||||
\h for help with SQL commands |
||||
\? for help on internal slash commands |
||||
\g or terminate with semicolon to execute query |
||||
\q to quit |
||||
|
||||
test=# CREATE TABLE lo (id oid); |
||||
CREATE |
||||
test=# \q |
||||
SnowWhite:$ |
||||
|
||||
Now the database with the table `lo' is created again, but we do not have |
||||
any information stored in it. But have the dump of complete Large Object |
||||
database, so we can recreate the contents of the whole database from the |
||||
directory /tmp/dump: |
||||
|
||||
SnowWhite:$ pg_dumplo -s /tmp/dump -d test -i |
||||
19338 lo id test/lo/id/19338 |
||||
SnowWhite:$ |
||||
|
||||
And this is everything. |
||||
|
||||
Summary: In this small example we have shown that pg_dumplo can be used to |
||||
completely dump the database's Large Objects very easily. |
||||
|
@ -1 +0,0 @@ |
||||
0.0.4 |
@ -1,379 +0,0 @@ |
||||
|
||||
#include <stdio.h> |
||||
#include <unistd.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/types.h> |
||||
#include <fcntl.h> |
||||
#include <errno.h> |
||||
#include <time.h> |
||||
|
||||
#include <libpq-fe.h> |
||||
#include <libpq/libpq-fs.h> |
||||
|
||||
#define _GNU_SOURCE |
||||
#include <getopt.h> |
||||
|
||||
extern int errno;
|
||||
|
||||
#define QUERY_BUFSIZ (8*1024) |
||||
#define DIR_UMASK 0755 |
||||
#define FILE_UMASK 0666 |
||||
|
||||
#define TRUE 1 |
||||
#define FALSE 0 |
||||
#define RE_OK 0 |
||||
#define RE_ERROR 1 |
||||
|
||||
typedef struct {
|
||||
char *table, |
||||
*attr; |
||||
long lo_oid; |
||||
} lo_attr; |
||||
|
||||
void usage() |
||||
{ |
||||
printf("\nPostgreSQL large objects dump"); |
||||
printf("\npg_lo_dump <option>\n\n"); |
||||
printf("-h --help this help\n");
|
||||
printf("-u --user='username' username for connection to server\n");
|
||||
printf("-p --password='password' password for connection to server\n");
|
||||
printf("-d --db='database' database name\n");
|
||||
printf("-t --host='hostname' server hostname\n");
|
||||
printf("-l <table.attr ...> dump attribute (columns) with LO to dump tree\n"); |
||||
printf("-i --import import large obj dump tree to DB\n"); |
||||
printf("-s --space=<dir> directory with dupm tree (for dump/import)\n"); |
||||
printf("\nExample (dump): pg_lo_dump -d my_db -s /my_dump/dir/ -l t1.a t1.b t2.a\n");
|
||||
printf("Example (import): pg_lo_dump -i -d my_db -s /my_dump/dir/\n");
|
||||
printf("\nNote: * option '-l' must be last option!\n");
|
||||
printf(" * option '-i' (--import) make new large obj in DB, not rewrite old,\n");
|
||||
printf(" import UPDATE oid numbers in table.attr only.\n");
|
||||
printf("\n\n");
|
||||
} |
||||
|
||||
typedef enum { |
||||
ARG_USER, |
||||
ARG_PWD, |
||||
ARG_DB, |
||||
ARG_HELP, |
||||
ARG_HOST |
||||
} _ARG_; |
||||
|
||||
/*-----
|
||||
* Init and allocate lo_attr structs |
||||
* |
||||
* ! data is **argv
|
||||
*----- |
||||
*/ |
||||
lo_attr *init_loa(char **data, int max, int start) |
||||
{ |
||||
lo_attr *l,
|
||||
*ll; |
||||
char **d,
|
||||
*loc, |
||||
buff[128]; |
||||
|
||||
if ((l = (lo_attr *) malloc(max * sizeof(lo_attr))) == NULL) { |
||||
fprintf(stderr, "%s: can't allocate memory\n", data[0]); |
||||
exit(RE_ERROR); |
||||
} |
||||
for(d=data+start, ll=l; *d != NULL; d++, ll++) { |
||||
strncpy(buff, *d, 128); |
||||
if ((loc = strchr(buff, '.')) == NULL) { |
||||
fprintf(stderr, "%s: '%s' is bad 'table.attr'\n", data[0], buff); |
||||
exit(RE_ERROR);
|
||||
} |
||||
*loc = '\0'; |
||||
ll->table = strdup(buff); |
||||
ll->attr = strdup(++loc); |
||||
} |
||||
ll++; |
||||
ll->table = ll->attr = (char *) NULL; |
||||
return l; |
||||
} |
||||
|
||||
/*-----
|
||||
* Check PG result |
||||
*----- |
||||
*/ |
||||
int check_res(PGresult *res, PGconn *conn)
|
||||
{ |
||||
if (!res && PQresultStatus(res) != PGRES_COMMAND_OK) { |
||||
fprintf(stderr, "%s\n",PQerrorMessage(conn)); |
||||
PQclear(res); |
||||
return FALSE; |
||||
} |
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK) { |
||||
fprintf(stderr, "Tuples is not OK.\n"); |
||||
PQclear(res); |
||||
return FALSE; |
||||
} |
||||
return TRUE;
|
||||
} |
||||
|
||||
|
||||
/*-----
|
||||
* LO dump |
||||
*----- |
||||
*/ |
||||
void dump_lo(PGconn *conn, char *space, lo_attr *loa, char *db, char *prog) |
||||
{ |
||||
PGresult *res;
|
||||
lo_attr *ploa; |
||||
FILE *majorfile; |
||||
char *dir, |
||||
path[BUFSIZ], |
||||
Qbuff[QUERY_BUFSIZ]; |
||||
|
||||
dir = space ? space : getenv("PWD");
|
||||
sprintf(path, "%s/%s", dir, db);
|
||||
if (mkdir(path, DIR_UMASK) == -1) { |
||||
if (errno != EEXIST) { |
||||
perror(path); |
||||
exit(RE_ERROR);
|
||||
}
|
||||
} |
||||
|
||||
sprintf(path, "%s/lo_dump.index", path);
|
||||
if ((majorfile = fopen(path, "w")) == NULL) { |
||||
perror(path); |
||||
exit(RE_ERROR); |
||||
} else { |
||||
time_t t; |
||||
time(&t); |
||||
fprintf(majorfile, "#\n# This is the PostgreSQL large object dump index\n#\n"); |
||||
fprintf(majorfile, "#\tDate: %s", ctime(&t)); |
||||
fprintf(majorfile, "#\tHost: %s\n", PQhost(conn) ? PQhost(conn) : "localhost"); |
||||
fprintf(majorfile, "#\tDatabase: %s\n", db); |
||||
fprintf(majorfile, "#\tUser: %s\n", PQuser(conn)); |
||||
fprintf(majorfile, "#\n# oid\ttable\tattribut\tinfile\n"); |
||||
} |
||||
|
||||
for(ploa=loa; ploa->table != NULL; ploa++) { |
||||
|
||||
/* query */ |
||||
sprintf(Qbuff, "SELECT %s FROM %s WHERE %s!=0",
|
||||
ploa->attr, ploa->table, ploa->attr); |
||||
|
||||
res = PQexec(conn, Qbuff); |
||||
|
||||
if (check_res(res, conn)) { |
||||
int tuples = PQntuples(res), |
||||
t; |
||||
char *val; |
||||
|
||||
/* Make DIR/FILE */ |
||||
if (tuples) { |
||||
sprintf(path, "%s/%s/%s", dir, db, ploa->table);
|
||||
if (mkdir(path, DIR_UMASK) == -1) { |
||||
if (errno != EEXIST) { |
||||
perror(path); |
||||
exit(RE_ERROR);
|
||||
}
|
||||
} |
||||
sprintf(path, "%s/%s", path, ploa->attr);
|
||||
if (mkdir(path, DIR_UMASK) == -1) { |
||||
if (errno != EEXIST) { |
||||
perror(path); |
||||
exit(RE_ERROR);
|
||||
}
|
||||
} |
||||
fprintf(stderr, "%s: dump %s.%s (%d lagre obj)\n", prog,
|
||||
ploa->table, ploa->attr, tuples); |
||||
} |
||||
|
||||
for(t=0; t<tuples; t++) { |
||||
val = PQgetvalue(res, t, 0); |
||||
if (!val) |
||||
continue; |
||||
|
||||
sprintf(path, "%s/%s/%s/%s/%s", dir, db, ploa->table, ploa->attr, val); |
||||
|
||||
if (lo_export(conn, (Oid) atol(val), path) < 0)
|
||||
fprintf(stderr, "%s\n", PQerrorMessage(conn)); |
||||
else |
||||
fprintf(majorfile, "%s\t%s\t%s\t%s/%s/%s/%s\n", val,
|
||||
ploa->table, ploa->attr, db, ploa->table, ploa->attr, val); |
||||
} |
||||
} |
||||
}
|
||||
fclose(majorfile); |
||||
} |
||||
|
||||
|
||||
/*-----
|
||||
* LO import |
||||
*----- |
||||
*/ |
||||
void import_lo(PGconn *conn, char *space, char *db, char *prog) |
||||
{ |
||||
PGresult *res;
|
||||
lo_attr loa; |
||||
FILE *majorfile; |
||||
long new_oid; |
||||
char *dir, |
||||
tab[128], attr[128], |
||||
path[BUFSIZ], lo_path[BUFSIZ], |
||||
Qbuff[QUERY_BUFSIZ]; |
||||
|
||||
dir = space ? space : getenv("PWD"); |
||||
sprintf(path, "%s/%s", dir, db);
|
||||
|
||||
sprintf(path, "%s/lo_dump.index", path);
|
||||
if ((majorfile = fopen(path, "r")) == NULL) { |
||||
perror(path); |
||||
exit(RE_ERROR); |
||||
}
|
||||
|
||||
while(fgets(Qbuff, QUERY_BUFSIZ, majorfile)) { |
||||
|
||||
if (*Qbuff == '#') |
||||
continue; |
||||
|
||||
fprintf(stdout, Qbuff); |
||||
|
||||
sscanf(Qbuff, "%ld\t%s\t%s\t%s\n", &loa.lo_oid, tab, attr, path);
|
||||
loa.table = tab; |
||||
loa.attr = attr; |
||||
|
||||
sprintf(lo_path, "%s/%s", dir, path);
|
||||
|
||||
/* import large obj */ |
||||
if ((new_oid = lo_import(conn, lo_path)) <= 0) { |
||||
fprintf(stderr, "%s\n",PQerrorMessage(conn)); |
||||
PQexec(conn, "ROLLBACK"); |
||||
fprintf(stderr, "\nROLLBACK\n"); |
||||
exit(RE_ERROR); |
||||
} |
||||
|
||||
/* query */ |
||||
sprintf(Qbuff, "UPDATE %s SET %s=%ld WHERE %s=%ld",
|
||||
loa.table, loa.attr, new_oid, loa.attr, loa.lo_oid); |
||||
|
||||
/*fprintf(stderr, Qbuff);*/ |
||||
|
||||
res = PQexec(conn, Qbuff); |
||||
|
||||
if (!res && PQresultStatus(res) != PGRES_COMMAND_OK) { |
||||
fprintf(stderr, "%s\n",PQerrorMessage(conn)); |
||||
PQclear(res); |
||||
PQexec(conn, "ROLLBACK"); |
||||
fprintf(stderr, "\nROLLBACK\n"); |
||||
exit(RE_ERROR); |
||||
}
|
||||
|
||||
}
|
||||
fclose(majorfile); |
||||
} |
||||
|
||||
/*-----
|
||||
* The mother of all C functions |
||||
*----- |
||||
*/ |
||||
int main(int argc, char **argv) |
||||
{ |
||||
PGconn *conn; |
||||
lo_attr *loa =NULL; |
||||
char *user =NULL,
|
||||
*pwd =NULL,
|
||||
*db =NULL, |
||||
*host =NULL,
|
||||
*space =NULL; |
||||
int import =FALSE; |
||||
|
||||
/* Parse argv */ |
||||
if (argc) { |
||||
int arg, l_index=0; |
||||
extern int optind; |
||||
typedef enum { |
||||
ARG_USER, |
||||
ARG_PWD, |
||||
ARG_DB, |
||||
ARG_HELP, |
||||
ARG_IMPORT, |
||||
ARG_SPACE, |
||||
ARG_HOST |
||||
} _ARG_; |
||||
|
||||
struct option l_opt[] = { |
||||
{ "help", 0, 0, ARG_HELP },
|
||||
{ "user", 1, 0, ARG_USER }, |
||||
{ "pwd", 1, 0, ARG_PWD }, |
||||
{ "db", 1, 0, ARG_DB }, |
||||
{ "host", 1, 0, ARG_HOST }, |
||||
{ "space", 1, 0, ARG_SPACE }, |
||||
{ "import", 0, 0, ARG_IMPORT }, |
||||
{ NULL, 0, 0, 0 } |
||||
};
|
||||
|
||||
while((arg = getopt_long(argc, argv, "hu:p:d:l:t:is:", l_opt, &l_index)) != -1) { |
||||
switch(arg) { |
||||
case ARG_HELP: |
||||
case 'h': |
||||
usage(); |
||||
exit(RE_OK); |
||||
case ARG_USER: |
||||
case 'u':
|
||||
user = strdup(optarg); |
||||
break;
|
||||
case ARG_HOST: |
||||
case 't':
|
||||
host = strdup(optarg); |
||||
break;
|
||||
case ARG_PWD: |
||||
case 'p':
|
||||
pwd = strdup(optarg); |
||||
break;
|
||||
case ARG_DB: |
||||
case 'd':
|
||||
db = strdup(optarg); |
||||
break; |
||||
case ARG_SPACE: |
||||
case 's':
|
||||
space = strdup(optarg); |
||||
break;
|
||||
case ARG_IMPORT: |
||||
case 'i':
|
||||
import = TRUE; |
||||
break;
|
||||
case 'l': |
||||
loa = init_loa(argv, argc-1, optind-1); |
||||
break;
|
||||
} |
||||
}
|
||||
}
|
||||
|
||||
if (!space && !getenv("PWD")) { |
||||
fprintf(stderr, "%s: can't set directory (not set '-s' or $PWD).\n", argv[0]); |
||||
exit(RE_ERROR); |
||||
} |
||||
|
||||
/* Make PG connection */ |
||||
conn = PQsetdbLogin(host, NULL, NULL, NULL, db, user, pwd); |
||||
|
||||
/* check to see that the backend connection was successfully made */ |
||||
if (PQstatus(conn) == CONNECTION_BAD) { |
||||
fprintf(stderr, "%s\n",PQerrorMessage(conn)); |
||||
exit(RE_ERROR); |
||||
} |
||||
|
||||
PQexec(conn, "BEGIN"); |
||||
|
||||
if (import) { |
||||
/* import obj */ |
||||
import_lo(conn, space, db, argv[0]); |
||||
} else if (loa) { |
||||
/* Dump obj */ |
||||
dump_lo(conn, space, loa, db, argv[0]); |
||||
} else { |
||||
fprintf(stderr, "%s: ERROR: bad arg!\n", argv[0]); |
||||
usage(); |
||||
}
|
||||
|
||||
PQexec(conn, "COMMIT"); |
||||
|
||||
/* bye PG */
|
||||
PQfinish(conn);
|
||||
exit(RE_OK); |
||||
} |
@ -1,23 +1,48 @@ |
||||
# $Header: /cvsroot/pgsql/contrib/pgbench/Makefile,v 1.1 2000/01/15 12:38:09 ishii Exp $
|
||||
#
|
||||
# $Header: /cvsroot/pgsql/contrib/pgbench/Makefile,v 1.2 2000/06/15 18:55:12 momjian Exp $
|
||||
#
|
||||
|
||||
SRCDIR= ../../src
|
||||
TOPDIR=../..
|
||||
|
||||
include $(SRCDIR)/Makefile.global |
||||
include ../Makefile.global |
||||
|
||||
CFLAGS:= -I$(LIBPQDIR) $(CFLAGS)
|
||||
NAME = pgbench
|
||||
|
||||
TARGET = pgbench
|
||||
OBJS = pgbench.o
|
||||
PROGRAM = $(NAME)
|
||||
OBJS = $(NAME).o
|
||||
DOCS = $(NAME).doc $(NAME)_jis.doc
|
||||
SQLS =
|
||||
BINS = $(PROGRAM)
|
||||
EXAMPLES=
|
||||
MODS =
|
||||
|
||||
all:: $(TARGET) |
||||
CFLAGS += -I$(LIBPQDIR)
|
||||
|
||||
$(TARGET): $(OBJS) |
||||
$(CC) -o $(TARGET) $(OBJS) -L$(LIBPQDIR) -lpq $(LDFLAGS)
|
||||
OTHER_CLEAN =
|
||||
|
||||
install: $(TARGET) |
||||
$(INSTALL) $(INSTL_EXE_OPTS) $(TARGET)$(X) $(BINDIR)/$(TARGET)$(X)
|
||||
all: $(PROGRAM) |
||||
|
||||
$(PROGRAM): $(OBJS) $(LIBPQDIR)/libpq.a |
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPQ)
|
||||
|
||||
install: install_doc install_bin |
||||
|
||||
install_doc: |
||||
for inst_file in $(DOCS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
|
||||
done
|
||||
|
||||
install_bin: |
||||
for inst_file in $(BINS); do \
|
||||
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
|
||||
done
|
||||
|
||||
depend dep: |
||||
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||
|
||||
clean: |
||||
$(RM) $(TARGET)$(X) $(OBJS)
|
||||
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||
|
||||
distclean: clean |
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
||||
|
@ -0,0 +1,53 @@ |
||||
|
||||
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,57 +1,4 @@ |
||||
--------------- soundex.sql: |
||||
|
||||
CREATE FUNCTION text_soundex(text) RETURNS text |
||||
AS '_OBJWD_/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'; |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
|
@ -1,29 +1,64 @@ |
||||
#
|
||||
# $Header: /cvsroot/pgsql/contrib/spi/Makefile,v 1.13 2000/06/15 18:55:17 momjian Exp $
|
||||
#
|
||||
|
||||
SRCDIR= ../../src
|
||||
TOPDIR=../..
|
||||
|
||||
include $(SRCDIR)/Makefile.global |
||||
include ../Makefile.global |
||||
|
||||
CFLAGS+= $(CFLAGS_SL)
|
||||
NAME =
|
||||
|
||||
PROGRAM =
|
||||
OBJS = autoinc.o insert_username.o moddatetime.o refint.o timetravel.o
|
||||
DOCS = spi.doc
|
||||
SQLS = $(OBJS:.o=.sql)
|
||||
BINS =
|
||||
EXAMPLES= $(OBJS:.o=.example)
|
||||
MODS = $(OBJS:.o=$(DLSUFFIX))
|
||||
|
||||
CFLAGS += -I. $(CFLAGS_SL)
|
||||
|
||||
ifdef REFINT_VERBOSE |
||||
CFLAGS+= -DREFINT_VERBOSE
|
||||
endif |
||||
|
||||
TARGETS= refint$(DLSUFFIX) refint.sql \
|
||||
timetravel$(DLSUFFIX) timetravel.sql \
|
||||
autoinc$(DLSUFFIX) autoinc.sql \
|
||||
moddatetime$(DLSUFFIX) moddatetime.sql \
|
||||
insert_username$(DLSUFFIX) insert_username.sql
|
||||
OTHER_CLEAN = $(SQLS)
|
||||
|
||||
all: $(MODS) $(SQLS) |
||||
|
||||
%.sql: %.sql.in |
||||
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||
|
||||
install: install_doc install_sql install_mod install_example |
||||
|
||||
install_doc: |
||||
for inst_file in $(DOCS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
|
||||
done
|
||||
|
||||
CLEANFILES+= $(TARGETS)
|
||||
install_sql: |
||||
for inst_file in $(SQLS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
|
||||
done
|
||||
|
||||
all:: $(TARGETS) |
||||
install_mod: |
||||
for inst_file in $(MODS); do \
|
||||
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
|
||||
done
|
||||
|
||||
%.sql: %.source |
||||
rm -f $@; \
|
||||
C=`pwd`; \
|
||||
sed -e "s:_OBJWD_:$$C:g" \
|
||||
-e "s:_DLSUFFIX_:$(DLSUFFIX):g" < $< > $@
|
||||
install_example: |
||||
for inst_file in $(EXAMPLES); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_EXAMPLESDIR); \
|
||||
done
|
||||
|
||||
depend dep: |
||||
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||
|
||||
clean: |
||||
rm -f $(TARGETS) *.o
|
||||
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||
|
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
||||
|
||||
|
||||
|
@ -1,109 +0,0 @@ |
||||
|
||||
Here are general trigger functions provided as workable examples |
||||
of using SPI and triggers. "General" means that functions may be |
||||
used for defining triggers for any tables but you have to specify |
||||
table/field names (as described below) while creating a trigger. |
||||
|
||||
1. refint.c - functions for implementing referential integrity. |
||||
|
||||
check_primary_key () is to used for foreign keys of a table. |
||||
|
||||
You are to create trigger (BEFORE INSERT OR UPDATE) using this |
||||
function on a table referencing another table. You are to specify |
||||
as function arguments: triggered table column names which correspond |
||||
to foreign key, referenced table name and column names in referenced |
||||
table which correspond to primary/unique key. |
||||
You may create as many triggers as you need - one trigger for |
||||
one reference. |
||||
|
||||
check_foreign_key () is to used for primary/unique keys of a table. |
||||
|
||||
You are to create trigger (BEFORE DELETE OR UPDATE) using this |
||||
function on a table referenced by another table(s). You are to specify |
||||
as function arguments: number of references for which function has to |
||||
performe checking, action if referencing key found ('cascade' - to delete |
||||
corresponding foreign key, 'restrict' - to abort transaction if foreign keys |
||||
exist, 'setnull' - to set foreign key referencing primary/unique key |
||||
being deleted to null), triggered table column names which correspond |
||||
to primary/unique key, referencing table name and column names corresponding |
||||
to foreign key (, ... - as many referencing tables/keys as specified |
||||
by first argument). |
||||
Note, that NOT NULL constraint and unique index have to be defined by |
||||
youself. |
||||
|
||||
There are examples in refint.example and regression tests |
||||
(sql/triggers.sql). |
||||
|
||||
To CREATE FUNCTIONs use refint.sql (will be made by gmake from |
||||
refint.source). |
||||
|
||||
|
||||
|
||||
|
||||
# Excuse me for my bad english. Massimo Lambertini |
||||
# |
||||
# |
||||
# New check foreign key |
||||
# |
||||
I think that cascade mode is to be considered like that the operation over |
||||
main table is to be made also in referenced table . |
||||
When i Delete , i must delete from referenced table , |
||||
but when i update , i update referenced table and not delete like unmodified refint.c . |
||||
|
||||
I made a new version of refint.c that when i update it check the type of modified key ( if is a text , char() i |
||||
added '') and then create a update query that do the right thing . |
||||
|
||||
For my point of view that policy is helpfull because i do not have in referenced table |
||||
loss of information . |
||||
|
||||
|
||||
In preprocessor subdir i have placed a little utility that from a SQL92 table definition, |
||||
it create all trigger for foreign key . |
||||
|
||||
|
||||
the schema that i use to analyze the problem is this |
||||
|
||||
create table |
||||
A |
||||
( key int4 not null primary key ,..., |
||||
) ; |
||||
|
||||
create table |
||||
REFERENCED_B |
||||
( key int 4 , ... , |
||||
foreign key ( key ) references A -- |
||||
); |
||||
|
||||
|
||||
-- |
||||
-- Trigger for REFERENCED_B |
||||
-- |
||||
|
||||
CREATE INDEX I_REFERENCED_B_KEY ON REFERENCED_B ( KEY ) ; |
||||
|
||||
CREATE TRIGGER T_P_REFERENCED_B_A BEFORE INSERT OR UPDATE ON REFERENCED_B FOR EACH ROW |
||||
EXECUTE PROCEDURE |
||||
check_primary_key('KEY','A','KEY' ); |
||||
|
||||
CREATE TRIGGER T_F_D_A_REFERENCED_B BEFORE DELETE ON A FOR EACH ROW |
||||
EXECUTE PROCEDURE |
||||
check_foreign_key(1,'cascade','KEY','REFERENCED_B ','KEY' ); |
||||
|
||||
CREATE TRIGGER T_F_U_A_REFERENCED_B AFTER UPDATE ON A FOR EACH ROW |
||||
EXECUTE PROCEDURE |
||||
check_foreign_key(1,'cascade','KEY','REFERENCED_B ','KEY' ); |
||||
|
||||
-- ******************************** |
||||
|
||||
I write TRIGGER T_F_U_A_REFERENCED_B ( AFTER ) and not BEFORE because if i set |
||||
BEFORE , when i try to modify ( update ) a key of A , i start a execution of TRIGGER T_P_REFERENCED_B_A |
||||
( check_primary_key) before the real modification of key in A , then the execution of ( check_primary_key) return |
||||
not ok. |
||||
With AFTER Clausole i modify first key of A then a update the value of referenced table REFERENCED_B. |
||||
|
||||
Try also the new_example.sql to view the modified policy. |
||||
I wish that my explain of problem is quite clear . |
||||
If there is miss understanding ( cause my bad english ) please send email to massimo.lambertini@everex.it |
||||
|
||||
|
||||
|
@ -1,6 +0,0 @@ |
||||
DROP FUNCTION autoinc(); |
||||
|
||||
CREATE FUNCTION autoinc() |
||||
RETURNS opaque |
||||
AS '_OBJWD_/autoinc_DLSUFFIX_' |
||||
LANGUAGE 'newC'; |
@ -1,6 +0,0 @@ |
||||
DROP FUNCTION insert_username(); |
||||
|
||||
CREATE FUNCTION insert_username() |
||||
RETURNS opaque |
||||
AS '_OBJWD_/insert_username_DLSUFFIX_' |
||||
LANGUAGE 'newC'; |
@ -1,6 +0,0 @@ |
||||
DROP FUNCTION moddatetime(); |
||||
|
||||
CREATE FUNCTION moddatetime() |
||||
RETURNS opaque |
||||
AS '_OBJWD_/moddatetime_DLSUFFIX_' |
||||
LANGUAGE 'newC'; |
@ -1,14 +0,0 @@ |
||||
DROP FUNCTION check_primary_key (); |
||||
DROP FUNCTION check_foreign_key (); |
||||
|
||||
CREATE FUNCTION check_primary_key () |
||||
RETURNS opaque |
||||
AS '_OBJWD_/refint_DLSUFFIX_' |
||||
LANGUAGE 'newC' |
||||
; |
||||
|
||||
CREATE FUNCTION check_foreign_key () |
||||
RETURNS opaque |
||||
AS '_OBJWD_/refint_DLSUFFIX_' |
||||
LANGUAGE 'newC' |
||||
; |
@ -1,12 +0,0 @@ |
||||
DROP FUNCTION timetravel(); |
||||
DROP FUNCTION set_timetravel(name, int4); |
||||
|
||||
CREATE FUNCTION timetravel() |
||||
RETURNS opaque |
||||
AS '_OBJWD_/timetravel_DLSUFFIX_' |
||||
LANGUAGE 'newC'; |
||||
|
||||
CREATE FUNCTION set_timetravel(name, int4) |
||||
RETURNS int4 |
||||
AS '_OBJWD_/timetravel_DLSUFFIX_' |
||||
LANGUAGE 'newC' WITH (isStrict); |
@ -0,0 +1,23 @@ |
||||
String io module for postgresql. |
||||
Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it> |
||||
|
||||
This software is distributed under the GNU General Public License |
||||
either version 2, or (at your option) any later version. |
||||
|
||||
|
||||
These output functions can be used as substitution of the standard text |
||||
output functions to get the value of text fields printed in the format |
||||
used for C strings. This allows the output of queries or the exported |
||||
files to be processed more easily using standard unix filter programs |
||||
like perl or awk. |
||||
|
||||
If you use the standard functions instead you could find a single tuple |
||||
splitted into many lines and the tabs embedded in the values could be |
||||
confused with those used as field delimters. |
||||
|
||||
My function translates all non-printing characters into corresponding |
||||
esacape sequences as defined by the C syntax. All you need to reconstruct |
||||
the exact value in your application is a corresponding unescape function |
||||
like the string_input defined in the source code. |
||||
|
||||
Massimo Dal Zotto <dz@cs.unitn.it> |
@ -0,0 +1,55 @@ |
||||
User locks, by Massimo Dal Zotto <dz@cs.unitn.it> |
||||
Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it> |
||||
|
||||
This software is distributed under the GNU General Public License |
||||
either version 2, or (at your option) any later version. |
||||
|
||||
|
||||
This loadable module, together with my user-lock.patch applied to the |
||||
backend, provides support for user-level long-term cooperative locks. |
||||
For example one can write: |
||||
|
||||
select some_fields, user_write_lock_oid(oid) from table where id='key'; |
||||
|
||||
Now if the returned user_write_lock_oid field is 1 you have acquired an |
||||
user lock on the oid of the selected tuple and can now do some long operation |
||||
on it, like let the data being edited by the user. |
||||
If it is 0 it means that the lock has been already acquired by some other |
||||
process and you should not use that item until the other has finished. |
||||
Note that in this case the query returns 0 immediately without waiting on |
||||
the lock. This is good if the lock is held for long time. |
||||
After you have finished your work on that item you can do: |
||||
|
||||
update table set some_fields where id='key'; |
||||
select user_write_unlock_oid(oid) from table where id='key'; |
||||
|
||||
You can also ignore the failure and go ahead but this could produce conflicts |
||||
or inconsistent data in your application. User locks require a cooperative |
||||
behavior between users. User locks don't interfere with the normal locks |
||||
used by postgres for transaction processing. |
||||
|
||||
This could also be done by setting a flag in the record itself but in |
||||
this case you have the overhead of the updates to the records and there |
||||
could be some locks not released if the backend or the application crashes |
||||
before resetting the lock flag. |
||||
It could also be done with a begin/end block but in this case the entire |
||||
table would be locked by postgres and it is not acceptable to do this for |
||||
a long period because other transactions would block completely. |
||||
|
||||
The generic user locks use two values, group and id, to identify a lock, |
||||
which correspond to ip_posid and ip_blkid of an ItemPointerData. |
||||
Group is a 16 bit value while id is a 32 bit integer which could also be |
||||
an oid. The oid user lock functions, which take only an oid as argument, |
||||
use a group equal to 0. |
||||
|
||||
The meaning of group and id is defined by the application. The user |
||||
lock code just takes two numbers and tells you if the corresponding |
||||
entity has been succesfully locked. What this mean is up to you. |
||||
|
||||
My succestion is that you use the group to identify an area of your |
||||
application and the id to identify an object in this area. |
||||
Or you can just lock the oid of the tuples which are by definition unique. |
||||
|
||||
Note also that a process can acquire more than one lock on the same entity |
||||
and it must release the lock the corresponding number of times. This can |
||||
be done calling the unlock funtion until it returns 0. |
@ -1,24 +1,48 @@ |
||||
# $Header: /cvsroot/pgsql/contrib/vacuumlo/Makefile,v 1.2 2000/05/29 05:44:32 tgl Exp $
|
||||
#
|
||||
# $Header: /cvsroot/pgsql/contrib/vacuumlo/Makefile,v 1.3 2000/06/15 18:55:31 momjian Exp $
|
||||
#
|
||||
|
||||
SRCDIR= ../../src
|
||||
TOPDIR=../..
|
||||
|
||||
include $(SRCDIR)/Makefile.global |
||||
include ../Makefile.global |
||||
|
||||
CONTRIBDIR=$(LIBDIR)/contrib
|
||||
NAME = vacuumlo
|
||||
|
||||
CFLAGS+= -I$(LIBPQDIR)
|
||||
PROGRAM = $(NAME)
|
||||
OBJS = $(NAME).o
|
||||
DOCS = $(NAME).doc
|
||||
SQLS =
|
||||
BINS = $(PROGRAM)
|
||||
EXAMPLES=
|
||||
MODS =
|
||||
|
||||
TARGETS= vacuumlo
|
||||
CLEANFILES+= $(TARGETS)
|
||||
CURDIR=`pwd`
|
||||
CFLAGS += -I$(LIBPQDIR)
|
||||
|
||||
all:: $(TARGETS) |
||||
OTHER_CLEAN =
|
||||
|
||||
$(TARGETS): vacuumlo.o |
||||
$(CC) -o vacuumlo -L $(LIBDIR) -lpq -lcrypt vacuumlo.o
|
||||
all: $(PROGRAM) |
||||
|
||||
clean: |
||||
rm -f $(TARGETS) *.o
|
||||
$(PROGRAM): $(OBJS) $(LIBPGEASYDIR)/libpgeasy.a |
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPGEASY)
|
||||
|
||||
dist: |
||||
tar cf vacuumlo.tar README Makefile vacuumlo.c
|
||||
install: install_doc install_bin |
||||
|
||||
install_doc: |
||||
for inst_file in $(DOCS); do \
|
||||
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
|
||||
done
|
||||
|
||||
install_bin: |
||||
for inst_file in $(BINS); do \
|
||||
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
|
||||
done
|
||||
|
||||
depend dep: |
||||
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||
|
||||
clean: |
||||
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||
|
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
||||
|
Loading…
Reference in new issue