Update of contrib stuff from massimo.
authorBruce Momjian <bruce@momjian.us>
Wed, 5 Nov 1997 21:38:25 +0000 (21:38 +0000)
committerBruce Momjian <bruce@momjian.us>
Wed, 5 Nov 1997 21:38:25 +0000 (21:38 +0000)
33 files changed:
contrib/array/Makefile [new file with mode: 0644]
contrib/array/array_iterator.c
contrib/array/array_iterator.doc
contrib/array/array_iterator.h [new file with mode: 0644]
contrib/array/array_iterator.sql.in [new file with mode: 0644]
contrib/datetime/Makefile
contrib/datetime/datetime_functions.c
contrib/datetime/datetime_functions.h [new file with mode: 0644]
contrib/datetime/datetime_functions.sql.in [new file with mode: 0644]
contrib/miscutil/Makefile [new file with mode: 0644]
contrib/miscutil/assert_test.c [new file with mode: 0644]
contrib/miscutil/assert_test.h [new file with mode: 0644]
contrib/miscutil/misc_utils.c [new file with mode: 0644]
contrib/miscutil/misc_utils.h [new file with mode: 0644]
contrib/miscutil/misc_utils.sql.in [new file with mode: 0644]
contrib/pginterface/README.orig [new file with mode: 0644]
contrib/pginterface/pginsert.c.orig [new file with mode: 0644]
contrib/pginterface/pginterface.c.orig [new file with mode: 0644]
contrib/pginterface/pgnulltest.c.orig [new file with mode: 0644]
contrib/pginterface/pgwordcount.c.orig [new file with mode: 0644]
contrib/sequence/Makefile [new file with mode: 0644]
contrib/sequence/set_sequence.c [new file with mode: 0644]
contrib/sequence/set_sequence.h [new file with mode: 0644]
contrib/sequence/set_sequence.sql.in [new file with mode: 0644]
contrib/string/Makefile [new file with mode: 0644]
contrib/string/string_io.c
contrib/string/string_io.h [new file with mode: 0644]
contrib/string/string_io.sql.in [new file with mode: 0644]
contrib/userlock/Makefile [new file with mode: 0644]
contrib/userlock/user_locks.c [new file with mode: 0644]
contrib/userlock/user_locks.doc [new file with mode: 0644]
contrib/userlock/user_locks.h [new file with mode: 0644]
contrib/userlock/user_locks.sql.in [new file with mode: 0644]

diff --git a/contrib/array/Makefile b/contrib/array/Makefile
new file mode 100644 (file)
index 0000000..03c57e5
--- /dev/null
@@ -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
index f4ecfad903fbb58e72c1026e89884a5652de195d..de8dac95de0d371b0998e73bfdb022d23d753ab2 100644 (file)
@@ -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>
 #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, charvalue)
 {
-   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, charvalue)
 {
-   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, charvalue)
 {
-   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, charvalue)
 {
-   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, charvalue)
 {
-   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, charvalue)
 {
-   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, charvalue)
 {
-   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, charvalue)
 {
-   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 */
index 01c1b2195cfbef6822ca6c47660942231ddbd8ec..031301799c6fc673180f699de563dd9deae30e73 100644 (file)
@@ -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 (file)
index 0000000..0d9c58e
--- /dev/null
@@ -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 (file)
index 0000000..6489545
--- /dev/null
@@ -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
index 930d6e57cfd9e6c271cc980f9f221bdf59ff9474..52023b8e8aff37cad5143eea77e75930f64d3644 100644 (file)
@@ -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
index d2c097583cf91d61a3644b2c7c405cc132e8f3a5..e925d985bfb6fb7b0ca433663c48056bd5f574b8 100644 (file)
  * 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 (file)
index 0000000..6847498
--- /dev/null
@@ -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 (file)
index 0000000..81e40aa
--- /dev/null
@@ -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 (file)
index 0000000..982515a
--- /dev/null
@@ -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 (file)
index 0000000..fa2ec1f
--- /dev/null
@@ -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 (file)
index 0000000..2af2887
--- /dev/null
@@ -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 (file)
index 0000000..3b8f379
--- /dev/null
@@ -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 (file)
index 0000000..7dd583c
--- /dev/null
@@ -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 (file)
index 0000000..0c90ba5
--- /dev/null
@@ -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 (file)
index 0000000..c52b5d1
--- /dev/null
@@ -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 (file)
index 0000000..82838c2
--- /dev/null
@@ -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 (file)
index 0000000..cdc4193
--- /dev/null
@@ -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 (file)
index 0000000..96873ca
--- /dev/null
@@ -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 (file)
index 0000000..859cf90
--- /dev/null
@@ -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 (file)
index 0000000..e82817f
--- /dev/null
@@ -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 (file)
index 0000000..7468efb
--- /dev/null
@@ -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 (file)
index 0000000..f5c6294
--- /dev/null
@@ -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 (file)
index 0000000..0f1421b
--- /dev/null
@@ -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 (file)
index 0000000..b9ff534
--- /dev/null
@@ -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
index c45db69187c752666feca6835bd8603e20348e91..5dd6346b56fd1fc0935fa03158f6c5133450e4f3 100644 (file)
 #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
 
 /*
  * 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 (file)
index 0000000..974f1f4
--- /dev/null
@@ -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 (file)
index 0000000..ad1a516
--- /dev/null
@@ -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 (file)
index 0000000..0865bde
--- /dev/null
@@ -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 (file)
index 0000000..efc9b0a
--- /dev/null
@@ -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 (file)
index 0000000..15ffe48
--- /dev/null
@@ -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 (file)
index 0000000..ab89048
--- /dev/null
@@ -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 (file)
index 0000000..da8d105
--- /dev/null
@@ -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