regress.c 14.0 KB
Newer Older
1
/*
2
 * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.36 2000/04/12 17:17:21 momjian Exp $
3 4
 */

5
#include <float.h>				/* faked on sunos */
6

7
#include "postgres.h"
M
Marc G. Fournier 已提交
8

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

#define P_MAXDIG 12
13 14 15
#define LDELIM			'('
#define RDELIM			')'
#define DELIM			','
16

17
typedef void *TUPLE;
18

19 20 21 22 23
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);
24
extern char overpaid(TUPLE tuple);
B
Bruce Momjian 已提交
25
extern int	boxarea(BOX *box);
26
extern char *reverse_name(char *string);
27 28

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

	switch (path->npts)
	{
43
		case 0:
44
			result = palloc(sizeof(double));
45 46 47 48 49 50 51 52 53 54 55 56
			*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);
57
			result = palloc(sizeof(double));
58 59 60 61 62 63
			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;
64
				pfree(tmp);
65 66 67

			}
			break;
68
	}
69
	return result;
70 71 72 73
}

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

	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;
98
			pfree(tmp);
99 100
		}

101
	return min;
102 103
}

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

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

114 115 116 117 118
	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);
	}
119

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

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

132 133 134 135 136
	Point	   *retval;
	int			i,
				j;
	LSEG		seg1,
				seg2;
137

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

141
#endif
142
	bool		found;			/* We've found the intersection */
143

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

146 147 148 149 150 151 152 153
	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;
		}
154

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

161
	return retval;
162 163 164 165
}


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


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

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

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

196 197
typedef struct
{
198 199 200
	Point		center;
	double		radius;
}			WIDGET;
201

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

#define NARGS	3

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

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

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

235
char *
236
widget_out(widget)
237
WIDGET	   *widget;
238
{
239
	char	   *result;
240

241
	if (widget == NULL)
242
		return NULL;
243

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

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

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

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

262
int
263 264
boxarea(box)

265
BOX		   *box;
266 267

{
268 269
	int			width,
				height;
270

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

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

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

#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;
320 321 322
	char	   *query,
			   *fieldval,
			   *fieldtype;
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

	(*level)++;

	SPI_connect();

368 369 370
	fieldval = SPI_getvalue(tuple, tupdesc, 1);
	fieldtype = SPI_gettype(tupdesc, 1);

371
	query = (char *) palloc(100 + NAMEDATALEN * 3 +
372 373 374
							strlen(fieldval) + strlen(fieldtype));

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

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

	inserted = SPI_processed;

385
	sprintf(query, "select count (*) from %s where %s = '%s'::%s",
V
Vadim B. Mikheev 已提交
386 387
			SPI_getrelname(rel),
			SPI_fname(tupdesc, 1),
388
			fieldval, fieldtype);
V
Vadim B. Mikheev 已提交
389

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

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

	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;

415
	return tuple;
V
Vadim B. Mikheev 已提交
416
}
417

418 419
HeapTuple	ttdummy(void);
int32		set_ttdummy(int32 on);
420

421
extern int4 nextval(struct varlena * seqin);
422 423 424

#define TTDUMMY_INFINITY	999999

425 426
static void *splan = NULL;
static bool ttoff = false;
427 428 429 430 431 432 433

HeapTuple
ttdummy()
{
	Trigger    *trigger;		/* to get trigger name */
	char	  **args;			/* arguments */
	int			attnum[2];		/* fnumbers of start/stop columns */
434 435 436 437
	Datum		oldon,
				oldoff;
	Datum		newon,
				newoff;
438 439 440 441 442 443 444 445 446 447 448 449 450 451
	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 已提交
452
		elog(ERROR, "ttdummy: triggers are not initialized");
453
	if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
B
Bruce Momjian 已提交
454
		elog(ERROR, "ttdummy: can't process STATEMENT events");
455
	if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
B
Bruce Momjian 已提交
456
		elog(ERROR, "ttdummy: must be fired before event");
457
	if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
458
		elog(ERROR, "ttdummy: can't process INSERT event");
459 460
	if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
		newtuple = CurrentTriggerData->tg_newtuple;
461

462
	trigtuple = CurrentTriggerData->tg_trigtuple;
463

464 465
	rel = CurrentTriggerData->tg_relation;
	relname = SPI_getrelname(rel);
466

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

474 475 476
	trigger = CurrentTriggerData->tg_trigger;

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

480 481 482
	args = trigger->tgargs;
	tupdesc = rel->rd_att;
	natts = tupdesc->natts;
483

484
	CurrentTriggerData = NULL;
485 486

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

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

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

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

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

529
	{
530 531 532 533
		struct varlena *seqname = textin("ttdummy_seq");

		newoff = nextval(seqname);
		pfree(seqname);
534
	}
535

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

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

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

565 566 567 568 569
	/* if there is no plan ... */
	if (splan == NULL)
	{
		void	   *pplan;
		Oid		   *ctypes;
570
		char	   *query;
571

572
		/* allocate space in preparation */
573
		ctypes = (Oid *) palloc(natts * sizeof(Oid));
574
		query = (char *) palloc(100 + 16 * natts);
575

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

587
		/* Prepare plan for query */
588
		pplan = SPI_prepare(query, natts, ctypes);
589
		if (pplan == NULL)
B
Bruce Momjian 已提交
590
			elog(ERROR, "ttdummy (%s): SPI_prepare returned %d", relname, SPI_result);
591

592 593
		pplan = SPI_saveplan(pplan);
		if (pplan == NULL)
B
Bruce Momjian 已提交
594
			elog(ERROR, "ttdummy (%s): SPI_saveplan returned %d", relname, SPI_result);
595

596 597
		splan = pplan;
	}
598

599
	ret = SPI_execp(splan, cvals, cnulls, 0);
600

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

604
	/* Tuple to return to upper Executor ... */
605
	if (newtuple)				/* UPDATE */
606 607
	{
		HeapTuple	tmptuple;
608 609 610

		tmptuple = SPI_copytuple(trigtuple);
		rettuple = SPI_modifytuple(rel, tmptuple, 1, &(attnum[1]), &newoff, NULL);
611
		SPI_freetuple(tmptuple);
612
	}
613 614
	else
/* DELETE */
615
		rettuple = trigtuple;
616 617 618 619

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

	pfree(relname);
620

621
	return rettuple;
622 623 624 625 626
}

int32
set_ttdummy(int32 on)
{
627 628

	if (ttoff)					/* OFF currently */
629 630
	{
		if (on == 0)
631
			return 0;
632

633 634
		/* turn ON */
		ttoff = false;
635
		return 0;
636
	}
637

638 639
	/* ON currently */
	if (on != 0)
640
		return 1;
641

642 643
	/* turn OFF */
	ttoff = true;
644

645
	return 1;
646 647

}