regress.c 16.8 KB
Newer Older
1
/*
2
 * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.61 2004/10/07 15:21:58 momjian 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

/*
31 32
 * Distance from a point to a path
 */
33 34
PG_FUNCTION_INFO_V1(regress_dist_ptpath);

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

	switch (path->npts)
	{
47
		case 0:
48
			PG_RETURN_NULL();
49
		case 1:
50
			result = point_dt(pt, &path->p[0]);
51 52 53 54 55 56 57 58 59 60 61
			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]);
62
				tmp = DatumGetFloat8(DirectFunctionCall2(dist_ps,
B
Bruce Momjian 已提交
63 64
													  PointPGetDatum(pt),
												  LsegPGetDatum(&lseg)));
65 66
				if (i == 0 || tmp < result)
					result = tmp;
67 68
			}
			break;
69
	}
70
	PG_RETURN_FLOAT8(result);
71 72
}

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

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

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

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

B
Bruce Momjian 已提交
110
	if (!have_min)
111 112 113
		PG_RETURN_NULL();

	PG_RETURN_FLOAT8(min);
114 115
}

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

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

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

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

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

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

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

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

167 168
	if (!found)
		PG_RETURN_NULL();
169

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


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

192 193
PG_FUNCTION_INFO_V1(overpaid);

194 195
Datum
overpaid(PG_FUNCTION_ARGS)
196
{
197
	HeapTupleHeader tuple = PG_GETARG_HEAPTUPLEHEADER(0);
198
	bool		isnull;
199
	int32		salary;
200

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

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

212 213
typedef struct
{
214 215
	Point		center;
	double		radius;
216
}	WIDGET;
217

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

#define NARGS	3

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

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

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

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

255
	if (widget == NULL)
256
		return NULL;
257

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

264 265
PG_FUNCTION_INFO_V1(pt_in_widget);

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

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

275
#define ABS(X) ((X) >= 0 ? (X) : -(X))
276

277 278
PG_FUNCTION_INFO_V1(boxarea);

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

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

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

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

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

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

	return n + len;
}

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

335 336
PG_FUNCTION_INFO_V1(funny_dup17);

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

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

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

	(*level)++;

	SPI_connect();

396 397 398
	fieldval = SPI_getvalue(tuple, tupdesc, 1);
	fieldtype = SPI_gettype(tupdesc, 1);

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

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

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

	inserted = SPI_processed;

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

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

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

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

	SPI_finish();

	(*level)--;

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

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

445
extern Datum ttdummy(PG_FUNCTION_ARGS);
446
extern Datum set_ttdummy(PG_FUNCTION_ARGS);
447 448 449

#define TTDUMMY_INFINITY	999999

450 451
static void *splan = NULL;
static bool ttoff = false;
452

453 454
PG_FUNCTION_INFO_V1(ttdummy);

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

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

490
	trigtuple = trigdata->tg_trigtuple;
491

492
	rel = trigdata->tg_relation;
493
	relname = SPI_getrelname(rel);
494

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

502
	trigger = trigdata->tg_trigger;
503 504

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

508 509 510
	args = trigger->tgargs;
	tupdesc = rel->rd_att;
	natts = tupdesc->natts;
511 512

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

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

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

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

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

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

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

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

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

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

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

602
		/* allocate space in preparation */
603
		ctypes = (Oid *) palloc(natts * sizeof(Oid));
604
		query = (char *) palloc(100 + 16 * natts);
605

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

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

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

626 627
		splan = pplan;
	}
628

629
	ret = SPI_execp(splan, cvals, cnulls, 0);
630

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

634
	/* Tuple to return to upper Executor ... */
635
	if (newtuple)				/* UPDATE */
636 637
	{
		HeapTuple	tmptuple;
638 639 640

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

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

	pfree(relname);
650

651
	return PointerGetDatum(rettuple);
652 653
}

654 655
PG_FUNCTION_INFO_V1(set_ttdummy);

656 657
Datum
set_ttdummy(PG_FUNCTION_ARGS)
658
{
659
	int32		on = PG_GETARG_INT32(0);
660 661

	if (ttoff)					/* OFF currently */
662 663
	{
		if (on == 0)
664
			PG_RETURN_INT32(0);
665

666 667
		/* turn ON */
		ttoff = false;
668
		PG_RETURN_INT32(0);
669
	}
670

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

675 676
	/* turn OFF */
	ttoff = true;
677

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


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