PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
long_xact.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright (C) 2006 Refractions Research Inc.
22 *
23 **********************************************************************/
24
25
26#include "postgres.h"
27#include "access/xact.h"
28#include "executor/spi.h" /* this is what you need to work with SPI */
29#include "commands/trigger.h" /* ... and triggers */
30#include "utils/lsyscache.h" /* for get_namespace_name() */
31#include "utils/rel.h"
32#include "../postgis_config.h"
33#include "lwgeom_pg.h"
34
35#define ABORT_ON_AUTH_FAILURE 1
36
37Datum check_authorization(PG_FUNCTION_ARGS);
38Datum getTransactionID(PG_FUNCTION_ARGS);
39
40/*
41 * This trigger will check for authorization before
42 * allowing UPDATE or DELETE of specific rows.
43 * Rows are identified by the provided column.
44 * Authorization info is extracted by the
45 * "authorization_table"
46 *
47 */
49Datum check_authorization(PG_FUNCTION_ARGS)
50{
51 TriggerData *trigdata = (TriggerData *) fcinfo->context;
52 char *colname;
53 HeapTuple rettuple_ok;
54 HeapTuple rettuple_fail;
55 TupleDesc tupdesc;
56 int SPIcode;
57 char query[1024];
58 const char *pk_id = NULL;
59 SPITupleTable *tuptable;
60 HeapTuple tuple;
61 char *lockcode;
62 char *authtable = "authorization_table";
63 const char *op;
64 char err_msg[256];
65
66
67 /* Make sure trigdata is pointing at what I expect */
68 if ( ! CALLED_AS_TRIGGER(fcinfo) )
69 {
70 elog(ERROR,"check_authorization: not fired by trigger manager");
71 }
72
73 if ( ! TRIGGER_FIRED_BEFORE(trigdata->tg_event) )
74 {
75 elog(ERROR,"check_authorization: not fired *before* event");
76 }
77
78 if ( TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event) )
79 {
80 rettuple_ok = trigdata->tg_newtuple;
81 rettuple_fail = NULL;
82 op = "UPDATE";
83 }
84 else if ( TRIGGER_FIRED_BY_DELETE(trigdata->tg_event) )
85 {
86 rettuple_ok = trigdata->tg_trigtuple;
87 rettuple_fail = NULL;
88 op = "DELETE";
89 }
90 else
91 {
92 elog(ERROR,"check_authorization: not fired by update or delete");
93 PG_RETURN_NULL();
94 }
95
96
97 tupdesc = trigdata->tg_relation->rd_att;
98
99 /* Connect to SPI manager */
100 SPIcode = SPI_connect();
101
102 if (SPIcode != SPI_OK_CONNECT)
103 {
104 elog(ERROR,"check_authorization: could not connect to SPI");
105 PG_RETURN_NULL() ;
106 }
107
108 colname = trigdata->tg_trigger->tgargs[0];
109 pk_id = SPI_getvalue(trigdata->tg_trigtuple, tupdesc,
110 SPI_fnumber(tupdesc, colname));
111
112 POSTGIS_DEBUG(3, "check_authorization called");
113
114 snprintf(query, sizeof(query), "SELECT authid FROM \"%s\" WHERE expires >= now() AND toid = '%d' AND rid = '%s'", authtable, trigdata->tg_relation->rd_id, pk_id);
115
116 POSTGIS_DEBUGF(3 ,"about to execute :%s", query);
117
118 SPIcode = SPI_exec(query,0);
119 if (SPIcode !=SPI_OK_SELECT )
120 elog(ERROR,"couldnt execute to test for lock :%s",query);
121
122 if (!SPI_processed )
123 {
124 POSTGIS_DEBUGF(3, "there is NO lock on row '%s'", pk_id);
125
126 SPI_finish();
127 return PointerGetDatum(rettuple_ok);
128 }
129
130 /* there is a lock - check to see if I have rights to it! */
131
132 tuptable = SPI_tuptable;
133 tupdesc = tuptable->tupdesc;
134 tuple = tuptable->vals[0];
135 lockcode = SPI_getvalue(tuple, tupdesc, 1);
136
137 POSTGIS_DEBUGF(3, "there is a lock on row '%s' (auth: '%s').", pk_id, lockcode);
138
139 /*
140 * check to see if temp_lock_have_table table exists
141 * (it might not exist if they own no locks)
142 */
143 snprintf(query, sizeof(query), "SELECT * FROM pg_class WHERE relname = 'temp_lock_have_table'");
144 SPIcode = SPI_exec(query,0);
145 if (SPIcode != SPI_OK_SELECT )
146 elog(ERROR,"couldnt execute to test for lockkey temp table :%s",query);
147 if (SPI_processed==0)
148 {
149 goto fail;
150 }
151
152 snprintf(query, sizeof(query), "SELECT * FROM temp_lock_have_table WHERE xideq( transid, getTransactionID() ) AND lockcode ='%s'", lockcode);
153
154 POSTGIS_DEBUGF(3, "about to execute :%s", query);
155
156 SPIcode = SPI_exec(query,0);
157 if (SPIcode != SPI_OK_SELECT )
158 elog(ERROR, "couldnt execute to test for lock acquire: %s", query);
159
160 if (SPI_processed >0)
161 {
162 POSTGIS_DEBUG(3, "I own the lock - I can modify the row");
163
164 SPI_finish();
165 return PointerGetDatum(rettuple_ok);
166 }
167
168fail:
169
170 snprintf(err_msg, sizeof(err_msg), "%s where \"%s\" = '%s' requires authorization '%s'",
171 op, colname, pk_id, lockcode);
172 err_msg[sizeof(err_msg)-1] = '\0';
173
174#ifdef ABORT_ON_AUTH_FAILURE
175 elog(ERROR, "%s", err_msg);
176#else
177 elog(NOTICE, "%s", err_msg);
178#endif
179
180 SPI_finish();
181 return PointerGetDatum(rettuple_fail);
182
183
184}
185
187Datum getTransactionID(PG_FUNCTION_ARGS)
188{
189 TransactionId xid = GetCurrentTransactionId();
190 PG_RETURN_DATUM( TransactionIdGetDatum(xid) );
191}
Datum getTransactionID(PG_FUNCTION_ARGS)
Definition long_xact.c:187
PG_FUNCTION_INFO_V1(check_authorization)
Datum check_authorization(PG_FUNCTION_ARGS)
Definition long_xact.c:49