PolarDB-for-PostgreSQL

Форк
0
638 строк · 13.7 Кб
1
/*
2
 * in/out function for ltree and lquery
3
 * Teodor Sigaev <teodor@stack.net>
4
 * contrib/ltree/ltree_io.c
5
 */
6
#include "postgres.h"
7

8
#include <ctype.h>
9

10
#include "ltree.h"
11
#include "utils/memutils.h"
12
#include "crc32.h"
13

14
PG_FUNCTION_INFO_V1(ltree_in);
15
PG_FUNCTION_INFO_V1(ltree_out);
16
PG_FUNCTION_INFO_V1(lquery_in);
17
PG_FUNCTION_INFO_V1(lquery_out);
18

19

20
#define UNCHAR ereport(ERROR, \
21
					   (errcode(ERRCODE_SYNTAX_ERROR), \
22
						errmsg("syntax error at position %d", \
23
						pos)));
24

25

26
typedef struct
27
{
28
	char	   *start;
29
	int			len;			/* length in bytes */
30
	int			flag;
31
	int			wlen;			/* length in characters */
32
} nodeitem;
33

34
#define LTPRS_WAITNAME	0
35
#define LTPRS_WAITDELIM 1
36

37
Datum
38
ltree_in(PG_FUNCTION_ARGS)
39
{
40
	char	   *buf = (char *) PG_GETARG_POINTER(0);
41
	char	   *ptr;
42
	nodeitem   *list,
43
			   *lptr;
44
	int			num = 0,
45
				totallen = 0;
46
	int			state = LTPRS_WAITNAME;
47
	ltree	   *result;
48
	ltree_level *curlevel;
49
	int			charlen;
50
	int			pos = 0;
51

52
	ptr = buf;
53
	while (*ptr)
54
	{
55
		charlen = pg_mblen(ptr);
56
		if (charlen == 1 && t_iseq(ptr, '.'))
57
			num++;
58
		ptr += charlen;
59
	}
60

61
	if (num + 1 > LTREE_MAX_LEVELS)
62
		ereport(ERROR,
63
				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
64
				 errmsg("number of ltree levels (%d) exceeds the maximum allowed (%d)",
65
						num + 1, LTREE_MAX_LEVELS)));
66
	list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
67
	ptr = buf;
68
	while (*ptr)
69
	{
70
		charlen = pg_mblen(ptr);
71

72
		if (state == LTPRS_WAITNAME)
73
		{
74
			if (ISALNUM(ptr))
75
			{
76
				lptr->start = ptr;
77
				lptr->wlen = 0;
78
				state = LTPRS_WAITDELIM;
79
			}
80
			else
81
				UNCHAR;
82
		}
83
		else if (state == LTPRS_WAITDELIM)
84
		{
85
			if (charlen == 1 && t_iseq(ptr, '.'))
86
			{
87
				lptr->len = ptr - lptr->start;
88
				if (lptr->wlen > 255)
89
					ereport(ERROR,
90
							(errcode(ERRCODE_NAME_TOO_LONG),
91
							 errmsg("name of level is too long"),
92
							 errdetail("Name length is %d, must "
93
									   "be < 256, in position %d.",
94
									   lptr->wlen, pos)));
95

96
				totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
97
				lptr++;
98
				state = LTPRS_WAITNAME;
99
			}
100
			else if (!ISALNUM(ptr))
101
				UNCHAR;
102
		}
103
		else
104
			/* internal error */
105
			elog(ERROR, "internal error in parser");
106

107
		ptr += charlen;
108
		lptr->wlen++;
109
		pos++;
110
	}
111

112
	if (state == LTPRS_WAITDELIM)
113
	{
114
		lptr->len = ptr - lptr->start;
115
		if (lptr->wlen > 255)
116
			ereport(ERROR,
117
					(errcode(ERRCODE_NAME_TOO_LONG),
118
					 errmsg("name of level is too long"),
119
					 errdetail("Name length is %d, must "
120
							   "be < 256, in position %d.",
121
							   lptr->wlen, pos)));
122

123
		totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
124
		lptr++;
125
	}
126
	else if (!(state == LTPRS_WAITNAME && lptr == list))
127
		ereport(ERROR,
128
				(errcode(ERRCODE_SYNTAX_ERROR),
129
				 errmsg("syntax error"),
130
				 errdetail("Unexpected end of line.")));
131

132
	result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
133
	SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
