~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/test/regress/regress.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * src/test/regress/regress.c
 
3
 */
 
4
 
 
5
#include "postgres.h"
 
6
 
 
7
#include <float.h>
 
8
#include <math.h>
 
9
 
 
10
#include "access/transam.h"
 
11
#include "access/xact.h"
 
12
#include "catalog/pg_type.h"
 
13
#include "commands/sequence.h"
 
14
#include "commands/trigger.h"
 
15
#include "executor/executor.h"
 
16
#include "executor/spi.h"
 
17
#include "utils/builtins.h"
 
18
#include "utils/geo_decls.h"
 
19
 
 
20
 
 
21
#define P_MAXDIG 12
 
22
#define LDELIM                  '('
 
23
#define RDELIM                  ')'
 
24
#define DELIM                   ','
 
25
 
 
26
extern Datum regress_dist_ptpath(PG_FUNCTION_ARGS);
 
27
extern Datum regress_path_dist(PG_FUNCTION_ARGS);
 
28
extern PATH *poly2path(POLYGON *poly);
 
29
extern Datum interpt_pp(PG_FUNCTION_ARGS);
 
30
extern void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 
31
extern Datum overpaid(PG_FUNCTION_ARGS);
 
32
extern Datum boxarea(PG_FUNCTION_ARGS);
 
33
extern char *reverse_name(char *string);
 
34
extern int      oldstyle_length(int n, text *t);
 
35
extern Datum int44in(PG_FUNCTION_ARGS);
 
36
extern Datum int44out(PG_FUNCTION_ARGS);
 
37
 
 
38
#ifdef PG_MODULE_MAGIC
 
39
PG_MODULE_MAGIC;
 
40
#endif
 
41
 
 
42
 
 
43
/*
 
44
 * Distance from a point to a path
 
45
 */
 
46
PG_FUNCTION_INFO_V1(regress_dist_ptpath);
 
47
 
 
48
Datum
 
49
regress_dist_ptpath(PG_FUNCTION_ARGS)
 
50
{
 
51
        Point      *pt = PG_GETARG_POINT_P(0);
 
52
        PATH       *path = PG_GETARG_PATH_P(1);
 
53
        float8          result = 0.0;   /* keep compiler quiet */
 
54
        float8          tmp;
 
55
        int                     i;
 
56
        LSEG            lseg;
 
57
 
 
58
        switch (path->npts)
 
59
        {
 
60
                case 0:
 
61
                        PG_RETURN_NULL();
 
62
                case 1:
 
63
                        result = point_dt(pt, &path->p[0]);
 
64
                        break;
 
65
                default:
 
66
 
 
67
                        /*
 
68
                         * the distance from a point to a path is the smallest distance
 
69
                         * from the point to any of its constituent segments.
 
70
                         */
 
71
                        Assert(path->npts > 1);
 
72
                        for (i = 0; i < path->npts - 1; ++i)
 
73
                        {
 
74
                                regress_lseg_construct(&lseg, &path->p[i], &path->p[i + 1]);
 
75
                                tmp = DatumGetFloat8(DirectFunctionCall2(dist_ps,
 
76
                                                                                                                 PointPGetDatum(pt),
 
77
                                                                                                          LsegPGetDatum(&lseg)));
 
78
                                if (i == 0 || tmp < result)
 
79
                                        result = tmp;
 
80
                        }
 
81
                        break;
 
82
        }
 
83
        PG_RETURN_FLOAT8(result);
 
84
}
 
85
 
 
86
/*
 
87
 * this essentially does a cartesian product of the lsegs in the
 
88
 * two paths, and finds the min distance between any two lsegs
 
89
 */
 
90
PG_FUNCTION_INFO_V1(regress_path_dist);
 
91
 
 
92
Datum
 
93
regress_path_dist(PG_FUNCTION_ARGS)
 
94
{
 
95
        PATH       *p1 = PG_GETARG_PATH_P(0);
 
96
        PATH       *p2 = PG_GETARG_PATH_P(1);
 
97
        bool            have_min = false;
 
98
        float8          min = 0.0;              /* initialize to keep compiler quiet */
 
99
        float8          tmp;
 
100
        int                     i,
 
101
                                j;
 
102
        LSEG            seg1,
 
103
                                seg2;
 
104
 
 
105
        for (i = 0; i < p1->npts - 1; i++)
 
106
        {
 
107
                for (j = 0; j < p2->npts - 1; j++)
 
108
                {
 
109
                        regress_lseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
 
110
                        regress_lseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
 
111
 
 
112
                        tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
 
113
                                                                                                         LsegPGetDatum(&seg1),
 
114
                                                                                                         LsegPGetDatum(&seg2)));
 
115
                        if (!have_min || tmp < min)
 
116
                        {
 
117
                                min = tmp;
 
118
                                have_min = true;
 
119
                        }
 
120
                }
 
