regress.c 13.9 KB
Newer Older
1
/*
B
Bruce Momjian 已提交
2
 * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.32 1999/05/25 16:15:26 momjian Exp $
3 4
 */

5
#include <float.h>				/* faked on sunos */
6
#include <stdio.h>
B
Bruce Momjian 已提交
7
#include <string.h>				/* for MemSet() */
8

M
Marc G. Fournier 已提交
9 10
#include <postgres.h>

11
#include "utils/geo_decls.h"	/* includes <math.h> */
12
#include "executor/executor.h"	/* For GetAttributeByName */
13 14

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

19
typedef void *TUPLE;
20

21 22 23 24 25
extern double *regress_dist_ptpath(Point *pt, PATH *path);
extern double *regress_path_dist(PATH *p1, PATH *p2);
extern PATH *poly2path(POLYGON *poly);
extern Point *interpt_pp(PATH *p1, PATH *p2);
extern void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
26
extern char overpaid(TUPLE tuple);
B
Bruce Momjian 已提交
27
extern int	boxarea(BOX *box);
28
extern char *reverse_name(char *string);
29 30

/*
31
** Distance from a point to a path
32
*/
33
double *
34
regress_dist_ptpath(pt, path)
35 36
Point	   *pt;
PATH	   *path;
37
{
38 39 40 41
	double	   *result;
	double	   *tmp;
	int			i;
	LSEG		lseg;
42 43 44

	switch (path->npts)
	{
45
		case 0:
46
			result = palloc(sizeof(double));
47 48 49 50 51 52 53 54 55 56 57 58
			*result = Abs((double) DBL_MAX);	/* +infinity */
			break;
		case 1:
			result = point_distance(pt, &path->p[0]);
			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);
59
			result = palloc(sizeof(double));
60 61 62 63 64 65
			for (i = 0; i < path->npts - 1; ++i)
			{
				regress_lseg_construct(&lseg, &path->p[i], &path->p[i + 1]);
				tmp = dist_ps(pt, &lseg);
				if (i == 0 || *tmp < *result)
					*result = *tmp;
66
				pfree(tmp);
67 68 69

			}
			break;
70
	}
71
	return result;
72 73 74 75
}

/* this essentially does a cartesian product of the lsegs in the
   two paths, and finds the min distance between any two lsegs */
76
double *
77
regress_path_dist(p1, p2)
78 79
PATH	   *p1;
PATH	   *p2;
80
{
81 82 83 84 85 86
	double	   *min,
			   *tmp;
	int			i,
				j;
	LSEG		seg1,
				seg2;
87 88 89 90 91 92 93 94 95 96 97 98 99

	regress_lseg_construct(&seg1, &p1->p[0], &p1->p[1]);
	regress_lseg_construct(&seg2, &p2->p[0], &p2->p[1]);
	min = lseg_distance(&seg1, &seg2);

	for (i = 0; i < p1->npts - 1; i++)
		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]);

			if (*min < *(tmp = lseg_distance(&seg1, &seg2)))
				*min = *tmp;
100
			pfree(tmp);
101 102
		}

103
	return min;
104 105
}

106
PATH *
107
poly2path(poly)
108
POLYGON    *poly;
109
{
110
	int			i;
111
	char	   *output = (char *) palloc(2 * (P_MAXDIG + 1) * poly->npts + 64);
112
	char		buf[2 * (P_MAXDIG) + 20];
113

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

116 117 118 119 120
	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);
	}
121

122 123
	sprintf(buf, "%c", RDELIM);
	strcat(output, buf);
124
	return path_in(output);
125 126
}

127
/* return the point where two paths intersect.	Assumes that they do. */
128
Point *
129
interpt_pp(p1, p2)
130 131
PATH	   *p1;
PATH	   *p2;
132
{
133

134 135 136 137 138
	Point	   *retval;
	int			i,
				j;
	LSEG		seg1,
				seg2;
139

M
 
Marc G. Fournier 已提交
140
#ifdef NOT_USED
141
	LINE	   *ln;
142

143
#endif
144
	bool		found;			/* We've found the intersection */
145

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

148 149 150 151 152 153 154 155
	for (i = 0; i < p1->npts - 1 && !found; i++)
		for (j = 0; j < p2->npts - 1 && !found; j++)
		{
			regress_lseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
			regress_lseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
			if (lseg_intersect(&seg1, &seg2))
				found = true;
		}
156

M
 
Marc G. Fournier 已提交
157
#ifdef NOT_USED
158 159
	ln = line_construct_pp(&seg2.p[0], &seg2.p[1]);
	retval = interpt_sl(&seg1, ln);
160
#endif
161 162
	retval = lseg_interpt(&seg1, &seg2);

163
	return retval;
164 165 166 167
}


