Commit f7f177d3 authored by Bruce Momjian's avatar Bruce Momjian

/contrib patch from Karel.

parent 82c47331
# Makefile for contrib code
#
# The following subdirs don't have a Makefile:
# The PostgreSQL contrib tree Makefile
#
# apache_logging
# linux
# mSQL-interface
# noupdate
# unixdate
# Portions Copyright (c) 1999-2000, PostgreSQL, Inc
#
# 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:
for dir in *; do \
for dir in $(WANTED_DIRS); do \
if [ -e $$dir/Makefile ]; then \
$(MAKE) -C $$dir $@ ; \
fi; \
done
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 *; do \
for dir in $(WANTED_DIRS); do \
if [ -e $$dir/Makefile ]; then \
$(MAKE) -C $$dir $@ ; \
fi; \
......
This directory contains the contribution functions or tools.
---------------------------------------------------------------------------
The PostgreSQL contrib tree
~~~~~~~~~~~~~~~~~~~~~~~~~~~
apache_logging -
Getting Apache to log to PostgreSQL
by Terry Mackintosh <terry@terrym.com>
FIXME:
os2client
odbc
spi/preprocessor
tools
array -
Array iterator functions
by Massimo Dal Zotto <dz@cs.unitn.it>
- in each directory must be Makefile, possible Makefile template
is below this text,
bit -
Bit type
by Adriaan Joubert <a.joubert@albourne.com>
--------
#
# $Header: /cvsroot/pgsql/contrib/README,v 1.18 2000/06/15 18:54:29 momjian Exp $
#
datetime -
Date & time functions
by Massimo Dal Zotto <dz@cs.unitn.it>
TOPDIR=../..
earthdistance -
Operator for computing earth distance for two points
by Hal Snyder <hal@vailsys.com>
include ../Makefile.global
findoidjoins -
Finds the joins used by oid columns by examining the actual
values in the oid columns and row oids.
by Bruce Momjian <root@candle.pha.pa.us>
NAME = some_name
fulltextindex -
Full text indexing using triggers
by Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl>
PROGRAM =
OBJS = $(NAME).o
DOCS = $(NAME).doc
SQLS = $(NAME).sql
BINS =
EXAMPLES=
MODS = $(NAME)$(DLSUFFIX)
isbn_issn -
PostgreSQL type extensions for ISBN (books) and ISSN (serials)
by Garrett A. Wollman <wollman@khavrinen.lcs.mit.edu>
CFLAGS += -I. $(CFLAGS_SL)
likeplanning -
Scripts to enable/disable new planning code for LIKE and regexp
pattern match operators. These will go away again once the code
is mature enough to enable by default.
by Tom Lane <tgl@sss.pgh.pa.us>
OTHER_CLEAN = $(SQLS)
linux -
Start postgres back end system
by Thomas Lockhart <lockhart@alumni.caltech.edu>
all: $(MODS) $(SQLS)
lo -
Large Object maintenance
by Peter Mount <peter@retep.org.uk>
%.sql: %.sql.in
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
miscutil -
Postgres assert checking and various utility functions
by Dal Zotto <dz@cs.unitn.it>
mSQL-interface -
mSQL API translation library
by Aldrin Leal <aldrin@americasnet.com>
install: install_doc install_sql install_mod install_bin install_example
noupdate -
trigger to prevent updates on single columns
install_doc:
for inst_file in $(DOCS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
done
pg_dumplo -
Dump large objects
install_sql:
for inst_file in $(SQLS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
done
soundex -
Prototype for soundex function
install_mod:
for inst_file in $(MODS); do \
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
done
spi -
A general trigger function autoinc() and so on.
install_bin:
for inst_file in $(BINS); do \
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
done
string -
C-like input/output conversion routines for strings
by Massimo Dal Zotto <dz@cs.unitn.it>
install_example:
for inst_file in $(EXAMPLES); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_EXAMPLESDIR); \
done
tools -
Assorted developer tools
by Massimo Dal Zotto <dz@cs.unitn.it>
depend dep:
$(CC) -MM -MG $(CFLAGS) *.c > depend
unixdate -
Conversions from integer to datetime
by Thomas Lockhart <lockhart@alumni.caltech.edu>
clean:
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
userlock -
User locks
by Massimo Dal Zotto <dz@cs.unitn.it>
vacuumlo -
Remove orphaned large objects
by Peter T Mount <peter@retep.org.uk>
pgbench -
TPC-B like benchmarking tool
by Tatsuo Ishii <t-ishii@sra.co.jp>
ifeq (depend,$(wildcard depend))
include depend
endif
-----------
\ No newline at end of file
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;
# 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'
#-------------------------------------------------------------------------
#
# 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 = ../..
SRCDIR = $(PGDIR)/src
include $(SRCDIR)/Makefile.global
CFLAGS += -I. $(CFLAGS_SL)
MODNAME = array_iterator
TOPDIR=../..
SQLDEFS = $(MODNAME).sql
include ../Makefile.global
MODULE = $(MODNAME)$(DLSUFFIX)
NAME = array_iterator
MODDIR = $(LIBDIR)/modules
PROGRAM =
OBJS = $(NAME).o
DOCS = $(NAME).doc
SQLS = $(NAME).sql
BINS =
EXAMPLES=
MODS = $(NAME)$(DLSUFFIX)
SQLDIR = $(LIBDIR)/sql
all: module sql
module: $(MODULE)
CFLAGS += -I. $(CFLAGS_SL)
sql: $(SQLDEFS)
OTHER_CLEAN = $(SQLS)
install: $(MODULE) $(SQLDEFS) $(MODDIR) $(SQLDIR)
cp -p $(MODULE) $(MODDIR)/
strip $(MODDIR)/$(MODULE)
cp -p $(SQLDEFS) $(SQLDIR)/
all: $(MODS) $(SQLS)
install-doc:
if [ -d "$(DOCDIR)" ]; then \
cp -p *.doc $(DOCDIR); \
else \
cp -p *.doc $(SQLDIR); \
fi
%.sql: %.sql.in
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
$(MODDIR):
mkdir -p $@
install: install_doc install_sql install_mod
$(SQLDIR):
mkdir -p $@
install_doc:
for inst_file in $(DOCS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
done
%.sql: %.sql.in
sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
install_sql:
for inst_file in $(SQLS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
done
.SUFFIXES: $(DLSUFFIX)
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:
$(CC) -MM $(CFLAGS) *.c >depend
$(CC) -MM -MG $(CFLAGS) *.c > depend
clean:
rm -f *~ $(MODULE) $(MODNAME).sql
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
ifeq (depend,$(wildcard depend))
include depend
......
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.
# 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
This diff is collapsed.
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;
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;
#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);
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
);
/* 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);
}
#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)));
}
}
#-------------------------------------------------------------------------
#
# 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
/*
* 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(&current_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:
*/
#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:
*/
-- 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
# PGLIB is probably /usr/local/pgsql/lib
#
# $Header: /cvsroot/pgsql/contrib/earthdistance/Makefile,v 1.2 2000/06/15 18:54:46 momjian Exp $
#
PGINCLUDE=${PGLIB}/../include
CFLAGS+=-I${PGINCLUDE}
TOPDIR=../..
install-earthdistance: ${PGLIB}/earthdistance.so
include ../Makefile.global
${PGLIB}/earthdistance.so: earthdistance.so
sudo install -C -g bin -o bin earthdistance.so ${PGLIB}
NAME = earthdistance
earthdistance.so: earthdistance.o
$(LD) -o $@ -Bshareable $<
PROGRAM =
OBJS = $(NAME).o
DOCS = $(NAME).doc
SQLS = $(NAME).sql
BINS =
EXAMPLES=
MODS = $(NAME)$(DLSUFFIX)
earthdistance.o: earthdistance.c
$(CC) -o $@ -c $(CFLAGS) $<
CFLAGS += -I. $(CFLAGS_SL)
OTHER_CLEAN = $(SQLS)
all: $(MODS) $(SQLS)
%.sql: %.sql.in
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
install: install_doc install_sql install_mod
install_doc:
for inst_file in $(DOCS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
done
install_sql:
for inst_file in $(SQLS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
done
install_mod:
for inst_file in $(MODS); do \
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
done
depend dep:
$(CC) -MM -MG $(CFLAGS) *.c > depend
clean:
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
ifeq (depend,$(wildcard depend))
include depend
endif
......@@ -7,8 +7,11 @@
#include <utils/palloc.h> /* for palloc */
/* Earth's radius is in statute miles. */
const EARTH_RADIUS = 3958.747716;
const TWO_PI = 2.0 * M_PI;
const int EARTH_RADIUS = 3958.747716;
const int TWO_PI = 2.0 * M_PI;
double *geo_distance(Point *pt1, Point *pt2);
/******************************************************
*
......
--------------- 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;
#
# Makefile, requires src/interfaces/libpgeasy
# $Header: /cvsroot/pgsql/contrib/findoidjoins/Attic/Makefile,v 1.5 2000/06/15 18:54:49 momjian Exp $
#
#
INSTALLDIR = /usr/local/pgsql
TARGET = findoidjoins
PGEASY = ../../src/interfaces/libpgeasy
CFLAGS = -g -Wall -I. -I$(PGEASY) -I$(INSTALLDIR)/include
LIBPGEASY = $(PGEASY)/libpgeasy.a
LDFLAGS = -L$(INSTALLDIR)/lib -lpq
TOPDIR=../..
all : $(TARGET)
include ../Makefile.global
findoidjoins: findoidjoins.c $(LIBPGEASY)
gcc -o $@ $(CFLAGS) $^ $(LDFLAGS)
NAME = findoidjoins
clean:
rm -f *.o $(TARGET) log core
PROGRAM = $(NAME)
OBJS = $(NAME).o
DOCS = $(NAME).doc
SQLS =
BINS = $(PROGRAM) make_oidjoins_check
EXAMPLES=
MODS =
CFLAGS += -I$(LIBPGEASYDIR) -I$(LIBPQDIR)
OTHER_CLEAN =
all: $(PROGRAM)
$(PROGRAM): $(OBJS) $(LIBPGEASYDIR)/libpgeasy.a
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPGEASY)
install:
install -s -o bin -g bin $(TARGET) $(INSTALLDIR)/bin
install: install_doc nstall_bin
install_doc:
for inst_file in $(DOCS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
done
install_bin:
for inst_file in $(BINS); do \
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
done
depend dep:
$(CC) -MM -MG $(CFLAGS) *.c > depend
clean:
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
ifeq (depend,$(wildcard depend))
include depend
endif
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%
SRCDIR= ../../src
#
# $Header: /cvsroot/pgsql/contrib/fulltextindex/Attic/Makefile,v 1.3 2000/06/15 18:54:51 momjian Exp $
#
include $(SRCDIR)/Makefile.global
TOPDIR=../..
CONTRIBDIR=$(LIBDIR)/contrib
include ../Makefile.global
CFLAGS+= $(CFLAGS_SL)
NAME = fti
TARGETS= fti$(DLSUFFIX)
CLEANFILES+= $(TARGETS)
CURDIR=`pwd`
PROGRAM =
OBJS = $(NAME).o
DOCS = $(NAME).doc
SQLS = $(NAME).sql
BINS = fti.pl
EXAMPLES=
MODS = $(NAME)$(DLSUFFIX)
all:: $(TARGETS)
CFLAGS += -I. $(CFLAGS_SL)
%.sql: %.source
rm -f $@; \
sed -e "s:_CURRENTDIR_:$(CURDIR):g" \
-e "s:_DLSUFFIX_:$(DLSUFFIX):g" < $< > $@
OTHER_CLEAN = $(SQLS)
clean:
rm -f $(TARGETS) *.o
all: $(MODS) $(SQLS)
dist:
tar cf fti.tar README BENCH Makefile fti.c timings.sh
%.sql: %.sql.in
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
install: install_doc install_sql install_mod install_bin
install_doc:
for inst_file in $(DOCS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
done
install_sql:
for inst_file in $(SQLS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
done
install_mod:
for inst_file in $(MODS); do \
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
done
install_bin:
for inst_file in $(BINS); do \
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
done
depend dep:
$(CC) -MM -MG $(CFLAGS) *.c > depend
clean:
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
ifeq (depend,$(wildcard depend))
include depend
endif
......@@ -94,4 +94,104 @@ Method 1 is very slow, 2 a lot faster, and for very large tables, 3 is
preferred.
BENCH:
~~~~~
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%
#!/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();
#
# PostgreSQL types for ISBN and ISSN identifiers.
# $Header: /cvsroot/pgsql/contrib/isbn_issn/Attic/Makefile,v 1.3 2000/06/15 18:54:53 momjian Exp $
#
# $Id: Makefile,v 1.2 2000/05/29 05:44:26 tgl Exp $
SRCDIR= ../../src
TOPDIR=../..
include $(SRCDIR)/Makefile.global
include ../Makefile.global
CFLAGS+= $(CFLAGS_SL)
NAME = isbn_issn
all: isbn$(DLSUFFIX) issn$(DLSUFFIX)
PROGRAM =
OBJS = $(NAME).o
DOCS = $(NAME).doc
SQLS = $(NAME).sql
BINS =
EXAMPLES=
MODS = $(NAME)$(DLSUFFIX)
install: isbn$(DLSUFFIX) issn$(DLSUFFIX)
install -c isbn$(DLSUFFIX) issn$(DLSUFFIX) /usr/local/pgsql/modules
CFLAGS += -I. $(CFLAGS_SL)
OTHER_CLEAN = $(SQLS)
all: $(MODS) $(SQLS)
%.sql: %.sql.in
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
install: install_doc install_sql install_mod
install_doc:
for inst_file in $(DOCS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
done
install_sql:
for inst_file in $(SQLS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
done
install_mod:
for inst_file in $(MODS); do \
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
done
depend dep:
$(CC) -MM -MG $(CFLAGS) *.c > depend
clean:
rm -f isbn$(DLSUFFIX) issn$(DLSUFFIX) *.o
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
ifeq (depend,$(wildcard depend))
include depend
endif
ISBN (books) and ISSN (serials)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This directory contains definitions for a couple of PostgreSQL
external types, for a couple of international-standard namespaces:
ISBN (books) and ISSN (serials). Rather than just using a char()
......
/*
* 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
*/
--
-- 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
--
/*
* 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
*/
--
-- 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
--
#
# 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 ../Makefile.global
include $(SRCDIR)/Makefile.global
NAME = lo
CONTRIBDIR=$(LIBDIR)/modules
PROGRAM =
OBJS = $(NAME).o
DOCS = $(NAME).doc
SQLS = $(NAME).sql
BINS =
EXAMPLES=
MODS = $(NAME)$(DLSUFFIX)
CFLAGS+= $(CFLAGS_SL)
CFLAGS += -I. $(CFLAGS_SL)
ifdef REFINT_VERBOSE
CFLAGS+= -DREFINT_VERBOSE
endif
TARGETS= lo$(DLSUFFIX) lo.sql
OTHER_CLEAN = $(SQLS)
all: $(MODS) $(SQLS)
CLEANFILES+= $(TARGETS)
all:: $(TARGETS)
%.sql: %.sql.in
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
install:: all $(CONTRIBDIR)
for f in *$(DLSUFFIX); do $(INSTALL) -c $$f $(CONTRIBDIR)/$$f; done
$(CONTRIBDIR):
mkdir -p $(CONTRIBDIR)
install: install_doc install_sql install_mod
%.sql: %.sql.in
rm -f $@; \
C=`pwd`; \
sed -e "s:_OBJWD_:$(CONTRIBDIR):g" \
-e "s:_DLSUFFIX_:$(DLSUFFIX):g" < $< > $@
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
PostgreSQL type extension for managing Large Objects
----------------------------------------------------
$Id: README,v 1.1 1998/06/16 07:07:11 momjian Exp $
Overview
One of the problems with the JDBC driver (and this affects the ODBC driver
......
--
-- 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
--
-- 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
--
......@@ -13,13 +10,13 @@ load '_OBJWD_/lo_DLSUFFIX_';
-- used by the lo type, it takes an oid and returns an lo object
create function lo_in(opaque)
returns opaque
as '_OBJWD_/lo_DLSUFFIX_'
as 'MODULE_PATHNAME'
language 'c';
-- used by the lo type, it returns the oid of the object
create function lo_out(opaque)
returns opaque
as '_OBJWD_/lo_DLSUFFIX_'
as 'MODULE_PATHNAME'
language 'c';
-- finally the type itself
......@@ -33,20 +30,20 @@ create type lo (
-- this returns the oid associated with a lo object
create function lo_oid(lo)
returns oid
as '_OBJWD_/lo_DLSUFFIX_'
as 'MODULE_PATHNAME'
language 'c';
-- this allows us to convert an oid to a managed lo object
-- ie: insert into test values (lo_import('/fullpath/file')::lo);
create function lo(oid)
returns lo
as '_OBJWD_/lo_DLSUFFIX_'
as 'MODULE_PATHNAME'
language 'c';
-- This is used in triggers
create function lo_manage()
returns opaque
as '_OBJWD_/lo_DLSUFFIX_'
as 'MODULE_PATHNAME'
language 'newC';
-- This allows us to map lo to oid
......
--
-- 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
Hello! :)
(Sorry for my english. But if i wrote in portuguese, you wouldn't
......
#-------------------------------------------------------------------------
#
# 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 = ../..
SRCDIR = $(PGDIR)/src
include $(SRCDIR)/Makefile.global
CFLAGS += -I. $(CFLAGS_SL)
MODNAME = misc_utils
SQLDEFS = $(MODNAME).sql
TOPDIR=../..
MODULE = $(MODNAME)$(DLSUFFIX)
include ../Makefile.global
MODDIR = $(LIBDIR)/modules
NAME = misc_utils
SQLDIR = $(LIBDIR)/sql
PROGRAM =
OBJS = $(NAME).o
DOCS = $(NAME).doc
SQLS = $(NAME).sql
BINS =
EXAMPLES=
MODS = $(NAME)$(DLSUFFIX)
all: module sql
module: $(MODULE)
sql: $(SQLDEFS)
CFLAGS += -I. $(CFLAGS_SL)
install: $(MODULE) $(SQLDEFS) $(MODDIR) $(SQLDIR)
cp -p $(MODULE) $(MODDIR)/
strip $(MODDIR)/$(MODULE)
cp -p $(SQLDEFS) $(SQLDIR)/
OTHER_CLEAN = $(SQLS)
install-doc:
if [ -d "$(DOCDIR)" ]; then \
cp -p *.doc $(DOCDIR); \
else \
cp -p *.doc $(SQLDIR); \
fi
all: $(MODS) $(SQLS)
$(MODDIR):
mkdir -p $@
%.sql: %.sql.in
$(SED) "s|MODULE_PATHNAME|$(CONTRIB_MODDIR)/$@|" < $< > $@
$(SQLDIR):
mkdir -p $@
install: install_doc install_sql install_mod
%.sql: %.sql.in
sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
install_doc:
for inst_file in $(DOCS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
done
.SUFFIXES: $(DLSUFFIX)
install_sql:
for inst_file in $(SQLS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_SQLDIR); \
done
%$(DLSUFFIX): %.c
$(CC) $(CFLAGS) -shared -o $@ $<
install_mod:
for inst_file in $(MODS); do \
$(INSTALL) $(INSTL_SHLIB_OPTS) $$inst_file $(CONTRIB_MODDIR); \
done
depend dep:
$(CC) -MM $(CFLAGS) *.c >depend
$(CC) -MM -MG $(CFLAGS) *.c > depend
clean:
rm -f *~ $(MODULE) $(MODNAME).sql
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
ifeq (depend,$(wildcard depend))
include depend
......
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>
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;
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;
DROP FUNCTION noup ();
CREATE FUNCTION noup ()
RETURNS opaque
AS '_OBJWD_/noup_DLSUFFIX_'
LANGUAGE 'newC'
;
-- 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';
#-------------------------------------------------------------------------
#
# 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
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>
#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)
#
# $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/Makefile,v 1.2 2000/06/15 18:55:10 momjian Exp $
#
PROGRAM = pg_dumplo
OBJECTS = pg_dumplo.o
TOPDIR=../..
CFLAGS = -Wall -fpic -g
CC = gcc
RM = rm -f
INCLUDE = -I/usr/include/postgresql
LIBS =-lpq
include ../Makefile.global
COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDE)
LINK = $(CC) $(CFLAGS) -o $@ $(LIBS)
NAME = pg_dumplo
PROGRAM = $(NAME)
OBJS = main.o lo_export.o lo_import.o utils.o
DOCS = $(NAME).doc
SQLS =
BINS = $(PROGRAM)
EXAMPLES=
MODS =
all: $(PROGRAM)
CFLAGS += -I$(LIBPQDIR)
$(PROGRAM): $(OBJECTS)
$(LINK) $(OBJECTS)
OTHER_CLEAN =
.c.o: $<
$(COMPILE) -c $<
all: $(PROGRAM)
$(PROGRAM): $(OBJS) $(LIBPQDIR)/libpq.a
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPQ)
install: install_doc install_bin
install_doc:
for inst_file in $(DOCS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
done
install_bin:
for inst_file in $(BINS); do \
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
done
depend dep:
$(CC) -MM -MG $(CFLAGS) *.c > depend
clean:
$(RM) -f *~ $(OBJECTS) $(PROGRAM)
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
ifeq (depend,$(wildcard depend))
include depend
endif
\ No newline at end of file
pg_dumplo - PostgreSQL large object dumper
How to use pg_dumplo?
=====================
Hmm... documentation is not available. For more information
see the help ( pg_dumplo -h ) and examples in this help.
(c) 2000, Pavel Janík ml. <Pavel.Janik@linux.cz>
Compilation:
- you need the PostgreSQL's devel. libs
- and type: 'make'
Karel Zak <zakkr@zf.jcu.cz>
Q: How do you use pg_dumplo?
============================
A: This is a small demo of backing up the database table with Large Objects:
We will create a demo database and a small and useless table `lo' inside
it:
SnowWhite:$ createdb test
CREATE DATABASE
Ok, our database with the name 'test' is created. Now we should create demo
table which will contain only one column with the name 'id' which will hold
the oid number of Large Object:
SnowWhite:$ psql test
Welcome to psql, the PostgreSQL interactive terminal.
Type: \copyright for distribution terms
\h for help with SQL commands
\? for help on internal slash commands
\g or terminate with semicolon to execute query
\q to quit
test=# CREATE TABLE lo (id oid);
CREATE
test=# \lo_import /etc/aliases
lo_import 19338
test=# INSERT INTO lo VALUES (19338);
INSERT 19352 1
test=# select * from lo;
id
-------
19338
(1 row)
test=# \q
In the above example you can see that we have also imported one "Large
Object" - the file /etc/aliases. It has an oid of 19338 so we have inserted
this oid number to the database table lo to the column id. The final SELECT
shows that we have one record in the table.
Now we can demonstrate the work of pg_dumplo. We will create dump directory
which will contain the whole dump of large objects (/tmp/dump):
mkdir -p /tmp/dump
Now we can dump all large objects from the database `test' which has an oid
stored in the column `id' in the table `lo':
SnowWhite:$ pg_dumplo -s /tmp/dump -d test -l lo.id
pg_dumplo: dump lo.id (1 large obj)
Voila, we have the dump of all Large Objects in our directory:
SnowWhite:$ tree /tmp/dump/
/tmp/dump/
`-- test
|-- lo
| `-- id
| `-- 19338
`-- lo_dump.index
3 directories, 2 files
SnowWhite:$
Isn't it nice :-) Yes, it is, but we are on the half of our way. We should
also be able to recreate the contents of the table lo and the Large Object
database when something went wrong. It is very easy, we will demonstrate
this via dropping the database and recreating it from scratch with
pg_dumplo:
SnowwWite:$ dropdb test
DROP DATABASE
SnowWhite:$ createdb test
CREATE DATABASE
Ok, our database with the name `test' is created again. We should also
create the table `lo' again:
SnowWhite:$ psql test
Welcome to psql, the PostgreSQL interactive terminal.
Type: \copyright for distribution terms
\h for help with SQL commands
\? for help on internal slash commands
\g or terminate with semicolon to execute query
\q to quit
test=# CREATE TABLE lo (id oid);
CREATE
test=# \q
SnowWhite:$
Now the database with the table `lo' is created again, but we do not have
any information stored in it. But have the dump of complete Large Object
database, so we can recreate the contents of the whole database from the
directory /tmp/dump:
SnowWhite:$ pg_dumplo -s /tmp/dump -d test -i
19338 lo id test/lo/id/19338
SnowWhite:$
And this is everything.
Summary: In this small example we have shown that pg_dumplo can be used to
completely dump the database's Large Objects very easily.
0.0.4
\ No newline at end of file
#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);
}
\ No newline at end of file
# $Header: /cvsroot/pgsql/contrib/pgbench/Makefile,v 1.1 2000/01/15 12:38:09 ishii Exp $
#
# $Header: /cvsroot/pgsql/contrib/pgbench/Makefile,v 1.2 2000/06/15 18:55:12 momjian Exp $
#
SRCDIR= ../../src
TOPDIR=../..
include $(SRCDIR)/Makefile.global
include ../Makefile.global
CFLAGS:= -I$(LIBPQDIR) $(CFLAGS)
NAME = pgbench
TARGET = pgbench
OBJS = pgbench.o
PROGRAM = $(NAME)
OBJS = $(NAME).o
DOCS = $(NAME).doc $(NAME)_jis.doc
SQLS =
BINS = $(PROGRAM)
EXAMPLES=
MODS =
all:: $(TARGET)
CFLAGS += -I$(LIBPQDIR)
$(TARGET): $(OBJS)
$(CC) -o $(TARGET) $(OBJS) -L$(LIBPQDIR) -lpq $(LDFLAGS)
OTHER_CLEAN =
install: $(TARGET)
$(INSTALL) $(INSTL_EXE_OPTS) $(TARGET)$(X) $(BINDIR)/$(TARGET)$(X)
all: $(PROGRAM)
$(PROGRAM): $(OBJS) $(LIBPQDIR)/libpq.a
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPQ)
install: install_doc install_bin
install_doc:
for inst_file in $(DOCS); do \
$(INSTALL) $(INSTL_LIB_OPTS) $$inst_file $(CONTRIB_DOCDIR); \
done
install_bin:
for inst_file in $(BINS); do \
$(INSTALL) $(INSTL_EXE_OPTS) $$inst_file $(CONTRIB_BINDIR); \
done
depend dep:
$(CC) -MM -MG $(CFLAGS) *.c > depend
clean:
$(RM) $(TARGET)$(X) $(OBJS)
$(RM) *~ $(OBJS) $(MODS) $(PROGRAM) depend $(OTHER_CLEAN) core log
distclean: clean
ifeq (depend,$(wildcard depend))
include depend
endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
DROP FUNCTION autoinc();
CREATE FUNCTION autoinc()
RETURNS opaque
AS '_OBJWD_/autoinc_DLSUFFIX_'
LANGUAGE 'newC';
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment