regress.c 16.9 KB
Newer Older
1
/*
2
 * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.54 2002/11/13 00:39:48 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 = palloc0(NAMEDATALEN)))
304
	{
305
		fprintf(stderr, "reverse_name: palloc failed\n");
306
		return NULL;
307
	}
308
	for (i = 0; i < NAMEDATALEN && string[i]; ++i)
309
		;
310
	if (i == NAMEDATALEN || !string[i])
311 312 313 314
		--i;
	len = i;
	for (; i >= 0; --i)
		new_string[len - i] = string[i];
315
	return new_string;
316
}
V
Vadim B. Mikheev 已提交
317

318 319 320 321 322 323
/* 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 已提交
324
	int			len = 0;
325 326 327 328 329 330 331

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

	return n + len;
}

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

343 344
PG_FUNCTION_INFO_V1(funny_dup17);

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

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

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

	(*level)++;

	SPI_connect();

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

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

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

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

	inserted = SPI_processed;

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

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

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

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

	SPI_finish();

	(*level)--;

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

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

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

#define TTDUMMY_INFINITY	999999

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

461 462
PG_FUNCTION_INFO_V1(ttdummy);

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

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

498
	trigtuple = trigdata->tg_trigtuple;
499

500
	rel = trigdata->tg_relation;
501
	relname = SPI_getrelname(rel);
502

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

510
	trigger = trigdata->tg_trigger;
511 512

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

634 635
		splan = pplan;
	}
636

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

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

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

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

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

	pfree(relname);
658

659
	return PointerGetDatum(rettuple);
660 661
}

662 663
PG_FUNCTION_INFO_V1(set_ttdummy);

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

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

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

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

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

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


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