/* like lseg_construct, but assume space already allocated */
168
void
169
regress_lseg_construct(lseg, pt1, pt2)
170 171 172
LSEG	   *lseg;
Point	   *pt1;
Point	   *pt2;
173
{
174 175 176 177 178
	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);
179 180 181
}


182 183
char
overpaid(tuple)
184
TUPLE		tuple;
185
{
186 187
	bool		isnull;
	long		salary;
188

189
	salary = (long) GetAttributeByName(tuple, "salary", &isnull);
190
	return salary > 699;
191 192
}

193 194
/* New type "widget"
 * This used to be "circle", but I added circle to builtins,
195
 *	so needed to make sure the names do not collide. - tgl 97/04/21
196 197
 */

198 199
typedef struct
{
200 201 202
	Point		center;
	double		radius;
}			WIDGET;
203

204 205
WIDGET	   *widget_in(char *str);
char	   *widget_out(WIDGET * widget);
206
int			pt_in_widget(Point *point, WIDGET * widget);
207 208 209

#define NARGS	3

210
WIDGET *
211
widget_in(str)
212
char	   *str;
213
{
214 215 216 217 218
	char	   *p,
			   *coord[NARGS],
				buf2[1000];
	int			i;
	WIDGET	   *result;
219 220

	if (str == NULL)
221
		return NULL;
222 223 224 225
	for (i = 0, p = str; *p && i < NARGS && *p != RDELIM; p++)
		if (*p == ',' || (*p == LDELIM && !i))
			coord[i++] = p + 1;
	if (i < NARGS - 1)
226
		return NULL;
227
	result = (WIDGET *) palloc(sizeof(WIDGET));
228 229 230 231
	result->center.x = atof(coord[0]);
	result->center.y = atof(coord[1]);
	result->radius = atof(coord[2]);

232
	sprintf(buf2, "widget_in: read (%f, %f, %f)\n", result->center.x,
233
			result->center.y, result->radius);
234
	return result;
235 236
}

237
char *
238
widget_out(widget)
239
WIDGET	   *widget;
240
{
241
	char	   *result;
242

243
	if (widget == NULL)
244
		return NULL;
245

246 247 248
	result = (char *) palloc(60);
	sprintf(result, "(%g,%g,%g)",
			widget->center.x, widget->center.y, widget->radius);
249
	return result;
250 251
}

252
int
253
pt_in_widget(point, widget)
254 255
Point	   *point;
WIDGET	   *widget;
256
{
257
	extern double point_dt();
258

259
	return point_dt(point, &widget->center) < widget->radius;
260 261 262 263
}

#define ABS(X) ((X) > 0 ? (X) : -(X))

264
int
265 266
boxarea(box)

267
BOX		   *box;
268 269

{
270 271
	int			width,
				height;
272

273
	width = ABS(box->high.x - box->low.x);
274
	height = ABS(box->high.y - box->low.y);
275
	return width * height;
276 277
}

278
char *
279
reverse_name(string)
280
char	   *string;
281
{
282
	int			i;
283 284
	int			len;
	char	   *new_string;
285

286
	if (!(new_string = palloc(NAMEDATALEN)))
287
	{
288
		fprintf(stderr, "reverse_name: palloc failed\n");
289
		return NULL;
290
	}
291 292
	MemSet(new_string, 0, NAMEDATALEN);
	for (i = 0; i < NAMEDATALEN && string[i]; ++i)
293
		;
294
	if (i == NAMEDATALEN || !string[i])
295 296 297 298
		--i;
	len = i;
	for (; i >= 0; --i)
		new_string[len - i] = string[i];
299
	return new_string;
300
}
V
Vadim B. Mikheev 已提交
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321

#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;
HeapTuple	funny_dup17(void);

HeapTuple						/* have to return HeapTuple to Executor */
funny_dup17()
{
	TransactionId *xid;
	int		   *level;
	bool	   *recursion;
	Relation	rel;
	TupleDesc	tupdesc;
	HeapTuple	tuple;
322
	char		sql[MAX_QUERY_SIZE];
V
Vadim B. Mikheev 已提交
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
	char	   *when;
	int			inserted;
	int			selected = 0;
	int			ret;

	tuple = CurrentTriggerData->tg_trigtuple;
	rel = CurrentTriggerData->tg_relation;
	tupdesc = rel->rd_att;
	if (TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
	{
		xid = &fd17b_xid;
		level = &fd17b_level;
		recursion = &fd17b_recursion;
		when = "BEFORE";
	}
	else
	{
		xid = &fd17a_xid;
		level = &fd17a_level;
		recursion = &fd17a_recursion;
		when = "AFTER ";
	}

	CurrentTriggerData = NULL;

	if (!TransactionIdIsCurrentTransactionId(*xid))
	{
		*xid = GetCurrentTransactionId();
		*level = 0;
		*recursion = true;
	}

	if (*level == 17)
	{
		*recursion = false;
358
		return tuple;
V
Vadim B. Mikheev 已提交
359 360 361
	}

	if (!(*recursion))
362
		return tuple;
V
Vadim B. Mikheev 已提交
363 364 365 366 367 368 369 370 371 372 373 374

	(*level)++;

	SPI_connect();

	sprintf(sql, "insert into %s select * from %s where %s = '%s'::%s",
			SPI_getrelname(rel), SPI_getrelname(rel),
			SPI_fname(tupdesc, 1),
			SPI_getvalue(tuple, tupdesc, 1),
			SPI_gettype(tupdesc, 1));

	if ((ret = SPI_exec(sql, 0)) < 0)
B
Bruce Momjian 已提交
375
		elog(ERROR, "funny_dup17 (fired %s) on level %3d: SPI_exec (insert ...) returned %d",
V
Vadim B. Mikheev 已提交
376 377 378 379 380 381 382 383 384 385 386
			 when, *level, ret);

	inserted = SPI_processed;

	sprintf(sql, "select count (*) from %s where %s = '%s'::%s",
			SPI_getrelname(rel),
			SPI_fname(tupdesc, 1),
			SPI_getvalue(tuple, tupdesc, 1),
			SPI_gettype(tupdesc, 1));

	if ((ret = SPI_exec(sql, 0)) < 0)
B
Bruce Momjian 已提交
387
		elog(ERROR, "funny_dup17 (fired %s) on level %3d: SPI_exec (select ...) returned %d",
V
Vadim B. Mikheev 已提交
388 389 390 391
			 when, *level, ret);

	if (SPI_processed > 0)
	{
392
		selected = int4in(
B
Bruce Momjian 已提交
393 394 395 396 397
						  SPI_getvalue(
									   SPI_tuptable->vals[0],
									   SPI_tuptable->tupdesc,
									   1
									   )
V
Vadim B. Mikheev 已提交
398 399 400 401 402 403 404 405 406 407 408 409 410
			);
	}

	elog(NOTICE, "funny_dup17 (fired %s) on level %3d: %d/%d tuples inserted/selected",
		 when, *level, inserted, selected);

	SPI_finish();

	(*level)--;

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

411
	return tuple;
V
Vadim B. Mikheev 已提交
412
}
413

414 415
HeapTuple	ttdummy(void);
int32		set_ttdummy(int32 on);
416

417
extern int4 nextval(struct varlena * seqin);
418 419 420

#define TTDUMMY_INFINITY	999999

421 422
static void *splan = NULL;
static bool ttoff = false;
423 424 425 426 427 428 429

HeapTuple
ttdummy()
{
	Trigger    *trigger;		/* to get trigger name */
	char	  **args;			/* arguments */
	int			attnum[2];		/* fnumbers of start/stop columns */
430 431 432 433
	Datum		oldon,
				oldoff;
	Datum		newon,
				newoff;
434 435 436 437 438 439 440 441 442 443 444 445 446 447
	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;

	if (!CurrentTriggerData)
B
Bruce Momjian 已提交
448
		elog(ERROR, "ttdummy: triggers are not initialized");
449
	if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
B
Bruce Momjian 已提交
450
		elog(ERROR, "ttdummy: can't process STATEMENT events");
451
	if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
B
Bruce Momjian 已提交
452
		elog(ERROR, "ttdummy: must be fired before event");
453
	if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
454
		elog(ERROR, "ttdummy: can't process INSERT event");
455 456
	if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
		newtuple = CurrentTriggerData->tg_newtuple;
457

458
	trigtuple = CurrentTriggerData->tg_trigtuple;
459

460 461
	rel = CurrentTriggerData->tg_relation;
	relname = SPI_getrelname(rel);
462

463
	/* check if TT is OFF for this relation */
464
	if (ttoff)					/* OFF - nothing to do */
465
	{
466
		pfree(relname);
467
		return (newtuple != NULL) ? newtuple : trigtuple;
468
	}
469

470 471 472
	trigger = CurrentTriggerData->tg_trigger;

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

476 477 478
	args = trigger->tgargs;
	tupdesc = rel->rd_att;
	natts = tupdesc->natts;
479

480
	CurrentTriggerData = NULL;
481 482

	for (i = 0; i < 2; i++)
483
	{
484 485
		attnum[i] = SPI_fnumber(tupdesc, args[i]);
		if (attnum[i] < 0)
B
Bruce Momjian 已提交
486
			elog(ERROR, "ttdummy (%s): there is no attribute %s", relname, args[i]);
487 488 489
		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]);
490
	}
