datetime -
Date & time functions
- by Sergio Lenzi <lenzi@bsi.com.br>
+ by Massimo Dal Zotto <dz@cs.unitn.it>
earthdistance -
Operator for computing earth distance for two points
A crude C/4GL
by Bruce Momjian <root@candle.pha.pa.us>
-sequence -
- Set a new sequence value
- by Massimo Dal Zotto <dz@cs.unitn.it>
-
soundex -
Prototype for soundex function
A general trigger function autoinc() and so on.
string -
- New input/output conversion routines for strings
+ C-like input/output conversion routines for strings
by Massimo Dal Zotto <dz@cs.unitn.it>
unixdate -
-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
+CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
MODNAME = array_iterator
MODULE = $(MODNAME)$(DLSUFFIX)
+MODDIR = $(LIBDIR)/modules
+
+SQLDIR = $(LIBDIR)/sql
+
all: module sql
module: $(MODULE)
sql: $(MODNAME).sql
-install: $(MODULE)
- cp -p $(MODULE) $(LIBDIR)/modules
- cd $(LIBDIR)/modules; strip $(MODULE)
+install: $(MODULE) $(MODDIR) $(SQLDIR)
+ cp -p $(MODULE) $(MODDIR)/
+ strip $(MODDIR)/$(MODULE)
+ cp -p $(MODNAME).sql $(SQLDIR)/
+
+$(MODDIR):
+ mkdir -p $@
+
+$(SQLDIR):
+ mkdir -p $@
%.sql: %.sql.in
- sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@
+ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX)
$(CC) -MM $(INCLUDE_OPT) *.c >depend
clean:
- rm -f $(MODULE) $(MODNAME).sql
+ rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend))
include depend
* elements of the array and the value and compute a result as
* the logical OR or AND of the iteration results.
*
- * Copyright (c) 1997, Massimo Dal Zotto <dz@cs.unitn.it>
+ * Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+ *
+ * This file is distributed under the GNU General Public License
+ * either version 2, or (at your option) any later version.
*/
#include <ctype.h>
TypeTupleForm typ_struct;
bool typbyval;
int typlen;
- func_ptr proc_fn;
- int pronargs;
+ FmgrInfo finfo;
int nitems,
i,
result;
typbyval = typ_struct->typbyval;
/* Lookup the function entry point */
- proc_fn = (func_ptr) NULL;
- fmgr_info(proc, &pronargs); /* (proc, &proc_fn, &pronargs); */
- if ((proc_fn == NULL) || (pronargs != 2))
+ fmgr_info(proc, &finfo);
+ if ((finfo.fn_oid == 0) || (finfo.fn_nargs != 2))
{
elog(ERROR, "array_iterator: fmgr_info lookup failed for oid %d", proc);
return (0);
switch (typlen)
{
case 1:
- result = (int) (*proc_fn) (*p, value);
+ result = (int) (*(finfo.fn_addr)) (*p, value);
break;
case 2:
- result = (int) (*proc_fn) (*(int16 *) p, value);
+ result = (int) (*(finfo.fn_addr)) (*(int16 *) p, value);
break;
case 3:
case 4:
- result = (int) (*proc_fn) (*(int32 *) p, value);
+ result = (int) (*(finfo.fn_addr)) (*(int32 *) p, value);
break;
}
p += typlen;
}
else
{
- result = (int) (*proc_fn) (p, value);
+ result = (int) (*(finfo.fn_addr)) (p, value);
if (typlen > 0)
p += typlen;
else
array, (Datum) value);
}
-/*
- * Iterator functions for type _char16. Note that the regexp
- * operators take the second argument of type text.
- */
-
-int32
-array_char16eq(ArrayType *array, char *value)
-{
- return array_iterator((Oid) 20, /* char16 */
- (Oid) 1275, /* char16eq */
- 0, /* logical or */
- array, (Datum) value);
-}
-
-int32
-array_all_char16eq(ArrayType *array, char *value)
-{
- return array_iterator((Oid) 20, /* char16 */
- (Oid) 1275, /* char16eq */
- 1, /* logical and */
- array, (Datum) value);
-}
-
-int32
-array_char16regexeq(ArrayType *array, char *value)
-{
- return array_iterator((Oid) 20, /* char16 */
- (Oid) 1288, /* char16regexeq */
- 0, /* logical or */
- array, (Datum) value);
-}
-
-int32
-array_all_char16regexeq(ArrayType *array, char *value)
-{
- return array_iterator((Oid) 20, /* char16 */
- (Oid) 1288, /* char16regexeq */
- 1, /* logical and */
- array, (Datum) value);
-}
-
/*
* Iterator functions for type _int4
*/
}
/* end of file */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- SQL code to define the new array iterator functions and operators
+-- array_iterator.sql --
+--
+-- SQL code to define the array iterator functions and operators.
+--
+-- Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+--
+-- This file is distributed under the GNU General Public License
+-- either version 2, or (at your option) any later version.
--- define the array operators *=, **=, *~ and **~ for type _text
+-- Define the array functions *=, **=, *~ and **~ for type _text
--
create function array_texteq(_text, text) returns bool
as 'MODULE_PATHNAME'
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
+-- Define the array functions *=, **=, *> and **> for type _int4
--
create function array_int4eq(_int4, int4) returns bool
as 'MODULE_PATHNAME'
as 'MODULE_PATHNAME'
language 'c';
+-- Define the operators corresponding to the above functions
+--
create operator *= (
leftarg=_int4,
rightarg=int4,
-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
+CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
MODNAME = datetime_functions
MODULE = $(MODNAME)$(DLSUFFIX)
+MODDIR = $(LIBDIR)/modules
+
+SQLDIR = $(LIBDIR)/sql
+
all: module sql
module: $(MODULE)
sql: $(MODNAME).sql
-install: $(MODULE)
- cp -p $(MODULE) $(LIBDIR)/modules
- cd $(LIBDIR)/modules; strip $(MODULE)
+install: $(MODULE) $(MODDIR) $(SQLDIR)
+ cp -p $(MODULE) $(MODDIR)/
+ strip $(MODDIR)/$(MODULE)
+ cp -p $(MODNAME).sql $(SQLDIR)/
+
+$(MODDIR):
+ mkdir -p $@
+
+$(SQLDIR):
+ mkdir -p $@
%.sql: %.sql.in
- sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@
+ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX)
$(CC) -MM $(INCLUDE_OPT) *.c >depend
clean:
- rm -f $(MODULE) $(MODNAME).sql
+ rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend))
include depend
*
* This file defines new functions for the time and date data types.
*
- * Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
+ * Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+ *
+ * This file is distributed under the GNU General Public License
+ * either version 2, or (at your option) any later version.
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h>
#include <string.h>
#include <limits.h>
#ifdef HAVE_FLOAT_H
sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
result = palloc(strlen(buf) + 1);
-
strcpy(result, buf);
return (result);
}
/* end of file */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
-Date & time functions for use in Postgres version 6.1 & up
-
-This functions replaces the original ones from the postgresql.org
-because the date & time structures has changed.
-
-There is a Makefile that should be "ajusted"
-for directories where postgres home after install.
-
-In this case: /usr/postgres.
-
-Hope this can help,
-
-
-Sergio Lenzi (lenzi@bsi.com.br)
+I have written some new funtions for time and date data types which can
+be used to extract hour,minutes,seconds from time values, and year,
+month,day from a date. There is also a time_difference and functions
+to convert a time to minutes or seconds.
+There are also new input/output functions for the time data type which
+allow the insertion of time attributes with value 24:00:00.
+This can be useful if your application needs to compute time difference
+from two time values representing an elapsed time of 24 hours.
+Massimo Dal Zotto <dz@cs.unitn.it>
+-- datetime_functions.sql --
+--
-- SQL code to define the new date and time functions and operators
+--
+-- Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+--
+-- This file is distributed under the GNU General Public License
+-- either version 2, or (at your option) any later version.
--- Define the new functions
+-- Define the new time functions.
--
create function hhmm_in(opaque) returns time
as 'MODULE_PATHNAME'
as 'MODULE_PATHNAME'
language 'c';
-
--- Define a new operator - for time
+-- Define new operator - for time.
--
create operator - (
leftarg=time,
rightarg=time,
procedure=time_difference);
-
--- Define functions to switch from time to hhmm representation
+-- Define functions to switch from time to hhmm representation.
--
-- select hhmm_mode();
-- select time_mode();
select ''time_mode''::text'
language 'sql';
-
-- Use these to do the updates manually
--
-- update pg_type set typinput ='hhmm_in' where typname='time';
#-------------------------------------------------------------------------
#
-# Makefile--
-# Makefile for array iterator functions.
+# Makefile --
+#
+# Makefile for the misc_util module.
#
#-------------------------------------------------------------------------
-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
+CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
MODNAME = misc_utils
MODULE = $(MODNAME)$(DLSUFFIX)
+MODDIR = $(LIBDIR)/modules
+
+SQLDIR = $(LIBDIR)/sql
+
all: module sql
module: $(MODULE)
sql: $(MODNAME).sql
-install: $(MODULE)
- cp -p $(MODULE) $(LIBDIR)/modules
- cd $(LIBDIR)/modules; strip $(MODULE)
+install: $(MODULE) $(MODDIR) $(SQLDIR)
+ cp -p $(MODULE) $(MODDIR)/
+ strip $(MODDIR)/$(MODULE)
+ cp -p $(MODNAME).sql $(SQLDIR)/
+
+$(MODDIR):
+ mkdir -p $@
+
+$(SQLDIR):
+ mkdir -p $@
%.sql: %.sql.in
- sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@
+ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX)
$(CC) -MM $(INCLUDE_OPT) *.c >depend
clean:
- rm -f $(MODULE) $(MODNAME).sql assert_test.so
+ rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend))
include depend
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-#ifndef ASSERT_TEST_H
-#define ASSERT_TEST_H
-
-int assert_enable(int val);
-int assert_test(int val);
-
-#endif
/*
- * utils.c --
+ * misc_utils.c --
*
- * This file defines various Postgres utility functions.
+ * This file defines miscellaneous PostgreSQL utility functions.
*
- * Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
+ * Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+ *
+ * This file is distributed under the GNU General Public License
+ * either version 2, or (at your option) any later version.
*/
#include <unistd.h>
#include "utils/palloc.h"
#include "misc_utils.h"
+#include "assert_test.h"
extern int ExecutorLimit(int limit);
extern void Async_Unlisten(char *relname, int pid);
+extern int assertTest(int val);
+
+#ifdef ASSERT_CHECKING_TEST
+extern int assertEnable(int val);
+#endif
int
query_limit(int limit)
return ((x < y) ? x : y);
}
+int
+assert_enable(int val)
+{
+ return assertEnable(val);
+}
+
+#ifdef ASSERT_CHECKING_TEST
+int
+assert_test(int val)
+{
+ return assertTest(val);
+}
+#endif
+
/* end of file */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+Miscellaneous utility functions for PostgreSQL.
+
+query_limit(n)
+
+ sets a limit on the maximum numbers of query returned from
+ a backend. It can be used to limit the result size retrieved
+ by the application for poor input data or to avoid accidental
+ table product while playying with sql.
+
+backend_pid()
+
+ return the pid of our corresponding backend.
+
+unlisten(relname)
+
+ unlisten from a relation or from all relations if the argument
+ is null, empty or '*'.
+ It is now obsoleted by the new unlisten command but still useful
+ if you want unlisten a name computed by the query.
+ Note that a listen/notify relname can be any ascii string, not
+ just valid relation names.
+
+min(x,y)
+max(x,y)
+
+ return the min or max bteween two integers.
+
+assert_enable(bool)
+
+ enable/disable assert checkings in the backend, if it has been
+ compiled with USE_ASSERT_CHECKING.
+
+assert_test(bool)
+
+ test the assert enable/disable code, if the backend has been
+ compiled with ASSERT_CHECKING_TEST.
+
+--
+Massimo Dal Zotto <dz@cs.unitn.it>
int unlisten(char *relname);
int max(int x, int y);
int min(int x, int y);
+int assert_enable(int val);
+#ifdef ASSERT_CHECKING_TEST
+int assert_test(int val);
+#endif
#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- SQL code to define the new array iterator functions and operators
+-- misc_utils.sql --
+--
+-- SQL code to define misc functions.
+--
+-- Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+--
+-- This file is distributed under the GNU General Public License
+-- either version 2, or (at your option) any later version.
--- min(x,y)
+-- Set the maximum number of tuples returned by a single query.
--
-create function min(int4,int4) returns int4
+create function query_limit(int4) returns int4
as 'MODULE_PATHNAME'
language 'C';
--- max(x,y)
+-- Return the pid of the backend.
--
-create function max(int4,int4) returns int4
+create function backend_pid() returns int4
as 'MODULE_PATHNAME'
language 'C';
--- Set the maximum number of tuples returned by a single query
+-- Unlisten from a relation.
--
-create function query_limit(int4) returns int4
+create function "unlisten"(name) returns int4
as 'MODULE_PATHNAME'
language 'C';
--- Return the pid of the backend
+-- Unlisten from all relations for this backend.
--
-create function backend_pid() returns int4
+create function "unlisten"() returns int4
+ as 'select "unlisten"(''*'')'
+ language 'sql';
+
+-- min(x,y)
+--
+create function min(int4,int4) returns int4
as 'MODULE_PATHNAME'
language 'C';
--- Unlisten from a relation
+-- max(x,y)
--
-create function unlisten(name) returns int4
+create function max(int4,int4) returns int4
as 'MODULE_PATHNAME'
language 'C';
--- Unlisten from all relations for this backend
+-- Enable/disable Postgres assert checking.
--
-create function unlisten() returns int4
- as 'delete from pg_listener where listenerpid = backend_pid();
- select 0'
- language 'sql';
+create function assert_enable(int4) returns int4
+ as 'MODULE_PATHNAME'
+ language 'C';
+
+-- Test Postgres assert checking.
+--
+-- create function assert_test(int4) returns int4
+-- as 'MODULE_PATHNAME'
+-- language 'C';
-- end of file
#-------------------------------------------------------------------------
#
-# Makefile--
-# Makefile for new string I/O functions.
+# Makefile --
+# Makefile for string I/O module.
#
#-------------------------------------------------------------------------
-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
+CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
MODNAME = string_io
MODULE = $(MODNAME)$(DLSUFFIX)
+MODDIR = $(LIBDIR)/modules
+
+SQLDIR = $(LIBDIR)/sql
+
all: module sql
module: $(MODULE)
sql: $(MODNAME).sql
-install: $(MODULE)
- cp -p $(MODULE) $(LIBDIR)/modules
- cd $(LIBDIR)/modules; strip $(MODULE)
+install: $(MODULE) $(MODDIR) $(SQLDIR)
+ cp -p $(MODULE) $(MODDIR)/
+ strip $(MODDIR)/$(MODULE)
+ cp -p $(MODNAME).sql $(SQLDIR)/
+
+$(MODDIR):
+ mkdir -p $@
+
+$(SQLDIR):
+ mkdir -p $@
%.sql: %.sql.in
- sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@
+ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX)
$(CC) -MM $(INCLUDE_OPT) *.c >depend
clean:
- rm -f $(MODULE) $(MODNAME).sql
+ rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend))
include depend
/*
* string_io.c --
*
- * This file defines new input/output conversion routines for strings.
+ * This file defines C-like input/output conversion routines for strings.
*
- * Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
+ * Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+ *
+ * This file is distributed under the GNU General Public License
+ * either version 2, or (at your option) any later version.
*/
#include <ctype.h>
* string_output() --
*
* This function takes a pointer to a string data and an optional
- * data size and returns a printable representation of the data
+ * data size and returns a printable representation of the string
* translating all escape sequences to C-like \nnn or \c escapes.
* 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.
+ * that data is a null terminated string.
*
* Returns:
* a pointer to a new string containing the printable
* 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.
+ * 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.
+ * 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.
+ * size of the new string is stored back.
*
* Returns:
* a pointer to the new string or the header.
return (string_output(str, 1));
}
-char *
-c_char2out(uint16 s)
-{
- return (string_output((char *) &s, 2));
-}
-
-char *
-c_char4out(uint32 s)
-{
- return (string_output((char *) &s, 4));
-}
-
-char *
-c_char8out(char *s)
-{
- return (string_output(s, 8));
-}
-
-char *
-c_char16out(char *s)
-{
- return (string_output(s, 16));
-}
-
/*
- * This can be used for text, bytea, SET and unknown data types
+ * This can be used for SET, bytea, text and unknown data types
*/
char *
return (result);
}
-char *
-c_char16in(char *str)
+int32 *
+c_charin(char *str)
{
- return (string_input(str, 16, 0, NULL));
+ return (string_input(str, 1, 0, NULL));
}
-
#endif
-
/* end of file */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+These output functions can be used as substitution of the standard text
+output functions to get the value of text fields printed in the format
+used for C strings. This allows the output of queries or the exported
+files to be processed more easily using standard unix filter programs
+like perl or awk.
+
+If you use the standard functions instead you could find a single tuple
+splitted into many lines and the tabs embedded in the values could be
+confused with those used as field delimters.
+
+My function translates all non-printing characters into corresponding
+esacape sequences as defined by the C syntax. All you need to reconstruct
+the exact value in your application is a corresponding unescape function
+like the string_input defined in the source code.
+
+Massimo Dal Zotto <dz@cs.unitn.it>
#if 0
struct varlena *c_textin(char *str);
char *c_char16in(char *str);
-
#endif
#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
+-- string_io.sql --
+--
-- 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';
+-- Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+--
+-- This file is distributed under the GNU General Public License
+-- either version 2, or (at your option) any later version.
+-- Define the new output functions.
+--
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';
as 'MODULE_PATHNAME'
language 'c';
+-- This is not needed because escapes are handled by the parser
+--
+-- create function c_textin(opaque)
+-- returns text
+-- as 'MODULE_PATHNAME'
+-- language 'c';
--- Define a function which sets the new output routines for char types
+-- 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'';
+ as 'update pg_type set typoutput=''c_textout'' where typname=''SET'';
+ update pg_type set typoutput=''c_varcharout'' where typname=''bpchar'';
update pg_type set typoutput=''c_textout'' where typname=''bytea'';
+ update pg_type set typoutput=''c_charout'' where typname=''char'';
+ update pg_type set typoutput=''c_textout'' where typname=''text'';
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
+-- Define a function which restores the standard 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'';
+ as 'update pg_type set typoutput=''textout'' where typname=''SET'';
+ update pg_type set typoutput=''varcharout'' where typname=''bpchar'';
update pg_type set typoutput=''textout'' where typname=''bytea'';
+ update pg_type set typoutput=''charout'' where typname=''char'';
+ update pg_type set typoutput=''textout'' where typname=''text'';
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
+-- Use these to do the changes manually.
--
+-- update pg_type set typoutput='textout' where typname='SET';
+-- update pg_type set typoutput='varcharout' where typname='bpchar';
+-- update pg_type set typoutput='textout' where typname='bytea';
-- 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_textout' where typname='SET';
+-- update pg_type set typoutput='c_varcharout' where typname='bpchar';
+-- update pg_type set typoutput='c_textout' where typname='bytea';
-- 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
#-------------------------------------------------------------------------
#
-# Makefile--
-# Makefile for new string I/O functions.
+# Makefile --
+# Makefile for the user_locks module.
#
#-------------------------------------------------------------------------
-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
+CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
MODNAME = user_locks
MODULE = $(MODNAME)$(DLSUFFIX)
+MODDIR = $(LIBDIR)/modules
+
+SQLDIR = $(LIBDIR)/sql
+
all: module sql
module: $(MODULE)
sql: $(MODNAME).sql
-install: $(MODULE)
- cp -p $(MODULE) $(LIBDIR)/modules
- cd $(LIBDIR)/modules; strip $(MODULE)
+install: $(MODULE) $(MODDIR) $(SQLDIR)
+ cp -p $(MODULE) $(MODDIR)/
+ strip $(MODDIR)/$(MODULE)
+ cp -p $(MODNAME).sql $(SQLDIR)/
+
+$(MODDIR):
+ mkdir -p $@
+
+$(SQLDIR):
+ mkdir -p $@
%.sql: %.sql.in
- sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@
+ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX)
$(CC) -MM $(INCLUDE_OPT) *.c >depend
clean:
- rm -f $(MODULE) $(MODNAME).sql
+ rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend))
include depend
* 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>
+ * Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+ *
+ * This file is distributed under the GNU General Public License
+ * either version 2, or (at your option) any later version.
*/
#include <stdio.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)
+user_lock(unsigned int id1, unsigned int id2, LOCKMODE lockmode)
{
LOCKTAG tag;
memset(&tag, 0, sizeof(LOCKTAG));
+ tag.dbId = MyDatabaseId;
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);
+ return LockAcquire(USER_LOCKMETHOD, &tag, lockmode);
}
int
-user_unlock(unsigned int id1, unsigned int id2, LOCKT lockt)
+user_unlock(unsigned int id1, unsigned int id2, LOCKMODE lockmode)
{
LOCKTAG tag;
memset(&tag, 0, sizeof(LOCKTAG));
+ tag.dbId = MyDatabaseId;
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);
+ return LockRelease(USER_LOCKMETHOD, &tag, lockmode);
}
int
PROC *proc;
SHMEM_OFFSET location;
- ShmemPIDLookup(getpid(), &location);
+ ShmemPIDLookup(MyProcPid, &location);
if (location == INVALID_OFFSET)
{
elog(NOTICE, "UserUnlockAll: unable to get proc ptr");
}
proc = (PROC *) MAKE_PTR(location);
- return LockReleaseAll(USER_LOCKS_TABLE_ID, &proc->lockQueue);
+ return LockReleaseAll(USER_LOCKMETHOD, &proc->lockQueue);
}
/* end of file */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
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:
-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"
- }
+ select some_fields, user_write_lock_oid(oid) from table where id='key';
+
+Now if the returned user_write_lock_oid field is 1 you have acquired an
+user lock on the oid of the selected tuple and can now do some long operation
+on it, like let the data being edited by the user.
+If it is 0 it means that the lock has been already acquired by some other
+process and you should not use that item until the other has finished.
+Note that in this case the query returns 0 immediately without waiting on
+the lock. This is good if the lock is held for long time.
+After you have finished your work on that item you can do:
+
+ update table set some_fields where id='key';
+ select user_write_unlock_oid(oid) from table where id='key';
+
+You can also ignore the failure and go ahead but this could produce conflicts
+or inconsistent data in your application. User locks require a cooperative
+behavior between users. User locks don't interfere with the normal locks
+used by postgres for transaction processing.
This could also be done by setting a flag in the record itself but in
-this case you have the overhead of the updates to the record and there
-may be some locks not released if the backend or the application crashes
-before resetting the flag.
+this case you have the overhead of the updates to the records and there
+could be some locks not released if the backend or the application crashes
+before resetting the lock flag.
It could also be done with a begin/end block but in this case the entire
table would be locked by postgres and it is not acceptable to do this for
a long period because other transactions would block completely.
-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.
+
+The generic user locks use two values, group and id, to identify a lock,
+which correspond to ip_posid and ip_blkid of an ItemPointerData.
+Group is a 16 bit value while id is a 32 bit integer which can also
+contain an oid. The oid user lock function, which take an oid as argument,
+use a group equal to 0.
+
+The meaning of group and id is defined by the application. The user
+lock code just takes two numbers and tells you if the corresponding
+entity has been succesfully locked. What this mean is up to you.
+
+My succestion is that you use the group to identify an area of your
+application and the id to identify an object in this area.
+Or you can just lock the oid of the tuples which are by definition unique.
+
+Note also that a process can acquire more than one lock on the same entity
+and it must release the lock the corresponding number of times. This can
+be done calling the unlock funtion until it returns 0.
#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_lock(unsigned int id1, unsigned int id2, LOCKMODE lockmode);
+int user_unlock(unsigned int id1, unsigned int id2, LOCKMODE lockmode);
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_unlock_all(void);
#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- SQL code to define the user locks functions
+-- user_locks.sql --
+--
+-- SQL code to define the user locks functions.
+--
+-- Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
+--
+-- This file is distributed under the GNU General Public License
+-- either version 2, or (at your option) any later version.
--- select user_lock(group,id,type);
+-- select user_lock(group,id,mode);
--
create function user_lock(int4,int4,int4) returns int4
as 'MODULE_PATHNAME'
language 'c';
--- select user_unlock(group,id,type);
+-- select user_unlock(group,id,mode);
--
create function user_unlock(int4,int4,int4) returns int4
as 'MODULE_PATHNAME'