mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
/contrib patch from Karel.
This commit is contained in:
@ -1,27 +1,59 @@
|
|||||||
# Makefile for contrib code
|
|
||||||
#
|
#
|
||||||
# The following subdirs don't have a Makefile:
|
# The PostgreSQL contrib tree Makefile
|
||||||
#
|
#
|
||||||
# apache_logging
|
# Portions Copyright (c) 1999-2000, PostgreSQL, Inc
|
||||||
# linux
|
|
||||||
# mSQL-interface
|
|
||||||
# noupdate
|
|
||||||
# unixdate
|
|
||||||
#
|
#
|
||||||
# The following subdirs give make errors:
|
# $Header: /cvsroot/pgsql/contrib/Makefile,v 1.4 2000/06/15 18:54:29 momjian Exp $
|
||||||
#
|
#
|
||||||
# earthdistance
|
|
||||||
# os2client
|
TOPDIR = ..
|
||||||
|
include Makefile.global
|
||||||
|
|
||||||
|
WANTED_DIRS = array \
|
||||||
|
earthdistance \
|
||||||
|
findoidjoins \
|
||||||
|
fulltextindex \
|
||||||
|
isbn_issn \
|
||||||
|
likeplanning \
|
||||||
|
linux \
|
||||||
|
lo \
|
||||||
|
mSQL-interface \
|
||||||
|
miscutil \
|
||||||
|
noupdate \
|
||||||
|
pg_dumplo \
|
||||||
|
pgbench \
|
||||||
|
soundex \
|
||||||
|
spi \
|
||||||
|
string \
|
||||||
|
tips \
|
||||||
|
tools \
|
||||||
|
unixdate \
|
||||||
|
userlock \
|
||||||
|
vacuumlo
|
||||||
|
# odbc
|
||||||
|
# os2client
|
||||||
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
for dir in *; do \
|
for dir in $(WANTED_DIRS); do \
|
||||||
if [ -e $$dir/Makefile ]; then \
|
if [ -e $$dir/Makefile ]; then \
|
||||||
$(MAKE) -C $$dir $@ ; \
|
$(MAKE) -C $$dir $@ ; \
|
||||||
fi; \
|
fi; \
|
||||||
done
|
done
|
||||||
|
|
||||||
.DEFAULT:
|
|
||||||
for dir in *; do \
|
install:
|
||||||
|
../config/mkinstalldirs $(CONTRIB_BINDIR) $(CONTRIB_MODDIR) $(CONTRIB_DOCDIR) $(CONTRIB_SQLDIR) $(CONTRIB_EXAMPLESDIR)
|
||||||
|
for dir in $(WANTED_DIRS); do \
|
||||||
|
if [ -e $$dir/Makefile ]; then \
|
||||||
|
$(MAKE) -C $$dir $@ ; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
$(INSTALL) $(INSTL_LIB_OPTS) Contrib.index $(CONTRIB_DOCDIR);
|
||||||
|
|
||||||
|
|
||||||
|
.DEFAULT:
|
||||||
|
for dir in $(WANTED_DIRS); do \
|
||||||
if [ -e $$dir/Makefile ]; then \
|
if [ -e $$dir/Makefile ]; then \
|
||||||
$(MAKE) -C $$dir $@ ; \
|
$(MAKE) -C $$dir $@ ; \
|
||||||
fi; \
|
fi; \
|
||||||
|
131
contrib/README
131
contrib/README
@ -1,94 +1,81 @@
|
|||||||
This directory contains the contribution functions or tools.
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
The PostgreSQL contrib tree
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
apache_logging -
|
FIXME:
|
||||||
Getting Apache to log to PostgreSQL
|
os2client
|
||||||
by Terry Mackintosh <terry@terrym.com>
|
odbc
|
||||||
|
spi/preprocessor
|
||||||
|
tools
|
||||||
|
|
||||||
|
|
||||||
array -
|
- in each directory must be Makefile, possible Makefile template
|
||||||
Array iterator functions
|
is below this text,
|
||||||
by Massimo Dal Zotto <dz@cs.unitn.it>
|
|
||||||
|
|
||||||
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 -
|
TOPDIR=../..
|
||||||
Date & time functions
|
|
||||||
by Massimo Dal Zotto <dz@cs.unitn.it>
|
|
||||||
|
|
||||||
earthdistance -
|
include ../Makefile.global
|
||||||
Operator for computing earth distance for two points
|
|
||||||
by Hal Snyder <hal@vailsys.com>
|
|
||||||
|
|
||||||
findoidjoins -
|
NAME = some_name
|
||||||
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>
|
|
||||||
|
|
||||||
fulltextindex -
|
PROGRAM =
|
||||||
Full text indexing using triggers
|
OBJS = $(NAME).o
|
||||||
by Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl>
|
DOCS = $(NAME).doc
|
||||||
|
SQLS = $(NAME).sql
|
||||||
|
BINS =
|
||||||
|
EXAMPLES=
|
||||||
|
MODS = $(NAME)$(DLSUFFIX)
|
||||||
|
|
||||||
isbn_issn -
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
PostgreSQL type extensions for ISBN (books) and ISSN (serials)
|
|
||||||
by Garrett A. Wollman <wollman@khavrinen.lcs.mit.edu>
|
|
||||||
|
|
||||||
likeplanning -
|
OTHER_CLEAN = $(SQLS)
|
||||||
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>
|
|
||||||
|
|
||||||
linux -
|
all: $(MODS) $(SQLS)
|
||||||
Start postgres back end system
|
|
||||||
by Thomas Lockhart <lockhart@alumni.caltech.edu>
|
|
||||||
|
|
||||||
lo -
|
%.sql: %.sql.in
|
||||||
Large Object maintenance
|
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||||
by Peter Mount <peter@retep.org.uk>
|
|
||||||
|
|
||||||
miscutil -
|
|
||||||
Postgres assert checking and various utility functions
|
|
||||||
by Dal Zotto <dz@cs.unitn.it>
|
|
||||||
|
|
||||||
mSQL-interface -
|
install: install_doc install_sql install_mod install_bin install_example
|
||||||
mSQL API translation library
|
|
||||||
by Aldrin Leal <aldrin@americasnet.com>
|
|
||||||
|
|
||||||
noupdate -
|
install_doc:
|
||||||
trigger to prevent updates on single columns
|
for inst_file in $(DOCS); do \
|
||||||
|
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
|
||||||
|
done
|
||||||
|
|
||||||
pg_dumplo -
|
install_sql:
|
||||||
Dump large objects
|
for inst_file in $(SQLS); do \
|
||||||
|
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
|
||||||
|
done
|
||||||
|
|
||||||
soundex -
|
install_mod:
|
||||||
Prototype for soundex function
|
for inst_file in $(MODS); do \
|
||||||
|
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
|
||||||
|
done
|
||||||
|
|
||||||
spi -
|
install_bin:
|
||||||
A general trigger function autoinc() and so on.
|
for inst_file in $(BINS); do \
|
||||||
|
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
|
||||||
|
done
|
||||||
|
|
||||||
string -
|
install_example:
|
||||||
C-like input/output conversion routines for strings
|
for inst_file in $(EXAMPLES); do \
|
||||||
by Massimo Dal Zotto <dz@cs.unitn.it>
|
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_EXAMPLESDIR); \
|
||||||
|
done
|
||||||
|
|
||||||
tools -
|
depend dep:
|
||||||
Assorted developer tools
|
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||||
by Massimo Dal Zotto <dz@cs.unitn.it>
|
|
||||||
|
|
||||||
unixdate -
|
clean:
|
||||||
Conversions from integer to datetime
|
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||||
by Thomas Lockhart <lockhart@alumni.caltech.edu>
|
|
||||||
|
|
||||||
userlock -
|
ifeq (depend,$(wildcard depend))
|
||||||
User locks
|
include depend
|
||||||
by Massimo Dal Zotto <dz@cs.unitn.it>
|
endif
|
||||||
|
-----------
|
||||||
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>
|
|
@ -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'
|
|
||||||
|
@ -1,65 +1,53 @@
|
|||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
#
|
||||||
# Makefile --
|
# $Header: /cvsroot/pgsql/contrib/array/Attic/Makefile,v 1.8 2000/06/15 18:54:31 momjian Exp $
|
||||||
#
|
#
|
||||||
# Makefile for array iterator module.
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
PGDIR = ../..
|
TOPDIR=../..
|
||||||
SRCDIR = $(PGDIR)/src
|
|
||||||
|
|
||||||
include $(SRCDIR)/Makefile.global
|
include ../Makefile.global
|
||||||
|
|
||||||
|
NAME = array_iterator
|
||||||
|
|
||||||
|
PROGRAM =
|
||||||
|
OBJS = $(NAME).o
|
||||||
|
DOCS = $(NAME).doc
|
||||||
|
SQLS = $(NAME).sql
|
||||||
|
BINS =
|
||||||
|
EXAMPLES=
|
||||||
|
MODS = $(NAME)$(DLSUFFIX)
|
||||||
|
|
||||||
CFLAGS += -I. $(CFLAGS_SL)
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
|
|
||||||
MODNAME = array_iterator
|
OTHER_CLEAN = $(SQLS)
|
||||||
|
|
||||||
SQLDEFS = $(MODNAME).sql
|
all: $(MODS) $(SQLS)
|
||||||
|
|
||||||
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
|
%.sql: %.sql.in
|
||||||
sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
|
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||||
|
|
||||||
.SUFFIXES: $(DLSUFFIX)
|
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
|
||||||
|
|
||||||
%$(DLSUFFIX): %.c
|
|
||||||
$(CC) $(CFLAGS) -shared -o $@ $<
|
|
||||||
|
|
||||||
depend dep:
|
depend dep:
|
||||||
$(CC) -MM $(CFLAGS) *.c >depend
|
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *~ $(MODULE) $(MODNAME).sql
|
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||||
|
|
||||||
ifeq (depend,$(wildcard depend))
|
ifeq (depend,$(wildcard depend))
|
||||||
include depend
|
include depend
|
||||||
|
49
contrib/array/README
Normal file
49
contrib/array/README
Normal file
@ -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
|
TOPDIR=../..
|
||||||
CFLAGS+=-I${PGINCLUDE}
|
|
||||||
|
|
||||||
install-earthdistance: ${PGLIB}/earthdistance.so
|
include ../Makefile.global
|
||||||
|
|
||||||
${PGLIB}/earthdistance.so: earthdistance.so
|
NAME = earthdistance
|
||||||
sudo install -C -g bin -o bin earthdistance.so ${PGLIB}
|
|
||||||
|
|
||||||
earthdistance.so: earthdistance.o
|
PROGRAM =
|
||||||
$(LD) -o $@ -Bshareable $<
|
OBJS = $(NAME).o
|
||||||
|
DOCS = $(NAME).doc
|
||||||
|
SQLS = $(NAME).sql
|
||||||
|
BINS =
|
||||||
|
EXAMPLES=
|
||||||
|
MODS = $(NAME)$(DLSUFFIX)
|
||||||
|
|
||||||
earthdistance.o: earthdistance.c
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
$(CC) -o $@ -c $(CFLAGS) $<
|
|
||||||
|
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
|
||||||
|
@ -7,8 +7,11 @@
|
|||||||
#include <utils/palloc.h> /* for palloc */
|
#include <utils/palloc.h> /* for palloc */
|
||||||
|
|
||||||
/* Earth's radius is in statute miles. */
|
/* Earth's radius is in statute miles. */
|
||||||
const EARTH_RADIUS = 3958.747716;
|
const int EARTH_RADIUS = 3958.747716;
|
||||||
const TWO_PI = 2.0 * M_PI;
|
const int TWO_PI = 2.0 * M_PI;
|
||||||
|
|
||||||
|
double *geo_distance(Point *pt1, Point *pt2);
|
||||||
|
|
||||||
|
|
||||||
/******************************************************
|
/******************************************************
|
||||||
*
|
*
|
||||||
|
@ -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
|
TOPDIR=../..
|
||||||
PGEASY = ../../src/interfaces/libpgeasy
|
|
||||||
CFLAGS = -g -Wall -I. -I$(PGEASY) -I$(INSTALLDIR)/include
|
|
||||||
LIBPGEASY = $(PGEASY)/libpgeasy.a
|
|
||||||
LDFLAGS = -L$(INSTALLDIR)/lib -lpq
|
|
||||||
|
|
||||||
all : $(TARGET)
|
include ../Makefile.global
|
||||||
|
|
||||||
findoidjoins: findoidjoins.c $(LIBPGEASY)
|
NAME = findoidjoins
|
||||||
gcc -o $@ $(CFLAGS) $^ $(LDFLAGS)
|
|
||||||
|
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_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:
|
clean:
|
||||||
rm -f *.o $(TARGET) log core
|
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||||
|
|
||||||
install:
|
|
||||||
install -s -o bin -g bin $(TARGET) $(INSTALLDIR)/bin
|
|
||||||
|
|
||||||
|
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)
|
PROGRAM =
|
||||||
CLEANFILES+= $(TARGETS)
|
OBJS = $(NAME).o
|
||||||
CURDIR=`pwd`
|
DOCS = $(NAME).doc
|
||||||
|
SQLS = $(NAME).sql
|
||||||
|
BINS = fti.pl
|
||||||
|
EXAMPLES=
|
||||||
|
MODS = $(NAME)$(DLSUFFIX)
|
||||||
|
|
||||||
all:: $(TARGETS)
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
|
|
||||||
%.sql: %.source
|
OTHER_CLEAN = $(SQLS)
|
||||||
rm -f $@; \
|
|
||||||
sed -e "s:_CURRENTDIR_:$(CURDIR):g" \
|
|
||||||
-e "s:_DLSUFFIX_:$(DLSUFFIX):g" < $< > $@
|
|
||||||
|
|
||||||
clean:
|
all: $(MODS) $(SQLS)
|
||||||
rm -f $(TARGETS) *.o
|
|
||||||
|
|
||||||
dist:
|
%.sql: %.sql.in
|
||||||
tar cf fti.tar README BENCH Makefile fti.c timings.sh
|
$(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
|
||||||
|
@ -94,4 +94,104 @@ Method 1 is very slow, 2 a lot faster, and for very large tables, 3 is
|
|||||||
preferred.
|
preferred.
|
||||||
|
|
||||||
|
|
||||||
|
BENCH:
|
||||||
|
~~~~~
|
||||||
|
|
||||||
Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl>
|
Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl>
|
||||||
|
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,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)
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
install -c isbn$(DLSUFFIX) issn$(DLSUFFIX) /usr/local/pgsql/modules
|
|
||||||
|
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:
|
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,3 +1,7 @@
|
|||||||
|
|
||||||
|
ISBN (books) and ISSN (serials)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
This directory contains definitions for a couple of PostgreSQL
|
This directory contains definitions for a couple of PostgreSQL
|
||||||
external types, for a couple of international-standard namespaces:
|
external types, for a couple of international-standard namespaces:
|
||||||
ISBN (books) and ISSN (serials). Rather than just using a char()
|
ISBN (books) and ISSN (serials). Rather than just using a char()
|
||||||
|
@ -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,39 +1,60 @@
|
|||||||
#
|
#
|
||||||
# PostgreSQL lo type
|
# $Header: /cvsroot/pgsql/contrib/lo/Makefile,v 1.3 2000/06/15 18:54:56 momjian Exp $
|
||||||
#
|
#
|
||||||
# Makefile pinched from the ip-mac contrib package
|
|
||||||
#
|
|
||||||
# $Id: Makefile,v 1.2 2000/05/29 05:44:27 tgl Exp $
|
|
||||||
|
|
||||||
SRCDIR= ../../src
|
TOPDIR=../..
|
||||||
|
|
||||||
include $(SRCDIR)/Makefile.global
|
include ../Makefile.global
|
||||||
|
|
||||||
CONTRIBDIR=$(LIBDIR)/modules
|
NAME = lo
|
||||||
|
|
||||||
CFLAGS+= $(CFLAGS_SL)
|
PROGRAM =
|
||||||
|
OBJS = $(NAME).o
|
||||||
|
DOCS = $(NAME).doc
|
||||||
|
SQLS = $(NAME).sql
|
||||||
|
BINS =
|
||||||
|
EXAMPLES=
|
||||||
|
MODS = $(NAME)$(DLSUFFIX)
|
||||||
|
|
||||||
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
|
|
||||||
ifdef REFINT_VERBOSE
|
ifdef REFINT_VERBOSE
|
||||||
CFLAGS+= -DREFINT_VERBOSE
|
CFLAGS+= -DREFINT_VERBOSE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
TARGETS= lo$(DLSUFFIX) lo.sql
|
OTHER_CLEAN = $(SQLS)
|
||||||
|
|
||||||
CLEANFILES+= $(TARGETS)
|
all: $(MODS) $(SQLS)
|
||||||
|
|
||||||
all:: $(TARGETS)
|
|
||||||
|
|
||||||
install:: all $(CONTRIBDIR)
|
|
||||||
for f in *$(DLSUFFIX); do $(INSTALL) -c $$f $(CONTRIBDIR)/$$f; done
|
|
||||||
|
|
||||||
$(CONTRIBDIR):
|
|
||||||
mkdir -p $(CONTRIBDIR)
|
|
||||||
|
|
||||||
%.sql: %.sql.in
|
%.sql: %.sql.in
|
||||||
rm -f $@; \
|
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||||
C=`pwd`; \
|
|
||||||
sed -e "s:_OBJWD_:$(CONTRIBDIR):g" \
|
|
||||||
-e "s:_DLSUFFIX_:$(DLSUFFIX):g" < $< > $@
|
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
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(TARGETS) *.o
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
PostgreSQL type extension for managing Large Objects
|
PostgreSQL type extension for managing Large Objects
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
||||||
$Id: README,v 1.1 1998/06/16 07:07:11 momjian Exp $
|
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
|
|
||||||
One of the problems with the JDBC driver (and this affects the ODBC driver
|
One of the problems with the JDBC driver (and this affects the ODBC driver
|
||||||
|
@ -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,11 +1,8 @@
|
|||||||
--
|
--
|
||||||
-- PostgreSQL code for LargeObjects
|
-- PostgreSQL code for LargeObjects
|
||||||
--
|
--
|
||||||
-- $Id: lo.sql.in,v 1.2 2000/05/29 01:59:02 tgl Exp $
|
-- $Id: lo.sql.in,v 1.3 2000/06/15 18:54:56 momjian Exp $
|
||||||
--
|
--
|
||||||
|
|
||||||
load '_OBJWD_/lo_DLSUFFIX_';
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Create the data type
|
-- Create the data type
|
||||||
--
|
--
|
||||||
@ -13,13 +10,13 @@ load '_OBJWD_/lo_DLSUFFIX_';
|
|||||||
-- used by the lo type, it takes an oid and returns an lo object
|
-- used by the lo type, it takes an oid and returns an lo object
|
||||||
create function lo_in(opaque)
|
create function lo_in(opaque)
|
||||||
returns opaque
|
returns opaque
|
||||||
as '_OBJWD_/lo_DLSUFFIX_'
|
as 'MODULE_PATHNAME'
|
||||||
language 'c';
|
language 'c';
|
||||||
|
|
||||||
-- used by the lo type, it returns the oid of the object
|
-- used by the lo type, it returns the oid of the object
|
||||||
create function lo_out(opaque)
|
create function lo_out(opaque)
|
||||||
returns opaque
|
returns opaque
|
||||||
as '_OBJWD_/lo_DLSUFFIX_'
|
as 'MODULE_PATHNAME'
|
||||||
language 'c';
|
language 'c';
|
||||||
|
|
||||||
-- finally the type itself
|
-- finally the type itself
|
||||||
@ -33,20 +30,20 @@ create type lo (
|
|||||||
-- this returns the oid associated with a lo object
|
-- this returns the oid associated with a lo object
|
||||||
create function lo_oid(lo)
|
create function lo_oid(lo)
|
||||||
returns oid
|
returns oid
|
||||||
as '_OBJWD_/lo_DLSUFFIX_'
|
as 'MODULE_PATHNAME'
|
||||||
language 'c';
|
language 'c';
|
||||||
|
|
||||||
-- this allows us to convert an oid to a managed lo object
|
-- this allows us to convert an oid to a managed lo object
|
||||||
-- ie: insert into test values (lo_import('/fullpath/file')::lo);
|
-- ie: insert into test values (lo_import('/fullpath/file')::lo);
|
||||||
create function lo(oid)
|
create function lo(oid)
|
||||||
returns lo
|
returns lo
|
||||||
as '_OBJWD_/lo_DLSUFFIX_'
|
as 'MODULE_PATHNAME'
|
||||||
language 'c';
|
language 'c';
|
||||||
|
|
||||||
-- This is used in triggers
|
-- This is used in triggers
|
||||||
create function lo_manage()
|
create function lo_manage()
|
||||||
returns opaque
|
returns opaque
|
||||||
as '_OBJWD_/lo_DLSUFFIX_'
|
as 'MODULE_PATHNAME'
|
||||||
language 'newC';
|
language 'newC';
|
||||||
|
|
||||||
-- This allows us to map lo to oid
|
-- This allows us to map lo to oid
|
||||||
|
@ -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
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
Hello! :)
|
Hello! :)
|
||||||
|
|
||||||
(Sorry for my english. But if i wrote in portuguese, you wouldn't
|
(Sorry for my english. But if i wrote in portuguese, you wouldn't
|
||||||
|
@ -1,65 +1,52 @@
|
|||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
#
|
||||||
# Makefile --
|
# $Header: /cvsroot/pgsql/contrib/miscutil/Attic/Makefile,v 1.8 2000/06/15 18:55:01 momjian Exp $
|
||||||
#
|
#
|
||||||
# Makefile for the misc_util module.
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
PGDIR = ../..
|
TOPDIR=../..
|
||||||
SRCDIR = $(PGDIR)/src
|
|
||||||
|
|
||||||
include $(SRCDIR)/Makefile.global
|
include ../Makefile.global
|
||||||
|
|
||||||
|
NAME = misc_utils
|
||||||
|
|
||||||
|
PROGRAM =
|
||||||
|
OBJS = $(NAME).o
|
||||||
|
DOCS = $(NAME).doc
|
||||||
|
SQLS = $(NAME).sql
|
||||||
|
BINS =
|
||||||
|
EXAMPLES=
|
||||||
|
MODS = $(NAME)$(DLSUFFIX)
|
||||||
|
|
||||||
CFLAGS += -I. $(CFLAGS_SL)
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
|
|
||||||
MODNAME = misc_utils
|
OTHER_CLEAN = $(SQLS)
|
||||||
|
|
||||||
SQLDEFS = $(MODNAME).sql
|
all: $(MODS) $(SQLS)
|
||||||
|
|
||||||
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
|
%.sql: %.sql.in
|
||||||
sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
|
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||||
|
|
||||||
.SUFFIXES: $(DLSUFFIX)
|
install: install_doc install_sql install_mod
|
||||||
|
|
||||||
%$(DLSUFFIX): %.c
|
install_doc:
|
||||||
$(CC) $(CFLAGS) -shared -o $@ $<
|
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:
|
depend dep:
|
||||||
$(CC) -MM $(CFLAGS) *.c >depend
|
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *~ $(MODULE) $(MODNAME).sql
|
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||||
|
|
||||||
ifeq (depend,$(wildcard depend))
|
ifeq (depend,$(wildcard depend))
|
||||||
include depend
|
include depend
|
||||||
|
43
contrib/miscutil/README
Normal file
43
contrib/miscutil/README
Normal file
@ -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>
|
20
contrib/noupdate/README
Normal file
20
contrib/noupdate/README
Normal file
@ -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
|
TOPDIR=../..
|
||||||
|
|
||||||
OBJECTS = pg_dumplo.o
|
|
||||||
|
|
||||||
CFLAGS = -Wall -fpic -g
|
include ../Makefile.global
|
||||||
CC = gcc
|
|
||||||
RM = rm -f
|
|
||||||
INCLUDE = -I/usr/include/postgresql
|
|
||||||
LIBS =-lpq
|
|
||||||
|
|
||||||
COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDE)
|
NAME = pg_dumplo
|
||||||
LINK = $(CC) $(CFLAGS) -o $@ $(LIBS)
|
|
||||||
|
|
||||||
|
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)
|
OTHER_CLEAN =
|
||||||
$(LINK) $(OBJECTS)
|
|
||||||
|
|
||||||
.c.o: $<
|
all: $(PROGRAM)
|
||||||
$(COMPILE) -c $<
|
|
||||||
|
$(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:
|
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
|
(c) 2000, Pavel Jan<61>k ml. <Pavel.Janik@linux.cz>
|
||||||
see the help ( pg_dumplo -h ) and examples in this help.
|
|
||||||
|
|
||||||
Compilation:
|
|
||||||
- you need the PostgreSQL's devel. libs
|
|
||||||
- and type: 'make'
|
|
||||||
|
|
||||||
|
Q: How do you use pg_dumplo?
|
||||||
Karel Zak <zakkr@zf.jcu.cz>
|
============================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
PROGRAM = $(NAME)
|
||||||
OBJS = pgbench.o
|
OBJS = $(NAME).o
|
||||||
|
DOCS = $(NAME).doc $(NAME)_jis.doc
|
||||||
|
SQLS =
|
||||||
|
BINS = $(PROGRAM)
|
||||||
|
EXAMPLES=
|
||||||
|
MODS =
|
||||||
|
|
||||||
all:: $(TARGET)
|
CFLAGS += -I$(LIBPQDIR)
|
||||||
|
|
||||||
$(TARGET): $(OBJS)
|
OTHER_CLEAN =
|
||||||
$(CC) -o $(TARGET) $(OBJS) -L$(LIBPQDIR) -lpq $(LDFLAGS)
|
|
||||||
|
|
||||||
install: $(TARGET)
|
all: $(PROGRAM)
|
||||||
$(INSTALL) $(INSTL_EXE_OPTS) $(TARGET)$(X) $(BINDIR)/$(TARGET)$(X)
|
|
||||||
|
$(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:
|
clean:
|
||||||
$(RM) $(TARGET)$(X) $(OBJS)
|
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||||
|
|
||||||
distclean: clean
|
ifeq (depend,$(wildcard depend))
|
||||||
|
include depend
|
||||||
|
endif
|
||||||
|
@ -1,166 +0,0 @@
|
|||||||
pgbench 1.2 README 2000/1/15 Tatsuo Ishii (t-ishii@sra.co.jp)
|
|
||||||
|
|
||||||
$B"#(Bpgbench $B$H$O!)(B
|
|
||||||
|
|
||||||
pgbench $B$O(B TPC-B$B$K;w$?%Y%s%A%^!<%/%F%9%H$r9T$J$&%W%m%0%i%`$G$9!#:#$N$H(B
|
|
||||||
$B$3$m(B PostgreSQL $B@lMQ$G$9!#(B
|
|
||||||
|
|
||||||
pgbench $B$O(B select/update/insert $B$r4^$`%H%i%s%6%/%7%g%s$r<B9T$7!"A4BN$N(B
|
|
||||||
$B<B9T;~4V$H<B:]$K40N;$7$?%H%i%s%6%/%7%g%s$N?t$+$i(B 1 $BIC4V$K<B9T$G$-$?%H(B
|
|
||||||
$B%i%s%6%/%7%g%s?t(B (tps) $B$rI=<($7$^$9!#=hM}$NBP>]$H$J$k%F!<%V%k$O%G%U%)(B
|
|
||||||
$B%k%H$G$O(B 10$BK|%?%W%k$N%G!<%?$r4^$_$^$9!#(B
|
|
||||||
|
|
||||||
$B<B:]$NI=<($O0J2<$N$h$&$J46$8$G$9!#(B
|
|
||||||
|
|
||||||
number of clients: 4
|
|
||||||
number of transactions per client: 100
|
|
||||||
number of processed transactions: 400/400
|
|
||||||
tps = 19.875015(including connections establishing)
|
|
||||||
tps = 20.098827(excluding connections establishing)
|
|
||||||
|
|
||||||
pgbench $B$O(B JDBCBench $B$H$$$&!"$b$H$b$H$O(B MySQL $BMQ$K=q$+$l$?(B JDBC $BMQ$N%Y(B
|
|
||||||
$B%s%A%^!<%/%W%m%0%i%`$r;29M$K:n@.$5$l$^$7$?!#(B
|
|
||||||
|
|
||||||
$B"#(Bpgbench $B$NFCD'(B
|
|
||||||
|
|
||||||
o C $B8@8l$H(B libpq $B$@$1$G=q$+$l$F$$$k$N$G0\?"@-$,9b$/!"4JC1$K%$%s%9%H!<(B
|
|
||||||
$B%k$G$-$^$9!#(B
|
|
||||||
|
|
||||||
o pgbench $B$O(B libpq $B$NHsF14|=hM}5!G=$r;H$C$F%^%k%A%f!<%64D6-$r%7%_%e%l!<(B
|
|
||||||
$B%H$7$^$9!#MF0W$KF1;~@\B34D6-$r%F%9%H$G$-$^$9!#(B
|
|
||||||
|
|
||||||
$B"#(Bpgbench $B$N%$%s%9%H!<%k(B
|
|
||||||
|
|
||||||
Makefile$B$N0lHV>e$K$"$k(B
|
|
||||||
|
|
||||||
POSTGRESHOME = /usr/local/pgsql
|
|
||||||
|
|
||||||
$B$rI,MW$K1~$8$F=$@5$7!"(Bconfigure;make $B$9$k$@$1$G$9!#(B
|
|
||||||
|
|
||||||
$B"#(Bpgbench $B$N;H$$J}(B
|
|
||||||
|
|
||||||
$B4pK\E*$J;H$$J}$O!"(B
|
|
||||||
|
|
||||||
$ pgbench [$B%G!<%?%Y!<%9L>(B]
|
|
||||||
|
|
||||||
$B$G$9!#%G!<%?%Y!<%9L>$r>JN,$9$k$H!"%f!<%6L>$HF1$8%G!<%?%Y!<%9$r;XDj$7$?(B
|
|
||||||
$B$b$N$H$_$J$7$^$9!#%G!<%?%Y!<%9$O8e=R$N(B -i $B%*%W%7%g%s$r;H$C$F$"$i$+$8$a(B
|
|
||||||
$B=i4|2=$7$F$*$/I,MW$,$"$j$^$9!#(B
|
|
||||||
|
|
||||||
pgbench $B$K$O$$$m$$$m$J%*%W%7%g%s$,$"$j$^$9!#(B
|
|
||||||
|
|
||||||
-h $B%[%9%HL>(B PostgreSQL$B$N%G!<%?%Y!<%9%G!<%b%s(B postmaster $B$NF0(B
|
|
||||||
$B$$$F$$$k%[%9%HL>$r;XDj$7$^$9!#>JN,$9$k$H<+%[%9%H$K(B Unix domain
|
|
||||||
socket $B$G@\B3$7$^$9!#(B
|
|
||||||
|
|
||||||
-p $B%]!<%HHV9f(B postmaster $B$N;HMQ$9$k%]!<%HHV9f$r;XDj$7$^$9!#>JN,$9$k$H(B 5432
|
|
||||||
$B$,;XDj$5$l$?$b$N$H$_$J$7$^$9!#(B
|
|
||||||
|
|
||||||
-c $B%/%i%$%"%s%H?t(B $BF1;~<B9T%/%i%$%"%s%H?t$r;XDj$7$^$9!#>JN,;~$O(B
|
|
||||||
1 $B$H$J$j$^$9!#(Bpgbench $B$OF1;~<B9T%/%i%$%"%s%HKh$K(B
|
|
||||||
$B%U%!%$%k%G%#%9%/%j%W%?$r;HMQ$9$k$N$G!";HMQ2DG=(B
|
|
||||||
$B%U%!%$%k%G%#%9%/%j%W%??t$r1[$($k%/%i%$%"%s%H?t$O(B
|
|
||||||
$B;XDj$G$-$^$;$s!#;HMQ2DG=%U%!%$%k%G%#%9%/%j%W%??t(B
|
|
||||||
$B$O(B limit $B$d(B ulimit $B%3%^%s%I$GCN$k$3$H$,$G$-$^$9!#(B
|
|
||||||
|
|
||||||
-t $B%H%i%s%6%/%7%g%s?t(B $B3F%/%i%$%"%s%H$,<B9T$9$k%H%i%s%6%/%7%g%s?t$r(B
|
|
||||||
$B;XDj$7$^$9!#>JN,;~$O(B 10 $B$H$J$j$^$9!#(B
|
|
||||||
|
|
||||||
-s $B%9%1!<%j%s%0%U%!%/%?!<(B
|
|
||||||
|
|
||||||
-i $B%*%W%7%g%s$H0l=o$K;HMQ$7$^$9!#(B
|
|
||||||
$B%9%1!<%j%s%0%U%!%/%?!<$O(B1$B0J>e$N@0?t!#%9%1!<%j%s%0%U%!(B
|
|
||||||
$B%/%?!<$rJQ$($k$3$H$K$h$j!"%F%9%H$NBP>]$H$J$k%F!<%V%k$N(B
|
|
||||||
$BBg$-$5$,(B 10$BK|(B x [$B%9%1!<%j%s%0%U%!%/%?!<(B]$B$K$J$j$^$9!#(B
|
|
||||||
$B%G%U%)%k%H$N%9%1!<%j%s%0%U%!%/%?!<$O(B 1 $B$G$9!#(B
|
|
||||||
|
|
||||||
-v $B$3$N%*%W%7%g%s$r;XDj$9$k$H!"%Y%s%A%^!<%/3+;OA0$K(B vacuum $B$H(B
|
|
||||||
history $B$N%/%j%"$r9T$J$$$^$9!#(B-v $B$H(B -n $B$r>JN,$9$k$H!"(B
|
|
||||||
$B:G>.8B$N(B vacuum $B$J$I$r9T$$$^$9!#$9$J$o$A!"(Bhistory $B$N:o=|!"(B
|
|
||||||
$B$H(B history, branches, history $B$N(B vacuum $B$r9T$$$^$9!#(B
|
|
||||||
$B$3$l$O!"(Bvacuum $B$N;~4V$r:G>.8B$K$7$J$,$i!"%Q%U%)!<%^%s%9$K(B
|
|
||||||
$B1F6A$9$k%4%_A]=|$r8z2LE*$K9T$$$^$9!#DL>o$O(B -v $B$H(B -n $B$r(B
|
|
||||||
$B>JN,$9$k$3$H$r$*$9$9$a$7$^$9!#(B
|
|
||||||
|
|
||||||
-n $B$3$N%*%W%7%g%s$r;XDj$9$k$H!"%Y%s%A%^!<%/3+;OA0$K(B vacuum $B$H(B
|
|
||||||
history $B$N%/%j%"$r9T$J$$$^$;$s!#(B
|
|
||||||
|
|
||||||
-S TPC-B$B$N%H%i%s%6%/%7%g%s$G$O$J$/!"8!:w$N$_$N%H%i%s%6%/%7%g%s$r(B
|
|
||||||
$B<B9T$7$^$9!#8!:w%9%T!<%I$rB,Dj$7$?$$$H$-$K;H$$$^$9!#(B
|
|
||||||
|
|
||||||
-d $B%G%P%C%0%*%W%7%g%s!#MM!9$J>pJs$,I=<($5$l$^$9!#(B
|
|
||||||
|
|
||||||
$B"#%G!<%?%Y!<%9$N=i4|2=(B
|
|
||||||
|
|
||||||
pgbench $B$G%Y%s%A%^!<%/%F%9%H$r<B;\$9$k$?$a$K$O!"$"$i$+$8$a%G!<%?%Y!<%9(B
|
|
||||||
$B$r=i4|2=$7!"%F%9%H%G!<%?$r:n$kI,MW$,$"$j$^$9!#(B
|
|
||||||
|
|
||||||
$ pgbench -i [$B%G!<%?%Y!<%9L>(B]
|
|
||||||
|
|
||||||
$B$3$l$K$h$j0J2<$N%F!<%V%k$,:n$i$l$^$9(B($B%9%1!<%j%s%0%U%!%/%?!<(B == 1 $B$N>l9g(B)$B!#(B
|
|
||||||
|
|
||||||
$B!vCm0U!v(B
|
|
||||||
$BF1$8L>A0$N%F!<%V%k$,$"$k$H:o=|$5$l$F$7$^$&$N$G$4Cm0U2<$5$$!*!*(B
|
|
||||||
|
|
||||||
$B%F!<%V%kL>(B $B%?%W%k?t(B
|
|
||||||
-------------------------
|
|
||||||
branches 1
|
|
||||||
tellers 10
|
|
||||||
accounts 100000
|
|
||||||
history 0
|
|
||||||
|
|
||||||
$B%9%1!<%j%s%0%U%!%/%?!<$r(B 10,100,1000 $B$J$I$KJQ99$9$k$H!">e5-%?%W%k?t$O(B
|
|
||||||
$B$=$l$K1~$8$F(B10$BG\!"(B100$BG\!"(B1000$BG\$K$J$j$^$9!#$?$H$($P!"%9%1!<%j%s%0%U%!(B
|
|
||||||
$B%/%?!<$r(B 10 $B$H$9$k$H!"(B
|
|
||||||
|
|
||||||
$B%F!<%V%kL>(B $B%?%W%k?t(B
|
|
||||||
-------------------------
|
|
||||||
branches 10
|
|
||||||
tellers 100
|
|
||||||
accounts 1000000
|
|
||||||
history 0
|
|
||||||
|
|
||||||
$B$K$J$j$^$9!#(B
|
|
||||||
|
|
||||||
$B"#!V%H%i%s%6%/%7%g%s!W$NDj5A(B
|
|
||||||
|
|
||||||
pgbench $B$G$O!"0J2<$N%7!<%1%s%9$rA4It40N;$7$F(B1$B%H%i%s%6%/%7%g%s$H?t$($F(B
|
|
||||||
$B$$$^$9!#(B
|
|
||||||
|
|
||||||
(1) begin;
|
|
||||||
|
|
||||||
(2) update accounts set abalance = abalance + :delta where aid = :aid;
|
|
||||||
$B$3$3$G!"(B:delta$B$O(B1$B$+$i(B1000$B$^$G$NCM$r<h$kMp?t!"(B:aid $B$O(B 1$B$+$i(B100000$B$^$G(B
|
|
||||||
$B$NCM$r<h$kMp?t$G$9!#0J2<!"Mp?t$NCM$O$=$l$>$l$3$N%H%i%s%6%/%7%g%s$N(B
|
|
||||||
$BCf$G$OF1$8CM$r;H$$$^$9!#(B
|
|
||||||
|
|
||||||
(3) select abalance from accounts where aid = :aid;
|
|
||||||
$B$3$3$G$O(B1$B7o$@$18!:w$5$l$^$9!#(B
|
|
||||||
|
|
||||||
(4) update tellers set tbalance = tbalance + :delta where tid = :tid;
|
|
||||||
$B$3$3$G(B :tid $B$O(B 1$B$+$i(B10$B$N4V$NCM$r$H$kMp?t$G$9!#(B
|
|
||||||
|
|
||||||
(5) update branches set bbalance = bbalance + :delta where bid = :bid;
|
|
||||||
$B$3$3$G(B :bid $B$O(B 1 $B$+$i(B[$B%9%1%j%s%0%U%!%/%?!<(B]$B$N4V$NCM$r<h$kMp?t$G$9!#(B
|
|
||||||
|
|
||||||
(6) insert into history(tid,bid,aid,delta) values(:tid,:bid,:aid,:delta);
|
|
||||||
|
|
||||||
(7) end;
|
|
||||||
|
|
||||||
$B"#:n<T$H%i%$%;%s%9>r7o(B
|
|
||||||
|
|
||||||
pgbench $B$O@P0f(B $BC#IW$K$h$C$F=q$+$l$^$7$?!#%i%$%;%s%9>r7o$O(B pgbench.c $B$N(B
|
|
||||||
$BKAF,$K=q$$$F$"$j$^$9!#$3$N>r7o$r<i$k8B$jL5=~$GMxMQ$7!"$^$?<+M3$K:FG[IU(B
|
|
||||||
$B$G$-$^$9!#(B
|
|
||||||
|
|
||||||
$B"#2~DjMzNr(B
|
|
||||||
|
|
||||||
2000/1/15 pgbench-1.2 $B$O(B PostgreSQL $B$K(B contribute $B$5$l$^$7$?!#(B
|
|
||||||
* -v $B%*%W%7%g%sDI2C(B
|
|
||||||
|
|
||||||
1999/09/29 pgbench-1.1 $B%j%j!<%9(B
|
|
||||||
* $BC+ED$5$s$K$h$k(Bcygwin$BBP1~%Q%C%A<h$j9~$_(B
|
|
||||||
* $B%P%C%/%(%s%I%/%i%C%7%e;~$NBP1~(B
|
|
||||||
* -S $B%*%W%7%g%sDI2C(B
|
|
||||||
|
|
||||||
1999/09/04 pgbench-1.0 $B%j%j!<%9(B
|
|
||||||
|
@ -1,44 +1,53 @@
|
|||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
#
|
||||||
# Makefile--
|
# $Header: /cvsroot/pgsql/contrib/soundex/Attic/Makefile,v 1.3 2000/06/15 18:55:15 momjian Exp $
|
||||||
# Makefile for soundex
|
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
PGDIR = ../..
|
TOPDIR=../..
|
||||||
SRCDIR = $(PGDIR)/src
|
|
||||||
|
|
||||||
include $(SRCDIR)/Makefile.global
|
include ../Makefile.global
|
||||||
|
|
||||||
|
NAME = soundex
|
||||||
|
|
||||||
|
PROGRAM =
|
||||||
|
OBJS = $(NAME).o
|
||||||
|
DOCS = $(NAME).doc
|
||||||
|
SQLS = $(NAME).sql
|
||||||
|
BINS =
|
||||||
|
EXAMPLES=
|
||||||
|
MODS = $(NAME)$(DLSUFFIX)
|
||||||
|
|
||||||
CFLAGS += -I. $(CFLAGS_SL)
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
|
|
||||||
MODNAME = soundex
|
OTHER_CLEAN = $(SQLS)
|
||||||
|
|
||||||
MODULE = $(MODNAME)$(DLSUFFIX)
|
all: $(MODS) $(SQLS)
|
||||||
|
|
||||||
all: module sql
|
|
||||||
|
|
||||||
module: $(MODULE)
|
|
||||||
|
|
||||||
sql: $(MODNAME).sql
|
|
||||||
|
|
||||||
install: $(MODULE)
|
|
||||||
cp -p $(MODULE) $(LIBDIR)/modules
|
|
||||||
cd $(LIBDIR)/modules; strip $(MODULE)
|
|
||||||
|
|
||||||
%.sql: %.sql.in
|
%.sql: %.sql.in
|
||||||
sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@
|
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||||
|
|
||||||
.SUFFIXES: $(DLSUFFIX)
|
install: install_doc install_sql install_mod
|
||||||
|
|
||||||
%$(DLSUFFIX): %.c
|
install_doc:
|
||||||
$(CC) $(CFLAGS) -shared -o $@ $<
|
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:
|
depend dep:
|
||||||
$(CC) -MM $(CFLAGS) *.c >depend
|
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(MODULE) $(MODNAME).sql
|
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||||
|
|
||||||
ifeq (depend,$(wildcard depend))
|
ifeq (depend,$(wildcard depend))
|
||||||
include depend
|
include depend
|
||||||
|
53
contrib/soundex/README
Normal file
53
contrib/soundex/README
Normal file
@ -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
|
CREATE FUNCTION text_soundex(text) RETURNS text
|
||||||
AS '_OBJWD_/soundex.so' LANGUAGE 'c';
|
AS 'MODULE_PATHNAME' LANGUAGE 'c';
|
||||||
|
|
||||||
SELECT text_soundex('hello world!');
|
|
||||||
|
|
||||||
CREATE TABLE s (nm text)\g
|
|
||||||
|
|
||||||
insert into s values ('john')\g
|
|
||||||
insert into s values ('joan')\g
|
|
||||||
insert into s values ('wobbly')\g
|
|
||||||
|
|
||||||
select * from s
|
|
||||||
where text_soundex(nm) = text_soundex('john')\g
|
|
||||||
|
|
||||||
select nm from s a, s b
|
|
||||||
where text_soundex(a.nm) = text_soundex(b.nm)
|
|
||||||
and a.oid <> b.oid\g
|
|
||||||
|
|
||||||
CREATE FUNCTION text_sx_eq(text, text) RETURNS bool AS
|
|
||||||
'select text_soundex($1) = text_soundex($2)'
|
|
||||||
LANGUAGE 'sql'\g
|
|
||||||
|
|
||||||
CREATE FUNCTION text_sx_lt(text,text) RETURNS bool AS
|
|
||||||
'select text_soundex($1) < text_soundex($2)'
|
|
||||||
LANGUAGE 'sql'\g
|
|
||||||
|
|
||||||
CREATE FUNCTION text_sx_gt(text,text) RETURNS bool AS
|
|
||||||
'select text_soundex($1) > text_soundex($2)'
|
|
||||||
LANGUAGE 'sql';
|
|
||||||
|
|
||||||
CREATE FUNCTION text_sx_le(text,text) RETURNS bool AS
|
|
||||||
'select text_soundex($1) <= text_soundex($2)'
|
|
||||||
LANGUAGE 'sql';
|
|
||||||
|
|
||||||
CREATE FUNCTION text_sx_ge(text,text) RETURNS bool AS
|
|
||||||
'select text_soundex($1) >= text_soundex($2)'
|
|
||||||
LANGUAGE 'sql';
|
|
||||||
|
|
||||||
CREATE FUNCTION text_sx_ne(text,text) RETURNS bool AS
|
|
||||||
'select text_soundex($1) <> text_soundex($2)'
|
|
||||||
LANGUAGE 'sql';
|
|
||||||
|
|
||||||
DROP OPERATOR #= (text,text)\g
|
|
||||||
|
|
||||||
CREATE OPERATOR #= (leftarg=text, rightarg=text, procedure=text_sx_eq,
|
|
||||||
commutator=text_sx_eq)\g
|
|
||||||
|
|
||||||
SELECT *
|
|
||||||
FROM s
|
|
||||||
WHERE text_sx_eq(nm,'john')\g
|
|
||||||
|
|
||||||
SELECT *
|
|
||||||
from s
|
|
||||||
where s.nm #= 'john';
|
|
||||||
|
|
||||||
|
@ -1,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
|
ifdef REFINT_VERBOSE
|
||||||
CFLAGS+= -DREFINT_VERBOSE
|
CFLAGS+= -DREFINT_VERBOSE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
TARGETS= refint$(DLSUFFIX) refint.sql \
|
OTHER_CLEAN = $(SQLS)
|
||||||
timetravel$(DLSUFFIX) timetravel.sql \
|
|
||||||
autoinc$(DLSUFFIX) autoinc.sql \
|
|
||||||
moddatetime$(DLSUFFIX) moddatetime.sql \
|
|
||||||
insert_username$(DLSUFFIX) insert_username.sql
|
|
||||||
|
|
||||||
CLEANFILES+= $(TARGETS)
|
all: $(MODS) $(SQLS)
|
||||||
|
|
||||||
all:: $(TARGETS)
|
%.sql: %.sql.in
|
||||||
|
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||||
|
|
||||||
%.sql: %.source
|
install: install_doc install_sql install_mod install_example
|
||||||
rm -f $@; \
|
|
||||||
C=`pwd`; \
|
install_doc:
|
||||||
sed -e "s:_OBJWD_:$$C:g" \
|
for inst_file in $(DOCS); do \
|
||||||
-e "s:_DLSUFFIX_:$(DLSUFFIX):g" < $< > $@
|
$(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_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:
|
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);
|
|
||||||
|
@ -1,65 +1,53 @@
|
|||||||
#-------------------------------------------------------------------------
|
#
|
||||||
|
# $Header: /cvsroot/pgsql/contrib/string/Attic/Makefile,v 1.8 2000/06/15 18:55:21 momjian Exp $
|
||||||
#
|
#
|
||||||
# Makefile --
|
|
||||||
#
|
|
||||||
# Makefile for string I/O module.
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
PGDIR = ../..
|
TOPDIR=../..
|
||||||
SRCDIR = $(PGDIR)/src
|
|
||||||
|
|
||||||
include $(SRCDIR)/Makefile.global
|
include ../Makefile.global
|
||||||
|
|
||||||
|
NAME = string_io
|
||||||
|
|
||||||
|
PROGRAM =
|
||||||
|
OBJS = $(NAME).o
|
||||||
|
DOCS = $(NAME).doc
|
||||||
|
SQLS = $(NAME).sql
|
||||||
|
BINS =
|
||||||
|
EXAMPLES=
|
||||||
|
MODS = $(NAME)$(DLSUFFIX)
|
||||||
|
|
||||||
CFLAGS += -I. $(CFLAGS_SL)
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
|
|
||||||
MODNAME = string_io
|
OTHER_CLEAN = $(SQLS)
|
||||||
|
|
||||||
SQLDEFS = $(MODNAME).sql
|
all: $(MODS) $(SQLS)
|
||||||
|
|
||||||
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
|
%.sql: %.sql.in
|
||||||
sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
|
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||||
|
|
||||||
.SUFFIXES: $(DLSUFFIX)
|
install: install_doc install_sql install_mod
|
||||||
|
|
||||||
%$(DLSUFFIX): %.c
|
install_doc:
|
||||||
$(CC) $(CFLAGS) -shared -o $@ $<
|
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:
|
depend dep:
|
||||||
$(CC) -MM $(CFLAGS) *.c >depend
|
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *~ $(MODULE) $(MODNAME).sql
|
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||||
|
|
||||||
ifeq (depend,$(wildcard depend))
|
ifeq (depend,$(wildcard depend))
|
||||||
include depend
|
include depend
|
||||||
|
23
contrib/string/README
Normal file
23
contrib/string/README
Normal file
@ -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>
|
@ -1,21 +1,21 @@
|
|||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
#
|
||||||
# Makefile --
|
# $Header: /cvsroot/pgsql/contrib/tools/Attic/Makefile,v 1.2 2000/06/15 18:55:22 momjian Exp $
|
||||||
#
|
#
|
||||||
# Makefile for contrib tools.
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
PGDIR = ../..
|
TOPDIR=../..
|
||||||
SRCDIR = $(PGDIR)/src
|
|
||||||
|
|
||||||
include $(SRCDIR)/Makefile.global
|
include ../Makefile.global
|
||||||
|
|
||||||
all:
|
NAME =
|
||||||
|
|
||||||
install:
|
PROGRAM =
|
||||||
|
OBJS =
|
||||||
|
DOCS =
|
||||||
|
SQLS =
|
||||||
|
BINS =
|
||||||
|
EXAMPLES=
|
||||||
|
MODS =
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *~
|
$(RM) *~
|
||||||
|
|
||||||
distclean: clean
|
|
||||||
|
@ -1,65 +1,52 @@
|
|||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
#
|
||||||
# Makefile --
|
# $Header: /cvsroot/pgsql/contrib/userlock/Attic/Makefile,v 1.8 2000/06/15 18:55:28 momjian Exp $
|
||||||
#
|
#
|
||||||
# Makefile for the user_locks module.
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
PGDIR = ../..
|
TOPDIR=../..
|
||||||
SRCDIR = $(PGDIR)/src
|
|
||||||
|
|
||||||
include $(SRCDIR)/Makefile.global
|
include ../Makefile.global
|
||||||
|
|
||||||
|
NAME = user_locks
|
||||||
|
|
||||||
|
PROGRAM =
|
||||||
|
OBJS = $(NAME).o
|
||||||
|
DOCS = $(NAME).doc
|
||||||
|
SQLS = $(NAME).sql
|
||||||
|
BINS =
|
||||||
|
EXAMPLES=
|
||||||
|
MODS = $(NAME)$(DLSUFFIX)
|
||||||
|
|
||||||
CFLAGS += -I. $(CFLAGS_SL)
|
CFLAGS += -I. $(CFLAGS_SL)
|
||||||
|
|
||||||
MODNAME = user_locks
|
OTHER_CLEAN = $(SQLS)
|
||||||
|
|
||||||
SQLDEFS = $(MODNAME).sql
|
all: $(MODS) $(SQLS)
|
||||||
|
|
||||||
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
|
%.sql: %.sql.in
|
||||||
sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
|
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
|
||||||
|
|
||||||
.SUFFIXES: $(DLSUFFIX)
|
install: install_doc install_sql install_mod
|
||||||
|
|
||||||
%$(DLSUFFIX): %.c
|
install_doc:
|
||||||
$(CC) $(CFLAGS) -shared -o $@ $<
|
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:
|
depend dep:
|
||||||
$(CC) -MM $(CFLAGS) *.c >depend
|
$(CC) -MM -MG $(CFLAGS) *.c > depend
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *~ $(MODULE) $(MODNAME).sql
|
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
|
||||||
|
|
||||||
ifeq (depend,$(wildcard depend))
|
ifeq (depend,$(wildcard depend))
|
||||||
include depend
|
include depend
|
||||||
|
55
contrib/userlock/README
Normal file
55
contrib/userlock/README
Normal file
@ -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
|
CFLAGS += -I$(LIBPQDIR)
|
||||||
CLEANFILES+= $(TARGETS)
|
|
||||||
CURDIR=`pwd`
|
|
||||||
|
|
||||||
all:: $(TARGETS)
|
OTHER_CLEAN =
|
||||||
|
|
||||||
$(TARGETS): vacuumlo.o
|
all: $(PROGRAM)
|
||||||
$(CC) -o vacuumlo -L $(LIBDIR) -lpq -lcrypt vacuumlo.o
|
|
||||||
|
|
||||||
clean:
|
$(PROGRAM): $(OBJS) $(LIBPGEASYDIR)/libpgeasy.a
|
||||||
rm -f $(TARGETS) *.o
|
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPGEASY)
|
||||||
|
|
||||||
dist:
|
install: install_doc install_bin
|
||||||
tar cf vacuumlo.tar README Makefile vacuumlo.c
|
|
||||||
|
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
|
||||||
|
@ -8,13 +8,13 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/contrib/vacuumlo/vacuumlo.c,v 1.3 2000/01/26 05:55:52 momjian Exp $
|
* $Header: /cvsroot/pgsql/contrib/vacuumlo/vacuumlo.c,v 1.4 2000/06/15 18:55:31 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.77 2000/06/11 11:39:47 petere Exp $
|
# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.78 2000/06/15 18:55:34 momjian Exp $
|
||||||
#
|
#
|
||||||
# NOTES
|
# NOTES
|
||||||
# Essentially all Postgres make files include this file and use the
|
# Essentially all Postgres make files include this file and use the
|
||||||
@ -54,10 +54,12 @@ BSD_SHLIB= true
|
|||||||
ELF_SYSTEM= @ELF_SYS@
|
ELF_SYSTEM= @ELF_SYS@
|
||||||
|
|
||||||
LIBPQDIR= $(SRCDIR)/interfaces/libpq
|
LIBPQDIR= $(SRCDIR)/interfaces/libpq
|
||||||
|
LIBPGEASYDIR= $(SRCDIR)/interfaces/libpgeasy
|
||||||
LIBPGTCLDIR= $(SRCDIR)/interfaces/libpgtcl
|
LIBPGTCLDIR= $(SRCDIR)/interfaces/libpgtcl
|
||||||
|
|
||||||
LIBPQ= -L$(LIBPQDIR) -lpq
|
LIBPQ= -L$(LIBPQDIR) -lpq
|
||||||
LIBPGTCL= -L$(LIBPGTCLDIR) -lpgtcl
|
LIBPGTCL= -L$(LIBPGTCLDIR) -lpgtcl
|
||||||
|
LIBPGEASY= -L$(LIBPGEASYDIR) -lpgeasy
|
||||||
|
|
||||||
# For convenience, POSTGRESDIR is where BINDIR, and LIBDIR
|
# For convenience, POSTGRESDIR is where BINDIR, and LIBDIR
|
||||||
# and other target destinations are rooted. Of course, each of these is
|
# and other target destinations are rooted. Of course, each of these is
|
||||||
|
Reference in New Issue
Block a user