121
        }
 
122
 
 
123
        if (!have_min)
 
124
                PG_RETURN_NULL();
 
125
 
 
126
        PG_RETURN_FLOAT8(min);
 
127
}
 
128
 
 
129
PATH *
 
130
poly2path(POLYGON *poly)
 
131
{
 
132
        int                     i;
 
133
        char       *output = (char *) palloc(2 * (P_MAXDIG + 1) * poly->npts + 64);
 
134
        char            buf[2 * (P_MAXDIG) + 20];
 
135
 
 
136
        sprintf(output, "(1, %*d", P_MAXDIG, poly->npts);
 
137
 
 
138
        for (i = 0; i < poly->npts; i++)
 
139
        {
 
140
                snprintf(buf, sizeof(buf), ",%*g,%*g",
 
141
                                 P_MAXDIG, poly->p[i].x, P_MAXDIG, poly->p[i].y);
 
142
                strcat(output, buf);
 
143
        }
 
144
 
 
145
        snprintf(buf, sizeof(buf), "%c", RDELIM);
 
146
        strcat(output, buf);
 
147
        return DatumGetPathP(DirectFunctionCall1(path_in,
 
148
                                                                                         CStringGetDatum(output)));
 
149
}
 
150
 
 
151
/* return the point where two paths intersect, or NULL if no intersection. */
 
152
PG_FUNCTION_INFO_V1(interpt_pp);
 
153
 
 
154
Datum
 
155
interpt_pp(PG_FUNCTION_ARGS)
 
156
{
 
157
        PATH       *p1 = PG_GETARG_PATH_P(0);
 
158
        PATH       *p2 = PG_GETARG_PATH_P(1);
 
159
        int                     i,
 
160
                                j;
 
161
        LSEG            seg1,
 
162
                                seg2;
 
163
        bool            found;                  /* We've found the intersection */
 
164
 
 
165
        found = false;                          /* Haven't found it yet */
 
166
 
 
167
        for (i = 0; i < p1->npts - 1 && !found; i++)
 
168
        {
 
169
                regress_lseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
 
170
                for (j = 0; j < p2->npts - 1 && !found; j++)
 
171
                {
 
172
                        regress_lseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
 
173
                        if (DatumGetBool(DirectFunctionCall2(lseg_intersect,
 
174
                                                                                                 LsegPGetDatum(&seg1),
 
175
                                                                                                 LsegPGetDatum(&seg2))))
 
176
                                found = true;
 
177
                }
 
178
        }
 
179
 
 
180
        if (!found)
 
181
                PG_RETURN_NULL();
 
182
 
 
183
        /*
 
184
         * Note: DirectFunctionCall2 will kick out an error if lseg_interpt()
 
185
         * returns NULL, but that should be impossible since we know the two
 
186
         * segments intersect.
 
187
         */
 
188
        PG_RETURN_DATUM(DirectFunctionCall2(lseg_interpt,
 
189
                                                                                LsegPGetDatum(&seg1),
 
190
                                                                                LsegPGetDatum(&seg2)));
 
191
}
 
192
 
 
193
 
 
194
/* like lseg_construct, but assume space already allocated */
 
195
void
 
196
regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 
197
{
 
198
        lseg->p[0].x = pt1->x;
 
199
        lseg->p[0].y = pt1->y;
 
200
        lseg->p[1].x = pt2->x;
 
201
        lseg->p[1].y = pt2->y;
 
202
        lseg->m = point_sl(pt1, pt2);
 
203
}
 
204
 
 
205
PG_FUNCTION_INFO_V1(overpaid);
 
206
 
 
207
Datum
 
208
overpaid(PG_FUNCTION_ARGS)
 
209
{
 
210
        HeapTupleHeader tuple = PG_GETARG_HEAPTUPLEHEADER(0);
 
211
        bool            isnull;
 
212
        int32           salary;
 
213
 
 
214
        salary = DatumGetInt32(GetAttributeByName(tuple, "salary", &isnull));
 
215
        if (isnull)
 
216
                PG_RETURN_NULL();
 
217
        PG_RETURN_BOOL(salary > 699);
 
218
}
 
219
 
 
220
/* New type "widget"
 
221
 * This used to be "circle", but I added circle to builtins,
 
222
 *      so needed to make sure the names do not collide. - tgl 97/04/21
 
223
 */
 
224
 
 
225
typedef struct
 
226
{
 
227
        Point           center;
 
228
        double          radius;
 
229
}       WIDGET;
 
230
 
 
231
WIDGET     *widget_in(char *str);
 
232
char       *widget_out(WIDGET * widget);
 
233
extern Datum pt_in_widget(PG_FUNCTION_ARGS);
 
234
 
 
235
#define NARGS   3
 
236
 
 
237
WIDGET *
 
238
widget_in(char *str)
 
239
{
 
240
        char       *p,
 
241
                           *coord[NARGS],
 
242
                                buf2[1000];
 
243
        int                     i;
 
244
        WIDGET     *result;
 
245
 
 
246
        if (str == NULL)
 
247
                return NULL;
 
248
        for (i = 0, p = str; *p && i < NARGS && *p != RDELIM; p++)
 
249
                if (*p == ',' || (*p == LDELIM && !i))
 
250
                        coord[i++] = p + 1;
 
251
        if (i < NARGS - 1)
 
252
                return NULL;
 
253
        result = (WIDGET *) palloc(sizeof(WIDGET));
 
254
        result->center.x = atof(coord[0]);
 
255
        result->center.y = atof(coord[1]);
 
256
        result->radius = atof(coord[2]);
 
257
 
 
258
        snprintf(buf2, sizeof(buf2), "widget_in: read (%f, %f, %f)\n",
 
259
                         result->center.x, result->center.y, result->radius);
 
260
        return result;
 
261
}
 
262
 
 
263
char *
 
264
widget_out(WIDGET * widget)
 
265
{
 
266
        char       *result;
 
267
 
 
268
        if (widget == NULL)
 
269
                return NULL;
 
270
 
 
271
        result = (char *) palloc(60);
 
272
        sprintf(result, "(%g,%g,%g)",
 
273
                        widget->center.x, widget->center.y, widget->radius);
 
274
        return result;
 
275
}
 
276
 
 
277
PG_FUNCTION_INFO_V1(pt_in_widget);
 
278
 
 
279
Datum
 
280
pt_in_widget(PG_FUNCTION_ARGS)
 
281
{
 
282
        Point      *point = PG_GETARG_POINT_P(0);
 
283
        WIDGET     *widget = (WIDGET *) PG_GETARG_POINTER(1);
 
284
 
 
285
        PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
 
286
}
 
287
 
 
288
PG_FUNCTION_INFO_V1(boxarea);
 
289
 
 
290
Datum
 
291
boxarea(PG_FUNCTION_ARGS)
 
292
{
 
293
        BOX                *box = PG_GETARG_BOX_P(0);
 
294
        double          width,
 
295
                                height;
 
296
 
 
297
        width = Abs(box->high.x - box->low.x);
 
298
        height = Abs(box->high.y - box->low.y);
 
299
        PG_RETURN_FLOAT8(width * height);
 
300
}
 
301
 
 
302
char *
 
303
reverse_name(char *string)
 
304
{
 
305
        int                     i;
 
306
        int                     len;
 
307
        char       *new_string;
 
308
 
 
309
        new_string = palloc0(NAMEDATALEN);
 
310
        for (i = 0; i < NAMEDATALEN && string[i]; ++i)
 
311
                ;
 
312
        if (i == NAMEDATALEN || !string[i])
 
313
                --i;
 
314
        len = i;
 
315
        for (; i >= 0; --i)
 
316
                new_string[len - i] = string[i];
 
317
        return new_string;
 
318
}
 
319
 
 
320
/*
 
321
 * This rather silly function is just to test that oldstyle functions
 
322
 * work correctly on toast-able inputs.
 
323
 */
 
324
int
 
325
oldstyle_length(int n, text *t)
 
326
{
 
327
        int                     len = 0;
 
328
 
 
329
        if (t)
 
330
                len = VARSIZE(t) - VARHDRSZ;
 
331
 
 
332
        return n + len;
 
333
}
 
334
 
 
335
 
 
336
static TransactionId fd17b_xid = InvalidTransactionId;
 
337
static TransactionId fd17a_xid = InvalidTransactionId;
 
338
static int      fd17b_level = 0;
 
339
static int      fd17a_level = 0;
 
340
static bool fd17b_recursion = true;
 
341
static bool fd17a_recursion = true;
 
342
extern Datum funny_dup17(PG_FUNCTION_ARGS);
 
343
 
 
344
PG_FUNCTION_INFO_V1(funny_dup17);
 
345
 
 
346
Datum
 
347
funny_dup17(PG_FUNCTION_ARGS)
 
348
{
 
349
        TriggerData *trigdata = (TriggerData *) fcinfo->context;
 
350
        TransactionId *xid;
 
351
        int                *level;
 
352
        bool       *recursion;
 
353
        Relation        rel;
 
354
        TupleDesc       tupdesc;
 
355
        HeapTuple       tuple;
 
356
        char       *query,
 
357
                           *fieldval,
 
358
                           *fieldtype;
 
359
        char       *when;
 
360
        int                     inserted;
 
361
        int                     selected = 0;
 
362
        int                     ret;
 
363
 
 
364
        if (!CALLED_AS_TRIGGER(fcinfo))
 
365
                elog(ERROR, "funny_dup17: not fired by trigger manager");
 
366
 
 
367
        tuple = trigdata->tg_trigtuple;
 
368
        rel = trigdata->tg_relation;
 
369
        tupdesc = rel->rd_att;
 
370
        if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
 
371
        {
 
372
                xid = &fd17b_xid;
 
373
                level = &fd17b_level;
 
374
                recursion = &fd17b_recursion;
 
375
                when = "BEFORE";
 
376
        }
 
377
        else
 
378
        {
 
379
                xid = &fd17a_xid;
 
380
                level = &fd17a_level;
 
381
                recursion = &fd17a_recursion;
 
382
                when = "AFTER ";
 
383
        }
 
384
 
 
385
        if (!TransactionIdIsCurrentTransactionId(*xid))
 
386
        {
 
387
                *xid = GetCurrentTransactionId();
 
388
                *level = 0;
 
389
                *recursion = true;
 
390
        }
 
391
 
 
392
        if (*level == 17)
 
393
        {
 
394
                *recursion = false;
 
395
                return PointerGetDatum(tuple);
 
396
        }
 
397
 
 
398
        if (!(*recursion))
 
399
                return PointerGetDatum(tuple);
 
400
 
 
401
        (*level)++;
 
402
 
 
403
        SPI_connect();
 
404
 
 
405
        fieldval = SPI_getvalue(tuple, tupdesc, 1);
 
406
        fieldtype = SPI_gettype(tupdesc, 1);
 
407
 
 
408
        query = (char *) palloc(100 + NAMEDATALEN * 3 +
 
409
                                                        strlen(fieldval) + strlen(fieldtype));
 
410
 
 
411
        sprintf(query, "insert into %s select * from %s where %s = '%s'::%s",
 
412
                        SPI_getrelname(rel), SPI_getrelname(rel),
 
413
                        SPI_fname(tupdesc, 1),
 
414
                        fieldval, fieldtype);
 
415
 
 
416
        if ((ret = SPI_exec(query, 0)) < 0)
 
417
                elog(ERROR, "funny_dup17 (fired %s) on level %3d: SPI_exec (insert ...) returned %d",
 
418
                         when, *level, ret);
 
419
 
 
420
        inserted = SPI_processed;
 
421
 
 
422
        sprintf(query, "select count (*) from %s where %s = '%s'::%s",
 
423
                        SPI_getrelname(rel),
 
424
                        SPI_fname(tupdesc, 1),
 
425
                        fieldval, fieldtype);
 
426
 
 
427
        if ((ret = SPI_exec(query, 0)) < 0)
 
428
                elog(ERROR, "funny_dup17 (fired %s) on level %3d: SPI_exec (select ...) returned %d",
 
429
                         when, *level, ret);
 
430
 
 
431
        if (SPI_processed > 0)
 
432
        {
 
433
                selected = DatumGetInt32(DirectFunctionCall1(int4in,
 
434
                                                                                                CStringGetDatum(SPI_getvalue(
 
435
                                                                                                           SPI_tuptable->vals[0],
 
436
                                                                                                           SPI_tuptable->tupdesc,
 
437
                                                                                                                                                         1
 
438
                                                                                                                                                ))));
 
439
        }
 
440
 
 
441
        elog(DEBUG4, "funny_dup17 (fired %s) on level %3d: %d/%d tuples inserted/selected",
 
442
                 when, *level, inserted, selected);
 
443
 
 
444
        SPI_finish();
 
445
 
 
446
        (*level)--;
 
447
 
 
448
        if (*level == 0)
 
449
                *xid = InvalidTransactionId;
 
450
 
 
451
        return PointerGetDatum(tuple);
 
452
}
 
453
 
 
454
extern Datum ttdummy(PG_FUNCTION_ARGS);
 
455
extern Datum set_ttdummy(PG_FUNCTION_ARGS);
 
456
 
 
457
#define TTDUMMY_INFINITY        999999
 
458
 
 
459
static SPIPlanPtr splan = NULL;
 
460
static bool ttoff = false;
 
461
 
 
462
PG_FUNCTION_INFO_V1(ttdummy);
 
463
 
 
464
Datum
 
465
ttdummy(PG_FUNCTION_ARGS)
 
466
{
 
467
        TriggerData *trigdata = (TriggerData *) fcinfo->context;
 
468
        Trigger    *trigger;            /* to get trigger name */
 
469
        char      **args;                       /* arguments */
 
470
        int                     attnum[2];              /* fnumbers of start/stop columns */
 
471
        Datum           oldon,
 
472
                                oldoff;
 
473
        Datum           newon,
 
474
                                newoff;
 
475
        Datum      *cvals;                      /* column values */
 
476
        char       *cnulls;                     /* column nulls */
 
477
        char       *relname;            /* triggered relation name */
 
478
        Relation        rel;                    /* triggered relation */
 
479
        HeapTuple       trigtuple;
 
480
        HeapTuple       newtuple = NULL;
 
481
        HeapTuple       rettuple;
 
482
        TupleDesc       tupdesc;                /* tuple description */
 
483
        int                     natts;                  /* # of attributes */
 
484
        bool            isnull;                 /* to know is some column NULL or not */
 
485
        int                     ret;
 
486
        int                     i;
 
487
 
 
488
        if (!CALLED_AS_TRIGGER(fcinfo))
 
489
                elog(ERROR, "ttdummy: not fired by trigger manager");
 
490
        if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
 
491
                elog(ERROR, "ttdummy: must be fired for row");
 
492
        if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
 
493
                elog(ERROR, "ttdummy: must be fired before event");
 
494
        if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
 
495
                elog(ERROR, "ttdummy: cannot process INSERT event");
 
496
        if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
 
497
                newtuple = trigdata->tg_newtuple;
 
498
 
 
499
        trigtuple = trigdata->tg_trigtuple;
 
500
 
 
501
        rel = trigdata->tg_relation;
 
502
        relname = SPI_getrelname(rel);
 
503
 
 
504
        /* check if TT is OFF for this relation */
 
505
        if (ttoff)                                      /* OFF - nothing to do */
 
506
        {
 
507
                pfree(relname);
 
508
                return PointerGetDatum((newtuple != NULL) ? newtuple : trigtuple);
 
509
        }
 
510
 
 
511
        trigger = trigdata->tg_trigger;
 
512
 
 
513
        if (trigger->tgnargs != 2)
 
514
                elog(ERROR, "ttdummy (%s): invalid (!= 2) number of arguments %d",
 
515
                         relname, trigger->tgnargs);
 
516
 
 
517
        args = trigger->tgargs;
 
518
        tupdesc = rel->rd_att;
 
519
        natts = tupdesc->natts;
 
520
 
 
521
        for (i = 0; i < 2; i++)
 
522
        {
 
523
                attnum[i] = SPI_fnumber(tupdesc, args[i]);
 
524
                if (attnum[i] < 0)
 
525
                        elog(ERROR, "ttdummy (%s): there is no attribute %s", relname, args[i]);
 
526
                if (SPI_gettypeid(tupdesc, attnum[i]) != INT4OID)
 
527
                        elog(ERROR, "ttdummy (%s): attributes %s and %s must be of abstime type",
 
528
                                 relname, args[0], args[1]);
 
529
        }
 
530
 
 
531
        oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull);
 
532
        if (isnull)
 