134
	result->numlevel = lptr - list;
135
	curlevel = LTREE_FIRST(result);
136
	lptr = list;
137
	while (lptr - list < result->numlevel)
138
	{
139
		curlevel->len = (uint16) lptr->len;
140
		memcpy(curlevel->name, lptr->start, lptr->len);
141
		curlevel = LEVEL_NEXT(curlevel);
142
		lptr++;
143
	}
144

145
	pfree(list);
146
	PG_RETURN_POINTER(result);
147
}
148

149
Datum
150
ltree_out(PG_FUNCTION_ARGS)
151
{
152
	ltree	   *in = PG_GETARG_LTREE_P(0);
153
	char	   *buf,
154
			   *ptr;
155
	int			i;
156
	ltree_level *curlevel;
157

158
	ptr = buf = (char *) palloc(VARSIZE(in));
159
	curlevel = LTREE_FIRST(in);
160
	for (i = 0; i < in->numlevel; i++)
161
	{
162
		if (i != 0)
163
		{
164
			*ptr = '.';
165
			ptr++;
166
		}
167
		memcpy(ptr, curlevel->name, curlevel->len);
168
		ptr += curlevel->len;
169
		curlevel = LEVEL_NEXT(curlevel);
170
	}
171

172
	*ptr = '\0';
173
	PG_FREE_IF_COPY(in, 0);
174

175
	PG_RETURN_POINTER(buf);
176
}
177

178
#define LQPRS_WAITLEVEL 0
179
#define LQPRS_WAITDELIM 1
180
#define LQPRS_WAITOPEN	2
181
#define LQPRS_WAITFNUM	3
182
#define LQPRS_WAITSNUM	4
183
#define LQPRS_WAITND	5
184
#define LQPRS_WAITCLOSE 6
185
#define LQPRS_WAITEND	7
186
#define LQPRS_WAITVAR	8
187

188

189
#define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
190
#define ITEMSIZE	MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
191
#define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
192

193
Datum
194
lquery_in(PG_FUNCTION_ARGS)
195
{
196
	char	   *buf = (char *) PG_GETARG_POINTER(0);
197
	char	   *ptr;
198
	int			num = 0,
199
				totallen = 0,
200
				numOR = 0;
201
	int			state = LQPRS_WAITLEVEL;
202
	lquery	   *result;
203
	nodeitem   *lptr = NULL;
204
	lquery_level *cur,
205
			   *curqlevel,
206
			   *tmpql;
207
	lquery_variant *lrptr = NULL;
208
	bool		hasnot = false;
209
	bool		wasbad = false;
210
	int			charlen;
211
	int			pos = 0;
212

213
	ptr = buf;
214
	while (*ptr)
215
	{
216
		charlen = pg_mblen(ptr);
217

218
		if (charlen == 1)
219
		{
220
			if (t_iseq(ptr, '.'))
221
				num++;
222
			else if (t_iseq(ptr, '|'))
223
				numOR++;
224
		}
225

226
		ptr += charlen;
227
	}
228

229
	num++;
230
	if (num > LQUERY_MAX_LEVELS)
231
		ereport(ERROR,
232
				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
233
				 errmsg("number of lquery levels (%d) exceeds the maximum allowed (%d)",
234
						num, LQUERY_MAX_LEVELS)));
235
	curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
236
	ptr = buf;
237
	while (*ptr)
