regress.c 16.8 KB
Newer Older
1
/*
2
 * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.67 2006/05/30 21:21:30 tgl Exp $
3 4
 */

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

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

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

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

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

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


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

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

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

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

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

84 85
Datum
regress_path_dist(PG_FUNCTION_ARGS)
86
{
87 88 89 90 91
	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;
92 93 94 95
	int			i,
				j;
	LSEG		seg1,
				seg2;
96 97

	for (i = 0; i < p1->npts - 1; i++)
98
	{
99 100 101 102 103
		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]);

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

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

	PG_RETURN_FLOAT8(min);
119 120
}

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

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

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

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

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

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

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

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

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

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


/* like lseg_construct, but assume space already allocated */
187
void
188
regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
189
{
190 191 192 193 194
	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);
195 196
}

197 198
PG_FUNCTION_INFO_V1(overpaid);

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

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

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

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

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

#define NARGS	3

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

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

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

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

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

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

269 270
PG_FUNCTION_INFO_V1(pt_in_widget);

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

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

280 281
PG_FUNCTION_INFO_V1(boxarea);

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

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

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

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

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

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

	return n + len;
}

V
Vadim B. Mikheev 已提交
327 328 329 330 331 332 333 334 335
#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;
336
extern Datum funny_dup17(PG_FUNCTION_ARGS);
V
Vadim B. Mikheev 已提交
337

338 339
PG_FUNCTION_INFO_V1(funny_dup17);

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

358 359 360 361 362
	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 已提交
363
	tupdesc = rel->rd_att;
364
	if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
V
Vadim B. Mikheev 已提交
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
	{
		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;
389
		return PointerGetDatum(tuple);
V
Vadim B. Mikheev 已提交
390 391 392
	}

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

	(*level)++;

	SPI_connect();

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

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

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

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

	inserted = SPI_processed;

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

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

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

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

	SPI_finish();

	(*level)--;

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

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

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

#define TTDUMMY_INFINITY	999999

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

456 457
PG_FUNCTION_INFO_V1(ttdummy);

458 459
Datum
ttdummy(PG_FUNCTION_ARGS)
460
{
461
	TriggerData *trigdata = (TriggerData *) fcinfo->context;
462 463 464
	Trigger    *trigger;		/* to get trigger name */
	char	  **args;			/* arguments */
	int			attnum[2];		/* fnumbers of start/stop columns */
465 466 467 468
	Datum		oldon,
				oldoff;
	Datum		newon,
				newoff;
469 470 471 472 473 474 475 476 477 478 479 480 481
	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;

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

493
	trigtuple = trigdata->tg_trigtuple;
494

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

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

505
	trigger = trigdata->tg_trigger;
506 507

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

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

	for (i = 0; i < 2; i++)
516
	{
517 518
		attnum[i] = SPI_fnumber(tupdesc, args[i]);
		if (attnum[i] < 0)
B
Bruce Momjian 已提交
519
			elog(ERROR, "ttdummy (%s): there is no attribute %s", relname, args[i]);
520 521 522
		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]);
523
	}
524 525

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

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

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

		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)
547
		{
548
			pfree(relname);		/* allocated in upper executor context */
549
			return PointerGetDatum(NULL);
550 551 552 553
		}
	}
	else if (oldoff != TTDUMMY_INFINITY)		/* DELETE */
	{
554
		pfree(relname);
555
		return PointerGetDatum(NULL);
556
	}
557

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

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

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

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

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

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

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

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

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

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

629 630
		splan = pplan;
	}
631

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

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

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

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

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

	pfree(relname);
653

654
	return PointerGetDatum(rettuple);
655 656
}

657 658
PG_FUNCTION_INFO_V1(set_ttdummy);

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

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

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

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

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

681
	PG_RETURN_INT32(1);
682
}
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


/*
 * 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);
}