regress.c 16.8 KB
Newer Older
1
/*
P
 
PostgreSQL Daemon 已提交
2
 * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.59 2003/11/29 19:52:14 pgsql 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
typedef TupleTableSlot *TUPLE;
19

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

/*
33 34
 * Distance from a point to a path
 */
35 36
PG_FUNCTION_INFO_V1(regress_dist_ptpath);

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

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

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

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

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

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

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

B
Bruce Momjian 已提交
112
	if (!have_min)
113 114 115
		PG_RETURN_NULL();

	PG_RETURN_FLOAT8(min);
116 117
}

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

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

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

134
	snprintf(buf, sizeof(buf), "%c", RDELIM);
135
	strcat(output, buf);
136 137
	return DatumGetPathP(DirectFunctionCall1(path_in,
											 CStringGetDatum(output)));
138 139
}

140
/* return the point where two paths intersect, or NULL if no intersection. */
141 142
PG_FUNCTION_INFO_V1(interpt_pp);

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

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

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

169 170
	if (!found)
		PG_RETURN_NULL();
171

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


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

194 195
PG_FUNCTION_INFO_V1(overpaid);

196 197
Datum
overpaid(PG_FUNCTION_ARGS)
198
{
199
	TUPLE		tuple = (TUPLE) PG_GETARG_POINTER(0);
200
	bool		isnull;
201
	int32		salary;
202

203
	salary = DatumGetInt32(GetAttributeByName(tuple, "salary", &isnull));
204 205 206
	if (isnull)
		PG_RETURN_NULL();
	PG_RETURN_BOOL(salary > 699);
207 208
}

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

214 215
typedef struct
{
216 217
	Point		center;
	double		radius;
218
}	WIDGET;
219

220
WIDGET	   *widget_in(char *str);
B
Bruce Momjian 已提交
221
char	   *widget_out(WIDGET * widget);
222
extern Datum pt_in_widget(PG_FUNCTION_ARGS);
223 224 225

#define NARGS	3

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

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

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

252
char *
B
Bruce Momjian 已提交
253
widget_out(WIDGET * widget)
254
{
255
	char	   *result;
256

257
	if (widget == NULL)
258
		return NULL;
259

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

266 267
PG_FUNCTION_INFO_V1(pt_in_widget);

268 269
Datum
pt_in_widget(PG_FUNCTION_ARGS)
270
{
271 272
	Point	   *point = PG_GETARG_POINT_P(0);
	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
273

274
	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
275 276
}

277
#define ABS(X) ((X) >= 0 ? (X) : -(X))
278

279 280
PG_FUNCTION_INFO_V1(boxarea);

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

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

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

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

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

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

	return n + len;
}

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

337 338
PG_FUNCTION_INFO_V1(funny_dup17);

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

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

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

	(*level)++;

	SPI_connect();

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

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

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

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

	inserted = SPI_processed;

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

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

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

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

	SPI_finish();

	(*level)--;

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

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

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

#define TTDUMMY_INFINITY	999999

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

455 456
PG_FUNCTION_INFO_V1(ttdummy);

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

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

492
	trigtuple = trigdata->tg_trigtuple;
493

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

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

504
	trigger = trigdata->tg_trigger;
505 506

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

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

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

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

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

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

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

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

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

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

572
	/* Fetch tuple values and nulls */
573 574
	cvals = (Datum *) palloc(natts * sizeof(Datum));
	cnulls = (char *) palloc(natts * sizeof(char));
575 576
	for (i = 0; i < natts; i++)
	{
577 578
		cvals[i] = SPI_getbinval((newtuple != NULL) ? newtuple : trigtuple,
								 tupdesc, i + 1, &isnull);
579 580
		cnulls[i] = (isnull) ? 'n' : ' ';
	}
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 589
		cnulls[attnum[1] - 1] = ' ';
	}
590 591
	else
/* DELETE */
592
	{
593
		cvals[attnum[1] - 1] = newoff;	/* stop_date eq current date */
594 595
		cnulls[attnum[1] - 1] = ' ';
	}
596

597 598 599 600 601
	/* if there is no plan ... */
	if (splan == NULL)
	{
		void	   *pplan;
		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 613
		for (i = 1; i <= natts; i++)
		{
614
			sprintf(query + strlen(query), "$%d%s",
615
					i, (i < natts) ? ", " : ")");
616 617
			ctypes[i - 1] = SPI_gettypeid(tupdesc, i);
		}
618

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

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

628 629
		splan = pplan;
	}
630

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

633
	if (ret < 0)
B
Bruce Momjian 已提交
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 642

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

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

	pfree(relname);
652

653
	return PointerGetDatum(rettuple);
654 655
}

656 657
PG_FUNCTION_INFO_V1(set_ttdummy);

658 659
Datum
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 669
		/* turn ON */
		ttoff = false;
670
		PG_RETURN_INT32(0);
671
	}
672

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

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

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


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