Commit eec4c736 authored by Marc G. Fournier's avatar Marc G. Fournier

From: Massimo Dal Zotto <dz@cs.unitn.it>

Here is a tar file the new directories, which substitute the old ones
in contrib. Please remove the old directories array, datetime, miscutil,
string and userlock before unpacking the tar file in contrib.

Note that as the modules are now installed in lib/modules I install all
my sql code in lib/sql. In my opinion also the other contributors should
follow these rules.
parent 3067ac8e
...@@ -12,7 +12,7 @@ array - ...@@ -12,7 +12,7 @@ array -
datetime - datetime -
Date & time functions Date & time functions
by Sergio Lenzi <lenzi@bsi.com.br> by Massimo Dal Zotto <dz@cs.unitn.it>
earthdistance - earthdistance -
Operator for computing earth distance for two points Operator for computing earth distance for two points
...@@ -66,10 +66,6 @@ pginterface - ...@@ -66,10 +66,6 @@ pginterface -
A crude C/4GL A crude C/4GL
by Bruce Momjian <root@candle.pha.pa.us> by Bruce Momjian <root@candle.pha.pa.us>
sequence -
Set a new sequence value
by Massimo Dal Zotto <dz@cs.unitn.it>
soundex - soundex -
Prototype for soundex function Prototype for soundex function
...@@ -77,7 +73,7 @@ spi - ...@@ -77,7 +73,7 @@ spi -
A general trigger function autoinc() and so on. A general trigger function autoinc() and so on.
string - string -
New input/output conversion routines for strings C-like input/output conversion routines for strings
by Massimo Dal Zotto <dz@cs.unitn.it> by Massimo Dal Zotto <dz@cs.unitn.it>
unixdate - unixdate -
......
...@@ -15,36 +15,35 @@ INCLUDE_OPT = -I ./ \ ...@@ -15,36 +15,35 @@ INCLUDE_OPT = -I ./ \
-I $(SRCDIR)/include \ -I $(SRCDIR)/include \
-I $(SRCDIR)/port/$(PORTNAME) -I $(SRCDIR)/port/$(PORTNAME)
CFLAGS += $(INCLUDE_OPT) CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
ifeq ($(PORTNAME), linux)
ifdef LINUX_ELF
ifeq ($(CC), gcc)
CFLAGS += -fPIC
endif
endif
endif
ifeq ($(PORTNAME), i386_solaris)
CFLAGS+= -fPIC
endif
MODNAME = array_iterator MODNAME = array_iterator
MODULE = $(MODNAME)$(DLSUFFIX) MODULE = $(MODNAME)$(DLSUFFIX)
MODDIR = $(LIBDIR)/modules
SQLDIR = $(LIBDIR)/sql
all: module sql all: module sql
module: $(MODULE) module: $(MODULE)
sql: $(MODNAME).sql sql: $(MODNAME).sql
install: $(MODULE) install: $(MODULE) $(MODDIR) $(SQLDIR)
cp -p $(MODULE) $(LIBDIR)/modules cp -p $(MODULE) $(MODDIR)/
cd $(LIBDIR)/modules; strip $(MODULE) strip $(MODDIR)/$(MODULE)
cp -p $(MODNAME).sql $(SQLDIR)/
$(MODDIR):
mkdir -p $@
$(SQLDIR):
mkdir -p $@
%.sql: %.sql.in %.sql: %.sql.in
sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX) .SUFFIXES: $(DLSUFFIX)
...@@ -55,7 +54,7 @@ depend dep: ...@@ -55,7 +54,7 @@ depend dep:
$(CC) -MM $(INCLUDE_OPT) *.c >depend $(CC) -MM $(INCLUDE_OPT) *.c >depend
clean: clean:
rm -f $(MODULE) $(MODNAME).sql rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend)) ifeq (depend,$(wildcard depend))
include depend include depend
......
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
* elements of the array and the value and compute a result as * elements of the array and the value and compute a result as
* the logical OR or AND of the iteration results. * 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> #include <ctype.h>
...@@ -33,8 +36,7 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value) ...@@ -33,8 +36,7 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
TypeTupleForm typ_struct; TypeTupleForm typ_struct;
bool typbyval; bool typbyval;
int typlen; int typlen;
func_ptr proc_fn; FmgrInfo finfo;
int pronargs;
int nitems, int nitems,
i, i,
result; result;
...@@ -70,9 +72,8 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value) ...@@ -70,9 +72,8 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
typbyval = typ_struct->typbyval; typbyval = typ_struct->typbyval;
/* Lookup the function entry point */ /* Lookup the function entry point */
proc_fn = (func_ptr) NULL; fmgr_info(proc, &finfo);
fmgr_info(proc, &pronargs); /* (proc, &proc_fn, &pronargs); */ if ((finfo.fn_oid == 0) || (finfo.fn_nargs != 2))
if ((proc_fn == NULL) || (pronargs != 2))
{ {
elog(ERROR, "array_iterator: fmgr_info lookup failed for oid %d", proc); elog(ERROR, "array_iterator: fmgr_info lookup failed for oid %d", proc);
return (0); return (0);
...@@ -88,21 +89,21 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value) ...@@ -88,21 +89,21 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
switch (typlen) switch (typlen)
{ {
case 1: case 1:
result = (int) (*proc_fn) (*p, value); result = (int) (*(finfo.fn_addr)) (*p, value);
break; break;
case 2: case 2:
result = (int) (*proc_fn) (*(int16 *) p, value); result = (int) (*(finfo.fn_addr)) (*(int16 *) p, value);
break; break;
case 3: case 3:
case 4: case 4:
result = (int) (*proc_fn) (*(int32 *) p, value); result = (int) (*(finfo.fn_addr)) (*(int32 *) p, value);
break; break;
} }
p += typlen; p += typlen;
} }
else else
{ {
result = (int) (*proc_fn) (p, value); result = (int) (*(finfo.fn_addr)) (p, value);
if (typlen > 0) if (typlen > 0)
p += typlen; p += typlen;
else else
...@@ -166,47 +167,6 @@ array_all_textregexeq(ArrayType *array, char *value) ...@@ -166,47 +167,6 @@ array_all_textregexeq(ArrayType *array, char *value)
array, (Datum) value); 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 * Iterator functions for type _int4
*/ */
...@@ -320,3 +280,11 @@ array_all_int4le(ArrayType *array, int4 value) ...@@ -320,3 +280,11 @@ array_all_int4le(ArrayType *array, int4 value)
} }
/* end of file */ /* 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 create function array_texteq(_text, text) returns bool
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
...@@ -38,47 +45,7 @@ create operator **~ ( ...@@ -38,47 +45,7 @@ create operator **~ (
rightarg=text, rightarg=text,
procedure=array_all_textregexeq); procedure=array_all_textregexeq);
-- Define the array functions *=, **=, *> and **> for type _int4
-- 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 create function array_int4eq(_int4, int4) returns bool
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
...@@ -128,6 +95,8 @@ create function array_all_int4le(_int4, int4) returns bool ...@@ -128,6 +95,8 @@ create function array_all_int4le(_int4, int4) returns bool
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
language 'c'; language 'c';
-- Define the operators corresponding to the above functions
--
create operator *= ( create operator *= (
leftarg=_int4, leftarg=_int4,
rightarg=int4, rightarg=int4,
......
...@@ -15,36 +15,35 @@ INCLUDE_OPT = -I ./ \ ...@@ -15,36 +15,35 @@ INCLUDE_OPT = -I ./ \
-I $(SRCDIR)/include \ -I $(SRCDIR)/include \
-I $(SRCDIR)/port/$(PORTNAME) -I $(SRCDIR)/port/$(PORTNAME)
CFLAGS += $(INCLUDE_OPT) CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
ifeq ($(PORTNAME), linux)
ifdef LINUX_ELF
ifeq ($(CC), gcc)
CFLAGS += -fPIC
endif
endif
endif
ifeq ($(PORTNAME), i386_solaris)
CFLAGS+= -fPIC
endif
MODNAME = datetime_functions MODNAME = datetime_functions
MODULE = $(MODNAME)$(DLSUFFIX) MODULE = $(MODNAME)$(DLSUFFIX)
MODDIR = $(LIBDIR)/modules
SQLDIR = $(LIBDIR)/sql
all: module sql all: module sql
module: $(MODULE) module: $(MODULE)
sql: $(MODNAME).sql sql: $(MODNAME).sql
install: $(MODULE) install: $(MODULE) $(MODDIR) $(SQLDIR)
cp -p $(MODULE) $(LIBDIR)/modules cp -p $(MODULE) $(MODDIR)/
cd $(LIBDIR)/modules; strip $(MODULE) strip $(MODDIR)/$(MODULE)
cp -p $(MODNAME).sql $(SQLDIR)/
$(MODDIR):
mkdir -p $@
$(SQLDIR):
mkdir -p $@
%.sql: %.sql.in %.sql: %.sql.in
sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX) .SUFFIXES: $(DLSUFFIX)
...@@ -55,7 +54,7 @@ depend dep: ...@@ -55,7 +54,7 @@ depend dep:
$(CC) -MM $(INCLUDE_OPT) *.c >depend $(CC) -MM $(INCLUDE_OPT) *.c >depend
clean: clean:
rm -f $(MODULE) $(MODNAME).sql rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend)) ifeq (depend,$(wildcard depend))
include depend include depend
......
...@@ -3,10 +3,13 @@ ...@@ -3,10 +3,13 @@
* *
* This file defines new functions for the time and date data types. * 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 <string.h>
#include <limits.h> #include <limits.h>
#ifdef HAVE_FLOAT_H #ifdef HAVE_FLOAT_H
...@@ -102,7 +105,6 @@ hhmm_out(TimeADT *time) ...@@ -102,7 +105,6 @@ hhmm_out(TimeADT *time)
sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
result = palloc(strlen(buf) + 1); result = palloc(strlen(buf) + 1);
strcpy(result, buf); strcpy(result, buf);
return (result); return (result);
...@@ -220,3 +222,11 @@ currentdate() ...@@ -220,3 +222,11 @@ currentdate()
} }
/* end of file */ /* 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 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,
This functions replaces the original ones from the postgresql.org month,day from a date. There is also a time_difference and functions
because the date & time structures has changed. to convert a time to minutes or seconds.
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)
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 -- 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 create function hhmm_in(opaque) returns time
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
...@@ -58,16 +65,14 @@ create function currentdate() returns date ...@@ -58,16 +65,14 @@ create function currentdate() returns date
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
language 'c'; language 'c';
-- Define new operator - for time.
-- Define a new operator - for time
-- --
create operator - ( create operator - (
leftarg=time, leftarg=time,
rightarg=time, rightarg=time,
procedure=time_difference); 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 hhmm_mode();
-- select time_mode(); -- select time_mode();
...@@ -84,7 +89,6 @@ create function time_mode() returns text ...@@ -84,7 +89,6 @@ create function time_mode() returns text
select ''time_mode''::text' select ''time_mode''::text'
language 'sql'; language 'sql';
-- Use these to do the updates manually -- Use these to do the updates manually
-- --
-- update pg_type set typinput ='hhmm_in' where typname='time'; -- update pg_type set typinput ='hhmm_in' where typname='time';
......
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Makefile-- # Makefile --
# Makefile for array iterator functions. #
# Makefile for the misc_util module.
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -15,36 +16,35 @@ INCLUDE_OPT = -I ./ \ ...@@ -15,36 +16,35 @@ INCLUDE_OPT = -I ./ \
-I $(SRCDIR)/include \ -I $(SRCDIR)/include \
-I $(SRCDIR)/port/$(PORTNAME) -I $(SRCDIR)/port/$(PORTNAME)
CFLAGS += $(INCLUDE_OPT) CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
ifeq ($(PORTNAME), linux)
ifdef LINUX_ELF
ifeq ($(CC), gcc)
CFLAGS += -fPIC
endif
endif
endif
ifeq ($(PORTNAME), i386_solaris)
CFLAGS+= -fPIC
endif
MODNAME = misc_utils MODNAME = misc_utils
MODULE = $(MODNAME)$(DLSUFFIX) MODULE = $(MODNAME)$(DLSUFFIX)
MODDIR = $(LIBDIR)/modules
SQLDIR = $(LIBDIR)/sql
all: module sql all: module sql
module: $(MODULE) module: $(MODULE)
sql: $(MODNAME).sql sql: $(MODNAME).sql
install: $(MODULE) install: $(MODULE) $(MODDIR) $(SQLDIR)
cp -p $(MODULE) $(LIBDIR)/modules cp -p $(MODULE) $(MODDIR)/
cd $(LIBDIR)/modules; strip $(MODULE) strip $(MODDIR)/$(MODULE)
cp -p $(MODNAME).sql $(SQLDIR)/
$(MODDIR):
mkdir -p $@
$(SQLDIR):
mkdir -p $@
%.sql: %.sql.in %.sql: %.sql.in
sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX) .SUFFIXES: $(DLSUFFIX)
...@@ -55,7 +55,7 @@ depend dep: ...@@ -55,7 +55,7 @@ depend dep:
$(CC) -MM $(INCLUDE_OPT) *.c >depend $(CC) -MM $(INCLUDE_OPT) *.c >depend
clean: clean:
rm -f $(MODULE) $(MODNAME).sql assert_test.so rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend)) ifeq (depend,$(wildcard depend))
include depend include depend
......
/*
* 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 */
#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 <unistd.h>
...@@ -12,9 +15,15 @@ ...@@ -12,9 +15,15 @@
#include "utils/palloc.h" #include "utils/palloc.h"
#include "misc_utils.h" #include "misc_utils.h"
#include "assert_test.h"
extern int ExecutorLimit(int limit); extern int ExecutorLimit(int limit);
extern void Async_Unlisten(char *relname, int pid); extern void Async_Unlisten(char *relname, int pid);
extern int assertTest(int val);
#ifdef ASSERT_CHECKING_TEST
extern int assertEnable(int val);
#endif
int int
query_limit(int limit) query_limit(int limit)
...@@ -47,4 +56,26 @@ min(int x, int y) ...@@ -47,4 +56,26 @@ min(int x, int y)
return ((x < y) ? x : y); 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 */ /* end of file */
/*
* Local variables:
* tab-width: 4
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/
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>
...@@ -6,5 +6,17 @@ int backend_pid(void); ...@@ -6,5 +6,17 @@ int backend_pid(void);
int unlisten(char *relname); int unlisten(char *relname);
int max(int x, int y); int max(int x, int y);
int min(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 #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' as 'MODULE_PATHNAME'
language 'C'; 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' as 'MODULE_PATHNAME'
language 'C'; 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' as 'MODULE_PATHNAME'
language 'C'; 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' as 'MODULE_PATHNAME'
language 'C'; 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' as 'MODULE_PATHNAME'
language 'C'; language 'C';
-- Unlisten from all relations for this backend -- Enable/disable Postgres assert checking.
-- --
create function unlisten() returns int4 create function assert_enable(int4) returns int4
as 'delete from pg_listener where listenerpid = backend_pid(); as 'MODULE_PATHNAME'
select 0' language 'C';
language 'sql';
-- Test Postgres assert checking.
--
-- create function assert_test(int4) returns int4
-- as 'MODULE_PATHNAME'
-- language 'C';
-- end of file -- end of file
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Makefile-- # Makefile --
# Makefile for new string I/O functions. # Makefile for string I/O module.
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -15,36 +15,35 @@ INCLUDE_OPT = -I ./ \ ...@@ -15,36 +15,35 @@ INCLUDE_OPT = -I ./ \
-I $(SRCDIR)/include \ -I $(SRCDIR)/include \
-I $(SRCDIR)/port/$(PORTNAME) -I $(SRCDIR)/port/$(PORTNAME)
CFLAGS += $(INCLUDE_OPT) CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
ifeq ($(PORTNAME), linux)
ifdef LINUX_ELF
ifeq ($(CC), gcc)
CFLAGS += -fPIC
endif
endif
endif
ifeq ($(PORTNAME), i386_solaris)
CFLAGS+= -fPIC
endif
MODNAME = string_io MODNAME = string_io
MODULE = $(MODNAME)$(DLSUFFIX) MODULE = $(MODNAME)$(DLSUFFIX)
MODDIR = $(LIBDIR)/modules
SQLDIR = $(LIBDIR)/sql
all: module sql all: module sql
module: $(MODULE) module: $(MODULE)
sql: $(MODNAME).sql sql: $(MODNAME).sql
install: $(MODULE) install: $(MODULE) $(MODDIR) $(SQLDIR)
cp -p $(MODULE) $(LIBDIR)/modules cp -p $(MODULE) $(MODDIR)/
cd $(LIBDIR)/modules; strip $(MODULE) strip $(MODDIR)/$(MODULE)
cp -p $(MODNAME).sql $(SQLDIR)/
$(MODDIR):
mkdir -p $@
$(SQLDIR):
mkdir -p $@
%.sql: %.sql.in %.sql: %.sql.in
sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX) .SUFFIXES: $(DLSUFFIX)
...@@ -55,7 +54,7 @@ depend dep: ...@@ -55,7 +54,7 @@ depend dep:
$(CC) -MM $(INCLUDE_OPT) *.c >depend $(CC) -MM $(INCLUDE_OPT) *.c >depend
clean: clean:
rm -f $(MODULE) $(MODNAME).sql rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend)) ifeq (depend,$(wildcard depend))
include depend include depend
......
/* /*
* string_io.c -- * 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> #include <ctype.h>
...@@ -33,14 +36,14 @@ ...@@ -33,14 +36,14 @@
* string_output() -- * string_output() --
* *
* This function takes a pointer to a string data and an optional * 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. * translating all escape sequences to C-like \nnn or \c escapes.
* The function is used by output methods of various string types. * The function is used by output methods of various string types.
* *
* Arguments: * Arguments:
* data - input data (can be NULL) * data - input data (can be NULL)
* size - optional size of data. A negative value indicates * size - optional size of data. A negative value indicates
* that data is a null terminated string. * that data is a null terminated string.
* *
* Returns: * Returns:
* a pointer to a new string containing the printable * a pointer to a new string containing the printable
...@@ -165,13 +168,13 @@ string_output(char *data, int size) ...@@ -165,13 +168,13 @@ string_output(char *data, int size)
* Arguments: * Arguments:
* str - input string possibly with escapes * str - input string possibly with escapes
* size - the required size of new data. A value of 0 * size - the required size of new data. A value of 0
* indicates a variable size string, while a * indicates a variable size string, while a
* negative value indicates a variable size string * negative value indicates a variable size string
* of size not greater than this absolute value. * of size not greater than this absolute value.
* hdrsize - size of an optional header to be allocated before * 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 * 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: * Returns:
* a pointer to the new string or the header. * a pointer to the new string or the header.
...@@ -293,32 +296,8 @@ c_charout(int32 c) ...@@ -293,32 +296,8 @@ c_charout(int32 c)
return (string_output(str, 1)); 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 * char *
...@@ -368,13 +347,19 @@ c_textin(char *str) ...@@ -368,13 +347,19 @@ c_textin(char *str)
return (result); return (result);
} }
char * int32 *
c_char16in(char *str) c_charin(char *str)
{ {
return (string_input(str, 16, 0, NULL)); return (string_input(str, 1, 0, NULL));
} }
#endif #endif
/* end of file */ /* end of file */
/*
* Local variables:
* tab-width: 4
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/
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>
...@@ -14,7 +14,14 @@ char *c_varcharout(char *s); ...@@ -14,7 +14,14 @@ char *c_varcharout(char *s);
#if 0 #if 0
struct varlena *c_textin(char *str); struct varlena *c_textin(char *str);
char *c_char16in(char *str); char *c_char16in(char *str);
#endif #endif
#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 -- 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) -- Copyright (c) 1998, Massimo Dal Zotto <dz@cs.unitn.it>
-- returns text --
-- as 'MODULE_PATHNAME' -- This file is distributed under the GNU General Public License
-- language 'c'; -- either version 2, or (at your option) any later version.
-- Define the new output functions.
--
create function c_charout(opaque) returns int4 create function c_charout(opaque) returns int4
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
language 'c'; 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 create function c_textout(opaque) returns int4
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
language 'c'; language 'c';
...@@ -35,70 +21,59 @@ create function c_varcharout(opaque) returns int4 ...@@ -35,70 +21,59 @@ create function c_varcharout(opaque) returns int4
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
language 'c'; 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(); -- select c_mode();
-- --
create function c_mode() returns text create function c_mode() returns text
as 'update pg_type set typoutput=''c_charout'' where typname=''char''; as 'update pg_type set typoutput=''c_textout'' where typname=''SET'';
update pg_type set typoutput=''c_char2out'' where typname=''char2''; update pg_type set typoutput=''c_varcharout'' where typname=''bpchar'';
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=''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=''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=''varchar'';
update pg_type set typoutput=''c_varcharout'' where typname=''bpchar'';
select ''c_mode''::text' select ''c_mode''::text'
language 'sql'; 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(); -- select pg_mode();
-- --
create function pg_mode() returns text create function pg_mode() returns text
as 'update pg_type set typoutput=''charout'' where typname=''char''; as 'update pg_type set typoutput=''textout'' where typname=''SET'';
update pg_type set typoutput=''char2out'' where typname=''char2''; update pg_type set typoutput=''varcharout'' where typname=''bpchar'';
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=''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=''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=''varchar'';
update pg_type set typoutput=''varcharout'' where typname=''bpchar'';
select ''pg_mode''::text' select ''pg_mode''::text'
language 'sql'; language 'sql';
-- Use these to do the changes manually.
-- Use these if you want do the updates 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='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='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='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='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_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='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='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='varchar';
-- update pg_type set typoutput='c_varcharout' where typname='bpchar';
-- end of file -- end of file
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Makefile-- # Makefile --
# Makefile for new string I/O functions. # Makefile for the user_locks module.
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -15,36 +15,35 @@ INCLUDE_OPT = -I ./ \ ...@@ -15,36 +15,35 @@ INCLUDE_OPT = -I ./ \
-I $(SRCDIR)/include \ -I $(SRCDIR)/include \
-I $(SRCDIR)/port/$(PORTNAME) -I $(SRCDIR)/port/$(PORTNAME)
CFLAGS += $(INCLUDE_OPT) CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
ifeq ($(PORTNAME), linux)
ifdef LINUX_ELF
ifeq ($(CC), gcc)
CFLAGS += -fPIC
endif
endif
endif
ifeq ($(PORTNAME), i386_solaris)
CFLAGS+= -fPIC
endif
MODNAME = user_locks MODNAME = user_locks
MODULE = $(MODNAME)$(DLSUFFIX) MODULE = $(MODNAME)$(DLSUFFIX)
MODDIR = $(LIBDIR)/modules
SQLDIR = $(LIBDIR)/sql
all: module sql all: module sql
module: $(MODULE) module: $(MODULE)
sql: $(MODNAME).sql sql: $(MODNAME).sql
install: $(MODULE) install: $(MODULE) $(MODDIR) $(SQLDIR)
cp -p $(MODULE) $(LIBDIR)/modules cp -p $(MODULE) $(MODDIR)/
cd $(LIBDIR)/modules; strip $(MODULE) strip $(MODDIR)/$(MODULE)
cp -p $(MODNAME).sql $(SQLDIR)/
$(MODDIR):
mkdir -p $@
$(SQLDIR):
mkdir -p $@
%.sql: %.sql.in %.sql: %.sql.in
sed "s|MODULE_PATHNAME|$(LIBDIR)/modules/$(MODULE)|" < $< > $@ sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX) .SUFFIXES: $(DLSUFFIX)
...@@ -55,7 +54,7 @@ depend dep: ...@@ -55,7 +54,7 @@ depend dep:
$(CC) -MM $(INCLUDE_OPT) *.c >depend $(CC) -MM $(INCLUDE_OPT) *.c >depend
clean: clean:
rm -f $(MODULE) $(MODNAME).sql rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend)) ifeq (depend,$(wildcard depend))
include depend include depend
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
* This loadable module, together with my user-lock.patch applied to the * This loadable module, together with my user-lock.patch applied to the
* backend, provides support for user-level long-term cooperative locks. * 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 <stdio.h>
...@@ -14,46 +17,40 @@ ...@@ -14,46 +17,40 @@
#include "postgres.h" #include "postgres.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/lock.h" #include "storage/lock.h"
#include "storage/lmgr.h"
#include "storage/proc.h" #include "storage/proc.h"
#include "storage/block.h"
#include "storage/multilev.h" #include "storage/multilev.h"
#include "utils/elog.h" #include "utils/elog.h"
#include "user_locks.h" #include "user_locks.h"
#define USER_LOCKS_TABLE_ID 0
extern Oid MyDatabaseId;
int int
user_lock(unsigned int id1, unsigned int id2, LOCKT lockt) user_lock(unsigned int id1, unsigned int id2, LOCKMODE lockmode)
{ {
LOCKTAG tag; LOCKTAG tag;
memset(&tag, 0, sizeof(LOCKTAG)); memset(&tag, 0, sizeof(LOCKTAG));
tag.dbId = MyDatabaseId;
tag.relId = 0; tag.relId = 0;
tag.dbId = MyDatabaseId;
tag.tupleId.ip_blkid.bi_hi = id2 >> 16; tag.tupleId.ip_blkid.bi_hi = id2 >> 16;
tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff; tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff;
tag.tupleId.ip_posid = (unsigned short) (id1 & 0xffff); tag.tupleId.ip_posid = (unsigned short) (id1 & 0xffff);
return LockAcquire(USER_LOCKS_TABLE_ID, &tag, lockt); return LockAcquire(USER_LOCKMETHOD, &tag, lockmode);
} }
int int
user_unlock(unsigned int id1, unsigned int id2, LOCKT lockt) user_unlock(unsigned int id1, unsigned int id2, LOCKMODE lockmode)
{ {
LOCKTAG tag; LOCKTAG tag;
memset(&tag, 0, sizeof(LOCKTAG)); memset(&tag, 0, sizeof(LOCKTAG));
tag.dbId = MyDatabaseId;
tag.relId = 0; tag.relId = 0;
tag.dbId = MyDatabaseId;
tag.tupleId.ip_blkid.bi_hi = id2 >> 16; tag.tupleId.ip_blkid.bi_hi = id2 >> 16;
tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff; tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff;
tag.tupleId.ip_posid = (unsigned short) (id1 & 0xffff); tag.tupleId.ip_posid = (unsigned short) (id1 & 0xffff);
return LockRelease(USER_LOCKS_TABLE_ID, &tag, lockt); return LockRelease(USER_LOCKMETHOD, &tag, lockmode);
} }
int int
...@@ -87,7 +84,7 @@ user_unlock_all() ...@@ -87,7 +84,7 @@ user_unlock_all()
PROC *proc; PROC *proc;
SHMEM_OFFSET location; SHMEM_OFFSET location;
ShmemPIDLookup(getpid(), &location); ShmemPIDLookup(MyProcPid, &location);
if (location == INVALID_OFFSET) if (location == INVALID_OFFSET)
{ {
elog(NOTICE, "UserUnlockAll: unable to get proc ptr"); elog(NOTICE, "UserUnlockAll: unable to get proc ptr");
...@@ -95,7 +92,15 @@ user_unlock_all() ...@@ -95,7 +92,15 @@ user_unlock_all()
} }
proc = (PROC *) MAKE_PTR(location); proc = (PROC *) MAKE_PTR(location);
return LockReleaseAll(USER_LOCKS_TABLE_ID, &proc->lockQueue); return LockReleaseAll(USER_LOCKMETHOD, &proc->lockQueue);
} }
/* end of file */ /* end of file */
/*
* Local variables:
* tab-width: 4
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/
...@@ -2,29 +2,49 @@ User locks, by Massimo Dal Zotto <dz@cs.unitn.it> ...@@ -2,29 +2,49 @@ User locks, by Massimo Dal Zotto <dz@cs.unitn.it>
This loadable module, together with my user-lock.patch applied to the This loadable module, together with my user-lock.patch applied to the
backend, provides support for user-level long-term cooperative locks. 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): select some_fields, user_write_lock_oid(oid) from table where id='key';
set rec [sql "select ...,user_write_lock_oid(oid) from table where id=$id"] Now if the returned user_write_lock_oid field is 1 you have acquired an
if {[keylget rec user_write_lock_oid] == 1} { user lock on the oid of the selected tuple and can now do some long operation
# the write lock has been acquired with the record, start on it, like let the data being edited by the user.
# a long editing session, then update the database and If it is 0 it means that the lock has been already acquired by some other
# release the lock. process and you should not use that item until the other has finished.
sql "update table set ... where id=$id" Note that in this case the query returns 0 immediately without waiting on
sql "select user_write_unlock_oid([keylget rec oid])" the lock. This is good if the lock is held for long time.
} else { After you have finished your work on that item you can do:
# the record has been read but the write lock couldn't be acquired,
# so it should not be modified by the application. update table set some_fields where id='key';
messageBox "This record is in use by another user, retry later" 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 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 this case you have the overhead of the updates to the records and there
may be some locks not released if the backend or the application crashes could be some locks not released if the backend or the application crashes
before resetting the flag. before resetting the lock flag.
It could also be done with a begin/end block but in this case the entire 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 table would be locked by postgres and it is not acceptable to do this for
a long period because other transactions would block completely. 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 The generic user locks use two values, group and id, to identify a lock,
could still modify an user-locked record if he wanted to ignore the 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 #ifndef USER_LOCKS_H
#define USER_LOCKS_H #define USER_LOCKS_H
int user_lock(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, LOCKT lockt); int user_unlock(unsigned int id1, unsigned int id2, LOCKMODE lockmode);
int user_write_lock(unsigned int id1, unsigned int id2); int user_write_lock(unsigned int id1, unsigned int id2);
int user_write_unlock(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_lock_oid(Oid oid);
...@@ -10,3 +10,11 @@ int user_write_unlock_oid(Oid oid); ...@@ -10,3 +10,11 @@ int user_write_unlock_oid(Oid oid);
int user_unlock_all(void); int user_unlock_all(void);
#endif #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 create function user_lock(int4,int4,int4) returns int4
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
language 'c'; language 'c';
-- select user_unlock(group,id,type); -- select user_unlock(group,id,mode);
-- --
create function user_unlock(int4,int4,int4) returns int4 create function user_unlock(int4,int4,int4) returns int4
as 'MODULE_PATHNAME' as 'MODULE_PATHNAME'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment