regress.c 16.9 KB
Newer Older
1
/*
2
 * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.68 2006/07/13 16:49:20 momjian Exp $
3 4
 */

5
#include "postgres.h"
M
Marc G. Fournier 已提交
6

7 8
#include <float.h>				/* faked on sunos */

9
#include "access/transam.h"
10
#include "utils/geo_decls.h"	/* includes <math.h> */
11
#include "executor/executor.h"	/* For GetAttributeByName */
12
#include "commands/sequence.h"	/* for nextval() */
13 14

#define P_MAXDIG 12
15 16 17
#define LDELIM			'('
#define RDELIM			')'
#define DELIM			','
18

19 20
extern Datum regress_dist_ptpath(PG_FUNCTION_ARGS);
extern Datum regress_path_dist(PG_FUNCTION_ARGS);
21
extern PATH *poly2path(POLYGON *poly);
22
extern Datum interpt_pp(PG_FUNCTION_ARGS);
23
extern void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
24
extern Datum overpaid(PG_FUNCTION_ARGS);
25
extern Datum boxarea(PG_FUNCTION_ARGS);
26
extern char *reverse_name(char *string);
B
Bruce Momjian 已提交
27
extern int	oldstyle_length(int n, text *t);
28 29
extern Datum int44in(PG_FUNCTION_ARGS);
extern Datum int44out(PG_FUNCTION_ARGS);
30

31
#ifdef PG_MODULE_MAGIC
32
PG_MODULE_MAGIC;
33 34 35
#endif


36
/*
37 38
 * Distance from a point to a path
 */
39 40
PG_FUNCTION_INFO_V1(regress_dist_ptpath);

41 42
Datum
regress_dist_ptpath(PG_FUNCTION_ARGS)
43
{
44 45 46 47
	Point	   *pt = PG_GETARG_POINT_P(0);
	PATH	   *path = PG_GETARG_PATH_P(1);
	float8		result = 0.0;	/* keep compiler quiet */
	float8		tmp;
48 49
	int			i;
	LSEG		lseg;
50 51 52

	switch (path->npts)
	{
53
		case 0:
54
			PG_RETURN_NULL();
55
		case 1:
56
			result = point_dt(pt, &path->p[0]);
57 58 59 60
			break;
		default:

			/*
B
Bruce Momjian 已提交
61 62
			 * the distance from a point to a path is the smallest distance
			 * from the point to any of its constituent segments.
63 64 65 66 67
			 */
			Assert(path->npts > 1);
			for (i = 0; i < path->npts - 1; ++i)
			{
				regress_lseg_construct(&lseg, &path->p[i], &path->p[i + 1]);
68
				tmp = DatumGetFloat8(DirectFunctionCall2(dist_ps,
B
Bruce Momjian 已提交
69 70
														 PointPGetDatum(pt),
													  LsegPGetDatum(&lseg)));
71 72
				if (i == 0 || tmp < result)
					result = tmp;
73 74
			}
			break;
75
	}
76
	PG_RETURN_FLOAT8(result);
77 78
}

79 80 81 82
/*
 * this essentially does a cartesian product of the lsegs in the
 * two paths, and finds the min distance between any two lsegs
 */
83 84
PG_FUNCTION_INFO_V1(regress_path_dist);

85 86
Datum
regress_path_dist(PG_FUNCTION_ARGS)
87
{
88 89 90 91 92
	PATH	   *p1 = PG_GETARG_PATH_P(0);
	PATH	   *p2 = PG_GETARG_PATH_P(1);
	bool		have_min = false;
	float8		min = 0.0;		/* initialize to keep compiler quiet */
	float8		tmp;
93 94 95 96
	int			i,
				j;
	LSEG		seg1,
				seg2;
97 98

	for (i = 0; i < p1->npts - 1; i++)
99
	{
100 101 102 103 104
		for (j = 0; j < p2->npts - 1; j++)
		{
			regress_lseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
			regress_lseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);

105 106
			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
													 LsegPGetDatum(&seg1),
B
Bruce Momjian 已提交
107
													 LsegPGetDatum(&seg2)));
108 109 110 111 112
			if (!have_min || tmp < min)
			{
				min = tmp;
				have_min = true;
			}
113
		}
114
	}
115

B
Bruce Momjian 已提交
116
	if (!have_min)
117 118 119
		PG_RETURN_NULL();

	PG_RETURN_FLOAT8(min);
120 121
}

122
PATH *
123
poly2path(POLYGON *poly)
124
{
125
	int			i;
126
	char	   *output = (char *) palloc(2 * (P_MAXDIG + 1) * poly->npts + 64);
127
	char		buf[2 * (P_MAXDIG) + 20];
128

129
	sprintf(output, "(1, %*d", P_MAXDIG, poly->npts);
130

131 132
	for (i = 0; i < poly->npts; i++)
	{
133 134
		snprintf(buf, sizeof(buf), ",%*g,%*g",
				 P_MAXDIG, poly->p[i].x, P_MAXDIG, poly->p[i].y);
135 136
		strcat(output, buf);
	}
137

138
	snprintf(buf, sizeof(buf), "%c", RDELIM);
139
	strcat(output, buf);
140 141
	return DatumGetPathP(DirectFunctionCall1(path_in,
											 CStringGetDatum(output)));
142 143
}

144
/* return the point where two paths intersect, or NULL if no intersection. */
145 146
PG_FUNCTION_INFO_V1(interpt_pp);

147 148
Datum
interpt_pp(PG_FUNCTION_ARGS)
149
{
150 151
	PATH	   *p1 = PG_GETARG_PATH_P(0);
	PATH	   *p2 = PG_GETARG_PATH_P(1);
152 153 154 155 156
	int			i,
				j;
	LSEG		seg1,
				seg2;
	bool		found;			/* We've found the intersection */
157

158
	found = false;				/* Haven't found it yet */
B
Bryan Henderson 已提交
159

160
	for (i = 0; i < p1->npts - 1 && !found; i++)
161 162
	{
		regress_lseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
163 164 165
		for (j = 0; j < p2->npts - 1 && !found; j++)
		{
			regress_lseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
166 167 168
			if (DatumGetBool(DirectFunctionCall2(lseg_intersect,
												 LsegPGetDatum(&seg1),
												 LsegPGetDatum(&seg2))))
169 170
				found = true;
		}
171
	}
172

173 174
	if (!found)
		PG_RETURN_NULL();
175

B
Bruce Momjian 已提交
176 177
	/*
	 * Note: DirectFunctionCall2 will kick out an error if lseg_interpt()
178 179 180 181 182 183
	 * returns NULL, but that should be impossible since we know the two
	 * segments intersect.
	 */
	PG_RETURN_DATUM(DirectFunctionCall2(lseg_interpt,
										LsegPGetDatum(&seg1),
										LsegPGetDatum(&seg2)));
184 185 186 187
}


/* like lseg_construct, but assume space already allocated */
188
void
189
regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
190
{
191 192 193 194 195
	lseg->p[0].x = pt1->x;
	lseg->p[0].y = pt1->y;
	lseg->p[1].x = pt2->x;
	lseg->p[1].y = pt2->y;
	lseg->m = point_sl(pt1, pt2);
196 197
}

198 199
PG_FUNCTION_INFO_V1(overpaid);

200 201
Datum
overpaid(PG_FUNCTION_ARGS)
202
{
203
	HeapTupleHeader tuple = PG_GETARG_HEAPTUPLEHEADER(0);
204
	bool		isnull;
205
	int32		salary;
206

207
	salary = DatumGetInt32(GetAttributeByName(tuple, "salary", &isnull));
208 209 210
	if (isnull)
		PG_RETURN_NULL();
	PG_RETURN_BOOL(salary > 699);
211 212
}

213 214
/* New type "widget"
 * This used to be "circle", but I added circle to builtins,
215
 *	so needed to make sure the names do not collide. - tgl 97/04/21
216 217
 */

218 219
typedef struct
{
220 221
	Point		center;
	double		radius;
222
}	WIDGET;
223

224
WIDGET	   *widget_in(char *str);
B
Bruce Momjian 已提交
225
char	   *widget_out(WIDGET * widget);
226
extern Datum pt_in_widget(PG_FUNCTION_ARGS);
227 228 229

#define NARGS	3

230
WIDGET *
231
widget_in(char *str)
232
{
233 234 235 236 237
	char	   *p,
			   *coord[NARGS],
				buf2[1000];
	int			i;
	WIDGET	   *result;
238 239

	if (str == NULL)
240
		return NULL;
241 242 243 244
	for (i = 0, p = str; *p && i < NARGS && *p != RDELIM; p++)
		if (*p == ',' || (*p == LDELIM && !i))
			coord[i++] = p + 1;
	if (i < NARGS - 1)
245
		return NULL;
246
	result = (WIDGET *) palloc(sizeof(WIDGET));
247 248 249 250
	result->center.x = atof(coord[0]);
	result->center.y = atof(coord[1]);
	result->radius = atof(coord[2]);

251 252
	snprintf(buf2, sizeof(buf2), "widget_in: read (%f, %f, %f)\n",
			 result->center.x, result->center.y, result->radius);
253
	return result;
254 255
}

256
char *
B
Bruce Momjian 已提交
257
widget_out(WIDGET * widget)
258
{
259
	char	   *result;
260

261
	if (widget == NULL)
262
		return NULL;
263

264 265 266
	result = (char *) palloc(60);
	sprintf(result, "(%g,%g,%g)",
			widget->center.x, widget->center.y, widget->radius);
267
	return result;
268 269
}

270 271
PG_FUNCTION_INFO_V1(pt_in_widget);

272 273
Datum
pt_in_widget(PG_FUNCTION_ARGS)
274
{
275 276
	Point	   *point = PG_GETARG_POINT_P(0);
	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
277

278
	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
279 280
}

281 282
PG_FUNCTION_INFO_V1(boxarea);

283 284
Datum
boxarea(PG_FUNCTION_ARGS)
285
{
286 287
	BOX		   *box = PG_GETARG_BOX_P(0);
	double		width,
288
				height;
289

290 291
	width = Abs(box->high.x - box->low.x);
	height = Abs(box->high.y - box->low.y);
292
	PG_RETURN_FLOAT8(width * height);
293 294
}

295
char *
296
reverse_name(char *string)
297
{
298
	int			i;
299 300
	int			len;
	char	   *new_string;
301

302
	new_string = palloc0(NAMEDATALEN);
303
	for (i = 0; i < NAMEDATALEN && string[i]; ++i)
304
		;
305
	if (i == NAMEDATALEN || !string[i])
306 307 308 309
		--i;
	len = i;
	for (; i >= 0; --i)
		new_string[len - i] = string[i];
310
	return new_string;
311
}
V
Vadim B. Mikheev 已提交
312

313 314
/*
 * This rather silly function is just to test that oldstyle functions
315 316 317 318 319
 * work correctly on toast-able inputs.
 */
int
oldstyle_length(int n, text *t)
{
B
Bruce Momjian 已提交
320
	int			len = 0;
321 322 323 324 325 326 327

	if (t)
		len = VARSIZE(t) - VARHDRSZ;

	return n + len;
}

V
Vadim B. Mikheev 已提交
328 329 330 331 332 333 334 335 336
#include "executor/spi.h"		/* this is what you need to work with SPI */
#include "commands/trigger.h"	/* -"- and triggers */

static TransactionId fd17b_xid = InvalidTransactionId;
static TransactionId fd17a_xid = InvalidTransactionId;
static int	fd17b_level = 0;
static int	fd17a_level = 0;
static bool fd17b_recursion = true;
static bool fd17a_recursion = true;
337
extern Datum funny_dup17(PG_FUNCTION_ARGS);
V
Vadim B. Mikheev 已提交
338

339 340
PG_FUNCTION_INFO_V1(funny_dup17);

341 342
Datum
funny_dup17(PG_FUNCTION_ARGS)
V
Vadim B. Mikheev 已提交
343
{
344
	TriggerData *trigdata = (TriggerData *) fcinfo->context;
V
Vadim B. Mikheev 已提交
345 346 347 348 349 350
	TransactionId *xid;
	int		   *level;
	bool	   *recursion;
	Relation	rel;
	TupleDesc	tupdesc;
	HeapTuple	tuple;
351 352 353
	char	   *query,
			   *fieldval,
			   *fieldtype;
V
Vadim B. Mikheev 已提交
354 355 356 357 358
	char	   *when;
	int			inserted;
	int			selected = 0;
	int			ret;

359 360 361 362 363
	if (!CALLED_AS_TRIGGER(fcinfo))
		elog(ERROR, "funny_dup17: not fired by trigger manager");

	tuple = trigdata->tg_trigtuple;
	rel = trigdata->tg_relation;
V
Vadim B. Mikheev 已提交
364
	tupdesc = rel->rd_att;
365
	if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
V
Vadim B. Mikheev 已提交
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
	{
		xid = &fd17b_xid;
		level = &fd17b_level;
		recursion = &fd17b_recursion;
		when = "BEFORE";
	}
	else
	{
		xid = &fd17a_xid;
		level = &fd17a_level;
		recursion = &fd17a_recursion;
		when = "AFTER ";
	}

	if (!TransactionIdIsCurrentTransactionId(*xid))
	{
		*xid = GetCurrentTransactionId();
		*level = 0;
		*recursion = true;
	}

	if (*level == 17)
	{
		*recursion = false;
390
		return PointerGetDatum(tuple);
V
Vadim B. Mikheev 已提交
391 392 393
	}

	if (!(*recursion))
394
		return PointerGetDatum(tuple);
V
Vadim B. Mikheev 已提交
395 396 397 398 399

	(*level)++;

	SPI_connect();

400 401 402
	fieldval = SPI_getvalue(tuple, tupdesc, 1);
	fieldtype = SPI_gettype(tupdesc, 1);

403
	query = (char *) palloc(100 + NAMEDATALEN * 3 +
404 405 406
							strlen(fieldval) + strlen(fieldtype));

	sprintf(query, "insert into %s select * from %s where %s = '%s'::%s",
V
Vadim B. Mikheev 已提交
407 408
			SPI_getrelname(rel), SPI_getrelname(rel),
			SPI_fname(tupdesc, 1),
409
			fieldval, fieldtype);
V
Vadim B. Mikheev 已提交
410

411
	if ((ret = SPI_exec(query, 0)) < 0)
B
Bruce Momjian 已提交
412
		elog(ERROR, "funny_dup17 (fired %s) on level %3d: SPI_exec (insert ...) returned %d",
V
Vadim B. Mikheev 已提交
413 414 415 416
			 when, *level, ret);

	inserted = SPI_processed;

417
	sprintf(query, "select count (*) from %s where %s = '%s'::%s",
V
Vadim B. Mikheev 已提交
418 419
			SPI_getrelname(rel),
			SPI_fname(tupdesc, 1),
420
			fieldval, fieldtype);
V
Vadim B. Mikheev 已提交
421

422
	if ((ret = SPI_exec(query, 0)) < 0)
B
Bruce Momjian 已提交
423
		elog(ERROR, "funny_dup17 (fired %s) on level %3d: SPI_exec (select ...) returned %d",
V
Vadim B. Mikheev 已提交
424 425 426 427
			 when, *level, ret);

	if (SPI_processed > 0)
	{
428
		selected = DatumGetInt32(DirectFunctionCall1(int4in,
B
Bruce Momjian 已提交
429 430 431 432 433
												CStringGetDatum(SPI_getvalue(
													   SPI_tuptable->vals[0],
													   SPI_tuptable->tupdesc,
																			 1
																		))));
V
Vadim B. Mikheev 已提交
434 435
	}

436
	elog(DEBUG4, "funny_dup17 (fired %s) on level %3d: %d/%d tuples inserted/selected",
V
Vadim B. Mikheev 已提交
437 438 439 440 441 442 443 444 445
		 when, *level, inserted, selected);

	SPI_finish();

	(*level)--;

	if (*level == 0)
		*xid = InvalidTransactionId;

446
	return PointerGetDatum(tuple);
V
Vadim B. Mikheev 已提交
447
}
448

449
extern Datum ttdummy(PG_FUNCTION_ARGS);
450
extern Datum set_ttdummy(PG_FUNCTION_ARGS);
451 452 453

#define TTDUMMY_INFINITY	999999

454 455
static void *splan = NULL;
static bool ttoff = false;
456

457 458
PG_FUNCTION_INFO_V1(ttdummy);

459 460
Datum
ttdummy(PG_FUNCTION_ARGS)
461
{
462
	TriggerData *trigdata = (TriggerData *) fcinfo->context;
463 464 465
	Trigger    *trigger;		/* to get trigger name */
	char	  **args;			/* arguments */
	int			attnum[2];		/* fnumbers of start/stop columns */
466 467 468 469
	Datum		oldon,
				oldoff;
	Datum		newon,
				newoff;
470 471 472 473 474 475 476 477 478 479 480 481 482
	Datum	   *cvals;			/* column values */
	char	   *cnulls;			/* column nulls */
	char	   *relname;		/* triggered relation name */
	Relation	rel;			/* triggered relation */
	HeapTuple	trigtuple;
	HeapTuple	newtuple = NULL;
	HeapTuple	rettuple;
	TupleDesc	tupdesc;		/* tuple description */
	int			natts;			/* # of attributes */
	bool		isnull;			/* to know is some column NULL or not */
	int			ret;
	int			i;

483 484 485
	if (!CALLED_AS_TRIGGER(fcinfo))
		elog(ERROR, "ttdummy: not fired by trigger manager");
	if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
B
Bruce Momjian 已提交
486
		elog(ERROR, "ttdummy: can't process STATEMENT events");
487
	if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
B
Bruce Momjian 已提交
488
		elog(ERROR, "ttdummy: must be fired before event");
489
	if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
490
		elog(ERROR, "ttdummy: can't process INSERT event");
491 492
	if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
		newtuple = trigdata->tg_newtuple;
493

494
	trigtuple = trigdata->tg_trigtuple;
495

496
	rel = trigdata->tg_relation;
497
	relname = SPI_getrelname(rel);
498

499
	/* check if TT is OFF for this relation */
500
	if (ttoff)					/* OFF - nothing to do */
501
	{
502
		pfree(relname);
503
		return PointerGetDatum((newtuple != NULL) ? newtuple : trigtuple);
504
	}
505

506
	trigger = trigdata->tg_trigger;
507 508

	if (trigger->tgnargs != 2)
509 510 511
		elog(ERROR, "ttdummy (%s): invalid (!= 2) number of arguments %d",
			 relname, trigger->tgnargs);

512 513 514
	args = trigger->tgargs;
	tupdesc = rel->rd_att;
	natts = tupdesc->natts;
515 516

	for (i = 0; i < 2; i++)
517
	{
518 519
		attnum[i] = SPI_fnumber(tupdesc, args[i]);
		if (attnum[i] < 0)
B
Bruce Momjian 已提交
520
			elog(ERROR, "ttdummy (%s): there is no attribute %s", relname, args[i]);
521 522 523
		if (SPI_gettypeid(tupdesc, attnum[i]) != INT4OID)
			elog(ERROR, "ttdummy (%s): attributes %s and %s must be of abstime type",
				 relname, args[0], args[1]);
524
	}
525 526

	oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull);
