| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * pg_config.c |
| 4 | * Expose same output as pg_config except as an SRF |
| 5 | * |
| 6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 7 | * Portions Copyright (c) 1994, Regents of the University of California |
| 8 | * |
| 9 | * IDENTIFICATION |
| 10 | * src/backend/utils/misc/pg_config.c |
| 11 | * |
| 12 | *------------------------------------------------------------------------- |
| 13 | */ |
| 14 | |
| 15 | #include "postgres.h" |
| 16 | |
| 17 | #include "funcapi.h" |
| 18 | #include "miscadmin.h" |
| 19 | #include "catalog/pg_type.h" |
| 20 | #include "common/config_info.h" |
| 21 | #include "utils/builtins.h" |
| 22 | #include "port.h" |
| 23 | |
| 24 | Datum |
| 25 | pg_config(PG_FUNCTION_ARGS) |
| 26 | { |
| 27 | ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; |
| 28 | Tuplestorestate *tupstore; |
| 29 | HeapTuple tuple; |
| 30 | TupleDesc tupdesc; |
| 31 | AttInMetadata *attinmeta; |
| 32 | MemoryContext per_query_ctx; |
| 33 | MemoryContext oldcontext; |
| 34 | ConfigData *configdata; |
| 35 | size_t configdata_len; |
| 36 | char *values[2]; |
| 37 | int i = 0; |
| 38 | |
| 39 | /* check to see if caller supports us returning a tuplestore */ |
| 40 | if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize)) |
| 41 | ereport(ERROR, |
| 42 | (errcode(ERRCODE_SYNTAX_ERROR), |
| 43 | errmsg("materialize mode required, but it is not " |
| 44 | "allowed in this context" ))); |
| 45 | |
| 46 | per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; |
| 47 | oldcontext = MemoryContextSwitchTo(per_query_ctx); |
| 48 | |
| 49 | /* get the requested return tuple description */ |
| 50 | tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); |
| 51 | |
| 52 | /* |
| 53 | * Check to make sure we have a reasonable tuple descriptor |
| 54 | */ |
| 55 | if (tupdesc->natts != 2 || |
| 56 | TupleDescAttr(tupdesc, 0)->atttypid != TEXTOID || |
| 57 | TupleDescAttr(tupdesc, 1)->atttypid != TEXTOID) |
| 58 | ereport(ERROR, |
| 59 | (errcode(ERRCODE_SYNTAX_ERROR), |
| 60 | errmsg("query-specified return tuple and " |
| 61 | "function return type are not compatible" ))); |
| 62 | |
| 63 | /* OK to use it */ |
| 64 | attinmeta = TupleDescGetAttInMetadata(tupdesc); |
| 65 | |
| 66 | /* let the caller know we're sending back a tuplestore */ |
| 67 | rsinfo->returnMode = SFRM_Materialize; |
| 68 | |
| 69 | /* initialize our tuplestore */ |
| 70 | tupstore = tuplestore_begin_heap(true, false, work_mem); |
| 71 | |
| 72 | configdata = get_configdata(my_exec_path, &configdata_len); |
| 73 | for (i = 0; i < configdata_len; i++) |
| 74 | { |
| 75 | values[0] = configdata[i].name; |
| 76 | values[1] = configdata[i].setting; |
| 77 | |
| 78 | tuple = BuildTupleFromCStrings(attinmeta, values); |
| 79 | tuplestore_puttuple(tupstore, tuple); |
| 80 | } |
| 81 | |
| 82 | /* |
| 83 | * no longer need the tuple descriptor reference created by |
| 84 | * TupleDescGetAttInMetadata() |
| 85 | */ |
| 86 | ReleaseTupleDesc(tupdesc); |
| 87 | |
| 88 | tuplestore_donestoring(tupstore); |
| 89 | rsinfo->setResult = tupstore; |
| 90 | |
| 91 | /* |
| 92 | * SFRM_Materialize mode expects us to return a NULL Datum. The actual |
| 93 | * tuples are in our tuplestore and passed back through rsinfo->setResult. |
| 94 | * rsinfo->setDesc is set to the tuple description that we actually used |
| 95 | * to build our tuples with, so the caller can verify we did what it was |
| 96 | * expecting. |
| 97 | */ |
| 98 | rsinfo->setDesc = tupdesc; |
| 99 | MemoryContextSwitchTo(oldcontext); |
| 100 | |
| 101 | return (Datum) 0; |
| 102 | } |
| 103 | |