533
                elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]);
 
534
 
 
535
        oldoff = SPI_getbinval(trigtuple, tupdesc, attnum[1], &isnull);
 
536
        if (isnull)
 
537
                elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]);
 
538
 
 
539
        if (newtuple != NULL)           /* UPDATE */
 
540
        {
 
541
                newon = SPI_getbinval(newtuple, tupdesc, attnum[0], &isnull);
 
542
                if (isnull)
 
543
                        elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]);
 
544
                newoff = SPI_getbinval(newtuple, tupdesc, attnum[1], &isnull);
 
545
                if (isnull)
 
546
                        elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]);
 
547
 
 
548
                if (oldon != newon || oldoff != newoff)
 
549
                        elog(ERROR, "ttdummy (%s): you cannot change %s and/or %s columns (use set_ttdummy)",
 
550
                                 relname, args[0], args[1]);
 
551
 
 
552
                if (newoff != TTDUMMY_INFINITY)
 
553
                {
 
554
                        pfree(relname);         /* allocated in upper executor context */
 
555
                        return PointerGetDatum(NULL);
 
556
                }
 
557
        }
 
558
        else if (oldoff != TTDUMMY_INFINITY)            /* DELETE */
 
559
        {
 
560
                pfree(relname);
 
561
                return PointerGetDatum(NULL);
 
562
        }
 
563
 
 
564
        newoff = DirectFunctionCall1(nextval, CStringGetTextDatum("ttdummy_seq"));
 
565
        /* nextval now returns int64; coerce down to int32 */
 
566
        newoff = Int32GetDatum((int32) DatumGetInt64(newoff));
 
567
 
 
568
        /* Connect to SPI manager */
 
569
        if ((ret = SPI_connect()) < 0)
 
570
                elog(ERROR, "ttdummy (%s): SPI_connect returned %d", relname, ret);
 
571
 
 
572
        /* Fetch tuple values and nulls */
 
573
        cvals = (Datum *) palloc(natts * sizeof(Datum));
 
574
        cnulls = (char *) palloc(natts * sizeof(char));
 
575
        for (i = 0; i < natts; i++)
 
576
        {
 
577
                cvals[i] = SPI_getbinval((newtuple != NULL) ? newtuple : trigtuple,
 
578
                                                                 tupdesc, i + 1, &isnull);
 
579
                cnulls[i] = (isnull) ? 'n' : ' ';
 
580
        }
 
581
 
 
582
        /* change date column(s) */
 
583
        if (newtuple)                           /* UPDATE */
 
584
        {
 
585
                cvals[attnum[0] - 1] = newoff;  /* start_date eq current date */
 
586
                cnulls[attnum[0] - 1] = ' ';
 
587
                cvals[attnum[1] - 1] = TTDUMMY_INFINITY;                /* stop_date eq INFINITY */
 
588
                cnulls[attnum[1] - 1] = ' ';
 
589
        }
 
590
        else
 
591
                /* DELETE */
 
592
        {
 
593
                cvals[attnum[1] - 1] = newoff;  /* stop_date eq current date */
 
594
                cnulls[attnum[1] - 1] = ' ';
 
595
        }
 
596
 
 
597
        /* if there is no plan ... */
 
598
        if (splan == NULL)
 
599
        {
 
600
                SPIPlanPtr      pplan;
 
601
                Oid                *ctypes;
 
602
                char       *query;
 
603
 
 
604
                /* allocate space in preparation */
 
605
                ctypes = (Oid *) palloc(natts * sizeof(Oid));
 
606
                query = (char *) palloc(100 + 16 * natts);
 
607
 
 
608
                /*
 
609
                 * Construct query: INSERT INTO _relation_ VALUES ($1, ...)
 
610
                 */
 
611
                sprintf(query, "INSERT INTO %s VALUES (", relname);
 
612
                for (i = 1; i <= natts; i++)
 
613
                {
 
614
                        sprintf(query + strlen(query), "$%d%s",
 
615
                                        i, (i < natts) ? ", " : ")");
 
616
                        ctypes[i - 1] = SPI_gettypeid(tupdesc, i);
 
617
                }
 
618
 
 
619
                /* Prepare plan for query */
 
620
                pplan = SPI_prepare(query, natts, ctypes);
 
621
                if (pplan == NULL)
 
622
                        elog(ERROR, "ttdummy (%s): SPI_prepare returned %d", relname, SPI_result);
 
623
 
 
624
                pplan = SPI_saveplan(pplan);
 
625
                if (pplan == NULL)
 
626
                        elog(ERROR, "ttdummy (%s): SPI_saveplan returned %d", relname, SPI_result);
 
627
 
 
628
                splan = pplan;
 
629
        }
 
