regress.c 16.9 KB
Newer Older
1
/*
2
 * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.53 2002/11/11 03:02:20 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
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
** Distance from a point to a path
34
*/
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
}

/* 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(poly)
118
POLYGON    *poly;
119
{
120
	int			i;
121
	char	   *output = (char *) palloc(2 * (P_MAXDIG + 1) * poly->npts + 64);
122
	char		buf[2 * (P_MAXDIG) + 20];
123

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

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

132 133
	sprintf(buf, "%c", RDELIM);
	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, pt1, pt2)
184 185 186
LSEG	   *lseg;
Point	   *pt1;
Point	   *pt2;
187
{
188 189 190 191 192
	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);
193 194
}

195 196
PG_FUNCTION_INFO_V1(overpaid);

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

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

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

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

221 222
WIDGET	   *widget_in(char *str);
char	   *widget_out(WIDGET * widget);
223
extern Datum pt_in_widget(PG_FUNCTION_ARGS);
224 225 226

#define NARGS	3

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

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

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

254
char *
255
widget_out(widget)
256
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
#define ABS(X) ((X) >= 0 ? (X) : -(X))
281

282 283
PG_FUNCTION_INFO_V1(boxarea);

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

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

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

303
	if (!(new_string = palloc(NAMEDATALEN)))
304
	{
305
		fprintf(stderr, "reverse_name: palloc failed\n");
306
		return NULL;
307
	}
308
	MemSet(new_string, 0, NAMEDATALEN);
309
	for (i = 0; i < NAMEDATALEN && string[i]; ++i)
310
		;
311
	if (i == NAMEDATALEN || !string[i])
312 313 314 315
		--i;
	len = i;
	for (; i >= 0; --i)
		new_string[len - i] = string[i];
316
	return new_string;
317
}
V
Vadim B. Mikheev 已提交
318

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

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

	return n + len;
}

V
Vadim B. Mikheev 已提交
333 334 335 336 337 338 339 340 341
#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;
342
extern Datum funny_dup17(PG_FUNCTION_ARGS);
V
Vadim B. Mikheev 已提交
343

344 345
PG_FUNCTION_INFO_V1(funny_dup17);

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

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

	if (!(*recursion))
399
		return PointerGetDatum(tuple);
V
Vadim B. Mikheev 已提交
400 401 402 403 404

	(*level)++;

	SPI_connect();

405 406 407
	fieldval = SPI_getvalue(tuple, tupdesc, 1);
	fieldtype = SPI_gettype(tupdesc, 1);

408
	query = (char *) palloc(100 + NAMEDATALEN * 3 +
409 410 411
							strlen(fieldval) + strlen(fieldtype));

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

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

	inserted = SPI_processed;

422
	sprintf(query, "select count (*) from %s where %s = '%s'::%s",
V
Vadim B. Mikheev 已提交
423 424
			SPI_getrelname(rel),
			SPI_fname(tupdesc, 1),
425
			fieldval, fieldtype);
V
Vadim B. Mikheev 已提交
426

427
	if ((ret = SPI_exec(query, 0)) < 0)
B
Bruce Momjian 已提交
428
		elog(ERROR, "funny_dup17 (fired %s) on level %3d: SPI_exec (select ...) returned %d",
V
Vadim B. Mikheev 已提交
429 430 431 432
			 when, *level, ret);

	if (SPI_processed > 0)
	{
433
		selected = DatumGetInt32(DirectFunctionCall1(int4in,
B
Bruce Momjian 已提交
434 435 436 437 438
											CStringGetDatum(SPI_getvalue(
												   SPI_tuptable->vals[0],
												   SPI_tuptable->tupdesc,
																		 1
																	))));
V
Vadim B. Mikheev 已提交
439 440
	}

B
Bruce Momjian 已提交
441
	elog(DEBUG3, "funny_dup17 (fired %s) on level %3d: %d/%d tuples inserted/selected",
V
Vadim B. Mikheev 已提交
442 443 444 445 446 447 448 449 450
		 when, *level, inserted, selected);

	SPI_finish();

	(*level)--;

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

451
	return PointerGetDatum(tuple);
V
Vadim B. Mikheev 已提交
452
}
453

454
extern Datum ttdummy(PG_FUNCTION_ARGS);
455
extern Datum set_ttdummy(PG_FUNCTION_ARGS);
456 457 458

#define TTDUMMY_INFINITY	999999

459 460
static void *splan = NULL;
static bool ttoff = false;
461

462 463
PG_FUNCTION_INFO_V1(ttdummy);

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

488 489 490
	if (!CALLED_AS_TRIGGER(fcinfo))
		elog(ERROR, "ttdummy: not fired by trigger manager");
	if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
B
Bruce Momjian 已提交
491
		elog(ERROR, "ttdummy: can't process STATEMENT events");
492
	if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
B
Bruce Momjian 已提交
493
		elog(ERROR, "ttdummy: must be fired before event");
494
	if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
495
		elog(ERROR, "ttdummy: can't process INSERT event");
496 497
	if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
		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 515 516
		elog(ERROR, "ttdummy (%s): invalid (!= 2) number of arguments %d",
			 relname, trigger->tgnargs);

517 518 519
	args = trigger->tgargs;
	tupdesc = rel->rd_att;
	natts = tupdesc->natts;
520 521

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

	oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull);
532
	if (isnull)
B
Bruce Momjian 已提交
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)
B
Bruce Momjian 已提交
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)
B
Bruce Momjian 已提交
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)
B
Bruce Momjian 已提交
546
			elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]);
547 548 549 550 551 552

		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)
553
		{
554
			pfree(relname);		/* allocated in upper executor context */