527
	if (isnull)
B
Bruce Momjian 已提交
528
		elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]);
529 530

	oldoff = SPI_getbinval(trigtuple, tupdesc, attnum[1], &isnull);
531
	if (isnull)
B
Bruce Momjian 已提交
532
		elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]);
533 534

	if (newtuple != NULL)		/* UPDATE */
535
	{
536
		newon = SPI_getbinval(newtuple, tupdesc, attnum[0], &isnull);
537
		if (isnull)
B
Bruce Momjian 已提交
538
			elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]);
539
		newoff = SPI_getbinval(newtuple, tupdesc, attnum[1], &isnull);
540
		if (isnull)
B
Bruce Momjian 已提交
541
			elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]);
542 543 544 545 546 547

		if (oldon != newon || oldoff != newoff)
			elog(ERROR, "ttdummy (%s): you can't change %s and/or %s columns (use set_ttdummy)",
				 relname, args[0], args[1]);

		if (newoff != TTDUMMY_INFINITY)
548
		{
549
			pfree(relname);		/* allocated in upper executor context */
550
			return PointerGetDatum(NULL);
551 552 553 554
		}
	}
	else if (oldoff != TTDUMMY_INFINITY)		/* DELETE */
	{
555
		pfree(relname);
556
		return PointerGetDatum(NULL);
557
	}
558

559
	{
B
Bruce Momjian 已提交
560
		text	   *seqname = DatumGetTextP(DirectFunctionCall1(textin,
B
Bruce Momjian 已提交
561
											CStringGetDatum("ttdummy_seq")));
562

563 564
		newoff = DirectFunctionCall1(nextval,
									 PointerGetDatum(seqname));
565 566
		/* nextval now returns int64; coerce down to int32 */
		newoff = Int32GetDatum((int32) DatumGetInt64(newoff));
567
		pfree(seqname);
568
	}
569

570 571
	/* Connect to SPI manager */
	if ((ret = SPI_connect()) < 0)
B
Bruce Momjian 已提交
572
		elog(ERROR, "ttdummy (%s): SPI_connect returned %d", relname, ret);
573

574
	/* Fetch tuple values and nulls */
575 576
	cvals = (Datum *) palloc(natts * sizeof(Datum));
	cnulls = (char *) palloc(natts * sizeof(char));
577 578
	for (i = 0; i < natts; i++)
	{
579 580
		cvals[i] = SPI_getbinval((newtuple != NULL) ? newtuple : trigtuple,
								 tupdesc, i + 1, &isnull);
581 582
		cnulls[i] = (isnull) ? 'n' : ' ';
	}
583

584
	/* change date column(s) */
585
	if (newtuple)				/* UPDATE */
586
	{
587
		cvals[attnum[0] - 1] = newoff;	/* start_date eq current date */
588
		cnulls[attnum[0] - 1] = ' ';
589
		cvals[attnum[1] - 1] = TTDUMMY_INFINITY;		/* stop_date eq INFINITY */
590 591
		cnulls[attnum[1] - 1] = ' ';
	}
592
	else
593
		/* DELETE */
594
	{
595
		cvals[attnum[1] - 1] = newoff;	/* stop_date eq current date */
596 597
		cnulls[attnum[1] - 1] = ' ';
	}
598