491 492

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

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

	if (newtuple != NULL)		/* UPDATE */
501
	{
502
		newon = SPI_getbinval(newtuple, tupdesc, attnum[0], &isnull);
503
		if (isnull)
B
Bruce Momjian 已提交
504
			elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]);
505
		newoff = SPI_getbinval(newtuple, tupdesc, attnum[1], &isnull);
506
		if (isnull)
B
Bruce Momjian 已提交
507
			elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]);
508 509 510 511 512 513

		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)
514
		{
515
			pfree(relname);		/* allocated in upper executor context */
516
			return NULL;
517 518 519 520
		}
	}
	else if (oldoff != TTDUMMY_INFINITY)		/* DELETE */
	{
521
		pfree(relname);
522
		return NULL;
523
	}
524

525
	{
526 527 528 529
		struct varlena *seqname = textin("ttdummy_seq");

		newoff = nextval(seqname);
		pfree(seqname);
530
	}
531

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

536
	/* Fetch tuple values and nulls */
537 538
	cvals = (Datum *) palloc(natts * sizeof(Datum));
	cnulls = (char *) palloc(natts * sizeof(char));
539 540
	for (i = 0; i < natts; i++)
	{
541 542
		cvals[i] = SPI_getbinval((newtuple != NULL) ? newtuple : trigtuple,
								 tupdesc, i + 1, &isnull);
543 544
		cnulls[i] = (isnull) ? 'n' : ' ';
	}
545

546
	/* change date column(s) */
547
	if (newtuple)				/* UPDATE */
548
	{
549
		cvals[attnum[0] - 1] = newoff;	/* start_date eq current date */
550
		cnulls[attnum[0] - 1] = ' ';
551
		cvals[attnum[1] - 1] = TTDUMMY_INFINITY;		/* stop_date eq INFINITY */
552 553
		cnulls[attnum[1] - 1] = ' ';
	}
554 555
	else
/* DELETE */
556
	{
557
		cvals[attnum[1] - 1] = newoff;	/* stop_date eq current date */
558 559
		cnulls[attnum[1] - 1] = ' ';
	}
560

561 562 563 564 565
	/* if there is no plan ... */
	if (splan == NULL)
	{
		void	   *pplan;
		Oid		   *ctypes;
566
		char		sql[MAX_QUERY_SIZE];
567

568 569
		/* allocate ctypes for preparation */
		ctypes = (Oid *) palloc(natts * sizeof(Oid));
570

571
		/*
572
		 * Construct query: INSERT INTO _relation_ VALUES ($1, ...)
573 574 575 576 577
		 */
		sprintf(sql, "INSERT INTO %s VALUES (", relname);
		for (i = 1; i <= natts; i++)
		{
			sprintf(sql + strlen(sql), "$%d%s",
578
					i, (i < natts) ? ", " : ")");
579 580
			ctypes[i - 1] = SPI_gettypeid(tupdesc, i);
		}
581

582 583 584
		/* Prepare plan for query */
		pplan = SPI_prepare(sql, natts, ctypes);
		if (pplan == NULL)
B
Bruce Momjian 已提交
585
			elog(ERROR, "ttdummy (%s): SPI_prepare returned %d", relname, SPI_result);
586

587 588
		pplan = SPI_saveplan(pplan);
		if (pplan == NULL)
B
Bruce Momjian 已提交
589
			elog(ERROR, "ttdummy (%s): SPI_saveplan returned %d", relname, SPI_result);
590

591 592
		splan = pplan;
	}
593

594
	ret = SPI_execp(splan, cvals, cnulls, 0);
595

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

599
	/* Tuple to return to upper Executor ... */
600
	if (newtuple)				/* UPDATE */
601 602
	{
		HeapTuple	tmptuple;
603 604 605 606

		tmptuple = SPI_copytuple(trigtuple);
		rettuple = SPI_modifytuple(rel, tmptuple, 1, &(attnum[1]), &newoff, NULL);
		SPI_pfree(tmptuple);
607
	}
608 609
	else
/* DELETE */
610
		rettuple = trigtuple;
611 612 613 614

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

	pfree(relname);
615

616
	return rettuple;
617 618 619 620 621
}

int32
set_ttdummy(int32 on)
{
622 623

	if (ttoff)					/* OFF currently */
624 625
	{
		if (on == 0)
626
			return 0;
627

628 629
		/* turn ON */
		ttoff = false;
630
		return 0;
631
	}
632

633 634
	/* ON currently */
	if (on != 0)
635
		return 1;
636

637 638
	/* turn OFF */
	ttoff = true;
639

640
	return 1;
641 642

}