238
	{
239
		charlen = pg_mblen(ptr);
240

241
		if (state == LQPRS_WAITLEVEL)
242
		{
243
			if (ISALNUM(ptr))
244
			{
245
				GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
246
				lptr->start = ptr;
247
				state = LQPRS_WAITDELIM;
248
				curqlevel->numvar = 1;
249
			}
250
			else if (charlen == 1 && t_iseq(ptr, '!'))
251
			{
252
				GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
253
				lptr->start = ptr + 1;
254
				state = LQPRS_WAITDELIM;
255
				curqlevel->numvar = 1;
256
				curqlevel->flag |= LQL_NOT;
257
				hasnot = true;
258
			}
259
			else if (charlen == 1 && t_iseq(ptr, '*'))
260
				state = LQPRS_WAITOPEN;
261
			else
262
				UNCHAR;
263
		}
264
		else if (state == LQPRS_WAITVAR)
265
		{
266
			if (ISALNUM(ptr))
267
			{
268
				lptr++;
269
				lptr->start = ptr;
270
				state = LQPRS_WAITDELIM;
271
				curqlevel->numvar++;
272
			}
273
			else
274
				UNCHAR;
275
		}
276
		else if (state == LQPRS_WAITDELIM)
277
		{
278
			if (charlen == 1 && t_iseq(ptr, '@'))
279
			{
280
				if (lptr->start == ptr)
281
					UNCHAR;
282
				lptr->flag |= LVAR_INCASE;
283
				curqlevel->flag |= LVAR_INCASE;
284
			}
285
			else if (charlen == 1 && t_iseq(ptr, '*'))
286
			{
287
				if (lptr->start == ptr)
288
					UNCHAR;
289
				lptr->flag |= LVAR_ANYEND;
290
				curqlevel->flag |= LVAR_ANYEND;
291
			}
292
			else if (charlen == 1 && t_iseq(ptr, '%'))
293
			{
294
				if (lptr->start == ptr)
295
					UNCHAR;
296
				lptr->flag |= LVAR_SUBLEXEME;
297
				curqlevel->flag |= LVAR_SUBLEXEME;
298
			}
299
			else if (charlen == 1 && t_iseq(ptr, '|'))
300
			{
301
				lptr->len = ptr - lptr->start -
302
					((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
303
					((lptr->flag & LVAR_INCASE) ? 1 : 0) -
304
					((lptr->flag & LVAR_ANYEND) ? 1 : 0);
305
				if (lptr->wlen > 255)
306
					ereport(ERROR,
307
							(errcode(ERRCODE_NAME_TOO_LONG),
308
							 errmsg("name of level is too long"),
309
							 errdetail("Name length is %d, must "
310
									   "be < 256, in position %d.",
311
									   lptr->wlen, pos)));
312

313
				state = LQPRS_WAITVAR;
314
			}
315
			else if (charlen == 1 && t_iseq(ptr, '.'))
316
			{
317
				lptr->len = ptr - lptr->start -
318
					((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
319
					((lptr->flag & LVAR_INCASE) ? 1 : 0) -
320
					((lptr->flag & LVAR_ANYEND) ? 1 : 0);
321
				if (lptr->wlen > 255)
322
					ereport(ERROR,
323
							(errcode(ERRCODE_NAME_TOO_LONG),
324
							 errmsg("name of level is too long"),
325
							 errdetail("Name length is %d, must "
326
									   "be < 256, in position %d.",
327
									   lptr->wlen, pos)));
328

329
				state = LQPRS_WAITLEVEL;
330
				curqlevel = NEXTLEV(curqlevel);
331
			}
332
			else if (ISALNUM(ptr))
333
			{
334
				if (lptr->flag)
335
					UNCHAR;
336
			}
337
			else
338
				UNCHAR;
339
		}
340
		else if (state == LQPRS_WAITOPEN)
341
		{
342
			if (charlen == 1 && t_iseq(ptr, '{'))
343
				state = LQPRS_WAITFNUM;
344
			else if (charlen == 1 && t_iseq(ptr, '.'))
345
			{
346
				curqlevel->low = 0;
347
				curqlevel->high = LTREE_MAX_LEVELS;
348
				curqlevel = NEXTLEV(curqlevel);
349
				state = LQPRS_WAITLEVEL;
350
			}
351
			else
352
				UNCHAR;
353
		}
354
		else if (state == LQPRS_WAITFNUM)
355
		{
356
			if (charlen == 1 && t_iseq(ptr, ','))
357
				state = LQPRS_WAITSNUM;
358
			else if (t_isdigit(ptr))
359
			{
360
				int			low = atoi(ptr);
361

362
				if (low < 0 || low > LTREE_MAX_LEVELS)
363
					ereport(ERROR,
364
							(errcode(ERRCODE_SYNTAX_ERROR),
365
							 errmsg("lquery syntax error"),
366
							 errdetail("Low limit (%d) exceeds the maximum allowed (%d).",
367
									   low, LTREE_MAX_LEVELS)));
368

369
				curqlevel->low = (uint16) low;
370
				state = LQPRS_WAITND;
371
			}
372
			else
373
				UNCHAR;
374
		}
375
		else if (state == LQPRS_WAITSNUM)
376
		{
377
			if (t_isdigit(ptr))
378
			{
379
				int			high = atoi(ptr);
380

381
				if (high < 0 || high > LTREE_MAX_LEVELS)
382
					ereport(ERROR,
383
							(errcode(ERRCODE_SYNTAX_ERROR),
384
							 errmsg("lquery syntax error"),
385
							 errdetail("High limit (%d) exceeds the maximum allowed (%d).",
386
									   high, LTREE_MAX_LEVELS)));
387

388
				curqlevel->high = (uint16) high;
389
				state = LQPRS_WAITCLOSE;
390
			}
391
			else if (charlen == 1 && t_iseq(ptr, '}'))
392
			{
393
				curqlevel->high = LTREE_MAX_LEVELS;
394
				state = LQPRS_WAITEND;
395
			}
396
			else
397
				UNCHAR;
398
		}
399
		else if (state == LQPRS_WAITCLOSE)
400
		{
401
			if (charlen == 1 && t_iseq(ptr, '}'))
402
				state = LQPRS_WAITEND;
403
			else if (!t_isdigit(ptr))
404
				UNCHAR;
405
		}
406
		else if (state == LQPRS_WAITND)
407
		{
408
			if (charlen == 1 && t_iseq(ptr, '}'))
409
			{
410
				curqlevel->high = curqlevel->low;
411
				state = LQPRS_WAITEND;
412
			}
413
			else if (charlen == 1 && t_iseq(ptr, ','))
414
				state = LQPRS_WAITSNUM;
415
			else if (!t_isdigit(ptr))
416
				UNCHAR;
417
		}
418
		else if (state == LQPRS_WAITEND)
419
		{
420
			if (charlen == 1 && t_iseq(ptr, '.'))
421
			{
422
				state = LQPRS_WAITLEVEL;
423
				curqlevel = NEXTLEV(curqlevel);
424
			}
425
			else
426
				UNCHAR;
427
		}
428
		else
429
			/* internal error */
430
			elog(ERROR, "internal error in parser");
431

432
		ptr += charlen;
433
		if (state == LQPRS_WAITDELIM)
434
			lptr->wlen++;
435
		pos++;
436
	}
437

438
	if (state == LQPRS_WAITDELIM)
439
	{
440
		if (lptr->start == ptr)
441
			ereport(ERROR,
442
					(errcode(ERRCODE_SYNTAX_ERROR),
443
					 errmsg("lquery syntax error"),
444
					 errdetail("Unexpected end of line.")));
445

446
		lptr->len = ptr - lptr->start -
447
			((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
448
			((lptr->flag & LVAR_INCASE) ? 1 : 0) -
449
			((lptr->flag & LVAR_ANYEND) ? 1 : 0);
450
		if (lptr->len == 0)
451
			ereport(ERROR,
452
					(errcode(ERRCODE_SYNTAX_ERROR),
453
					 errmsg("lquery syntax error"),
454
					 errdetail("Unexpected end of line.")));
455

456
		if (lptr->wlen > 255)
457
			ereport(ERROR,
458
					(errcode(ERRCODE_NAME_TOO_LONG),
459
					 errmsg("name of level is too long"),
460
					 errdetail("Name length is %d, must "
461
							   "be < 256, in position %d.",
462
							   lptr->wlen, pos)));
463
	}
464
	else if (state == LQPRS_WAITOPEN)
465
		curqlevel->high = LTREE_MAX_LEVELS;
466
	else if (state != LQPRS_WAITEND)
467
		ereport(ERROR,
468
				(errcode(ERRCODE_SYNTAX_ERROR),
469
				 errmsg("lquery syntax error"),
470
				 errdetail("Unexpected end of line.")));
471

472
	curqlevel = tmpql;
473
	totallen = LQUERY_HDRSIZE;
474
	while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
475
	{
476
		totallen += LQL_HDRSIZE;
477
		if (curqlevel->numvar)
478
		{
479
			lptr = GETVAR(curqlevel);
480
			while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
481
			{
482
				totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
483
				lptr++;
484
			}
485
		}
486
		else if (curqlevel->low > curqlevel->high)
487
			ereport(ERROR,
488
					(errcode(ERRCODE_SYNTAX_ERROR),
489
					 errmsg("lquery syntax error"),
490
					 errdetail("Low limit (%d) is greater than upper (%d).",
491
							   curqlevel->low, curqlevel->high)));
492

493
		curqlevel = NEXTLEV(curqlevel);
494
	}
495

496
	result = (lquery *) palloc0(totallen);
497
	SET_VARSIZE(result, totallen);
498
	result->numlevel = num;
499
	result->firstgood = 0;
500
	result->flag = 0;
501
	if (hasnot)
502
		result->flag |= LQUERY_HASNOT;
503
	cur = LQUERY_FIRST(result);
504
	curqlevel = tmpql;
505
	while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
506
	{
507
		memcpy(cur, curqlevel, LQL_HDRSIZE);
508
		cur->totallen = LQL_HDRSIZE;
509
		if (curqlevel->numvar)
510
		{
511
			lrptr = LQL_FIRST(cur);
512
			lptr = GETVAR(curqlevel);
513
			while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
514
			{
515
				cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
516
				lrptr->len = lptr->len;
517
				lrptr->flag = lptr->flag;
518
				lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
519
				memcpy(lrptr->name, lptr->start, lptr->len);
520
				lptr++;
521
				lrptr = LVAR_NEXT(lrptr);
522
			}
523
			pfree(GETVAR(curqlevel));
524
			if (cur->numvar > 1 || cur->flag != 0)
525
				wasbad = true;
526
			else if (wasbad == false)
527
				(result->firstgood)++;
528
		}
529
		else
530
			wasbad = true;
531
		curqlevel = NEXTLEV(curqlevel);
532
		cur = LQL_NEXT(cur);
533
	}
534

535
	pfree(tmpql);
536
	PG_RETURN_POINTER(result);
537
}
538

539
Datum
540
lquery_out(PG_FUNCTION_ARGS)
541
{
542
	lquery	   *in = PG_GETARG_LQUERY_P(0);
543
	char	   *buf,
544
			   *ptr;
545
	int			i,
546
				j,
547
				totallen = 1;
548
	lquery_level *curqlevel;
549
	lquery_variant *curtlevel;
550

551
	curqlevel = LQUERY_FIRST(in);
552
	for (i = 0; i < in->numlevel; i++)
553
	{
554
		totallen++;
555
		if (curqlevel->numvar)
556
			totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
557
		else
558
			totallen += 2 * 11 + 4;
559
		curqlevel = LQL_NEXT(curqlevel);
560
	}
561

562
	ptr = buf = (char *) palloc(totallen);
563
	curqlevel = LQUERY_FIRST(in);
564
	for (i = 0; i < in->numlevel; i++)
565
	{
566
		if (i != 0)
567
		{
568
			*ptr = '.';
569
			ptr++;
570
		}
571
		if (curqlevel->numvar)
572
		{
573
			if (curqlevel->flag & LQL_NOT)
574
			{
575
				*ptr = '!';
576
				ptr++;
577
			}
578
			curtlevel = LQL_FIRST(curqlevel);
579
			for (j = 0; j < curqlevel->numvar; j++)
580
			{
581
				if (j != 0)
582
				{
583
					*ptr = '|';
584
					ptr++;
585
				}
586
				memcpy(ptr, curtlevel->name, curtlevel->len);
587
				ptr += curtlevel->len;
588
				if ((curtlevel->flag & LVAR_SUBLEXEME))
589
				{
590
					*ptr = '%';
591
					ptr++;
592
				}
593
				if ((curtlevel->flag & LVAR_INCASE))
594
				{
595
					*ptr = '@';
596
					ptr++;
597
				}
598
				if ((curtlevel->flag & LVAR_ANYEND))
599
				{
600
					*ptr = '*';
601
					ptr++;
602
				}
603
				curtlevel = LVAR_NEXT(curtlevel);
604
			}
605
		}
606
		else
607
		{
608
			if (curqlevel->low == curqlevel->high)
609
			{
610
				sprintf(ptr, "*{%d}", curqlevel->low);
611
			}
612
			else if (curqlevel->low == 0)
613
			{
614
				if (curqlevel->high == LTREE_MAX_LEVELS)
615
				{
616
					*ptr = '*';
617
					*(ptr + 1) = '\0';
618
				}
619
				else
620
					sprintf(ptr, "*{,%d}", curqlevel->high);
621
			}
622
			else if (curqlevel->high == LTREE_MAX_LEVELS)
623
			{
624
				sprintf(ptr, "*{%d,}", curqlevel->low);
625
			}
626
			else
627
				sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
628
			ptr = strchr(ptr, '\0');
629
		}
630

631
		curqlevel = LQL_NEXT(curqlevel);
632
	}
633

634
	*ptr = '\0';
635
	PG_FREE_IF_COPY(in, 0);
636

637
	PG_RETURN_POINTER(buf);
638
}
639

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.