630
 
 
631
        ret = SPI_execp(splan, cvals, cnulls, 0);
 
632
 
 
633
        if (ret < 0)
 
634
                elog(ERROR, "ttdummy (%s): SPI_execp returned %d", relname, ret);
 
635
 
 
636
        /* Tuple to return to upper Executor ... */
 
637
        if (newtuple)                           /* UPDATE */
 
638
        {
 
639
                HeapTuple       tmptuple;
 
640
 
 
641
                tmptuple = SPI_copytuple(trigtuple);
 
642
                rettuple = SPI_modifytuple(rel, tmptuple, 1, &(attnum[1]), &newoff, NULL);
 
643
                SPI_freetuple(tmptuple);
 
644
        }
 
645
        else
 
646
                /* DELETE */
 
647
                rettuple = trigtuple;
 
648
 
 
649
        SPI_finish();                           /* don't forget say Bye to SPI mgr */
 
650
 
 
651
        pfree(relname);
 
652
 
 
653
        return PointerGetDatum(rettuple);
 
654
}
 
655
 
 
656
PG_FUNCTION_INFO_V1(set_ttdummy);
 
657
 
 
658
Datum
 
659
set_ttdummy(PG_FUNCTION_ARGS)
 
660
{
 
661
        int32           on = PG_GETARG_INT32(0);
 
662
 
 
663
        if (ttoff)                                      /* OFF currently */
 
664
        {
 
665
                if (on == 0)
 
666
                        PG_RETURN_INT32(0);
 
667
 
 
668
                /* turn ON */
 
669
                ttoff = false;
 
670
                PG_RETURN_INT32(0);
 
671
        }
 
672
 
 
673
        /* ON currently */
 
674
        if (on != 0)
 
675
                PG_RETURN_INT32(1);
 
676
 
 
677
        /* turn OFF */
 
678
        ttoff = true;
 
679
 
 
680
        PG_RETURN_INT32(1);
 
681
}
 
682
 
 
683
 
 
684
/*
 
685
 * Type int44 has no real-world use, but the regression tests use it.
 
686
 * It's a four-element vector of int4's.
 
687
 */
 
688
 
 
689
/*
 
690
 *              int44in                 - converts "num num ..." to internal form
 
691
 *
 
692
 *              Note: Fills any missing positions with zeroes.
 
693
 */
 
694
PG_FUNCTION_INFO_V1(int44in);
 
695
 
 
696
Datum
 
697
int44in(PG_FUNCTION_ARGS)
 
698
{
 
699
        char       *input_string = PG_GETARG_CSTRING(0);
 
700
        int32      *result = (int32 *) palloc(4 * sizeof(int32));
 
701
        int                     i;
 
702
 
 
703
        i = sscanf(input_string,
 
704
                           "%d, %d, %d, %d",
 
705
                           &result[0],
 
706
                           &result[1],
 
707
                           &result[2],
 
708
                           &result[3]);
 
709
        while (i < 4)
 
710
                result[i++] = 0;
 
711
 
 
712
        PG_RETURN_POINTER(result);
 
713
}
 
714
 
 
715
/*
 
716
 *              int44out                - converts internal form to "num num ..."
 
717
 */
 
718
PG_FUNCTION_INFO_V1(int44out);
 
719
 
 
720
Datum
 
721
int44out(PG_FUNCTION_ARGS)
 
722
{
 
723
        int32      *an_array = (int32 *) PG_GETARG_POINTER(0);
 
724
        char       *result = (char *) palloc(16 * 4);           /* Allow 14 digits +
 
725
                                                                                                                 * sign */
 
726
        int                     i;
 
727
        char       *walk;
 
728
 
 
729
        walk = result;
 
730
        for (i = 0; i < 4; i++)
 
731
        {
 
732
                pg_ltoa(an_array[i], walk);
 
733
                while (*++walk != '\0')
 
734
                        ;
 
735
                *walk++ = ' ';
 
736
        }
 
737
        *--walk = '\0';
 
738
        PG_RETURN_CSTRING(result);
 
739
}