555
			return PointerGetDatum(NULL);
556 557 558 559
		}
	}
	else if (oldoff != TTDUMMY_INFINITY)		/* DELETE */
	{
560
		pfree(relname);
561
		return PointerGetDatum(NULL);
562
	}
563

564
	{
B
Bruce Momjian 已提交
565 566
		text	   *seqname = DatumGetTextP(DirectFunctionCall1(textin,
										CStringGetDatum("ttdummy_seq")));
567

568 569
		newoff = DirectFunctionCall1(nextval,
									 PointerGetDatum(seqname));
570 571
		/* nextval now returns int64; coerce down to int32 */
		newoff = Int32GetDatum((int32) DatumGetInt64(newoff));
572
		pfree(seqname);
573
	}
574

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

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

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

604 605 606 607 608
	/* if there is no plan ... */
	if (splan == NULL)
	{
		void	   *pplan;
		Oid		   *ctypes;
609
		char	   *query;
610

611
		/* allocate space in preparation */
612
		ctypes = (Oid *) palloc(natts * sizeof(Oid));
613
		query = (char *) palloc(100 + 16 * natts);
614

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

626
		/* Prepare plan for query */
627
		pplan = SPI_prepare(query, natts, ctypes);
628
		if (pplan == NULL)
B
Bruce Momjian 已提交
629
			elog(ERROR, "ttdummy (%s): SPI_prepare returned %d", relname, SPI_result);
630

631 632
		pplan = SPI_saveplan(pplan);
		if (pplan == NULL)
B
Bruce Momjian 已提交
633
			elog(ERROR, "ttdummy (%s): SPI_saveplan returned %d", relname, SPI_result);
634

635 636
		splan = pplan;
	}
637

638
	ret = SPI_execp(splan, cvals, cnulls, 0);
639

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

643
	/* Tuple to return to upper Executor ... */
644
	if (newtuple)				/* UPDATE */
645 646
	{
		HeapTuple	tmptuple;
647 648 649

		tmptuple = SPI_copytuple(trigtuple);
		rettuple = SPI_modifytuple(rel, tmptuple, 1, &(attnum[1]), &newoff, NULL);
650
		SPI_freetuple(tmptuple);
651
	}
652 653
	else
/* DELETE */
654
		rettuple = trigtuple;
655 656 657 658

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

	pfree(relname);
659

660
	return PointerGetDatum(rettuple);
661 662
}

663 664
PG_FUNCTION_INFO_V1(set_ttdummy);

665 666
Datum
set_ttdummy(PG_FUNCTION_ARGS)
667
{
668
	int32		on = PG_GETARG_INT32(0);
669 670

	if (ttoff)					/* OFF currently */
671 672
	{
		if (on == 0)
673
			PG_RETURN_INT32(0);
674

675 676
		/* turn ON */
		ttoff = false;
677
		PG_RETURN_INT32(0);
678
	}
679

680 681
	/* ON currently */
	if (on != 0)
682
		PG_RETURN_INT32(1);
683

684 685
	/* turn OFF */
	ttoff = true;
686

687
	PG_RETURN_INT32(1);
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 742 743 744 745 746


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