From: Sandro Santilli Date: Fri, 15 Apr 2005 15:09:20 +0000 (+0000) Subject: Renamed examples/ to extras/. Added WFS_locks. X-Git-Tag: pgis_1_1_0~430 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ae330d306aff12580987ac4297d799e25d069280;p=postgis Renamed examples/ to extras/. Added WFS_locks. git-svn-id: http://svn.osgeo.org/postgis/trunk@1623 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/extras/WFS_locks/Makefile b/extras/WFS_locks/Makefile new file mode 100644 index 000000000..882a14979 --- /dev/null +++ b/extras/WFS_locks/Makefile @@ -0,0 +1,33 @@ +CFLAGS += -I$(shell pg_config --includedir-server) +CC = gcc +MODULE_FILENAME = $(PWD)/libWFS_locks.so + +ifneq ($(findstring 7.1,$(shell pg_config --version)),) + USE_VERSION=71 +else + ifneq ($(findstring 7.2,$(VERSION)),) + USE_VERSION=72 + else + ifneq ($(findstring 7.3,$(VERSION)),) + USE_VERSION=73 + else + ifneq ($(findstring 7.4,$(VERSION)),) + USE_VERSION=74 + else + USE_VERSION=80 + endif + endif + endif +endif + + +all: libWFS_locks.so WFS_locks.sql + +libWFS_locks.so: WFS_locks.c + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< + +WFS_locks.sql: WFS_locks.sql.in + cpp -P -traditional-cpp -DUSE_VERSION=$(USE_VERSION) $< | sed -e 's:@MODULE_FILENAME@:$(MODULE_FILENAME):g' | grep -v '^#' > $@ + +clean: + rm -f libWFS_locks.so WFS_locks.sql diff --git a/extras/WFS_locks/README b/extras/WFS_locks/README new file mode 100644 index 000000000..68ae60e95 --- /dev/null +++ b/extras/WFS_locks/README @@ -0,0 +1,40 @@ + +Thu Mar 24 17:25:48 CET 2005 +---------------------------- + +This module and associated pl/pgsql functions have been implemented +to provide long locking support required by Web Feature Service +specification (https://portal.opengeospatial.org/files/?artifact_id=7176) + +It is based on original work by David Blasby +and has been modified and packaged by Sandro Santilli . + + + Usage: + + -- Check updates and deletes of rows in + -- given table for being authorized. + -- Identify rows using value. + SELECT CheckAuth([], , ) + + -- Set lock/authorization for specific row in table + -- is a text value, is a timestamp + -- defaulting to now()+1hour. + -- Returns 1 if lock has been assigned, 0 otherwise + -- (already locked by other auth) + SELECT LockRow([],
, , , []) + + -- Remove all locks held by specified authorization id. + -- Returns the number of locks released. + SELECT UnlockRows() + + -- Add an authorization token to be used in current + -- transaction. + SELECT AddAuth() + + WARNING! users must use serializable transaction level + (see http://www.postgresql.org/docs/7.4/static/transaction-iso.html) + otherwise locking mechanism would break + + + --strk; diff --git a/extras/WFS_locks/WFS_locks.c b/extras/WFS_locks/WFS_locks.c new file mode 100644 index 000000000..69c85b9e0 --- /dev/null +++ b/extras/WFS_locks/WFS_locks.c @@ -0,0 +1,139 @@ +#include "postgres.h" +#include "executor/spi.h" /* this is what you need to work with SPI */ +#include "commands/trigger.h" /* ... and triggers */ +#include "utils/lsyscache.h" /* for get_namespace_name() */ + +//#define PGIS_DEBUG 1 + +Datum check_authorization(PG_FUNCTION_ARGS); + +/* + * This trigger will check for authorization before + * allowing UPDATE or DELETE of specific rows. + * Rows are identified by the provided column. + * Authorization info is extracted by the + * "authorization_table" + * + */ +PG_FUNCTION_INFO_V1(check_authorization); +Datum check_authorization(PG_FUNCTION_ARGS) +{ + TriggerData *trigdata = (TriggerData *) fcinfo->context; + char *colname; + HeapTuple rettuple; + TupleDesc tupdesc; + int SPIcode; + char query[1024]; + const char *pk_id = NULL; + SPITupleTable *tuptable; + HeapTuple tuple; + char *lockcode; + char *authtable = "authorization_table"; + + + /* Make sure trigdata is pointing at what I expect */ + if (!CALLED_AS_TRIGGER(fcinfo)) + elog(ERROR,"check_authorization: not fired by trigger manager"); + + if (! (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event) || + TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) ) + elog(ERROR,"check_authorization: not fired by update or delete"); + + rettuple = trigdata->tg_newtuple; + tupdesc = trigdata->tg_relation->rd_att; + + /* Connect to SPI manager */ + SPIcode = SPI_connect(); + + if (SPIcode != SPI_OK_CONNECT) + { + elog(ERROR,"check_authorization: could not connect to SPI"); + PG_RETURN_NULL() ; + } + + colname = trigdata->tg_trigger->tgargs[0]; + pk_id = SPI_getvalue(trigdata->tg_trigtuple, tupdesc, + SPI_fnumber(tupdesc, colname)); + +#if PGIS_DEBUG + elog(NOTICE,"check_authorization(%s.%s.%s=%s)", + nspname, relname, colname, pk_id); +#endif + + sprintf(query,"SELECT authid FROM \"%s\" WHERE expires >= now() AND toid = '%d' AND rid = '%s'", authtable, trigdata->tg_relation->rd_id, pk_id); + +#if PGIS_DEBUG > 1 + elog(NOTICE,"about to execute :%s", query); +#endif + + SPIcode = SPI_exec(query,0); + if (SPIcode !=SPI_OK_SELECT ) + elog(ERROR,"couldnt execute to test for lock :%s",query); + + if (!SPI_processed ) + { +#if PGIS_DEBUG + elog(NOTICE,"there is NOT a lock on row '%s'", pk_id); +#endif + SPI_finish(); + return PointerGetDatum(trigdata->tg_trigtuple); + } + + // there is a lock - check to see if I have rights to it! + + tuptable = SPI_tuptable; + tupdesc = SPI_tuptable->tupdesc; + tuple = tuptable->vals[0]; + lockcode = SPI_getvalue(tuple, tupdesc, 1); + +#if PGIS_DEBUG + elog(NOTICE,"there is a lock on this row!"); +#endif + + // check to see if temp_lock_have_table table exists + // (it might not exist if they own no locks + sprintf(query,"SELECT * FROM pg_class WHERE relname = 'temp_lock_have_table'"); + SPIcode = SPI_exec(query,0); + if (SPIcode != SPI_OK_SELECT ) + elog(ERROR,"couldnt execute to test for lockkey temp table :%s",query); + if (SPI_processed==0) + { + SPI_finish(); + + elog(ERROR,"Unauthorized modification (requires auth: '%s')", + lockcode); + elog(NOTICE,"Modificaton of row '%s' requires authorization '%s'", + pk_id, lockcode); + // ignore requested delete or update + return PointerGetDatum(trigdata->tg_trigtuple); + } + + sprintf(query, "SELECT * FROM temp_lock_have_table WHERE lockcode ='%s'",lockcode); + +#if PGIS_DEBUG + elog(NOTICE,"about to execute :%s", query); +#endif + + SPIcode = SPI_exec(query,0); + if (SPIcode != SPI_OK_SELECT ) + elog(ERROR,"couldnt execute to test for lock aquire: %s", query); + + if (SPI_processed >0) + { +#if PGIS_DEBUG + elog(NOTICE,"I own the lock - I can modify the row"); +#endif + SPI_finish(); + return PointerGetDatum(rettuple); + } + + SPI_finish(); + + elog(ERROR,"Unauthorized modification (requires auth: '%s')", + lockcode); + elog(NOTICE,"Modificaton of row '%s' requires authorization '%s'", + pk_id, lockcode); + // ignore the command + return PointerGetDatum(trigdata->tg_trigtuple); + +} diff --git a/extras/WFS_locks/WFS_locks.sql.in b/extras/WFS_locks/WFS_locks.sql.in new file mode 100644 index 000000000..dc8a91340 --- /dev/null +++ b/extras/WFS_locks/WFS_locks.sql.in @@ -0,0 +1,208 @@ +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- $Id$ +-- +-- PostGIS - Spatial Types for PostgreSQL +-- http://postgis.refractions.net +-- Copyright 2001-2003 Refractions Research Inc. +-- +-- This is free software; you can redistribute and/or modify it under +-- the terms of the GNU General Public Licence. See the COPYING file. +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#define CREATEFUNCTION CREATE OR REPLACE FUNCTION + +#if USE_VERSION > 72 +# define _IMMUTABLE_STRICT IMMUTABLE STRICT +# define _IMMUTABLE IMMUTABLE +# define _STABLE_STRICT STABLE STRICT +# define _STABLE STABLE +# define _VOLATILE_STRICT VOLATILE STRICT +# define _VOLATILE VOLATILE +# define _STRICT STRICT +#else +# define _IMMUTABLE_STRICT with(iscachable,isstrict) +# define _IMMUTABLE with(iscachable) +# define _STABLE_STRICT with(isstrict) +# define _STABLE +# define _VOLATILE_STRICT with(isstrict) +# define _VOLATILE +# define _STRICT with(isstrict) +#endif + + +----------------------------------------------------------------------- +-- LONG TERM LOCKING +----------------------------------------------------------------------- + +-- UnlockRows(authid) +-- removes all locks held by the given auth +-- returns the number of locks released +CREATEFUNCTION UnlockRows(text) + RETURNS int + AS ' +DECLARE + ret int; +BEGIN + EXECUTE ''DELETE FROM authorization_table where authid = '' || + quote_literal($1); + + GET DIAGNOSTICS ret = ROW_COUNT; + + RETURN ret; +END; +' +LANGUAGE 'plpgsql' _VOLATILE_STRICT; + +-- LockRow([schema], table, rowid, auth, [expires]) +-- Returns 1 if successfully obtained the lock, 0 otherwise +CREATEFUNCTION LockRow(text, text, text, text, timestamp) + RETURNS int + AS ' +DECLARE + myschema alias for $1; + mytable alias for $2; + myrid alias for $3; + authid alias for $4; + expires alias for $5; + ret int; + mytoid oid; + myrec RECORD; + +BEGIN + EXECUTE ''DELETE FROM authorization_table WHERE expires < now()''; + + SELECT c.oid INTO mytoid FROM pg_class c, pg_namespace n + WHERE c.relname = mytable + AND c.relnamespace = n.oid + AND n.nspname = myschema; + + -- RAISE NOTICE ''toid: %'', mytoid; + + FOR myrec IN SELECT * FROM authorization_table WHERE + toid = mytoid AND rid = myrid + LOOP + IF myrec.authid != authid THEN + RETURN 0; + ELSE + RETURN 1; + END IF; + END LOOP; + + EXECUTE ''INSERT INTO authorization_table VALUES (''|| + quote_literal(mytoid)||'',''||quote_literal(myrid)|| + '',''||quote_literal(expires)|| + '',''||quote_literal(authid) ||'')''; + + GET DIAGNOSTICS ret = ROW_COUNT; + + RETURN ret; +END;' +LANGUAGE 'plpgsql' _VOLATILE_STRICT; + +-- LockRow(schema, table, rid, authid); +CREATEFUNCTION LockRow(text, text, text, text) + RETURNS int + AS +'SELECT LockRow($1, $2, $3, $4, now()::timestamp+''1:00'');' + LANGUAGE 'sql' _VOLATILE_STRICT; + +-- LockRow(table, rid, authid); +CREATEFUNCTION LockRow(text, text, text) + RETURNS int + AS +#if USE_VERSION >= 73 +'SELECT LockRow(current_schema(), $1, $2, $3, now()::timestamp+''1:00'');' +#else +'SELECT LockRow('''', $1, $2, $3, now()::timestamp+''1:00'');' +#endif + LANGUAGE 'sql' _VOLATILE_STRICT; + +-- LockRow(schema, table, rid, expires); +CREATEFUNCTION LockRow(text, text, text, timestamp) + RETURNS int + AS +#if USE_VERSION >= 73 +'SELECT LockRow(current_schema(), $1, $2, $3, $4);' +#else +'SELECT LockRow('''', $1, $2, $3, $4);' +#endif + LANGUAGE 'sql' _VOLATILE_STRICT; + + +CREATEFUNCTION AddAuth(text) + RETURNS BOOLEAN + AS ' +DECLARE + lockid alias for $1; + okay boolean; + myrec record; +BEGIN + -- check to see if table exists + -- if not, CREATE TEMP TABLE mylock (transid xid, lockcode text) + okay := ''f''; + FOR myrec IN SELECT * FROM pg_class WHERE relname = ''temp_lock_have_table'' LOOP + okay := ''t''; + END LOOP; + IF (okay <> ''t'') THEN + CREATE TEMP TABLE temp_lock_have_table (lockcode text) + ON COMMIT DELETE ROWS; + END IF; + + -- INSERT INTO mylock VALUES ( $1) + EXECUTE ''INSERT INTO temp_lock_have_table VALUES ( ''|| + quote_literal(lockid) ||'')''; + + RETURN true::boolean; +END; +' +LANGUAGE PLPGSQL; + + +-- CheckAuth( ,
, ) +CREATEFUNCTION CheckAuth(text, text, text) + RETURNS INT + AS ' +DECLARE + schema text; +BEGIN + +#if USE_VERSION >= 73 + if ( $1 != '''' ) THEN + schema = $1; + ELSE + SELECT current_schema() into schema; + END IF; +#endif + + EXECUTE ''CREATE TRIGGER check_auth BEFORE UPDATE OR DELETE ON '' +#if USE_VERSION >= 73 + || quote_ident(schema) || ''.'' || quote_ident($2) +#else + || quote_ident($2) +#endif + ||'' FOR EACH ROW EXECUTE PROCEDURE CheckAuthTrigger('' + || quote_literal($3) || '')''; + RETURN 0; +END; +' +LANGUAGE 'plpgsql'; + +-- CheckAuth(
, ) +CREATEFUNCTION CheckAuth(text, text) + RETURNS INT + AS + 'SELECT CheckAuth('''', $1, $2)' + LANGUAGE 'SQL'; + +CREATEFUNCTION CheckAuthTrigger() + RETURNS trigger AS + '@MODULE_FILENAME@', 'check_authorization' + LANGUAGE C; + + +--------------------------------------------------------------- +-- END +--------------------------------------------------------------- + diff --git a/examples/ogc_test_suite/.cvsignore b/extras/ogc_test_suite/.cvsignore similarity index 100% rename from examples/ogc_test_suite/.cvsignore rename to extras/ogc_test_suite/.cvsignore diff --git a/examples/ogc_test_suite/1_schema.sql b/extras/ogc_test_suite/1_schema.sql similarity index 100% rename from examples/ogc_test_suite/1_schema.sql rename to extras/ogc_test_suite/1_schema.sql diff --git a/examples/ogc_test_suite/2_queries.sql b/extras/ogc_test_suite/2_queries.sql similarity index 100% rename from examples/ogc_test_suite/2_queries.sql rename to extras/ogc_test_suite/2_queries.sql diff --git a/examples/ogc_test_suite/3_cleanup.sql b/extras/ogc_test_suite/3_cleanup.sql similarity index 100% rename from examples/ogc_test_suite/3_cleanup.sql rename to extras/ogc_test_suite/3_cleanup.sql diff --git a/examples/ogc_test_suite/Makefile b/extras/ogc_test_suite/Makefile similarity index 100% rename from examples/ogc_test_suite/Makefile rename to extras/ogc_test_suite/Makefile diff --git a/examples/ogc_test_suite/README b/extras/ogc_test_suite/README similarity index 100% rename from examples/ogc_test_suite/README rename to extras/ogc_test_suite/README diff --git a/examples/wkb_reader/.cvsignore b/extras/wkb_reader/.cvsignore similarity index 100% rename from examples/wkb_reader/.cvsignore rename to extras/wkb_reader/.cvsignore diff --git a/examples/wkb_reader/Makefile b/extras/wkb_reader/Makefile similarity index 100% rename from examples/wkb_reader/Makefile rename to extras/wkb_reader/Makefile diff --git a/examples/wkb_reader/README b/extras/wkb_reader/README similarity index 100% rename from examples/wkb_reader/README rename to extras/wkb_reader/README diff --git a/examples/wkb_reader/printwkb.c b/extras/wkb_reader/printwkb.c similarity index 100% rename from examples/wkb_reader/printwkb.c rename to extras/wkb_reader/printwkb.c diff --git a/examples/wkb_reader/readwkb.c b/extras/wkb_reader/readwkb.c similarity index 100% rename from examples/wkb_reader/readwkb.c rename to extras/wkb_reader/readwkb.c diff --git a/examples/wkb_reader/wkbtest.h b/extras/wkb_reader/wkbtest.h similarity index 100% rename from examples/wkb_reader/wkbtest.h rename to extras/wkb_reader/wkbtest.h