aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/array/Makefile62
-rw-r--r--contrib/array/array_iterator.c407
-rw-r--r--contrib/array/array_iterator.doc56
-rw-r--r--contrib/array/array_iterator.h27
-rw-r--r--contrib/array/array_iterator.sql.in191
-rw-r--r--contrib/datetime/Makefile68
-rw-r--r--contrib/datetime/datetime_functions.c207
-rw-r--r--contrib/datetime/datetime_functions.h19
-rw-r--r--contrib/datetime/datetime_functions.sql.in96
-rw-r--r--contrib/miscutil/Makefile62
-rw-r--r--contrib/miscutil/assert_test.c43
-rw-r--r--contrib/miscutil/assert_test.h7
-rw-r--r--contrib/miscutil/misc_utils.c50
-rw-r--r--contrib/miscutil/misc_utils.h10
-rw-r--r--contrib/miscutil/misc_utils.sql.in40
-rw-r--r--contrib/pginterface/README.orig42
-rw-r--r--contrib/pginterface/pginsert.c.orig102
-rw-r--r--contrib/pginterface/pginterface.c.orig232
-rw-r--r--contrib/pginterface/pgnulltest.c.orig143
-rw-r--r--contrib/pginterface/pgwordcount.c.orig72
-rw-r--r--contrib/sequence/Makefile62
-rw-r--r--contrib/sequence/set_sequence.c41
-rw-r--r--contrib/sequence/set_sequence.h9
-rw-r--r--contrib/sequence/set_sequence.sql.in33
-rw-r--r--contrib/string/Makefile62
-rw-r--r--contrib/string/string_io.c524
-rw-r--r--contrib/string/string_io.h19
-rw-r--r--contrib/string/string_io.sql.in104
-rw-r--r--contrib/userlock/Makefile62
-rw-r--r--contrib/userlock/user_locks.c100
-rw-r--r--contrib/userlock/user_locks.doc30
-rw-r--r--contrib/userlock/user_locks.h12
-rw-r--r--contrib/userlock/user_locks.sql.in69
33 files changed, 2516 insertions, 547 deletions
diff --git a/contrib/array/Makefile b/contrib/array/Makefile
new file mode 100644
index 00000000000..03c57e57c68
--- /dev/null
+++ b/contrib/array/Makefile
@@ -0,0 +1,62 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for array iterator functions.
+#
+#-------------------------------------------------------------------------
+
+PGDIR = ../..
+SRCDIR = $(PGDIR)/src
+
+include $(SRCDIR)/Makefile.global
+
+INCLUDE_OPT = -I ./ \
+ -I $(SRCDIR)/ \
+ -I $(SRCDIR)/include \
+ -I $(SRCDIR)/port/$(PORTNAME)
+
+CFLAGS += $(INCLUDE_OPT)
+
+ifeq ($(PORTNAME), linux)
+ ifdef LINUX_ELF
+ ifeq ($(CC), gcc)
+ CFLAGS += -fPIC
+ endif
+ endif
+endif
+
+ifeq ($(PORTNAME), i386_solaris)
+ CFLAGS+= -fPIC
+endif
+
+MODNAME = array_iterator
+
+MODULE = $(MODNAME)$(DLSUFFIX)
+
+all: module sql
+
+module: $(MODULE)
+
+sql: $(MODNAME).sql
+
+install: $(MODULE)
+ cp -p $(MODULE) $(LIBDIR)
+ cd $(LIBDIR); strip $(MODULE)
+
+%.sql: %.sql.in
+ sed "s|MODULE_PATHNAME|$(LIBDIR)/$(MODULE)|" < $< > $@
+
+.SUFFIXES: $(DLSUFFIX)
+
+%$(DLSUFFIX): %.c
+ cc $(CFLAGS) -shared -o $@ $<
+
+depend dep:
+ $(CC) -MM $(INCLUDE_OPT) *.c >depend
+
+clean:
+ rm -f $(MODULE) $(MODNAME).sql
+
+ifeq (depend,$(wildcard depend))
+include depend
+endif
diff --git a/contrib/array/array_iterator.c b/contrib/array/array_iterator.c
index f4ecfad903f..de8dac95de0 100644
--- a/contrib/array/array_iterator.c
+++ b/contrib/array/array_iterator.c
@@ -1,30 +1,12 @@
/*
* array_iterator.c --
*
- * This file defines a new group of operators which take an
+ * This file defines a new class of operators which take an
* array and a scalar value, iterate a scalar operator over the
* elements of the array and the value and compute a result as
- * the logical OR or AND of the results.
- * For example array_int4eq returns true if some of the elements
- * of an array of int4 is equal to the given value:
+ * the logical OR or AND of the iteration results.
*
- * array_int4eq({1,2,3}, 1) --> true
- * array_int4eq({1,2,3}, 4) --> false
- *
- * If we have defined T array types and O scalar operators
- * we can define T x O array operators, each of them has a name
- * like "array_<basetype><operation>" and takes an array of type T
- * iterating the operator O over all the elements. Note however
- * that some of the possible combination are invalid, for example
- * the array_int4_like because there is no like operator for int4.
- * It is now possible to write queries which look inside the arrays:
- *
- * create table t(id int4[], txt text[]);
- * select * from t where t.id *= 123;
- * select * from t where t.txt *~ '[a-z]';
- * select * from t where t.txt[1:3] **~ '[a-z]';
- *
- * Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
+ * Copyright (c) 1997, Massimo Dal Zotto <dz@cs.unitn.it>
*/
#include <ctype.h>
@@ -33,242 +15,297 @@
#include <string.h>
#include "postgres.h"
-#include "pg_type.h"
#include "miscadmin.h"
-#include "syscache.h"
#include "access/xact.h"
+#include "backend/fmgr.h"
+#include "catalog/pg_type.h"
+#include "utils/array.h"
#include "utils/builtins.h"
-#include "utils/elog.h"
+#include "utils/memutils.h"
+#include "utils/syscache.h"
+
+#include "array_iterator.h"
static int32
array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
{
- HeapTuple typ_tuple;
- TypeTupleForm typ_struct;
- bool typbyval;
- int typlen;
- func_ptr proc_fn;
- int pronargs;
- int nitems,
- i,
- result;
- int ndim,
- *dim;
- char *p;
-
- /* Sanity checks */
- if ((array == (ArrayType *) NULL)
- || (ARR_IS_LO(array) == true))
- {
- /* elog(NOTICE, "array_iterator: array is null"); */
- return (0);
- }
- ndim = ARR_NDIM(array);
- dim = ARR_DIMS(array);
- nitems = getNitems(ndim, dim);
- if (nitems == 0)
- {
- /* elog(NOTICE, "array_iterator: nitems = 0"); */
- return (0);
- }
+ HeapTuple typ_tuple;
+ TypeTupleForm typ_struct;
+ bool typbyval;
+ int typlen;
+ func_ptr proc_fn;
+ int pronargs;
+ int nitems, i, result;
+ int ndim, *dim;
+ char *p;
- /* Lookup element type information */
- typ_tuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(elemtype), 0, 0, 0);
- if (!HeapTupleIsValid(typ_tuple))
- {
- elog(WARN, "array_iterator: cache lookup failed for type %d", elemtype);
- return 0;
- }
- typ_struct = (TypeTupleForm) GETSTRUCT(typ_tuple);
- typlen = typ_struct->typlen;
- typbyval = typ_struct->typbyval;
-
- /* Lookup the function entry point */
- proc_fn == (func_ptr) NULL;
- fmgr_info(proc, &proc_fn, &pronargs);
- if ((proc_fn == NULL) || (pronargs != 2))
- {
- elog(WARN, "array_iterator: fmgr_info lookup failed for oid %d", proc);
- return (0);
- }
+ /* Sanity checks */
+ if ((array == (ArrayType *) NULL)
+ || (ARR_IS_LO(array) == true)) {
+ /* elog(NOTICE, "array_iterator: array is null"); */
+ return (0);
+ }
+ ndim = ARR_NDIM(array);
+ dim = ARR_DIMS(array);
+ nitems = getNitems(ndim, dim);
+ if (nitems == 0) {
+ /* elog(NOTICE, "array_iterator: nitems = 0"); */
+ return (0);
+ }
- /* Scan the array and apply the operator to each element */
- result = 0;
- p = ARR_DATA_PTR(array);
- for (i = 0; i < nitems; i++)
- {
- if (typbyval)
- {
- switch (typlen)
- {
- case 1:
- result = (int) (*proc_fn) (*p, value);
- break;
- case 2:
- result = (int) (*proc_fn) (*(int16 *) p, value);
- break;
- case 3:
- case 4:
- result = (int) (*proc_fn) (*(int32 *) p, value);
- break;
- }
- p += typlen;
- }
- else
- {
- result = (int) (*proc_fn) (p, value);
- if (typlen > 0)
- {
- p += typlen;
- }
- else
- {
- p += INTALIGN(*(int32 *) p);
- }
- }
- if (result)
- {
- if (!and)
- {
- return (1);
- }
- }
- else
- {
- if (and)
- {
- return (0);
- }
- }
- }
+ /* Lookup element type information */
+ typ_tuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(elemtype),0,0,0);
+ if (!HeapTupleIsValid(typ_tuple)) {
+ elog(WARN,"array_iterator: cache lookup failed for type %d", elemtype);
+ return 0;
+ }
+ typ_struct = (TypeTupleForm) GETSTRUCT(typ_tuple);
+ typlen = typ_struct->typlen;
+ typbyval = typ_struct->typbyval;
- if (and && result)
- {
+ /* Lookup the function entry point */
+ proc_fn = (func_ptr) NULL;
+ fmgr_info(proc, &proc_fn, &pronargs);
+ if ((proc_fn == NULL) || (pronargs != 2)) {
+ elog(WARN, "array_iterator: fmgr_info lookup failed for oid %d", proc);
+ return (0);
+ }
+
+ /* Scan the array and apply the operator to each element */
+ result = 0;
+ p = ARR_DATA_PTR(array);
+ for (i = 0; i < nitems; i++) {
+ if (typbyval) {
+ switch(typlen) {
+ case 1:
+ result = (int) (*proc_fn)(*p, value);
+ break;
+ case 2:
+ result = (int) (*proc_fn)(* (int16 *) p, value);
+ break;
+ case 3:
+ case 4:
+ result = (int) (*proc_fn)(* (int32 *) p, value);
+ break;
+ }
+ p += typlen;
+ } else {
+ result = (int) (*proc_fn)(p, value);
+ if (typlen > 0) {
+ p += typlen;
+ } else {
+ p += INTALIGN(* (int32 *) p);
+ }
+ }
+ if (result) {
+ if (!and) {
return (1);
- }
- else
- {
+ }
+ } else {
+ if (and) {
return (0);
+ }
}
+ }
+
+ if (and && result) {
+ return (1);
+ } else {
+ return (0);
+ }
}
/*
- * Iterators for type _text
+ * Iterator functions for type _text
*/
int32
-array_texteq(ArrayType *array, char *value)
+array_texteq(ArrayType *array, char* value)
{
- return array_iterator((Oid) 25, /* text */
- (Oid) 67, /* texteq */
- 0, /* logical or */
- array, (Datum) value);
+ return array_iterator((Oid) 25, /* text */
+ (Oid) 67, /* texteq */
+ 0, /* logical or */
+ array, (Datum)value);
}
int32
-array_all_texteq(ArrayType *array, char *value)
+array_all_texteq(ArrayType *array, char* value)
{
- return array_iterator((Oid) 25, /* text */
- (Oid) 67, /* texteq */
- 1, /* logical and */
- array, (Datum) value);
+ return array_iterator((Oid) 25, /* text */
+ (Oid) 67, /* texteq */
+ 1, /* logical and */
+ array, (Datum)value);
}
int32
-array_textregexeq(ArrayType *array, char *value)
+array_textregexeq(ArrayType *array, char* value)
{
- return array_iterator((Oid) 25, /* text */
- (Oid) 81, /* textregexeq */
- 0, /* logical or */
- array, (Datum) value);
+ return array_iterator((Oid) 25, /* text */
+ (Oid) 1254, /* textregexeq */
+ 0, /* logical or */
+ array, (Datum)value);
}
int32
-array_all_textregexeq(ArrayType *array, char *value)
+array_all_textregexeq(ArrayType *array, char* value)
{
- return array_iterator((Oid) 25, /* text */
- (Oid) 81, /* textregexeq */
- 1, /* logical and */
- array, (Datum) value);
+ return array_iterator((Oid) 25, /* text */
+ (Oid) 1254, /* textregexeq */
+ 1, /* logical and */
+ array, (Datum)value);
}
/*
- * Iterators for type _char16. Note that the regexp operators
- * take the second argument of type text.
+ * Iterator functions for type _char16. Note that the regexp
+ * operators take the second argument of type text.
*/
int32
-array_char16eq(ArrayType *array, char *value)
+array_char16eq(ArrayType *array, char* value)
{
- return array_iterator((Oid) 20, /* char16 */
- (Oid) 490, /* char16eq */
- 0, /* logical or */
- array, (Datum) value);
+ return array_iterator((Oid) 20, /* char16 */
+ (Oid) 1275, /* char16eq */
+ 0, /* logical or */
+ array, (Datum)value);
}
int32
-array_all_char16eq(ArrayType *array, char *value)
+array_all_char16eq(ArrayType *array, char* value)
{
- return array_iterator((Oid) 20, /* char16 */
- (Oid) 490, /* char16eq */
- 1, /* logical and */
- array, (Datum) value);
+ return array_iterator((Oid) 20, /* char16 */
+ (Oid) 1275, /* char16eq */
+ 1, /* logical and */
+ array, (Datum)value);
}
int32
-array_char16regexeq(ArrayType *array, char *value)
+array_char16regexeq(ArrayType *array, char* value)
{
- return array_iterator((Oid) 20, /* char16 */
- (Oid) 700, /* char16regexeq */
- 0, /* logical or */
- array, (Datum) value);
+ return array_iterator((Oid) 20, /* char16 */
+ (Oid) 1288, /* char16regexeq */
+ 0, /* logical or */
+ array, (Datum)value);
}
int32
-array_all_char16regexeq(ArrayType *array, char *value)
+array_all_char16regexeq(ArrayType *array, char* value)
{
- return array_iterator((Oid) 20, /* char16 */
- (Oid) 700, /* char16regexeq */
- 1, /* logical and */
- array, (Datum) value);
+ return array_iterator((Oid) 20, /* char16 */
+ (Oid) 1288, /* char16regexeq */
+ 1, /* logical and */
+ array, (Datum)value);
}
/*
- * Iterators for type _int4
+ * Iterator functions for type _int4
*/
int32
array_int4eq(ArrayType *array, int4 value)
{
- return array_iterator((Oid) 23, /* int4 */
- (Oid) 65, /* int4eq */
- 0, /* logical or */
- array, (Datum) value);
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 65, /* int4eq */
+ 0, /* logical or */
+ array, (Datum)value);
}
int32
array_all_int4eq(ArrayType *array, int4 value)
{
- return array_iterator((Oid) 23, /* int4 */
- (Oid) 65, /* int4eq */
- 1, /* logical and */
- array, (Datum) value);
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 65, /* int4eq */
+ 1, /* logical and */
+ array, (Datum)value);
+}
+
+int32
+array_int4ne(ArrayType *array, int4 value)
+{
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 144, /* int4ne */
+ 0, /* logical or */
+ array, (Datum)value);
+}
+
+int32
+array_all_int4ne(ArrayType *array, int4 value)
+{
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 144, /* int4ne */
+ 1, /* logical and */
+ array, (Datum)value);
}
int32
array_int4gt(ArrayType *array, int4 value)
{
- return array_iterator((Oid) 23, /* int4 */
- (Oid) 147, /* int4gt */
- 0, /* logical or */
- array, (Datum) value);
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 147, /* int4gt */
+ 0, /* logical or */
+ array, (Datum)value);
}
int32
array_all_int4gt(ArrayType *array, int4 value)
{
- return array_iterator((Oid) 23, /* int4 */
- (Oid) 147, /* int4gt */
- 1, /* logical and */
- array, (Datum) value);
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 147, /* int4gt */
+ 1, /* logical and */
+ array, (Datum)value);
+}
+
+int32
+array_int4ge(ArrayType *array, int4 value)
+{
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 150, /* int4ge */
+ 0, /* logical or */
+ array, (Datum)value);
+}
+
+int32
+array_all_int4ge(ArrayType *array, int4 value)
+{
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 150, /* int4ge */
+ 1, /* logical and */
+ array, (Datum)value);
+}
+
+int32
+array_int4lt(ArrayType *array, int4 value)
+{
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 66, /* int4lt */
+ 0, /* logical or */
+ array, (Datum)value);
+}
+
+int32
+array_all_int4lt(ArrayType *array, int4 value)
+{
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 66, /* int4lt */
+ 1, /* logical and */
+ array, (Datum)value);
+}
+
+int32
+array_int4le(ArrayType *array, int4 value)
+{
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 149, /* int4le */
+ 0, /* logical or */
+ array, (Datum)value);
+}
+
+int32
+array_all_int4le(ArrayType *array, int4 value)
+{
+ return array_iterator((Oid) 23, /* int4 */
+ (Oid) 149, /* int4le */
+ 1, /* logical and */
+ array, (Datum)value);
}
+
+/* end of file */
diff --git a/contrib/array/array_iterator.doc b/contrib/array/array_iterator.doc
index 01c1b2195cf..031301799c6 100644
--- a/contrib/array/array_iterator.doc
+++ b/contrib/array/array_iterator.doc
@@ -1,26 +1,44 @@
-From: Massimo Dal Zotto <dz@cs.unitn.it>
-Date: Mon, 6 May 1996 01:03:37 +0200 (MET DST)
-Subject: [PG95]: new operators for arrays
+Array iterator functions, by Massimo Dal Zotto <dz@cs.unitn.it>
-- -----BEGIN PGP SIGNED MESSAGE-----
+This loadable module defines a new class of functions which take
+an array and a scalar value, iterate a scalar operator over the
+elements of the array and the value, and compute a result as
+the logical OR or AND of the iteration results.
+For example array_int4eq returns true if some of the elements
+of an array of int4 is equal to the given value:
-Hi,
+ array_int4eq({1,2,3}, 1) --> true
+ array_int4eq({1,2,3}, 4) --> false
-I have written an extension to Postgres95 which allows to use qualification
-clauses based on the values of single elements of arrays.
-For example I can now select rows having some or all element of an array
+If we have defined T array types and O scalar operators we can
+define T x O x 2 array functions, each of them has a name like
+"array_[all_]<basetype><operation>" and takes an array of type T
+iterating the operator O over all the elements. Note however
+that some of the possible combination are invalid, for example
+the array_int4_like because there is no like operator for int4.
+
+We can then define new operators based on these functions and use
+them to write queries with qualification clauses based on the
+values of some of the elements of an array.
+For example to select rows having some or all element of an array
attribute equal to a given value or matching a regular expression:
-select * from t where t.foo *= 'bar';
-select * from t where t.foo **~ '^ba[rz]';
+ create table t(id int4[], txt text[]);
+
+ -- 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 ? Do you think this could be a useful feature for next release ?
-Here is my code, it can be compiled and loaded as a dynamic module without
-need to recompile the backend. I have defined only the few operators I needed,
-the list can be extended. Feddback is welcome.
+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.
diff --git a/contrib/array/array_iterator.h b/contrib/array/array_iterator.h
new file mode 100644
index 00000000000..0d9c58ed00b
--- /dev/null
+++ b/contrib/array/array_iterator.h
@@ -0,0 +1,27 @@
+#ifndef ARRAY_ITERATOR_H
+#define ARRAY_ITERATOR_H
+
+static int32 array_iterator(Oid elemtype, Oid proc, int and,
+ ArrayType *array, Datum value);
+int32 array_texteq(ArrayType *array, char* value);
+int32 array_all_texteq(ArrayType *array, char* value);
+int32 array_textregexeq(ArrayType *array, char* value);
+int32 array_all_textregexeq(ArrayType *array, char* value);
+int32 array_char16eq(ArrayType *array, char* value);
+int32 array_all_char16eq(ArrayType *array, char* value);
+int32 array_char16regexeq(ArrayType *array, char* value);
+int32 array_all_char16regexeq(ArrayType *array, char* value);
+int32 array_int4eq(ArrayType *array, int4 value);
+int32 array_all_int4eq(ArrayType *array, int4 value);
+int32 array_int4ne(ArrayType *array, int4 value);
+int32 array_all_int4ne(ArrayType *array, int4 value);
+int32 array_int4gt(ArrayType *array, int4 value);
+int32 array_all_int4gt(ArrayType *array, int4 value);
+int32 array_int4ge(ArrayType *array, int4 value);
+int32 array_all_int4ge(ArrayType *array, int4 value);
+int32 array_int4lt(ArrayType *array, int4 value);
+int32 array_all_int4lt(ArrayType *array, int4 value);
+int32 array_int4le(ArrayType *array, int4 value);
+int32 array_all_int4le(ArrayType *array, int4 value);
+
+#endif
diff --git a/contrib/array/array_iterator.sql.in b/contrib/array/array_iterator.sql.in
new file mode 100644
index 00000000000..6489545d97d
--- /dev/null
+++ b/contrib/array/array_iterator.sql.in
@@ -0,0 +1,191 @@
+-- SQL code to define the new array iterator functions and operators
+
+-- define the array operators *=, **=, *~ and **~ for type _text
+--
+create function array_texteq(_text, text) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_texteq(_text, text) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_textregexeq(_text, text) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_textregexeq(_text, text) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create operator *= (
+ leftarg=_text,
+ rightarg=text,
+ procedure=array_texteq);
+
+create operator **= (
+ leftarg=_text,
+ rightarg=text,
+ procedure=array_all_texteq);
+
+create operator *~ (
+ leftarg=_text,
+ rightarg=text,
+ procedure=array_textregexeq);
+
+create operator **~ (
+ leftarg=_text,
+ rightarg=text,
+ procedure=array_all_textregexeq);
+
+
+-- define the array operators *=, **=, *~ and **~ for type _char16
+--
+create function array_char16eq(_char16, char16) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_char16eq(_char16, char16) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_char16regexeq(_char16, text) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_char16regexeq(_char16, text) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create operator *= (
+ leftarg=_char16,
+ rightarg=char16,
+ procedure=array_char16eq);
+
+create operator **= (
+ leftarg=_char16,
+ rightarg=char16,
+ procedure=array_all_char16eq);
+
+create operator *~ (
+ leftarg=_char16,
+ rightarg=text,
+ procedure=array_char16regexeq);
+
+create operator **~ (
+ leftarg=_char16,
+ rightarg=text,
+ procedure=array_all_char16regexeq);
+
+
+-- define the array operators *=, **=, *> and **> for type _int4
+--
+create function array_int4eq(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_int4eq(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_int4ne(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_int4ne(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_int4gt(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_int4gt(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_int4ge(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_int4ge(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_int4lt(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_int4lt(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_int4le(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function array_all_int4le(_int4, int4) returns bool
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create operator *= (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_int4eq);
+
+create operator **= (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_all_int4eq);
+
+create operator *<> (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_int4ne);
+
+create operator **<> (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_all_int4ne);
+
+create operator *> (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_int4gt);
+
+create operator **> (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_all_int4gt);
+
+create operator *>= (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_int4ge);
+
+create operator **>= (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_all_int4ge);
+
+create operator *< (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_int4lt);
+
+create operator **< (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_all_int4lt);
+
+create operator *<= (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_int4le);
+
+create operator **<= (
+ leftarg=_int4,
+ rightarg=int4,
+ procedure=array_all_int4le);
+
+-- end of file
diff --git a/contrib/datetime/Makefile b/contrib/datetime/Makefile
index 930d6e57cfd..52023b8e8af 100644
--- a/contrib/datetime/Makefile
+++ b/contrib/datetime/Makefile
@@ -1,12 +1,62 @@
-D=/usr/postgres
-P=$D/lib/datetime_functions.so
-CFLAGS=-fpic -O -I../../src/include -I../../src/backend
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for new date/time functions.
+#
+#-------------------------------------------------------------------------
-all: $P datetime_functions.sql
+PGDIR = ../..
+SRCDIR = $(PGDIR)/src
-$P:datetime_functions.o
- ld -Bshareable -o $P datetime_functions.o
+include $(SRCDIR)/Makefile.global
-datetime_functions.sql: datetime.prot
- sh datetime.prot $P
- psql -c "\idatetime_functions.sql" template1
+INCLUDE_OPT = -I ./ \
+ -I $(SRCDIR)/ \
+ -I $(SRCDIR)/include \
+ -I $(SRCDIR)/port/$(PORTNAME)
+
+CFLAGS += $(INCLUDE_OPT)
+
+ifeq ($(PORTNAME), linux)
+ ifdef LINUX_ELF
+ ifeq ($(CC), gcc)
+ CFLAGS += -fPIC
+ endif
+ endif
+endif
+
+ifeq ($(PORTNAME), i386_solaris)
+ CFLAGS+= -fPIC
+endif
+
+MODNAME = datetime_functions
+
+MODULE = $(MODNAME)$(DLSUFFIX)
+
+all: module sql
+
+module: $(MODULE)
+
+sql: $(MODNAME).sql
+
+install: $(MODULE)
+ cp -p $(MODULE) $(LIBDIR)
+ cd $(LIBDIR); strip $(MODULE)
+
+%.sql: %.sql.in
+ sed "s|MODULE_PATHNAME|$(LIBDIR)/$(MODULE)|" < $< > $@
+
+.SUFFIXES: $(DLSUFFIX)
+
+%$(DLSUFFIX): %.c
+ cc $(CFLAGS) -shared -o $@ $<
+
+depend dep:
+ $(CC) -MM $(INCLUDE_OPT) *.c >depend
+
+clean:
+ rm -f $(MODULE) $(MODNAME).sql
+
+ifeq (depend,$(wildcard depend))
+include depend
+endif
diff --git a/contrib/datetime/datetime_functions.c b/contrib/datetime/datetime_functions.c
index d2c097583cf..e925d985bfb 100644
--- a/contrib/datetime/datetime_functions.c
+++ b/contrib/datetime/datetime_functions.c
@@ -6,113 +6,208 @@
* Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
*/
-#include <time.h>
+#include <stdio.h> /* for sprintf() */
+#include <string.h>
+#include <limits.h>
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
#include "postgres.h"
-#include "utils/palloc.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
+#include "utils/nabstime.h"
#include "utils/datetime.h"
+#include "access/xact.h"
+#include "datetime_functions.h"
-TimeADT *
-time_difference(TimeADT *time1, TimeADT *time2)
+/* Constant to replace calls to date2j(2000,1,1) */
+#define JDATE_2000 2451545
+
+/*
+ * 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;
+
+ int nf;
+ char lowstr[MAXDATELEN+1];
+ char *field[MAXDATEFIELDS];
+ int dtype;
+ int ftype[MAXDATEFIELDS];
+
+ if (!PointerIsValid(str))
+ elog(WARN,"Bad (null) time external representation",NULL);
+
+ if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
+ || (DecodeTimeOnly( field, ftype, nf, &dtype, tm, &fsec) != 0))
+ elog(WARN,"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))) {
+ elog(WARN,
+ "time_in: hour must be limited to values 0 through 24:00 "
+ "in \"%s\"",
+ str);
+ }
+ if ((tm->tm_min < 0) || (tm->tm_min > 59))
+ elog(WARN,"Minute must be limited to values 0 through 59 in '%s'",str);
+ if ((tm->tm_sec < 0) || ((tm->tm_sec + fsec) >= 60))
+ elog(WARN,"Second must be limited to values 0 through < 60 in '%s'",
+ str);
+
+ time = PALLOCTYPE(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)
{
- TimeADT *result = (TimeADT *) palloc(sizeof(TimeADT));
+ 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 = *time1 - *time2;
- return (result);
+ result = PALLOC(strlen(buf)+1);
+
+ strcpy( result, buf);
+
+ return(result);
}
-TimeADT *
-currenttime()
+TimeADT *
+hhmm(TimeADT *time)
{
- time_t current_time;
- struct tm *tm;
- TimeADT *result = (TimeADT *) palloc(sizeof(TimeADT));
-
- current_time = time(NULL);
- tm = localtime(&current_time);
- *result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec);
- return (result);
+ TimeADT *result = PALLOCTYPE(TimeADT);
+
+ *result = (((int) *time) / 60 * 60);
+
+ return(result);
}
-DateADT
-currentdate()
+TimeADT *
+time_difference(TimeADT *time1, TimeADT *time2)
{
- time_t current_time;
- struct tm *tm;
- DateADT result;
+ TimeADT *time = PALLOCTYPE(TimeADT);
- current_time = time(NULL);
- tm = localtime(&current_time);
+ *time = (*time1 - *time2);
+ return(time);
+}
+
+int4
+time_hours(TimeADT *time)
+{
+ return (((int) *time) / 3600);
+}
- result = date2j(tm->tm_year, tm->tm_mon + 1, tm->tm_mday) -
- date2j(100, 1, 1);
- return (result);
+int4
+time_minutes(TimeADT *time)
+{
+ return ((((int) *time) / 60) % 60);
}
int4
-hours(TimeADT *time)
+time_seconds(TimeADT *time)
{
- return (*time / (60 * 60));
+ return (((int) *time) % 60);
}
int4
-minutes(TimeADT *time)
+as_minutes(TimeADT *time)
{
- return (((int) (*time / 60)) % 60);
+ return (((int) *time) / 60);
}
int4
-seconds(TimeADT *time)
+as_seconds(TimeADT *time)
{
- return (((int) *time) % 60);
+ return ((int) *time);
}
int4
-day(DateADT *date)
+date_day(DateADT val)
{
- struct tm tm;
+ int year, month, day;
- j2date((*date + date2j(2000, 1, 1)),
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
+ j2date(val + JDATE_2000, &year, &month, &day);
- return (tm.tm_mday);
+ return (day);
}
int4
-month(DateADT *date)
+date_month(DateADT val)
{
- struct tm tm;
+ int year, month, day;
- j2date((*date + date2j(2000, 1, 1)),
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
+ j2date(val + JDATE_2000, &year, &month, &day);
- return (tm.tm_mon);
+ return (month);
}
int4
-year(DateADT *date)
+date_year(DateADT val)
{
- struct tm tm;
+ int year, month, day;
- j2date((*date + date2j(2000, 1, 1)),
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
+ j2date(val + JDATE_2000, &year, &month, &day);
- return (tm.tm_year);
+ return (year);
}
-int4
-asminutes(TimeADT *time)
+TimeADT *
+currenttime()
{
- int seconds = (int) *time;
+ TimeADT *result = PALLOCTYPE(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 (seconds / 60);
+ return (result);
}
-int4
-asseconds(TimeADT *time)
+DateADT
+currentdate()
{
- int seconds = (int) *time;
+ DateADT date;
+ struct tm tt, *tm = &tt;
- return (seconds);
+ GetCurrentTime(tm);
+ date = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - JDATE_2000);
+ return (date);
}
+
+/* end of file */
diff --git a/contrib/datetime/datetime_functions.h b/contrib/datetime/datetime_functions.h
new file mode 100644
index 00000000000..68474984059
--- /dev/null
+++ b/contrib/datetime/datetime_functions.h
@@ -0,0 +1,19 @@
+#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);
+
+#endif
diff --git a/contrib/datetime/datetime_functions.sql.in b/contrib/datetime/datetime_functions.sql.in
new file mode 100644
index 00000000000..81e40aa9af1
--- /dev/null
+++ b/contrib/datetime/datetime_functions.sql.in
@@ -0,0 +1,96 @@
+-- SQL code to define the new date and time functions and operators
+
+-- Define the new 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 a 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
diff --git a/contrib/miscutil/Makefile b/contrib/miscutil/Makefile
new file mode 100644
index 00000000000..982515ab296
--- /dev/null
+++ b/contrib/miscutil/Makefile
@@ -0,0 +1,62 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for array iterator functions.
+#
+#-------------------------------------------------------------------------
+
+PGDIR = ../..
+SRCDIR = $(PGDIR)/src
+
+include $(SRCDIR)/Makefile.global
+
+INCLUDE_OPT = -I ./ \
+ -I $(SRCDIR)/ \
+ -I $(SRCDIR)/include \
+ -I $(SRCDIR)/port/$(PORTNAME)
+
+CFLAGS += $(INCLUDE_OPT)
+
+ifeq ($(PORTNAME), linux)
+ ifdef LINUX_ELF
+ ifeq ($(CC), gcc)
+ CFLAGS += -fPIC
+ endif
+ endif
+endif
+
+ifeq ($(PORTNAME), i386_solaris)
+ CFLAGS+= -fPIC
+endif
+
+MODNAME = misc_utils
+
+MODULE = $(MODNAME)$(DLSUFFIX)
+
+all: module sql
+
+module: $(MODULE)
+
+sql: $(MODNAME).sql
+
+install: $(MODULE)
+ cp -p $(MODULE) $(LIBDIR)
+ cd $(LIBDIR); strip $(MODULE)
+
+%.sql: %.sql.in
+ sed "s|MODULE_PATHNAME|$(LIBDIR)/$(MODULE)|" < $< > $@
+
+.SUFFIXES: $(DLSUFFIX)
+
+%$(DLSUFFIX): %.c
+ cc $(CFLAGS) -shared -o $@ $<
+
+depend dep:
+ $(CC) -MM $(INCLUDE_OPT) *.c >depend
+
+clean:
+ rm -f $(MODULE) $(MODNAME).sql assert_test.so
+
+ifeq (depend,$(wildcard depend))
+include depend
+endif
diff --git a/contrib/miscutil/assert_test.c b/contrib/miscutil/assert_test.c
new file mode 100644
index 00000000000..fa2ec1fcaad
--- /dev/null
+++ b/contrib/miscutil/assert_test.c
@@ -0,0 +1,43 @@
+/*
+ * assert_test.c --
+ *
+ * This file tests Postgres assert checking.
+ *
+ * Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
+ */
+
+#include "postgres.h"
+#include "assert_test.h"
+
+extern int assertTest(int val);
+extern int assertEnable(int val);
+
+int
+assert_enable(int val)
+{
+ return assertEnable(val);
+}
+
+int
+assert_test(int val)
+{
+ return assertTest(val);
+}
+
+/*
+
+-- Enable/disable Postgres assert checking.
+--
+create function assert_enable(int4) returns int4
+ as '/usr/local/pgsql/lib/assert_test.so'
+ language 'C';
+
+-- Test Postgres assert checking.
+--
+create function assert_test(int4) returns int4
+ as '/usr/local/pgsql/lib/assert_test.so'
+ language 'C';
+
+*/
+
+/* end of file */
diff --git a/contrib/miscutil/assert_test.h b/contrib/miscutil/assert_test.h
new file mode 100644
index 00000000000..2af288729aa
--- /dev/null
+++ b/contrib/miscutil/assert_test.h
@@ -0,0 +1,7 @@
+#ifndef ASSERT_TEST_H
+#define ASSERT_TEST_H
+
+int assert_enable(int val);
+int assert_test(int val);
+
+#endif
diff --git a/contrib/miscutil/misc_utils.c b/contrib/miscutil/misc_utils.c
new file mode 100644
index 00000000000..3b8f379d21f
--- /dev/null
+++ b/contrib/miscutil/misc_utils.c
@@ -0,0 +1,50 @@
+/*
+ * utils.c --
+ *
+ * This file defines various Postgres utility functions.
+ *
+ * Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
+ */
+
+#include <unistd.h>
+
+#include "postgres.h"
+#include "utils/palloc.h"
+
+#include "misc_utils.h"
+
+extern int ExecutorLimit(int limit);
+extern void Async_Unlisten(char *relname, int pid);
+
+int
+query_limit(int limit)
+{
+ return ExecutorLimit(limit);
+}
+
+int
+backend_pid()
+{
+ return getpid();
+}
+
+int
+unlisten(char *relname)
+{
+ Async_Unlisten(relname, getpid());
+ return 0;
+}
+
+int
+max(int x, int y)
+{
+ return ((x > y) ? x : y);
+}
+
+int
+min(int x, int y)
+{
+ return ((x < y) ? x : y);
+}
+
+/* end of file */
diff --git a/contrib/miscutil/misc_utils.h b/contrib/miscutil/misc_utils.h
new file mode 100644
index 00000000000..7dd583c2646
--- /dev/null
+++ b/contrib/miscutil/misc_utils.h
@@ -0,0 +1,10 @@
+#ifndef MISC_UTILS_H
+#define MISC_UTILS_H
+
+int query_limit(int limit);
+int backend_pid(void);
+int unlisten(char *relname);
+int max(int x, int y);
+int min(int x, int y);
+
+#endif
diff --git a/contrib/miscutil/misc_utils.sql.in b/contrib/miscutil/misc_utils.sql.in
new file mode 100644
index 00000000000..0c90ba52eb9
--- /dev/null
+++ b/contrib/miscutil/misc_utils.sql.in
@@ -0,0 +1,40 @@
+-- SQL code to define the new array iterator functions and operators
+
+-- min(x,y)
+--
+create function min(int4,int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- max(x,y)
+--
+create function max(int4,int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- Set the maximum number of tuples returned by a single query
+--
+create function query_limit(int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- Return the pid of the backend
+--
+create function backend_pid() returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- Unlisten from a relation
+--
+create function unlisten(name) returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- Unlisten from all relations for this backend
+--
+create function unlisten() returns int4
+ as 'delete from pg_listener where listenerpid = backend_pid();
+ select 0'
+ language 'sql';
+
+-- end of file
diff --git a/contrib/pginterface/README.orig b/contrib/pginterface/README.orig
new file mode 100644
index 00000000000..c52b5d1190a
--- /dev/null
+++ b/contrib/pginterface/README.orig
@@ -0,0 +1,42 @@
+
+
+ Pginterface 2.0
+
+Attached is a copy of the Postgres support routines I wrote to allow me
+to more cleanly interface to the libpg library, more like a 4gl SQL
+interface.
+
+It has several features that may be useful for others:
+
+I have simplified the C code that calls libpq by wrapping all the
+functionality of libpq in calls to connectdb(), doquery(), fetch(),
+fetchwithnulls() and disconnectdb(). Each call returns a structure or
+value, so if you need to do more work with the result, you can. Also, I
+have a global variable that allows you to disable the error checking I
+have added to the doquery() routine.
+
+I have added a function called fetch(), which allows you to pass
+pointers as parameters, and on return the variables are filled with the
+data from the binary cursor you opened. These binary cursors are not
+useful if you are running the query engine on a system with a different
+architecture than the database server. If you pass a NULL pointer, the
+column is skipped, and you can use libpq to handle it as you wish.
+
+I have used sigprocmask() to block the reception of certain signals
+while the program is executing SQL queries. This prevents a user
+pressing Control-C from stopping all the back ends. It blocks SIGHUP,
+SIGINT, and SIGTERM, but does not block SIGQUIT or obviously kill -9.
+If your platform does not support sigprocmask(), you can remove those
+function calls. ( Am I correct that abnormal termination can cause
+shared memory resynchronization?)
+
+There is a demo program called pginsert that demonstrates how the
+library can be used.
+
+You can create a library of pginterface.c and halt.c, and just include
+pginterface.h in your source code.
+
+I am willing to maintain this if people find problems or want additional
+functionality.
+
+Bruce Momjian (root@candle.pha.pa.us)
diff --git a/contrib/pginterface/pginsert.c.orig b/contrib/pginterface/pginsert.c.orig
new file mode 100644
index 00000000000..82838c2f8cc
--- /dev/null
+++ b/contrib/pginterface/pginsert.c.orig
@@ -0,0 +1,102 @@
+/*
+ * insert.c
+ *
+*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <time.h>
+#include <libpq-fe.h>
+#include "halt.h"
+#include "pginterface.h"
+
+int
+main(int argc, char **argv)
+{
+ char query[4000];
+ int row = 1;
+ int aint;
+ float afloat;
+ double adouble;
+ char achar[11],
+ achar16[17],
+ abpchar[11],
+ avarchar[51],
+ atext[51];
+ time_t aabstime;
+
+ if (argc != 2)
+ halt("Usage: %s database\n", argv[0]);
+
+ connectdb(argv[1], NULL, NULL, NULL, NULL);
+
+ on_error_continue();
+ doquery("DROP TABLE testfetch");
+ on_error_stop();
+
+ doquery("\
+ CREATE TABLE testfetch( \
+ aint int4, \
+ afloat float4, \
+ adouble float8, \
+ achar char, \
+ achar16 char16, \
+ abpchar char(10), \
+ avarchar varchar(50), \
+ atext text, \
+ aabstime abstime) \
+ ");
+
+ while (1)
+ {
+ sprintf(query, "INSERT INTO testfetch VALUES ( \
+ %d, \
+ 2322.12, \
+ '923121.0323'::float8, \
+ 'A', \
+ 'Betty', \
+ 'Charley', \
+ 'Doug', \
+ 'Ernie', \
+ 'now' )", row);
+ doquery(query);
+
+ doquery("BEGIN WORK");
+ doquery("DECLARE c_testfetch BINARY CURSOR FOR \
+ SELECT * FROM testfetch");
+
+ doquery("FETCH ALL IN c_testfetch");
+
+ while (fetch(
+ &aint,
+ &afloat,
+ &adouble,
+ achar,
+ achar16,
+ abpchar,
+ avarchar,
+ atext,
+ &aabstime) != END_OF_TUPLES)
+ printf("int %d\nfloat %f\ndouble %f\nchar %s\nchar16 %s\n\
+bpchar %s\nvarchar %s\ntext %s\nabstime %s",
+ aint,
+ afloat,
+ adouble,
+ achar,
+ achar16,
+ abpchar,
+ avarchar,
+ atext,
+ ctime(&aabstime));
+
+
+ doquery("CLOSE c_testfetch");
+ doquery("COMMIT WORK");
+ printf("--- %-d rows inserted so far\n", row);
+
+ row++;
+ }
+
+ disconnectdb();
+ return 0;
+}
diff --git a/contrib/pginterface/pginterface.c.orig b/contrib/pginterface/pginterface.c.orig
new file mode 100644
index 00000000000..cdc419352aa
--- /dev/null
+++ b/contrib/pginterface/pginterface.c.orig
@@ -0,0 +1,232 @@
+/*
+ * pginterface.c
+ *
+*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <libpq-fe.h>
+#include "halt.h"
+#include "pginterface.h"
+
+static void sig_disconnect();
+static void set_signals();
+
+#define NUL '\0'
+
+/* GLOBAL VARIABLES */
+static PGconn *conn;
+static PGresult *res = NULL;
+
+#define ON_ERROR_STOP 0
+#define ON_ERROR_CONTINUE 1
+
+static int on_error_state = ON_ERROR_STOP;
+
+/* LOCAL VARIABLES */
+static sigset_t block_sigs,
+ unblock_sigs;
+static int tuple;
+
+/*
+**
+** connectdb - returns PGconn structure
+**
+*/
+PGconn *
+connectdb(char *dbName,
+ char *pghost,
+ char *pgport,
+ char *pgoptions,
+ char *pgtty)
+{
+ /* make a connection to the database */
+ conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
+ if (PQstatus(conn) == CONNECTION_BAD)
+ halt("Connection to database '%s' failed.\n%s\n", dbName,
+ PQerrorMessage(conn));
+ set_signals();
+ return conn;
+}
+
+/*
+**
+** disconnectdb
+**
+*/
+void
+disconnectdb()
+{
+ PQfinish(conn);
+}
+
+/*
+**
+** doquery - returns PGresult structure
+**
+*/
+PGresult *
+doquery(char *query)
+{
+ if (res != NULL)
+ PQclear(res);
+
+ sigprocmask(SIG_SETMASK, &block_sigs, NULL);
+ res = PQexec(conn, query);
+ sigprocmask(SIG_SETMASK, &unblock_sigs, NULL);
+
+ if (on_error_state == ON_ERROR_STOP &&
+ (res == NULL ||
+ PQresultStatus(res) == PGRES_BAD_RESPONSE ||
+ PQresultStatus(res) == PGRES_NONFATAL_ERROR ||
+ PQresultStatus(res) == PGRES_FATAL_ERROR))
+ {
+ if (res != NULL)
+ fprintf(stderr, "query error: %s\n", PQcmdStatus(res));
+ else
+ fprintf(stderr, "connection error: %s\n", PQerrorMessage(conn));
+ PQfinish(conn);
+ halt("failed request: %s\n", query);
+ }
+ tuple = 0;
+ return res;
+}
+
+/*
+**
+** fetch - returns tuple number (starts at 0), or the value END_OF_TUPLES
+** NULL pointers are skipped
+**
+*/
+int
+fetch(void *param,...)
+{
+ va_list ap;
+ int arg,
+ num_fields;
+
+ num_fields = PQnfields(res);
+
+ if (tuple >= PQntuples(res))
+ return END_OF_TUPLES;
+
+ va_start(ap, param);
+ for (arg = 0; arg < num_fields; arg++)
+ {
+ if (param != NULL)
+ {
+ if (PQfsize(res, arg) == -1)
+ {
+ memcpy(param, PQgetvalue(res, tuple, arg), PQgetlength(res, tuple, arg));
+ ((char *) param)[PQgetlength(res, tuple, arg)] = NUL;
+ }
+ else
+ memcpy(param, PQgetvalue(res, tuple, arg), PQfsize(res, arg));
+ }
+ param = va_arg(ap, char *);
+ }
+ va_end(ap);
+ return tuple++;
+}
+
+/*
+**
+** fetchwithnulls - returns tuple number (starts at 0),
+** or the value END_OF_TUPLES
+** Returns true or false into null indicator variables
+** NULL pointers are skipped
+*/
+int
+fetchwithnulls(void *param,...)
+{
+ va_list ap;
+ int arg,
+ num_fields;
+
+ num_fields = PQnfields(res);
+
+ if (tuple >= PQntuples(res))
+ return END_OF_TUPLES;
+
+ va_start(ap, param);
+ for (arg = 0; arg < num_fields; arg++)
+ {
+ if (param != NULL)
+ {
+ if (PQfsize(res, arg) == -1)
+ {
+ memcpy(param, PQgetvalue(res, tuple, arg), PQgetlength(res, tuple, arg));
+ ((char *) param)[PQgetlength(res, tuple, arg)] = NUL;
+ }
+ else
+ memcpy(param, PQgetvalue(res, tuple, arg), PQfsize(res, arg));
+ }
+ param = va_arg(ap, char *);
+ if (PQgetisnull(res, tuple, arg) != 0)
+ *(int *) param = 1;
+ else
+ *(int *) param = 0;
+ param = va_arg(ap, char *);
+ }
+ va_end(ap);
+ return tuple++;
+}
+
+/*
+**
+** on_error_stop
+**
+*/
+void
+on_error_stop()
+{
+ on_error_state = ON_ERROR_STOP;
+}
+
+/*
+**
+** on_error_continue
+**
+*/
+void
+on_error_continue()
+{
+ on_error_state = ON_ERROR_CONTINUE;
+}
+
+/*
+**
+** sig_disconnect
+**
+*/
+static void
+sig_disconnect()
+{
+ fprintf(stderr, "exiting...\n");
+ PQfinish(conn);
+ exit(1);
+}
+
+/*
+**
+** set_signals
+**
+*/
+static void
+set_signals()
+{
+ sigemptyset(&block_sigs);
+ sigemptyset(&unblock_sigs);
+ sigaddset(&block_sigs, SIGTERM);
+ sigaddset(&block_sigs, SIGHUP);
+ sigaddset(&block_sigs, SIGINT);
+/* sigaddset(&block_sigs,SIGQUIT); no block */
+ sigprocmask(SIG_SETMASK, &unblock_sigs, NULL);
+ signal(SIGTERM, sig_disconnect);
+ signal(SIGHUP, sig_disconnect);
+ signal(SIGINT, sig_disconnect);
+ signal(SIGQUIT, sig_disconnect);
+}
diff --git a/contrib/pginterface/pgnulltest.c.orig b/contrib/pginterface/pgnulltest.c.orig
new file mode 100644
index 00000000000..96873ca7c81
--- /dev/null
+++ b/contrib/pginterface/pgnulltest.c.orig
@@ -0,0 +1,143 @@
+/*
+ * pgnulltest.c
+ *
+*/
+
+#define TEST_NON_NULLS
+
+#include <stdio.h>
+#include <signal.h>
+#include <time.h>
+#include <halt.h>
+#include <libpq-fe.h>
+#include <pginterface.h>
+
+int
+main(int argc, char **argv)
+{
+ char query[4000];
+ int row = 1;
+ int aint;
+ float afloat;
+ double adouble;
+ char achar[11],
+ achar16[17],
+ abpchar[11],
+ avarchar[51],
+ atext[51];
+ time_t aabstime;
+ int aint_null,
+ afloat_null,
+ adouble_null,
+ achar_null,
+ achar16_null,
+ abpchar_null,
+ avarchar_null,
+ atext_null,
+ aabstime_null;
+
+ if (argc != 2)
+ halt("Usage: %s database\n", argv[0]);
+
+ connectdb(argv[1], NULL, NULL, NULL, NULL);
+
+ on_error_continue();
+ doquery("DROP TABLE testfetch");
+ on_error_stop();
+
+ doquery("\
+ CREATE TABLE testfetch( \
+ aint int4, \
+ afloat float4, \
+ adouble float8, \
+ achar char, \
+ achar16 char16, \
+ abpchar char(10), \
+ avarchar varchar(50), \
+ atext text, \
+ aabstime abstime) \
+ ");
+
+#ifdef TEST_NON_NULLS
+ sprintf(query, "INSERT INTO testfetch VALUES ( \
+ 0, \
+ 0, \
+ 0, \
+ '', \
+ '', \
+ '', \
+ '', \
+ '', \
+ '');");
+#else
+ sprintf(query, "INSERT INTO testfetch VALUES ( \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL);");
+#endif
+ doquery(query);
+
+ doquery("BEGIN WORK");
+ doquery("DECLARE c_testfetch BINARY CURSOR FOR \
+ SELECT * FROM testfetch");
+
+ doquery("FETCH ALL IN c_testfetch");
+
+ if (fetchwithnulls(
+ &aint,
+ &aint_null,
+ &afloat,
+ &afloat_null,
+ &adouble,
+ &adouble_null,
+ achar,
+ &achar_null,
+ achar16,
+ &achar16_null,
+ abpchar,
+ &abpchar_null,
+ avarchar,
+ &avarchar_null,
+ atext,
+ &atext_null,
+ &aabstime,
+ &aabstime_null) != END_OF_TUPLES)
+ printf("int %d\nfloat %f\ndouble %f\nchar %s\nchar16 %s\n\
+bpchar %s\nvarchar %s\ntext %s\nabstime %s\n",
+ aint,
+ afloat,
+ adouble,
+ achar,
+ achar16,
+ abpchar,
+ avarchar,
+ atext,
+ ctime(&aabstime));
+ printf("NULL:\nint %d\nfloat %d\ndouble %d\nchar %d\nchar16 %d\n\
+bpchar %d\nvarchar %d\ntext %d\nabstime %d\n",
+ aint_null,
+ afloat_null,
+ adouble_null,
+ achar_null,
+ achar16_null,
+ abpchar_null,
+ avarchar_null,
+ atext_null,
+ aabstime_null);
+
+
+ doquery("CLOSE c_testfetch");
+ doquery("COMMIT WORK");
+ printf("--- %-d rows inserted so far\n", row);
+
+ row++;
+
+ disconnectdb();
+ return 0;
+}
diff --git a/contrib/pginterface/pgwordcount.c.orig b/contrib/pginterface/pgwordcount.c.orig
new file mode 100644
index 00000000000..859cf90b2ad
--- /dev/null
+++ b/contrib/pginterface/pgwordcount.c.orig
@@ -0,0 +1,72 @@
+/*
+ * wordcount.c
+ *
+*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <time.h>
+#include "halt.h"
+#include <libpq-fe.h>
+#include "pginterface.h"
+
+int
+main(int argc, char **argv)
+{
+ char query[4000];
+ int row = 0;
+ int count;
+ char line[4000];
+
+ if (argc != 2)
+ halt("Usage: %s database\n", argv[0]);
+
+ connectdb(argv[1], NULL, NULL, NULL, NULL);
+ on_error_continue();
+ doquery("DROP TABLE words");
+ on_error_stop();
+
+ doquery("\
+ CREATE TABLE words( \
+ matches int4, \
+ word text ) \
+ ");
+ doquery("\
+ CREATE INDEX i_words_1 ON words USING btree ( \
+ word text_ops )\
+ ");
+
+ while (1)
+ {
+ if (scanf("%s", line) != 1)
+ break;
+ doquery("BEGIN WORK");
+ sprintf(query, "\
+ DECLARE c_words BINARY CURSOR FOR \
+ SELECT count(*) \
+ FROM words \
+ WHERE word = '%s'", line);
+ doquery(query);
+ doquery("FETCH ALL IN c_words");
+
+ while (fetch(&count) == END_OF_TUPLES)
+ count = 0;
+ doquery("CLOSE c_words");
+ doquery("COMMIT WORK");
+
+ if (count == 0)
+ sprintf(query, "\
+ INSERT INTO words \
+ VALUES (1, '%s')", line);
+ else
+ sprintf(query, "\
+ UPDATE words \
+ SET matches = matches + 1 \
+ WHERE word = '%s'", line);
+ doquery(query);
+ row++;
+ }
+
+ disconnectdb();
+ return 0;
+}
diff --git a/contrib/sequence/Makefile b/contrib/sequence/Makefile
new file mode 100644
index 00000000000..e82817fd15a
--- /dev/null
+++ b/contrib/sequence/Makefile
@@ -0,0 +1,62 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for new sequence functions.
+#
+#-------------------------------------------------------------------------
+
+PGDIR = ../..
+SRCDIR = $(PGDIR)/src
+
+include $(SRCDIR)/Makefile.global
+
+INCLUDE_OPT = -I ./ \
+ -I $(SRCDIR)/ \
+ -I $(SRCDIR)/include \
+ -I $(SRCDIR)/port/$(PORTNAME)
+
+CFLAGS += $(INCLUDE_OPT)
+
+ifeq ($(PORTNAME), linux)
+ ifdef LINUX_ELF
+ ifeq ($(CC), gcc)
+ CFLAGS += -fPIC
+ endif
+ endif
+endif
+
+ifeq ($(PORTNAME), i386_solaris)
+ CFLAGS+= -fPIC
+endif
+
+MODNAME = set_sequence
+
+MODULE = $(MODNAME)$(DLSUFFIX)
+
+all: module sql
+
+module: $(MODULE)
+
+sql: $(MODNAME).sql
+
+install: $(MODULE)
+ cp -p $(MODULE) $(LIBDIR)
+ cd $(LIBDIR); strip $(MODULE)
+
+%.sql: %.sql.in
+ sed "s|MODULE_PATHNAME|$(LIBDIR)/$(MODULE)|" < $< > $@
+
+.SUFFIXES: $(DLSUFFIX)
+
+%$(DLSUFFIX): %.c
+ cc $(CFLAGS) -shared -o $@ $<
+
+depend dep:
+ $(CC) -MM $(INCLUDE_OPT) *.c >depend
+
+clean:
+ rm -f $(MODULE) $(MODNAME).sql
+
+ifeq (depend,$(wildcard depend))
+include depend
+endif
diff --git a/contrib/sequence/set_sequence.c b/contrib/sequence/set_sequence.c
new file mode 100644
index 00000000000..7468efb5fd7
--- /dev/null
+++ b/contrib/sequence/set_sequence.c
@@ -0,0 +1,41 @@
+/*
+ * set_sequence.c --
+ *
+ * Set a new sequence value.
+ *
+ * Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
+ */
+
+#include "postgres.h"
+#include "nodes/parsenodes.h"
+#include "commands/sequence.h"
+
+#include "set_sequence.h"
+
+extern int setval(struct varlena *seqin, int4 val);
+
+int
+set_currval(struct varlena *sequence, int4 nextval)
+{
+ return setval(sequence, nextval);
+}
+
+int
+next_id(struct varlena *sequence)
+{
+ return nextval(sequence);
+}
+
+int
+last_id(struct varlena *sequence)
+{
+ return currval(sequence);
+}
+
+int
+set_last_id(struct varlena *sequence, int4 nextval)
+{
+ return setval(sequence, nextval);
+}
+
+/* end of file */
diff --git a/contrib/sequence/set_sequence.h b/contrib/sequence/set_sequence.h
new file mode 100644
index 00000000000..f5c62949663
--- /dev/null
+++ b/contrib/sequence/set_sequence.h
@@ -0,0 +1,9 @@
+#ifndef SET_SEQUENCE_H
+#define SET_SEQUENCE_H
+
+int set_currval(struct varlena *sequence, int4 nextval);
+int next_id(struct varlena *sequence);
+int last_id(struct varlena *sequence);
+int set_last_id(struct varlena *sequence, int4 nextval);
+
+#endif
diff --git a/contrib/sequence/set_sequence.sql.in b/contrib/sequence/set_sequence.sql.in
new file mode 100644
index 00000000000..0f1421b71bd
--- /dev/null
+++ b/contrib/sequence/set_sequence.sql.in
@@ -0,0 +1,33 @@
+-- SQL code to define new sequence utilities
+
+-- Set a new sequence value
+--
+create function set_currval(text, int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- Increment the value of sequence
+--
+-- select next_id('sequence_name');
+--
+create function next_id(text) returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- Return the last value set for a sequence
+--
+-- select last_id('sequence_name');
+--
+create function last_id(text) returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- Set the current value of a sequence
+--
+-- select set_last_id('sequence_name', 1);
+--
+create function set_last_id(text,int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- end of file
diff --git a/contrib/string/Makefile b/contrib/string/Makefile
new file mode 100644
index 00000000000..b9ff534137e
--- /dev/null
+++ b/contrib/string/Makefile
@@ -0,0 +1,62 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for new string I/O functions.
+#
+#-------------------------------------------------------------------------
+
+PGDIR = ../..
+SRCDIR = $(PGDIR)/src
+
+include $(SRCDIR)/Makefile.global
+
+INCLUDE_OPT = -I ./ \
+ -I $(SRCDIR)/ \
+ -I $(SRCDIR)/include \
+ -I $(SRCDIR)/port/$(PORTNAME)
+
+CFLAGS += $(INCLUDE_OPT)
+
+ifeq ($(PORTNAME), linux)
+ ifdef LINUX_ELF
+ ifeq ($(CC), gcc)
+ CFLAGS += -fPIC
+ endif
+ endif
+endif
+
+ifeq ($(PORTNAME), i386_solaris)
+ CFLAGS+= -fPIC
+endif
+
+MODNAME = string_io
+
+MODULE = $(MODNAME)$(DLSUFFIX)
+
+all: module sql
+
+module: $(MODULE)
+
+sql: $(MODNAME).sql
+
+install: $(MODULE)
+ cp -p $(MODULE) $(LIBDIR)
+ cd $(LIBDIR); strip $(MODULE)
+
+%.sql: %.sql.in
+ sed "s|MODULE_PATHNAME|$(LIBDIR)/$(MODULE)|" < $< > $@
+
+.SUFFIXES: $(DLSUFFIX)
+
+%$(DLSUFFIX): %.c
+ cc $(CFLAGS) -shared -o $@ $<
+
+depend dep:
+ $(CC) -MM $(INCLUDE_OPT) *.c >depend
+
+clean:
+ rm -f $(MODULE) $(MODNAME).sql
+
+ifeq (depend,$(wildcard depend))
+include depend
+endif
diff --git a/contrib/string/string_io.c b/contrib/string/string_io.c
index c45db69187c..5dd6346b56f 100644
--- a/contrib/string/string_io.c
+++ b/contrib/string/string_io.c
@@ -14,17 +14,19 @@
#include "utils/palloc.h"
#include "utils/builtins.h"
+#include "string_io.h"
+
/* define this if you want to see iso-8859 characters */
#define ISO8859
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
-#define VALUE(char) ((char) - '0')
-#define DIGIT(val) ((val) + '0')
-#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#define VALUE(char) ((char) - '0')
+#define DIGIT(val) ((val) + '0')
+#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
#ifndef ISO8859
-#define NOTPRINTABLE(c) (!isprint(c))
+#define NOTPRINTABLE(c) (!isprint(c))
#else
-#define NOTPRINTABLE(c) (!isprint(c) && ((c) < 0xa0))
+#define NOTPRINTABLE(c) (!isprint(c) && ((c) < 0xa0))
#endif
/*
@@ -36,129 +38,115 @@
* The function is used by output methods of various string types.
*
* Arguments:
- * data - input data (can be NULL)
- * size - optional size of data. A negative value indicates
- * that data is a null terminated string.
+ * data - input data (can be NULL)
+ * size - optional size of data. A negative value indicates
+ * that data is a null terminated string.
*
* Returns:
- * a pointer to a new string containing the printable
- * representation of data.
+ * a pointer to a new string containing the printable
+ * representation of data.
*/
-char *
+char *
string_output(char *data, int size)
{
- register unsigned char c,
- *p,
- *r,
- *result;
- register int l,
- len;
-
- if (data == NULL)
- {
- result = (char *) palloc(2);
- result[0] = '-';
- result[1] = '\0';
- return (result);
- }
-
- if (size < 0)
- {
- size = strlen(data);
- }
+ register unsigned char c, *p, *r, *result;
+ register int l, len;
- /* adjust string length for escapes */
- len = size;
- for (p = data, l = size; l > 0; p++, l--)
- {
- switch (*p)
- {
- case '\\':
- case '"':
- case '{':
- case '}':
- case '\b':
- case '\f':
- case '\n':
- case '\r':
- case '\t':
- case '\v':
- len++;
- break;
- default:
- if (NOTPRINTABLE(*p))
- {
- len += 3;
- }
- }
+ if (data == NULL) {
+ result = (char *) palloc(2);
+ result[0] = '-';
+ result[1] = '\0';
+ return (result);
+ }
+
+ if (size < 0) {
+ size = strlen(data);
+ }
+
+ /* adjust string length for escapes */
+ len = size;
+ for (p=data,l=size; l>0; p++,l--) {
+ switch (*p) {
+ case '\\':
+ case '"' :
+ case '{':
+ case '}':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ len++;
+ break;
+ default:
+ if (NOTPRINTABLE(*p)) {
+ len += 3;
+ }
}
- len++;
-
- result = (char *) palloc(len);
-
- for (p = data, r = result, l = size; (l > 0) && (c = *p); p++, l--)
- {
- switch (c)
- {
- case '\\':
- case '"':
- case '{':
- case '}':
- *r++ = '\\';
- *r++ = c;
- break;
- case '\b':
- *r++ = '\\';
- *r++ = 'b';
- break;
- case '\f':
- *r++ = '\\';
- *r++ = 'f';
- break;
- case '\n':
- *r++ = '\\';
- *r++ = 'n';
- break;
- case '\r':
- *r++ = '\\';
- *r++ = 'r';
- break;
- case '\t':
- *r++ = '\\';
- *r++ = 't';
- break;
- case '\v':
- *r++ = '\\';
- *r++ = 'v';
- break;
- default:
- if (NOTPRINTABLE(c))
- {
- *r = '\\';
- r += 3;
- *r-- = DIGIT(c & 07);
- c >>= 3;
- *r-- = DIGIT(c & 07);
- c >>= 3;
- *r = DIGIT(c & 03);
- r += 3;
- }
- else
- {
- *r++ = c;
- }
- }
+ }
+ len++;
+
+ result = (char *) palloc(len);
+
+ for (p=data,r=result,l=size; (l > 0) && (c = *p); p++,l--) {
+ switch (c) {
+ case '\\':
+ case '"' :
+ case '{':
+ case '}':
+ *r++ = '\\';
+ *r++ = c;
+ break;
+ case '\b':
+ *r++ = '\\';
+ *r++ = 'b';
+ break;
+ case '\f':
+ *r++ = '\\';
+ *r++ = 'f';
+ break;
+ case '\n':
+ *r++ = '\\';
+ *r++ = 'n';
+ break;
+ case '\r':
+ *r++ = '\\';
+ *r++ = 'r';
+ break;
+ case '\t':
+ *r++ = '\\';
+ *r++ = 't';
+ break;
+ case '\v':
+ *r++ = '\\';
+ *r++ = 'v';
+ break;
+ default:
+ if (NOTPRINTABLE(c)) {
+ *r = '\\';
+ r += 3;
+ *r-- = DIGIT(c & 07);
+ c >>= 3;
+ *r-- = DIGIT(c & 07);
+ c >>= 3;
+ *r = DIGIT(c & 03);
+ r += 3;
+ } else {
+ *r++ = c;
+ }
}
- *r = '\0';
+ }
+ *r = '\0';
- return ((char *) result);
+ return((char *) result);
}
/*
* string_input() --
*
- * This function accepts a C string in input and copies it into a new
+ * This function accepts a C string in input and copies it into a new
* object allocated with palloc() translating all escape sequences.
* An optional header can be allocatd before the string, for example
* to hold the length of a varlena object.
@@ -167,231 +155,211 @@ string_output(char *data, int size)
* receive strings in internal form.
*
* Arguments:
- * str - input string possibly with escapes
- * size - the required size of new data. A value of 0
- * indicates a variable size string, while a
- * negative value indicates a variable size string
- * of size not greater than this absolute value.
- * hdrsize - size of an optional header to be allocated before
- * the data. It must then be filled by the caller.
- * rtn_size - an optional pointer to an int variable where the
- * size of the new string is stored back.
+ * str - input string possibly with escapes
+ * size - the required size of new data. A value of 0
+ * indicates a variable size string, while a
+ * negative value indicates a variable size string
+ * of size not greater than this absolute value.
+ * hdrsize - size of an optional header to be allocated before
+ * the data. It must then be filled by the caller.
+ * rtn_size - an optional pointer to an int variable where the
+ * size of the new string is stored back.
*
* Returns:
- * a pointer to the new string or the header.
+ * a pointer to the new string or the header.
*/
-char *
+char *
string_input(char *str, int size, int hdrsize, int *rtn_size)
{
- register unsigned char *p,
- *r;
- unsigned char *result;
- int len;
-
- if ((str == NULL) || (hdrsize < 0))
- {
- return (char *) NULL;
- }
-
- /* Compute result size */
- len = strlen(str);
- for (p = str; *p;)
- {
- if (*p++ == '\\')
- {
- if (ISOCTAL(*p))
- {
- if (ISOCTAL(*(p + 1)))
- {
- p++;
- len--;
- }
- if (ISOCTAL(*(p + 1)))
- {
- p++;
- len--;
- }
- }
- if (*p)
- p++;
- len--;
+ register unsigned char *p, *r;
+ unsigned char *result;
+ int len;
+
+ if ((str == NULL) || (hdrsize < 0)) {
+ return (char *) NULL;
+ }
+
+ /* Compute result size */
+ len = strlen(str);
+ for (p=str; *p; ) {
+ if (*p++ == '\\') {
+ if (ISOCTAL(*p)) {
+ if (ISOCTAL(*(p+1))) {
+ p++;
+ len--;
}
+ if (ISOCTAL(*(p+1))) {
+ p++;
+ len--;
+ }
+ }
+ if (*p) p++;
+ len--;
}
-
- /* result has variable length */
- if (size == 0)
- {
- size = len + 1;
- }
- else
- /* result has variable length with maximum size */
- if (size < 0)
- {
- size = MIN(len, -size) + 1;
- }
-
- result = (char *) palloc(hdrsize + size);
- memset(result, 0, hdrsize + size);
- if (rtn_size)
- {
- *rtn_size = size;
- }
-
- r = result + hdrsize;
- for (p = str; *p;)
- {
- register unsigned char c;
-
- if ((c = *p++) == '\\')
- {
- switch (c = *p++)
- {
- case '\0':
- p--;
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- c = VALUE(c);
- if (isdigit(*p))
- {
- c = (c << 3) + VALUE(*p++);
- }
- if (isdigit(*p))
- {
- c = (c << 3) + VALUE(*p++);
- }
- *r++ = c;
- break;
- case 'b':
- *r++ = '\b';
- break;
- case 'f':
- *r++ = '\f';
- break;
- case 'n':
- *r++ = '\n';
- break;
- case 'r':
- *r++ = '\r';
- break;
- case 't':
- *r++ = '\t';
- break;
- case 'v':
- *r++ = '\v';
- break;
- default:
- *r++ = c;
- }
+ }
+
+ /* result has variable length */
+ if (size == 0) {
+ size = len+1;
+ } else
+
+ /* result has variable length with maximum size */
+ if (size < 0) {
+ size = MIN(len, - size)+1;
+ }
+
+ result = (char *) palloc(hdrsize+size);
+ memset(result, 0, hdrsize+size);
+ if (rtn_size) {
+ *rtn_size = size;
+ }
+
+ r = result + hdrsize;
+ for (p=str; *p; ) {
+ register unsigned char c;
+ if ((c = *p++) == '\\') {
+ switch (c = *p++) {
+ case '\0':
+ p--;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ c = VALUE(c);
+ if (isdigit(*p)) {
+ c = (c<<3) + VALUE(*p++);
}
- else
- {
- *r++ = c;
+ if (isdigit(*p)) {
+ c = (c<<3) + VALUE(*p++);
}
+ *r++ = c;
+ break;
+ case 'b':
+ *r++ = '\b';
+ break;
+ case 'f':
+ *r++ = '\f';
+ break;
+ case 'n':
+ *r++ = '\n';
+ break;
+ case 'r':
+ *r++ = '\r';
+ break;
+ case 't':
+ *r++ = '\t';
+ break;
+ case 'v':
+ *r++ = '\v';
+ break;
+ default:
+ *r++ = c;
+ }
+ } else {
+ *r++ = c;
}
+ }
- return ((char *) result);
+ return((char *) result);
}
-char *
+char *
c_charout(int32 c)
{
- char str[2];
+ char str[2];
- str[0] = (char) c;
- str[1] = '\0';
+ str[0] = (char) c;
+ str[1] = '\0';
- return (string_output(str, 1));
+ return (string_output(str, 1));
}
-char *
+char *
c_char2out(uint16 s)
{
- return (string_output((char *) &s, 2));
+ return (string_output((char *) &s, 2));
}
-char *
+char *
c_char4out(uint32 s)
{
- return (string_output((char *) &s, 4));
+ return (string_output((char *) &s, 4));
}
-char *
+char *
c_char8out(char *s)
{
- return (string_output(s, 8));
+ return (string_output(s, 8));
}
-char *
+char *
c_char16out(char *s)
{
- return (string_output(s, 16));
+ return (string_output(s, 16));
}
/*
* This can be used for text, bytea, SET and unknown data types
*/
-char *
-c_textout(struct varlena * vlena)
+char *
+c_textout(struct varlena *vlena)
{
- int len = 0;
- char *s = NULL;
-
- if (vlena)
- {
- len = VARSIZE(vlena) - VARHDRSZ;
- s = VARDATA(vlena);
- }
- return (string_output(s, len));
+ int len = 0;
+ char *s = NULL;
+
+ if (vlena) {
+ len = VARSIZE(vlena) - VARHDRSZ;
+ s = VARDATA(vlena);
+ }
+ return (string_output(s, len));
}
/*
* This can be used for varchar and bpchar strings
*/
-char *
+char *
c_varcharout(char *s)
{
- int len;
+ int len = 0;
- if (s)
- {
- len = *(int32 *) s - 4;
- s += 4;
- }
- return (string_output(s, len));
+ if (s) {
+ len = *(int32*)s - 4;
+ s += 4;
+ }
+ return (string_output(s, len));
}
-#ifdef 0
+#if 0
struct varlena *
c_textin(char *str)
{
- struct varlena *result;
- int len;
+ struct varlena *result;
+ int len;
- if (str == NULL)
- {
- return ((struct varlena *) NULL);
- }
+ if (str == NULL) {
+ return ((struct varlena *) NULL);
+ }
- result = (struct varlena *) string_input(str, 0, VARHDRSZ, &len);
- VARSIZE(result) = len;
+ result = (struct varlena *) string_input(str, 0, VARHDRSZ, &len);
+ VARSIZE(result) = len;
- return (result);
+ return (result);
}
-char *
+char *
c_char16in(char *str)
{
- return (string_input(str, 16, 0, NULL));
+ return (string_input(str, 16, 0, NULL));
}
-
#endif
+
+
+/* end of file */
diff --git a/contrib/string/string_io.h b/contrib/string/string_io.h
new file mode 100644
index 00000000000..974f1f42623
--- /dev/null
+++ b/contrib/string/string_io.h
@@ -0,0 +1,19 @@
+#ifndef STRING_IO_H
+#define STRING_IO_H
+
+char *string_output(char *data, int size);
+char *string_input(char *str, int size, int hdrsize, int *rtn_size);
+char *c_charout(int32 c);
+char *c_char2out(uint16 s);
+char *c_char4out(uint32 s);
+char *c_char8out(char *s);
+char *c_char16out(char *s);
+char *c_textout(struct varlena *vlena);
+char *c_varcharout(char *s);
+
+#if 0
+struct varlena *c_textin(char *str);
+char *c_char16in(char *str);
+#endif
+
+#endif
diff --git a/contrib/string/string_io.sql.in b/contrib/string/string_io.sql.in
new file mode 100644
index 00000000000..ad1a51607cd
--- /dev/null
+++ b/contrib/string/string_io.sql.in
@@ -0,0 +1,104 @@
+-- SQL code to define the new string I/O functions
+
+-- This is not needed because escapes are handled by the parser
+--
+-- create function c_textin(opaque)
+-- returns text
+-- as 'MODULE_PATHNAME'
+-- language 'c';
+
+create function c_charout(opaque) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function c_char2out(opaque) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function c_char4out(opaque) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function c_char8out(opaque) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function c_char16out(opaque) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function c_textout(opaque) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+create function c_varcharout(opaque) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+
+-- Define a function which sets the new output routines for char types
+--
+-- select c_mode();
+--
+create function c_mode() returns text
+ as 'update pg_type set typoutput=''c_charout'' where typname=''char'';
+ update pg_type set typoutput=''c_char2out'' where typname=''char2'';
+ update pg_type set typoutput=''c_char4out'' where typname=''char4'';
+ update pg_type set typoutput=''c_char8out'' where typname=''char8'';
+ update pg_type set typoutput=''c_char16out'' where typname=''char16'';
+ update pg_type set typoutput=''c_textout'' where typname=''text'';
+ update pg_type set typoutput=''c_textout'' where typname=''bytea'';
+ update pg_type set typoutput=''c_textout'' where typname=''unknown'';
+ update pg_type set typoutput=''c_textout'' where typname=''SET'';
+ update pg_type set typoutput=''c_varcharout'' where typname=''varchar'';
+ update pg_type set typoutput=''c_varcharout'' where typname=''bpchar'';
+ select ''c_mode''::text'
+ language 'sql';
+
+-- Define a function which restores the original routines for char types
+--
+-- select pg_mode();
+--
+create function pg_mode() returns text
+ as 'update pg_type set typoutput=''charout'' where typname=''char'';
+ update pg_type set typoutput=''char2out'' where typname=''char2'';
+ update pg_type set typoutput=''char4out'' where typname=''char4'';
+ update pg_type set typoutput=''char8out'' where typname=''char8'';
+ update pg_type set typoutput=''char16out'' where typname=''char16'';
+ update pg_type set typoutput=''textout'' where typname=''text'';
+ update pg_type set typoutput=''textout'' where typname=''bytea'';
+ update pg_type set typoutput=''textout'' where typname=''unknown'';
+ update pg_type set typoutput=''textout'' where typname=''SET'';
+ update pg_type set typoutput=''varcharout'' where typname=''varchar'';
+ update pg_type set typoutput=''varcharout'' where typname=''bpchar'';
+ select ''pg_mode''::text'
+ language 'sql';
+
+
+-- Use these if you want do the updates manually
+--
+-- update pg_type set typoutput='charout' where typname='char';
+-- update pg_type set typoutput='char2out' where typname='char2';
+-- update pg_type set typoutput='char4out' where typname='char4';
+-- update pg_type set typoutput='char8out' where typname='char8';
+-- update pg_type set typoutput='char16out' where typname='char16';
+-- update pg_type set typoutput='textout' where typname='text';
+-- update pg_type set typoutput='textout' where typname='bytea';
+-- update pg_type set typoutput='textout' where typname='unknown';
+-- update pg_type set typoutput='textout' where typname='SET';
+-- update pg_type set typoutput='varcharout' where typname='varchar';
+-- update pg_type set typoutput='varcharout' where typname='bpchar';
+--
+-- update pg_type set typoutput='c_charout' where typname='char';
+-- update pg_type set typoutput='c_char2out' where typname='char2';
+-- update pg_type set typoutput='c_char4out' where typname='char4';
+-- update pg_type set typoutput='c_char8out' where typname='char8';
+-- update pg_type set typoutput='c_char16out' where typname='char16';
+-- update pg_type set typoutput='c_textout' where typname='text';
+-- update pg_type set typoutput='c_textout' where typname='bytea';
+-- update pg_type set typoutput='c_textout' where typname='unknown';
+-- update pg_type set typoutput='c_textout' where typname='SET';
+-- update pg_type set typoutput='c_varcharout' where typname='varchar';
+-- update pg_type set typoutput='c_varcharout' where typname='bpchar';
+
+-- end of file
diff --git a/contrib/userlock/Makefile b/contrib/userlock/Makefile
new file mode 100644
index 00000000000..0865bde7321
--- /dev/null
+++ b/contrib/userlock/Makefile
@@ -0,0 +1,62 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for new string I/O functions.
+#
+#-------------------------------------------------------------------------
+
+PGDIR = ../..
+SRCDIR = $(PGDIR)/src
+
+include $(SRCDIR)/Makefile.global
+
+INCLUDE_OPT = -I ./ \
+ -I $(SRCDIR)/ \
+ -I $(SRCDIR)/include \
+ -I $(SRCDIR)/port/$(PORTNAME)
+
+CFLAGS += $(INCLUDE_OPT)
+
+ifeq ($(PORTNAME), linux)
+ ifdef LINUX_ELF
+ ifeq ($(CC), gcc)
+ CFLAGS += -fPIC
+ endif
+ endif
+endif
+
+ifeq ($(PORTNAME), i386_solaris)
+ CFLAGS+= -fPIC
+endif
+
+MODNAME = user_locks
+
+MODULE = $(MODNAME)$(DLSUFFIX)
+
+all: module sql
+
+module: $(MODULE)
+
+sql: $(MODNAME).sql
+
+install: $(MODULE)
+ cp -p $(MODULE) $(LIBDIR)
+ cd $(LIBDIR); strip $(MODULE)
+
+%.sql: %.sql.in
+ sed "s|MODULE_PATHNAME|$(LIBDIR)/$(MODULE)|" < $< > $@
+
+.SUFFIXES: $(DLSUFFIX)
+
+%$(DLSUFFIX): %.c
+ cc $(CFLAGS) -shared -o $@ $<
+
+depend dep:
+ $(CC) -MM $(INCLUDE_OPT) *.c >depend
+
+clean:
+ rm -f $(MODULE) $(MODNAME).sql
+
+ifeq (depend,$(wildcard depend))
+include depend
+endif
diff --git a/contrib/userlock/user_locks.c b/contrib/userlock/user_locks.c
new file mode 100644
index 00000000000..efc9b0a4644
--- /dev/null
+++ b/contrib/userlock/user_locks.c
@@ -0,0 +1,100 @@
+/*
+ * user_locks.c --
+ *
+ * This loadable module, together with my user-lock.patch applied to the
+ * backend, provides support for user-level long-term cooperative locks.
+ *
+ * Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "postgres.h"
+#include "miscadmin.h"
+#include "storage/lock.h"
+#include "storage/lmgr.h"
+#include "storage/proc.h"
+#include "storage/block.h"
+#include "storage/multilev.h"
+#include "utils/elog.h"
+
+#include "user_locks.h"
+
+#define USER_LOCKS_TABLE_ID 0
+
+extern Oid MyDatabaseId;
+
+int
+user_lock(unsigned int id1, unsigned int id2, LOCKT lockt)
+{
+ LOCKTAG tag;
+
+ memset(&tag,0,sizeof(LOCKTAG));
+ tag.relId = 0;
+ tag.dbId = MyDatabaseId;
+ tag.tupleId.ip_blkid.bi_hi = id2 >> 16;
+ tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff;
+ tag.tupleId.ip_posid = (unsigned short) (id1 & 0xffff);
+
+ return LockAcquire(USER_LOCKS_TABLE_ID, &tag, lockt);
+}
+
+int
+user_unlock(unsigned int id1, unsigned int id2, LOCKT lockt)
+{
+ LOCKTAG tag;
+
+ memset(&tag, 0,sizeof(LOCKTAG));
+ tag.relId = 0;
+ tag.dbId = MyDatabaseId;
+ tag.tupleId.ip_blkid.bi_hi = id2 >> 16;
+ tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff;
+ tag.tupleId.ip_posid = (unsigned short) (id1 & 0xffff);
+
+ return LockRelease(USER_LOCKS_TABLE_ID, &tag, lockt);
+}
+
+int
+user_write_lock(unsigned int id1, unsigned int id2)
+{
+ return user_lock(id1, id2, WRITE_LOCK);
+}
+
+
+int
+user_write_unlock(unsigned int id1, unsigned int id2)
+{
+ return user_unlock(id1, id2, WRITE_LOCK);
+}
+
+int
+user_write_lock_oid(Oid oid)
+{
+ return user_lock(0, oid, WRITE_LOCK);
+}
+
+int
+user_write_unlock_oid(Oid oid)
+{
+ return user_unlock(0, oid, WRITE_LOCK);
+}
+
+int
+user_unlock_all()
+{
+ PROC *proc;
+ SHMEM_OFFSET location;
+
+ ShmemPIDLookup(getpid(),&location);
+ if (location == INVALID_OFFSET) {
+ elog(NOTICE, "UserUnlockAll: unable to get proc ptr");
+ return -1;
+ }
+
+ proc = (PROC *) MAKE_PTR(location);
+ return LockReleaseAll(USER_LOCKS_TABLE_ID, &proc->lockQueue);
+}
+
+/* end of file */
diff --git a/contrib/userlock/user_locks.doc b/contrib/userlock/user_locks.doc
new file mode 100644
index 00000000000..15ffe48f13b
--- /dev/null
+++ b/contrib/userlock/user_locks.doc
@@ -0,0 +1,30 @@
+User locks, by Massimo Dal Zotto <dz@cs.unitn.it>
+
+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 (this example is written in TclX):
+
+ set rec [sql "select ...,user_write_lock_oid(oid) from table where id=$id"]
+ if {[keylget rec user_write_lock_oid] == 1} {
+ # the write lock has been acquired with the record, start
+ # a long editing session, then update the database and
+ # release the lock.
+ sql "update table set ... where id=$id"
+ sql "select user_write_unlock_oid([keylget rec oid])"
+ } else {
+ # the record has been read but the write lock couldn't be acquired,
+ # so it should not be modified by the application.
+ messageBox "This record is in use by another user, retry later"
+ }
+
+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 record and there
+may be some locks not released if the backend or the application crashes
+before resetting the 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.
+Note that this type of locks are handled cooperatively by the application
+and do not interfere with the normal locks used by postgres. So an user
+could still modify an user-locked record if he wanted to ignore the lock.
diff --git a/contrib/userlock/user_locks.h b/contrib/userlock/user_locks.h
new file mode 100644
index 00000000000..ab890483fa4
--- /dev/null
+++ b/contrib/userlock/user_locks.h
@@ -0,0 +1,12 @@
+#ifndef USER_LOCKS_H
+#define USER_LOCKS_H
+
+int user_lock(unsigned int id1, unsigned int id2, LOCKT lockt);
+int user_unlock(unsigned int id1, unsigned int id2, LOCKT lockt);
+int user_write_lock(unsigned int id1, unsigned int id2);
+int user_write_unlock(unsigned int id1, unsigned int id2);
+int user_write_lock_oid(Oid oid);
+int user_write_unlock_oid(Oid oid);
+int user_unlock_all(void);
+
+#endif
diff --git a/contrib/userlock/user_locks.sql.in b/contrib/userlock/user_locks.sql.in
new file mode 100644
index 00000000000..da8d105de9c
--- /dev/null
+++ b/contrib/userlock/user_locks.sql.in
@@ -0,0 +1,69 @@
+-- SQL code to define the user locks functions
+
+-- select user_lock(group,id,type);
+--
+create function user_lock(int4,int4,int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_unlock(group,id,type);
+--
+create function user_unlock(int4,int4,int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_write_lock(group,id);
+--
+create function user_write_lock(int4,int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_write_unlock(group,id);
+--
+create function user_write_unlock(int4,int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_write_lock(group,oid);
+--
+create function user_write_lock(int4,oid) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_write_unlock(group,oid);
+--
+create function user_write_unlock(int4,oid) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_write_lock_oid(oid);
+--
+create function user_write_lock_oid(oid) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_write_unlock_oid(oid);
+--
+create function user_write_unlock_oid(oid) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_write_lock_oid(int4);
+--
+create function user_write_lock_oid(int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_write_unlock_oid(int4);
+--
+create function user_write_unlock_oid(int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- select user_unlock_all();
+--
+create function user_unlock_all() returns int4
+ as 'MODULE_PATHNAME'
+ language 'c';
+
+-- end of file