599 600 601 602 603
	/* if there is no plan ... */
	if (splan == NULL)
	{
		void	   *pplan;
		Oid		   *ctypes;
604
		char	   *query;
605

606
		/* allocate space in preparation */
607
		ctypes = (Oid *) palloc(natts * sizeof(Oid));
608
		query = (char *) palloc(100 + 16 * natts);
609

610
		/*
611
		 * Construct query: INSERT INTO _relation_ VALUES ($1, ...)
612
		 */
613
		sprintf(query, "INSERT INTO %s VALUES (", relname);
614 615
		for (i = 1; i <= natts; i++)
		{
616
			sprintf(query + strlen(query), "$%d%s",
617
					i, (i < natts) ? ", " : ")");
618 619
			ctypes[i - 1] = SPI_gettypeid(tupdesc, i);
		}
620

621
		/* Prepare plan for query */
622
		pplan = SPI_prepare(query, natts, ctypes);
623
		if (pplan == NULL)
B
Bruce Momjian 已提交
624
			elog(ERROR, "ttdummy (%s): SPI_prepare returned %d", relname, SPI_result);
625

626 627
		pplan = SPI_saveplan(pplan);
		if (pplan == NULL)
B
Bruce Momjian 已提交
628
			elog(ERROR, "ttdummy (%s): SPI_saveplan returned %d", relname, SPI_result);
629

630 631
		splan = pplan;
	}
632

633
	ret = SPI_execp(splan, cvals, cnulls, 0);
634

635
	if (ret < 0)
B
Bruce Momjian 已提交
636
		elog(ERROR, "ttdummy (%s): SPI_execp returned %d", relname, ret);
637

638
	/* Tuple to return to upper Executor ... */
639
	if (newtuple)				/* UPDATE */
640 641
	{
		HeapTuple	tmptuple;
642 643 644

		tmptuple = SPI_copytuple(trigtuple);
		rettuple = SPI_modifytuple(rel, tmptuple, 1, &(attnum[1]), &newoff, NULL);
645
		SPI_freetuple(tmptuple);
646
	}
647
	else
648
		/* DELETE */
649
		rettuple = trigtuple;
650 651 652 653

	SPI_finish();				/* don't forget say Bye to SPI mgr */

	pfree(relname);
654

655
	return PointerGetDatum(rettuple);
656 657
}

658 659
PG_FUNCTION_INFO_V1(set_ttdummy);

660 661
Datum
set_ttdummy(PG_FUNCTION_ARGS)
662
{
663
	int32		on = PG_GETARG_INT32(0);
664 665

	if (ttoff)					/* OFF currently */
666 667
	{
		if (on == 0)
668
			PG_RETURN_INT32(0);
669

670 671
		/* turn ON */
		ttoff = false;
672
		PG_RETURN_INT32(0);
673
	}
674

675 676
	/* ON currently */
	if (on != 0)
677
		PG_RETURN_INT32(1);
678

679 680
	/* turn OFF */
	ttoff = true;
681

682
	PG_RETURN_INT32(1);
683
}
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741


/*
 * Type int44 has no real-world use, but the regression tests use it.
 * It's a four-element vector of int4's.
 */

/*
 *		int44in			- converts "num num ..." to internal form
 *
 *		Note: Fills any missing positions with zeroes.
 */
PG_FUNCTION_INFO_V1(int44in);

Datum
int44in(PG_FUNCTION_ARGS)
{
	char	   *input_string = PG_GETARG_CSTRING(0);
	int32	   *result = (int32 *) palloc(4 * sizeof(int32));
	int			i;

	i = sscanf(input_string,
			   "%d, %d, %d, %d",
			   &result[0],
			   &result[1],
			   &result[2],
			   &result[3]);
	while (i < 4)
		result[i++] = 0;

	PG_RETURN_POINTER(result);
}

/*
 *		int44out		- converts internal form to "num num ..."
 */
PG_FUNCTION_INFO_V1(int44out);

Datum
int44out(PG_FUNCTION_ARGS)
{
	int32	   *an_array = (int32 *) PG_GETARG_POINTER(0);
	char	   *result = (char *) palloc(16 * 4);		/* Allow 14 digits +
														 * sign */
	int			i;
	char	   *walk;

	walk = result;
	for (i = 0; i < 4; i++)
	{
		pg_ltoa(an_array[i], walk);
		while (*++walk != '\0')
			;
		*walk++ = ' ';
	}
	*--walk = '\0';
	PG_RETURN_CSTRING(result);
}