]> granicus.if.org Git - postgis/commitdiff
Renamed examples/ to extras/. Added WFS_locks.
authorSandro Santilli <strk@keybit.net>
Fri, 15 Apr 2005 15:09:20 +0000 (15:09 +0000)
committerSandro Santilli <strk@keybit.net>
Fri, 15 Apr 2005 15:09:20 +0000 (15:09 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@1623 b70326c6-7e19-0410-871a-916f4a2858ee

16 files changed:
extras/WFS_locks/Makefile [new file with mode: 0644]
extras/WFS_locks/README [new file with mode: 0644]
extras/WFS_locks/WFS_locks.c [new file with mode: 0644]
extras/WFS_locks/WFS_locks.sql.in [new file with mode: 0644]
extras/ogc_test_suite/.cvsignore [moved from examples/ogc_test_suite/.cvsignore with 100% similarity]
extras/ogc_test_suite/1_schema.sql [moved from examples/ogc_test_suite/1_schema.sql with 100% similarity]
extras/ogc_test_suite/2_queries.sql [moved from examples/ogc_test_suite/2_queries.sql with 100% similarity]
extras/ogc_test_suite/3_cleanup.sql [moved from examples/ogc_test_suite/3_cleanup.sql with 100% similarity]
extras/ogc_test_suite/Makefile [moved from examples/ogc_test_suite/Makefile with 100% similarity]
extras/ogc_test_suite/README [moved from examples/ogc_test_suite/README with 100% similarity]
extras/wkb_reader/.cvsignore [moved from examples/wkb_reader/.cvsignore with 100% similarity]
extras/wkb_reader/Makefile [moved from examples/wkb_reader/Makefile with 100% similarity]
extras/wkb_reader/README [moved from examples/wkb_reader/README with 100% similarity]
extras/wkb_reader/printwkb.c [moved from examples/wkb_reader/printwkb.c with 100% similarity]
extras/wkb_reader/readwkb.c [moved from examples/wkb_reader/readwkb.c with 100% similarity]
extras/wkb_reader/wkbtest.h [moved from examples/wkb_reader/wkbtest.h with 100% similarity]

diff --git a/extras/WFS_locks/Makefile b/extras/WFS_locks/Makefile
new file mode 100644 (file)
index 0000000..882a149
--- /dev/null
@@ -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 (file)
index 0000000..68ae60e
--- /dev/null
@@ -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 <dblasby@openplans.org>
+and has been modified and packaged by Sandro Santilli <strk@refractions.net>.
+
+
+  Usage:
+       
+       -- Check updates and deletes of rows in
+       -- given table for being authorized.
+       -- Identify rows using <column> value.
+       SELECT CheckAuth([<schema>], <table>, <column>)
+
+       -- Set lock/authorization for specific row in table
+       -- <authid> is a text value, <expires> is a timestamp
+       -- defaulting to now()+1hour.
+       -- Returns 1 if lock has been assigned, 0 otherwise
+       -- (already locked by other auth)
+       SELECT LockRow([<schema>], <table>, <rowid>, <authid>, [<expires>])
+
+       -- Remove all locks held by specified authorization id.
+       -- Returns the number of locks released.
+       SELECT UnlockRows(<authid>)
+
+       -- Add an authorization token to be used in current
+       -- transaction. 
+       SELECT AddAuth(<authid>)
+
+  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 (file)
index 0000000..69c85b9
--- /dev/null
@@ -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 (file)
index 0000000..dc8a913
--- /dev/null
@@ -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( <schema>, <table>, <ridcolumn> )
+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(<table>, <ridcolumn>)
+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
+---------------------------------------------------------------
+