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