/[rserv]/lib/rserv.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /lib/rserv.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations)
Wed Dec 20 17:22:35 2000 UTC (23 years, 4 months ago) by dpavlin
Branch: MAIN
Branch point for: DbP
File MIME type: text/plain
Initial revision

1 dpavlin 1.1 /* rserv.c
2     * Support functions for erServer replication.
3     * (c) 2000 Vadim Mikheev, PostgreSQL Inc.
4     */
5    
6     #include "executor/spi.h" /* this is what you need to work with SPI */
7     #include "commands/trigger.h" /* -"- and triggers */
8     #include "utils/tqual.h" /* -"- and SnapshotData */
9     #include <ctype.h> /* tolower () */
10    
11     #ifdef PG_FUNCTION_INFO_V1
12     #define CurrentTriggerData ((TriggerData *) fcinfo->context)
13     #endif
14    
15     #ifdef PG_FUNCTION_INFO_V1
16     PG_FUNCTION_INFO_V1(_rserv_log_);
17     PG_FUNCTION_INFO_V1(_rserv_sync_);
18     PG_FUNCTION_INFO_V1(_rserv_debug_);
19     Datum _rserv_log_(PG_FUNCTION_ARGS);
20     Datum _rserv_sync_(PG_FUNCTION_ARGS);
21     Datum _rserv_debug_(PG_FUNCTION_ARGS);
22     #else
23     HeapTuple _rserv_log_(void);
24     int32 _rserv_sync_(int32);
25     int32 _rserv_debug_(int32);
26     #endif
27    
28     static int debug = 0;
29    
30     static char* OutputValue(char *key, char *buf, int size);
31    
32     #ifdef PG_FUNCTION_INFO_V1
33     Datum
34     _rserv_log_(PG_FUNCTION_ARGS)
35     #else
36     HeapTuple
37     _rserv_log_()
38     #endif
39     {
40     Trigger *trigger; /* to get trigger name */
41     int nargs; /* # of args specified in CREATE TRIGGER */
42     char **args; /* argument: argnum */
43     Relation rel; /* triggered relation */
44     HeapTuple tuple; /* tuple to return */
45     HeapTuple newtuple = NULL;/* tuple to return */
46     TupleDesc tupdesc; /* tuple description */
47     int keynum;
48     char *key;
49     char *okey;
50     char *newkey = NULL;
51     int deleted;
52     char sql[8192];
53     char outbuf[8192];
54     char oidbuf[64];
55     int ret;
56    
57     /* Called by trigger manager ? */
58     if (!CurrentTriggerData)
59     elog(ERROR, "_rserv_log_: triggers are not initialized");
60    
61     /* Should be called for ROW trigger */
62     if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
63     elog(ERROR, "_rserv_log_: can't process STATEMENT events");
64    
65     tuple = CurrentTriggerData->tg_trigtuple;
66    
67     trigger = CurrentTriggerData->tg_trigger;
68     nargs = trigger->tgnargs;
69     args = trigger->tgargs;
70    
71     if (nargs != 1) /* odd number of arguments! */
72     elog(ERROR, "_rserv_log_: need in *one* argument");
73    
74     keynum = atoi(args[0]);
75    
76     if (keynum < 0 && keynum != ObjectIdAttributeNumber)
77     elog(ERROR, "_rserv_log_: invalid keynum %d", keynum);
78    
79     rel = CurrentTriggerData->tg_relation;
80     tupdesc = rel->rd_att;
81    
82     deleted = (TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event)) ?
83     1 : 0;
84    
85     if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
86     newtuple = CurrentTriggerData->tg_newtuple;
87    
88     /*
89     * Setting CurrentTriggerData to NULL prevents direct calls to trigger
90     * functions in queries. Normally, trigger functions have to be called
91     * by trigger manager code only.
92     */
93     CurrentTriggerData = NULL;
94    
95     /* Connect to SPI manager */
96     if ((ret = SPI_connect()) < 0)
97     elog(ERROR, "_rserv_log_: SPI_connect returned %d", ret);
98    
99     if (keynum == ObjectIdAttributeNumber)
100     {
101     sprintf(oidbuf, "%u", tuple->t_data->t_oid);
102     key = oidbuf;
103     }
104     else
105     key = SPI_getvalue(tuple, tupdesc, keynum);
106    
107     if (key == NULL)
108     elog(ERROR, "_rserv_log_: key must be not null");
109    
110     if (newtuple && keynum != ObjectIdAttributeNumber)
111     {
112     newkey = SPI_getvalue(newtuple, tupdesc, keynum);
113     if (newkey == NULL)
114     elog(ERROR, "_rserv_log_: key must be not null");
115     if (strcmp(newkey, key) == 0)
116     newkey = NULL;
117     else
118     deleted = 1; /* old key was deleted */
119     }
120    
121     if (strpbrk(key, "\\ \n'"))
122     okey = OutputValue(key, outbuf, sizeof(outbuf));
123     else
124     okey = key;
125    
126     sprintf(sql, "update _RSERV_LOG_ set logid = %d, logtime = now(), "
127     "deleted = %d where reloid = %u and key = '%s'",
128     GetCurrentTransactionId(), deleted, rel->rd_id, okey);
129    
130     if (debug)
131     elog(NOTICE, sql);
132    
133     ret = SPI_exec(sql, 0);
134    
135     if (ret < 0)
136     elog(ERROR, "_rserv_log_: SPI_exec(update) returned %d", ret);
137    
138     /*
139     * If no tuple was UPDATEd then do INSERT...
140     */
141     if (SPI_processed > 1)
142     elog(ERROR, "_rserv_log_: duplicate tuples");
143     else if (SPI_processed == 0)
144     {
145     sprintf(sql, "insert into _RSERV_LOG_ "
146     "(reloid, logid, logtime, deleted, key) "
147     "values (%u, %d, now(), %d, '%s')",
148     rel->rd_id, GetCurrentTransactionId(),
149     deleted, okey);
150    
151     if (debug)
152     elog(NOTICE, sql);
153    
154     ret = SPI_exec(sql, 0);
155    
156     if (ret < 0)
157     elog(ERROR, "_rserv_log_: SPI_exec(insert) returned %d", ret);
158     }
159    
160     if (okey != key && okey != outbuf)
161     pfree(okey);
162    
163     if (newkey)
164     {
165     if (strpbrk(newkey, "\\ \n'"))
166     okey = OutputValue(newkey, outbuf, sizeof(outbuf));
167     else
168     okey = newkey;
169    
170     sprintf(sql, "insert into _RSERV_LOG_ "
171     "(reloid, logid, logtime, deleted, key) "
172     "values (%u, %d, now(), 0, '%s')",
173     rel->rd_id, GetCurrentTransactionId(), okey);
174    
175     if (debug)
176     elog(NOTICE, sql);
177    
178     ret = SPI_exec(sql, 0);
179    
180     if (ret < 0)
181     elog(ERROR, "_rserv_log_: SPI_exec returned %d", ret);
182    
183     if (okey != newkey && okey != outbuf)
184     pfree(okey);
185     }
186    
187     SPI_finish();
188    
189     #ifdef PG_FUNCTION_INFO_V1
190     return (PointerGetDatum(tuple));
191     #else
192     return (tuple);
193     #endif
194     }
195    
196     #ifdef PG_FUNCTION_INFO_V1
197     Datum
198     _rserv_sync_(PG_FUNCTION_ARGS)
199     #else
200     int32
201     _rserv_sync_(int32 server)
202     #endif
203     {
204     #ifdef PG_FUNCTION_INFO_V1
205     int32 server = PG_GETARG_INT32(0);
206     #endif
207     char sql[8192];
208     char buf[8192];
209     char *active = buf;
210     uint32 xcnt;
211     int ret;
212    
213     if (SerializableSnapshot == NULL)
214     elog(ERROR, "_rserv_sync_: SerializableSnapshot is NULL");
215    
216     buf[0] = 0;
217     for (xcnt = 0; xcnt < SerializableSnapshot->xcnt; xcnt++)
218     {
219     sprintf(buf + strlen(buf), "%s%u", (xcnt) ? ", " : "",
220     SerializableSnapshot->xip[xcnt]);
221     }
222    
223     if ((ret = SPI_connect()) < 0)
224     elog(ERROR, "_rserv_sync_: SPI_connect returned %d", ret);
225    
226     sprintf(sql, "insert into _RSERV_SYNC_ "
227     "(server, syncid, synctime, status, minid, maxid, active) "
228     "values (%u, currval('_rserv_sync_seq_'), now(), 0, %d, %d, '%s')",
229     server, SerializableSnapshot->xmin, SerializableSnapshot->xmax, active);
230    
231     ret = SPI_exec(sql, 0);
232    
233     if (ret < 0)
234     elog(ERROR, "_rserv_sync_: SPI_exec returned %d", ret);
235    
236     SPI_finish();
237    
238     return (0);
239     }
240    
241     #ifdef PG_FUNCTION_INFO_V1
242     Datum
243     _rserv_debug_(PG_FUNCTION_ARGS)
244     #else
245     int32
246     _rserv_debug_(int32 newval)
247     #endif
248     {
249     #ifdef PG_FUNCTION_INFO_V1
250     int32 newval = PG_GETARG_INT32(0);
251     #endif
252     int32 oldval = debug;
253    
254     debug = newval;
255    
256     return (oldval);
257     }
258    
259     #define ExtendBy 1024
260    
261     static char*
262     OutputValue(char *key, char *buf, int size)
263     {
264     int i = 0;
265     char *out = buf;
266     char *subst = NULL;
267     int slen = 0;
268    
269     size--;
270     for ( ; ; )
271     {
272     switch (*key)
273     {
274     case '\\': subst ="\\\\";
275     slen = 2;
276     break;
277     case ' ': subst = "\\011";
278     slen = 4;
279     break;
280     case '\n': subst = "\\012";
281     slen = 4;
282     break;
283     case '\'': subst = "\\047";
284     slen = 4;
285     break;
286     case '\0': out[i] = 0;
287     return(out);
288     default: slen = 1;
289     break;
290     }
291    
292     if (i + slen >= size)
293     {
294     if (out == buf)
295     {
296     out = (char*) palloc(size + ExtendBy);
297     strncpy(out, buf, i);
298     size += ExtendBy;
299     }
300     else
301     {
302     out = (char*) repalloc(out, size + ExtendBy);
303     size += ExtendBy;
304     }
305     }
306    
307     if (slen == 1)
308     out[i++] = *key;
309     else
310     {
311     memcpy(out + i, subst, slen);
312     i += slen;
313     }
314     key++;
315     }
316    
317     return(out);
318    
319     }

  ViewVC Help
Powered by ViewVC 1.1.26