PostgreSQL Source Code: contrib/tablefunc/tablefunc.c Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
34
35#include <math.h>
36
46
48 .name = "tablefunc",
49 .version = PG_VERSION
50);
51
56 bool randomAccess);
62 char *key_fld,
63 char *parent_key_fld,
64 char *orderby_fld,
65 char *branch_delim,
66 char *start_with,
67 int max_depth,
68 bool show_branch,
69 bool show_serial,
71 bool randomAccess,
74 char *parent_key_fld,
76 char *orderby_fld,
77 char *branch_delim,
78 char *start_with,
79 char *branch,
80 int level,
81 int *serial,
82 int max_depth,
83 bool show_branch,
84 bool show_serial,
88
89typedef struct
90{
96
97#define xpfree(var_) \
98 do { \
99 if (var_ != NULL) \
100 { \
101 pfree(var_); \
102 var_ = NULL; \
103 } \
104 } while (0)
105
106#define xpstrdup(tgtvar_, srcvar_) \
107 do { \
108 if (srcvar_) \
109 tgtvar_ = pstrdup(srcvar_); \
110 else \
111 tgtvar_ = NULL; \
112 } while (0)
113
114#define xstreq(tgtvar_, srcvar_) \
115 (((tgtvar_ == NULL) && (srcvar_ == NULL)) || \
116 ((tgtvar_ != NULL) && (srcvar_ != NULL) && (strcmp(tgtvar_, srcvar_) == 0)))
117
118
119#define INT32_STRLEN 12
120
121
123{
127
128#define MAX_CATNAME_LEN NAMEDATALEN
129#define INIT_CATS 64
130
131#define crosstab_HashTableLookup(HASHTAB, CATNAME, CATDESC) \
132do { \
133 crosstab_HashEnt *hentry; char key[MAX_CATNAME_LEN]; \
134 \
135 MemSet(key, 0, MAX_CATNAME_LEN); \
136 snprintf(key, MAX_CATNAME_LEN - 1, "%s", CATNAME); \
137 hentry = (crosstab_HashEnt*) hash_search(HASHTAB, \
138 key, HASH_FIND, NULL); \
139 if (hentry) \
140 CATDESC = hentry->catdesc; \
141 else \
142 CATDESC = NULL; \
143} while(0)
144
145#define crosstab_HashTableInsert(HASHTAB, CATDESC) \
146do { \
147 crosstab_HashEnt *hentry; bool found; char key[MAX_CATNAME_LEN]; \
148 \
149 MemSet(key, 0, MAX_CATNAME_LEN); \
150 snprintf(key, MAX_CATNAME_LEN - 1, "%s", CATDESC->catname); \
151 hentry = (crosstab_HashEnt*) hash_search(HASHTAB, \
152 key, HASH_ENTER, &found); \
153 if (found) \
154 ereport(ERROR, \
155 (errcode(ERRCODE_DUPLICATE_OBJECT), \
156 errmsg("duplicate category name"))); \
157 hentry->catdesc = CATDESC; \
158} while(0)
159
160
162{
166
167
168
169
170
171
172
173
177{
185 bool use_carry;
187
188
190 {
191 int32 num_tuples;
192
193
195
196
197
198
200
201
203 if (num_tuples < 0)
205 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
206 errmsg("number of rows cannot be negative")));
208
209
211
212
213
214
215
216
217
222
224
226 }
227
228
230
234 mean = fctx->mean;
235 stddev = fctx->stddev;
238
239 if (call_cntr < max_calls)
240 {
242
243 if (use_carry)
244 {
245
246
247
249 result = carry_val;
250 }
251 else
252 {
255
256
258
259
260 result = mean + (stddev * normval_1);
261
262
263 fctx->carry_val = mean + (stddev * normval_2);
265 }
266
267
269 }
270 else
271
273}
274
275
276
277
278
279
280
281
282
283
284
285
286static void
288{
290 u2,
291 v1,
292 v2,
293 s;
294
295 do
296 {
299
300 v1 = (2.0 * u1) - 1.0;
301 v2 = (2.0 * u2) - 1.0;
302
303 s = v1 * v1 + v2 * v2;
304 } while (s >= 1.0);
305
306 if (s == 0)
307 {
308 *x1 = 0;
309 *x2 = 0;
310 }
311 else
312 {
313 s = sqrt((-2.0 * log(s)) / s);
314 *x1 = v1 * s;
315 *x2 = v2 * s;
316 }
317}
318
319
320
321
322
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
359{
369 bool firstpass;
370 char *lastrowid;
371 int i;
372 int num_categories;
375 int ret;
377
378
381 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
382 errmsg("set-valued function called in context that cannot accept a set")));
385 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
386 errmsg("materialize mode required, but it is not allowed in this context")));
387
389
390
392
393
396
397
399 {
403 }
404
406 spi_tupdesc = spi_tuptable->tupdesc;
407
408
409
410
411
412
413
414
415
416
417
418
419 if (spi_tupdesc->natts != 3)
421 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
422 errmsg("invalid crosstab source data query"),
423 errdetail("The query must return 3 columns: row_name, category, and value.")));
424
425
427 {
429
430 break;
432
434 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
435 errmsg("function returning record called in context "
436 "that cannot accept type record")));
437 break;
438 default:
439
441 (errcode(ERRCODE_DATATYPE_MISMATCH),
442 errmsg("return type must be a row type")));
443 break;
444 }
445
446
447
448
449
451
452
453
454
456
457
459
460
461 tupstore =
464
466
467
468
469
470
472
473
474 max_calls = proc;
475
476
477 num_categories = tupdesc->natts - 1;
478
479 firstpass = true;
480 lastrowid = NULL;
481
482 for (call_cntr = 0; call_cntr < max_calls; call_cntr++)
483 {
484 bool skip_tuple = false;
486
487
488 values = (char **) palloc0((1 + num_categories) * sizeof(char *));
489
490
491
492
493
494 for (i = 0; i < num_categories; i++)
495 {
497 char *rowid;
498
499
500 if (call_cntr >= max_calls)
501 break;
502
503
504 spi_tuple = spi_tuptable->vals[call_cntr];
505
506
507 rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
508
509
510
511
512
513 if (i == 0)
514 {
516
517
518
519
520
521 if (!firstpass && xstreq(lastrowid, rowid))
522 {
524 skip_tuple = true;
525 break;
526 }
527 }
528
529
530
531
532
534 {
535
536
537
538
539
540
541
543
544
545
546
547
548
549 if (i < (num_categories - 1))
550 call_cntr++;
552 }
553 else
554 {
555
556
557
558
559
560 call_cntr--;
562 break;
563 }
564 }
565
566 if (!skip_tuple)
567 {
569
570
574 }
575
576
579 firstpass = false;
580
581
582 for (i = 0; i < num_categories + 1; i++)
586 }
587
588
591 rsinfo->setDesc = tupdesc;
592
593
595
596 return (Datum) 0;
597}
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
637{
645
646
649 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
650 errmsg("set-valued function called in context that cannot accept a set")));
654 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
655 errmsg("materialize mode required, but it is not allowed in this context")));
656
659
660
662
663
664
665
666
667
668
669
670 if (tupdesc->natts < 2)
672 (errcode(ERRCODE_DATATYPE_MISMATCH),
673 errmsg("invalid crosstab return type"),
674 errdetail("Return row must have at least two columns.")));
675
676
678
679
681
682
685 tupdesc,
687
688
689
690
691
692
693
694
695 rsinfo->setDesc = tupdesc;
697
698 return (Datum) 0;
699}
700
701
702
703
706{
709 int ret;
712
713
716 ctl.hcxt = per_query_ctx;
717
718
719
720
721
726
727
729
730
733
734
736 {
740
741
742
743
744
745 if (spi_tupdesc->natts != 1)
747 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
748 errmsg("invalid crosstab categories query"),
749 errdetail("The query must return one column.")));
750
751 for (i = 0; i < proc; i++)
752 {
754 char *catname;
756
757
758 spi_tuple = spi_tuptable->vals[i];
759
760
761 catname = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
762 if (catname == NULL)
764 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
765 errmsg("crosstab category value must not be null")));
766
768
770 catdesc->catname = catname;
772
773
775
777 }
778 }
779
781
782 elog(ERROR, "load_categories_hash: SPI_finish() failed");
783
785}
786
787
788
789
794 bool randomAccess)
795{
801 int ret;
803
804
806
807
809
810
813
814
816 {
819 int ncols = spi_tupdesc->natts;
820 char *rowid;
821 char *lastrowid = NULL;
822 bool firstpass = true;
824 int j;
825 int result_ncols;
826
827 if (num_categories == 0)
828 {
829
831 (errcode(ERRCODE_CARDINALITY_VIOLATION),
832 errmsg("crosstab categories query must return at least one row")));
833 }
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848 if (ncols < 3)
850 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
851 errmsg("invalid crosstab source data query"),
852 errdetail("The query must return at least 3 columns: row_name, category, and value.")));
853
854 result_ncols = (ncols - 2) + num_categories;
855
856
857 if (tupdesc->natts != result_ncols)
859 (errcode(ERRCODE_DATATYPE_MISMATCH),
860 errmsg("invalid crosstab return type"),
861 errdetail("Return row must have %d columns, not %d.",
862 result_ncols, tupdesc->natts)));
863
864
865 values = (char **) palloc0(result_ncols * sizeof(char *));
866
867 for (i = 0; i < proc; i++)
868 {
871 char *catname;
872
873
874 spi_tuple = spi_tuptable->vals[i];
875
876
877 rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
878
879
880
881
882
883 if (firstpass || (lastrowid, rowid))
884 {
885
886
887
888
889 if (!firstpass)
890 {
891
893
895
896 for (j = 0; j < result_ncols; j++)
898 }
899
901 for (j = 1; j < ncols - 2; j++)
903
904
905 firstpass = false;
906 }
907
908
909 catname = SPI_getvalue(spi_tuple, spi_tupdesc, ncols - 1);
910
911 if (catname != NULL)
912 {
914
915 if (catdesc)
918 }
919
922 }
923
924
926
928 }
929
931
932 elog(ERROR, "get_crosstab_tuplestore: SPI_finish() failed");
933
934 return tupstore;
935}
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
972
973#define CONNECTBY_NCOLS 4
974#define CONNECTBY_NCOLS_NOBRANCH 3
975
978{
984 char *branch_delim = NULL;
985 bool show_branch = false;
986 bool show_serial = false;
992
993
996 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
997 errmsg("set-valued function called in context that cannot accept a set")));
1001 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1002 errmsg("materialize mode required, but it is not allowed in this context")));
1003
1004 if (fcinfo->nargs == 6)
1005 {
1007 show_branch = true;
1008 }
1009 else
1010
1011 branch_delim = pstrdup("~");
1012
1015
1016
1018
1019
1021
1022
1024
1025
1028 key_fld,
1029 parent_key_fld,
1030 NULL,
1031 branch_delim,
1032 start_with,
1033 max_depth,
1034 show_branch,
1035 show_serial,
1036 per_query_ctx,
1038 attinmeta);
1039 rsinfo->setDesc = tupdesc;
1040
1042
1043
1044
1045
1046
1047
1048
1049
1050 return (Datum) 0;
1051}
1052
1056{
1063 char *branch_delim = NULL;
1064 bool show_branch = false;
1065 bool show_serial = true;
1071
1072
1075 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1076 errmsg("set-valued function called in context that cannot accept a set")));
1080 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1081 errmsg("materialize mode required, but it is not allowed in this context")));
1082
1083 if (fcinfo->nargs == 7)
1084 {
1086 show_branch = true;
1087 }
1088 else
1089
1090 branch_delim = pstrdup("~");
1091
1094
1095
1097
1098
1100
1101
1103
1104
1107 key_fld,
1108 parent_key_fld,
1109 orderby_fld,
1110 branch_delim,
1111 start_with,
1112 max_depth,
1113 show_branch,
1114 show_serial,
1115 per_query_ctx,
1117 attinmeta);
1118 rsinfo->setDesc = tupdesc;
1119
1121
1122
1123
1124
1125
1126
1127
1128
1129 return (Datum) 0;
1130}
1131
1132
1133
1134
1135
1138 char *key_fld,
1139 char *parent_key_fld,
1140 char *orderby_fld,
1141 char *branch_delim,
1142 char *start_with,
1143 int max_depth,
1144 bool show_branch,
1145 bool show_serial,
1147 bool randomAccess,
1149{
1152 int serial = 1;
1153
1154
1156
1157
1159
1160
1162
1164
1165
1167 parent_key_fld,
1169 orderby_fld,
1170 branch_delim,
1171 start_with,
1172 start_with,
1173 0,
1174 &serial,
1175 max_depth,
1176 show_branch,
1177 show_serial,
1178 per_query_ctx,
1179 attinmeta,
1180 tupstore);
1181
1183
1184 return tupstore;
1185}
1186
1187static void
1189 char *parent_key_fld,
1191 char *orderby_fld,
1192 char *branch_delim,
1193 char *start_with,
1194 char *branch,
1195 int level,
1196 int *serial,
1197 int max_depth,
1198 bool show_branch,
1199 bool show_serial,
1203{
1205 int ret;
1207 int serial_column;
1210 char *current_key;
1211 char *current_key_parent;
1214 char *current_branch;
1216
1217 if (max_depth > 0 && level > max_depth)
1218 return;
1219
1221
1222
1223 if (!show_serial)
1224 {
1225 appendStringInfo(&sql, "SELECT %s, %s FROM %s WHERE %s = %s AND %s IS NOT NULL AND %s <> %s",
1226 key_fld,
1227 parent_key_fld,
1229 parent_key_fld,
1231 key_fld, key_fld, parent_key_fld);
1232 serial_column = 0;
1233 }
1234 else
1235 {
1236 appendStringInfo(&sql, "SELECT %s, %s FROM %s WHERE %s = %s AND %s IS NOT NULL AND %s <> %s ORDER BY %s",
1237 key_fld,
1238 parent_key_fld,
1240 parent_key_fld,
1242 key_fld, key_fld, parent_key_fld,
1243 orderby_fld);
1244 serial_column = 1;
1245 }
1246
1247 if (show_branch)
1249 else
1251
1252
1253 if (level == 0)
1254 {
1255
1256 values[0] = start_with;
1257
1258
1260
1261
1262 sprintf(current_level, "%d", level);
1263 values[2] = current_level;
1264
1265
1266 if (show_branch)
1267 values[3] = start_with;
1268
1269
1270 if (show_serial)
1271 {
1272 sprintf(serial_str, "%d", (*serial)++);
1273 if (show_branch)
1274 values[4] = serial_str;
1275 else
1276 values[3] = serial_str;
1277 }
1278
1279
1281
1282
1284
1285
1286 level++;
1287 }
1288
1289
1292
1293
1295 {
1303
1304
1305
1306
1307
1309
1313
1314 for (i = 0; i < proc; i++)
1315 {
1316
1318 appendStringInfo(&chk_branchstr, "%s%s%s", branch_delim, branch, branch_delim);
1319
1320
1321 spi_tuple = tuptable->vals[i];
1322
1323
1324 current_key = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
1325
1326
1327 current_key_parent = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
1328
1329
1330 sprintf(current_level, "%d", level);
1331
1332
1333 if (current_key)
1334 {
1336 branch_delim, current_key, branch_delim);
1337 if (strstr(chk_branchstr.data, chk_current_key.data))
1339 (errcode(ERRCODE_INVALID_RECURSION),
1340 errmsg("infinite recursion detected")));
1341 }
1342
1343
1344 if (current_key)
1345 appendStringInfo(&branchstr, "%s%s", branch_delim, current_key);
1346 current_branch = branchstr.data;
1347
1348
1349 values[0] = current_key;
1350 values[1] = current_key_parent;
1351 values[2] = current_level;
1352 if (show_branch)
1353 values[3] = current_branch;
1354 if (show_serial)
1355 {
1356 sprintf(serial_str, "%d", (*serial)++);
1357 if (show_branch)
1358 values[4] = serial_str;
1359 else
1360 values[3] = serial_str;
1361 }
1362
1364
1365
1367
1369
1370
1371 if (current_key)
1373 parent_key_fld,
1375 orderby_fld,
1376 branch_delim,
1377 current_key,
1378 current_branch,
1379 level + 1,
1380 serial,
1381 max_depth,
1382 show_branch,
1383 show_serial,
1384 per_query_ctx,
1385 attinmeta,
1386 tupstore);
1387
1388 xpfree(current_key);
1389 xpfree(current_key_parent);
1390
1391
1395 }
1396
1400 }
1401}
1402
1403
1404
1405
1406static void
1408{
1409 int expected_cols;
1410
1411
1412 if (show_branch)
1414 else
1416 if (show_serial)
1417 expected_cols++;
1418
1419 if (td->natts != expected_cols)
1421 (errcode(ERRCODE_DATATYPE_MISMATCH),
1422 errmsg("invalid connectby return type"),
1423 errdetail("Return row must have %d columns, not %d.",
1424 expected_cols, td->natts)));
1425
1426
1427
1428
1431 (errcode(ERRCODE_DATATYPE_MISMATCH),
1432 errmsg("invalid connectby return type"),
1433 errdetail("Third return column (depth) must be type %s.",
1435
1436
1437 if (show_branch && TupleDescAttr(td, 3)->atttypid != TEXTOID)
1439 (errcode(ERRCODE_DATATYPE_MISMATCH),
1440 errmsg("invalid connectby return type"),
1441 errdetail("Fourth return column (branch) must be type %s.",
1443
1444
1445 if (show_branch && show_serial &&
1448 (errcode(ERRCODE_DATATYPE_MISMATCH),
1449 errmsg("invalid connectby return type"),
1450 errdetail("Fifth return column (serial) must be type %s.",
1452 if (!show_branch && show_serial &&
1455 (errcode(ERRCODE_DATATYPE_MISMATCH),
1456 errmsg("invalid connectby return type"),
1457 errdetail("Fourth return column (serial) must be type %s.",
1459
1460
1461}
1462
1463
1464
1465
1466static void
1468{
1469 Oid ret_atttypid;
1470 Oid sql_atttypid;
1471 int32 ret_atttypmod;
1472 int32 sql_atttypmod;
1473
1474
1475
1476
1477 if (sql_tupdesc->natts < 2)
1479 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1480 errmsg("invalid connectby source data query"),
1481 errdetail("The query must return at least two columns.")));
1482
1483
1484
1485
1486
1487 ret_atttypid = TupleDescAttr(ret_tupdesc, 0)->atttypid;
1488 sql_atttypid = TupleDescAttr(sql_tupdesc, 0)->atttypid;
1489 ret_atttypmod = TupleDescAttr(ret_tupdesc, 0)->atttypmod;
1490 sql_atttypmod = TupleDescAttr(sql_tupdesc, 0)->atttypmod;
1491 if (ret_atttypid != sql_atttypid ||
1492 (ret_atttypmod >= 0 && ret_atttypmod != sql_atttypmod))
1494 (errcode(ERRCODE_DATATYPE_MISMATCH),
1495 errmsg("invalid connectby return type"),
1496 errdetail("Source key type %s does not match return key type %s.",
1499
1500 ret_atttypid = TupleDescAttr(ret_tupdesc, 1)->atttypid;
1501 sql_atttypid = TupleDescAttr(sql_tupdesc, 1)->atttypid;
1502 ret_atttypmod = TupleDescAttr(ret_tupdesc, 1)->atttypmod;
1503 sql_atttypmod = TupleDescAttr(sql_tupdesc, 1)->atttypmod;
1504 if (ret_atttypid != sql_atttypid ||
1505 (ret_atttypmod >= 0 && ret_atttypmod != sql_atttypmod))
1507 (errcode(ERRCODE_DATATYPE_MISMATCH),
1508 errmsg("invalid connectby return type"),
1509 errdetail("Source parent key type %s does not match return parent key type %s.",
1512
1513
1514}
1515
1516
1517
1518
1519static void
1521{
1522 int i;
1523 Oid ret_atttypid;
1524 Oid sql_atttypid;
1525 int32 ret_atttypmod;
1526 int32 sql_atttypmod;
1527
1528 if (ret_tupdesc->natts < 2)
1530 (errcode(ERRCODE_DATATYPE_MISMATCH),
1531 errmsg("invalid crosstab return type"),
1532 errdetail("Return row must have at least two columns.")));
1533 Assert(sql_tupdesc->natts == 3);
1534
1535
1536 ret_atttypid = TupleDescAttr(ret_tupdesc, 0)->atttypid;
1537 sql_atttypid = TupleDescAttr(sql_tupdesc, 0)->atttypid;
1538 ret_atttypmod = TupleDescAttr(ret_tupdesc, 0)->atttypmod;
1539 sql_atttypmod = TupleDescAttr(sql_tupdesc, 0)->atttypmod;
1540 if (ret_atttypid != sql_atttypid ||
1541 (ret_atttypmod >= 0 && ret_atttypmod != sql_atttypmod))
1543 (errcode(ERRCODE_DATATYPE_MISMATCH),
1544 errmsg("invalid crosstab return type"),
1545 errdetail("Source row_name datatype %s does not match return row_name datatype %s.",
1548
1549
1550
1551
1552
1553
1554 sql_atttypid = TupleDescAttr(sql_tupdesc, 2)->atttypid;
1555 sql_atttypmod = TupleDescAttr(sql_tupdesc, 2)->atttypmod;
1556 for (i = 1; i < ret_tupdesc->natts; i++)
1557 {
1558 ret_atttypid = TupleDescAttr(ret_tupdesc, i)->atttypid;
1559 ret_atttypmod = TupleDescAttr(ret_tupdesc, i)->atttypmod;
1560
1561 if (ret_atttypid != sql_atttypid ||
1562 (ret_atttypmod >= 0 && ret_atttypmod != sql_atttypmod))
1564 (errcode(ERRCODE_DATATYPE_MISMATCH),
1565 errmsg("invalid crosstab return type"),
1566 errdetail("Source value datatype %s does not match return value datatype %s in column %d.",
1569 i + 1)));
1570 }
1571
1572
1573}
static Datum values[MAXATTR]
long hash_get_num_entries(HTAB *hashp)
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
@ SFRM_Materialize_Random
Datum Float8GetDatum(float8 X)
#define PG_GETARG_TEXT_PP(n)
#define PG_GETARG_FLOAT8(n)
#define PG_GETARG_INT32(n)
char * format_type_with_typemod(Oid type_oid, int32 typemod)
char * format_type_be(Oid type_oid)
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
#define SRF_IS_FIRSTCALL()
#define SRF_PERCALL_SETUP()
#define SRF_RETURN_NEXT(_funcctx, _result)
#define SRF_FIRSTCALL_INIT()
#define SRF_RETURN_DONE(_funcctx)
Assert(PointerIsAligned(start, uint64))
void heap_freetuple(HeapTuple htup)
if(TABLE==NULL||TABLE_index==NULL)
char * pstrdup(const char *in)
void pfree(void *pointer)
void * palloc0(Size size)
#define IsA(nodeptr, _type_)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
double pg_prng_double(pg_prng_state *state)
pg_prng_state pg_global_prng_state
char * quote_literal_cstr(const char *rawstr)
SPITupleTable * SPI_tuptable
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
int SPI_execute(const char *src, bool read_only, long tcount)
void resetStringInfo(StringInfo str)
void appendStringInfo(StringInfo str, const char *fmt,...)
void appendStringInfoString(StringInfo str, const char *s)
void initStringInfo(StringInfo str)
MemoryContext ecxt_per_query_memory
MemoryContext multi_call_memory_ctx
SetFunctionReturnMode returnMode
Tuplestorestate * setResult
crosstab_cat_desc * catdesc
char internal_catname[MAX_CATNAME_LEN]
#define crosstab_HashTableInsert(HASHTAB, CATDESC)
#define xpstrdup(tgtvar_, srcvar_)
static void compatCrosstabTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc)
struct crosstab_cat_desc crosstab_cat_desc
Datum connectby_text(PG_FUNCTION_ARGS)
Datum normal_rand(PG_FUNCTION_ARGS)
Datum crosstab(PG_FUNCTION_ARGS)
#define CONNECTBY_NCOLS_NOBRANCH
static void get_normal_pair(float8 *x1, float8 *x2)
#define crosstab_HashTableLookup(HASHTAB, CATNAME, CATDESC)
PG_MODULE_MAGIC_EXT(.name="tablefunc",.version=PG_VERSION)
static Tuplestorestate * get_crosstab_tuplestore(char *sql, HTAB *crosstab_hash, TupleDesc tupdesc, bool randomAccess)
Datum connectby_text_serial(PG_FUNCTION_ARGS)
static void build_tuplestore_recursively(char *key_fld, char *parent_key_fld, char *relname, char *orderby_fld, char *branch_delim, char *start_with, char *branch, int level, int *serial, int max_depth, bool show_branch, bool show_serial, MemoryContext per_query_ctx, AttInMetadata *attinmeta, Tuplestorestate *tupstore)
Datum crosstab_hash(PG_FUNCTION_ARGS)
static void compatConnectbyTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc)
#define xstreq(tgtvar_, srcvar_)
static void validateConnectbyTupleDesc(TupleDesc td, bool show_branch, bool show_serial)
static Tuplestorestate * connectby(char *relname, char *key_fld, char *parent_key_fld, char *orderby_fld, char *branch_delim, char *start_with, int max_depth, bool show_branch, bool show_serial, MemoryContext per_query_ctx, bool randomAccess, AttInMetadata *attinmeta)
PG_FUNCTION_INFO_V1(normal_rand)
struct crosstab_hashent crosstab_HashEnt
static HTAB * load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
char * text_to_cstring(const text *t)