| 636 | */ |
| 637 | PG_FUNCTION_INFO_V1(crosstab_hash); |
| 638 | Datum |
| 639 | crosstab_hash(PG_FUNCTION_ARGS) |
| 640 | { |
| 641 | char *sql = text_to_cstring(PG_GETARG_TEXT_PP(0)); |
| 642 | char *cats_sql = text_to_cstring(PG_GETARG_TEXT_PP(1)); |
| 643 | ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; |
| 644 | TupleDesc tupdesc; |
| 645 | MemoryContext per_query_ctx; |
| 646 | MemoryContext oldcontext; |
| 647 | HTAB *crosstab_hash; |
| 648 | |
| 649 | /* check to see if caller supports us returning a tuplestore */ |
| 650 | if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) |
| 651 | ereport(ERROR, |
| 652 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 653 | errmsg("set-valued function called in context that cannot accept a set"))); |
| 654 | if (!(rsinfo->allowedModes & SFRM_Materialize) || |
| 655 | rsinfo->expectedDesc == NULL) |
| 656 | ereport(ERROR, |
| 657 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 658 | errmsg("materialize mode required, but it is not allowed in this context"))); |
| 659 | |
| 660 | per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; |
| 661 | oldcontext = MemoryContextSwitchTo(per_query_ctx); |
| 662 | |
| 663 | /* get the requested return tuple description */ |
| 664 | tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); |
| 665 | |
| 666 | /* |
| 667 | * Check to make sure we have a reasonable tuple descriptor |
| 668 | * |
| 669 | * Note we will attempt to coerce the values into whatever the return |
| 670 | * attribute type is and depend on the "in" function to complain if |
| 671 | * needed. |
| 672 | */ |
| 673 | if (tupdesc->natts < 2) |
| 674 | ereport(ERROR, |
| 675 | (errcode(ERRCODE_SYNTAX_ERROR), |
| 676 | errmsg("query-specified return tuple and " \ |
| 677 | "crosstab function are not compatible"))); |
| 678 | |
| 679 | /* load up the categories hash table */ |
| 680 | crosstab_hash = load_categories_hash(cats_sql, per_query_ctx); |
| 681 | |
| 682 | /* let the caller know we're sending back a tuplestore */ |
| 683 | rsinfo->returnMode = SFRM_Materialize; |
| 684 | |
| 685 | /* now go build it */ |
| 686 | rsinfo->setResult = get_crosstab_tuplestore(sql, |
| 687 | crosstab_hash, |
| 688 | tupdesc, |
| 689 | rsinfo->allowedModes & SFRM_Materialize_Random); |
| 690 | |
| 691 | /* |
| 692 | * SFRM_Materialize mode expects us to return a NULL Datum. The actual |
| 693 | * tuples are in our tuplestore and passed back through rsinfo->setResult. |
| 694 | * rsinfo->setDesc is set to the tuple description that we actually used |
| 695 | * to build our tuples with, so the caller can verify we did what it was |
nothing calls this directly
no test coverage detected