|
17 | 17 | #include "catalog/pg_type.h" |
18 | 18 | #include "commands/createas.h" |
19 | 19 | #include "commands/defrem.h" |
| 20 | +#include "commands/explain_dr.h" |
20 | 21 | #include "commands/explain_format.h" |
21 | 22 | #include "commands/prepare.h" |
22 | 23 | #include "foreign/fdwapi.h" |
@@ -50,14 +51,6 @@ ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL; |
50 | 51 | explain_get_index_name_hook_type explain_get_index_name_hook = NULL; |
51 | 52 |
|
52 | 53 |
|
53 | | -/* Instrumentation data for SERIALIZE option */ |
54 | | -typedef struct SerializeMetrics |
55 | | -{ |
56 | | - uint64 bytesSent; /* # of bytes serialized */ |
57 | | - instr_time timeSpent; /* time spent serializing */ |
58 | | - BufferUsage bufferUsage; /* buffers accessed during serialization */ |
59 | | -} SerializeMetrics; |
60 | | - |
61 | 54 | /* |
62 | 55 | * Various places within need to convert bytes to kilobytes. Round these up |
63 | 56 | * to the next whole kilobyte. |
@@ -161,7 +154,6 @@ static ExplainWorkersState *ExplainCreateWorkersState(int num_workers); |
161 | 154 | static void ExplainOpenWorker(int n, ExplainState *es); |
162 | 155 | static void ExplainCloseWorker(int n, ExplainState *es); |
163 | 156 | static void ExplainFlushWorkersState(ExplainState *es); |
164 | | -static SerializeMetrics GetSerializationMetrics(DestReceiver *dest); |
165 | 157 |
|
166 | 158 |
|
167 | 159 |
|
@@ -4939,292 +4931,3 @@ ExplainFlushWorkersState(ExplainState *es) |
4939 | 4931 | pfree(wstate->worker_state_save); |
4940 | 4932 | pfree(wstate); |
4941 | 4933 | } |
4942 | | - |
4943 | | -/* |
4944 | | - * DestReceiver functions for SERIALIZE option |
4945 | | - * |
4946 | | - * A DestReceiver for query tuples, that serializes passed rows into RowData |
4947 | | - * messages while measuring the resources expended and total serialized size, |
4948 | | - * while never sending the data to the client. This allows measuring the |
4949 | | - * overhead of deTOASTing and datatype out/sendfuncs, which are not otherwise |
4950 | | - * exercisable without actually hitting the network. |
4951 | | - */ |
4952 | | -typedef struct SerializeDestReceiver |
4953 | | -{ |
4954 | | - DestReceiver pub; |
4955 | | - ExplainState *es; /* this EXPLAIN statement's ExplainState */ |
4956 | | - int8 format; /* text or binary, like pq wire protocol */ |
4957 | | - TupleDesc attrinfo; /* the output tuple desc */ |
4958 | | - int nattrs; /* current number of columns */ |
4959 | | - FmgrInfo *finfos; /* precomputed call info for output fns */ |
4960 | | - MemoryContext tmpcontext; /* per-row temporary memory context */ |
4961 | | - StringInfoData buf; /* buffer to hold the constructed message */ |
4962 | | - SerializeMetrics metrics; /* collected metrics */ |
4963 | | -} SerializeDestReceiver; |
4964 | | - |
4965 | | -/* |
4966 | | - * Get the function lookup info that we'll need for output. |
4967 | | - * |
4968 | | - * This is a subset of what printtup_prepare_info() does. We don't need to |
4969 | | - * cope with format choices varying across columns, so it's slightly simpler. |
4970 | | - */ |
4971 | | -static void |
4972 | | -serialize_prepare_info(SerializeDestReceiver *receiver, |
4973 | | - TupleDesc typeinfo, int nattrs) |
4974 | | -{ |
4975 | | - /* get rid of any old data */ |
4976 | | - if (receiver->finfos) |
4977 | | - pfree(receiver->finfos); |
4978 | | - receiver->finfos = NULL; |
4979 | | - |
4980 | | - receiver->attrinfo = typeinfo; |
4981 | | - receiver->nattrs = nattrs; |
4982 | | - if (nattrs <= 0) |
4983 | | - return; |
4984 | | - |
4985 | | - receiver->finfos = (FmgrInfo *) palloc0(nattrs * sizeof(FmgrInfo)); |
4986 | | - |
4987 | | - for (int i = 0; i < nattrs; i++) |
4988 | | - { |
4989 | | - FmgrInfo *finfo = receiver->finfos + i; |
4990 | | - Form_pg_attribute attr = TupleDescAttr(typeinfo, i); |
4991 | | - Oid typoutput; |
4992 | | - Oid typsend; |
4993 | | - bool typisvarlena; |
4994 | | - |
4995 | | - if (receiver->format == 0) |
4996 | | - { |
4997 | | - /* wire protocol format text */ |
4998 | | - getTypeOutputInfo(attr->atttypid, |
4999 | | - &typoutput, |
5000 | | - &typisvarlena); |
5001 | | - fmgr_info(typoutput, finfo); |
5002 | | - } |
5003 | | - else if (receiver->format == 1) |
5004 | | - { |
5005 | | - /* wire protocol format binary */ |
5006 | | - getTypeBinaryOutputInfo(attr->atttypid, |
5007 | | - &typsend, |
5008 | | - &typisvarlena); |
5009 | | - fmgr_info(typsend, finfo); |
5010 | | - } |
5011 | | - else |
5012 | | - ereport(ERROR, |
5013 | | - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
5014 | | - errmsg("unsupported format code: %d", receiver->format))); |
5015 | | - } |
5016 | | -} |
5017 | | - |
5018 | | -/* |
5019 | | - * serializeAnalyzeReceive - collect tuples for EXPLAIN (SERIALIZE) |
5020 | | - * |
5021 | | - * This should match printtup() in printtup.c as closely as possible, |
5022 | | - * except for the addition of measurement code. |
5023 | | - */ |
5024 | | -static bool |
5025 | | -serializeAnalyzeReceive(TupleTableSlot *slot, DestReceiver *self) |
5026 | | -{ |
5027 | | - TupleDesc typeinfo = slot->tts_tupleDescriptor; |
5028 | | - SerializeDestReceiver *myState = (SerializeDestReceiver *) self; |
5029 | | - MemoryContext oldcontext; |
5030 | | - StringInfo buf = &myState->buf; |
5031 | | - int natts = typeinfo->natts; |
5032 | | - instr_time start, |
5033 | | - end; |
5034 | | - BufferUsage instr_start; |
5035 | | - |
5036 | | - /* only measure time, buffers if requested */ |
5037 | | - if (myState->es->timing) |
5038 | | - INSTR_TIME_SET_CURRENT(start); |
5039 | | - if (myState->es->buffers) |
5040 | | - instr_start = pgBufferUsage; |
5041 | | - |
5042 | | - /* Set or update my derived attribute info, if needed */ |
5043 | | - if (myState->attrinfo != typeinfo || myState->nattrs != natts) |
5044 | | - serialize_prepare_info(myState, typeinfo, natts); |
5045 | | - |
5046 | | - /* Make sure the tuple is fully deconstructed */ |
5047 | | - slot_getallattrs(slot); |
5048 | | - |
5049 | | - /* Switch into per-row context so we can recover memory below */ |
5050 | | - oldcontext = MemoryContextSwitchTo(myState->tmpcontext); |
5051 | | - |
5052 | | - /* |
5053 | | - * Prepare a DataRow message (note buffer is in per-query context) |
5054 | | - * |
5055 | | - * Note that we fill a StringInfo buffer the same as printtup() does, so |
5056 | | - * as to capture the costs of manipulating the strings accurately. |
5057 | | - */ |
5058 | | - pq_beginmessage_reuse(buf, PqMsg_DataRow); |
5059 | | - |
5060 | | - pq_sendint16(buf, natts); |
5061 | | - |
5062 | | - /* |
5063 | | - * send the attributes of this tuple |
5064 | | - */ |
5065 | | - for (int i = 0; i < natts; i++) |
5066 | | - { |
5067 | | - FmgrInfo *finfo = myState->finfos + i; |
5068 | | - Datum attr = slot->tts_values[i]; |
5069 | | - |
5070 | | - if (slot->tts_isnull[i]) |
5071 | | - { |
5072 | | - pq_sendint32(buf, -1); |
5073 | | - continue; |
5074 | | - } |
5075 | | - |
5076 | | - if (myState->format == 0) |
5077 | | - { |
5078 | | - /* Text output */ |
5079 | | - char *outputstr; |
5080 | | - |
5081 | | - outputstr = OutputFunctionCall(finfo, attr); |
5082 | | - pq_sendcountedtext(buf, outputstr, strlen(outputstr)); |
5083 | | - } |
5084 | | - else |
5085 | | - { |
5086 | | - /* Binary output */ |
5087 | | - bytea *outputbytes; |
5088 | | - |
5089 | | - outputbytes = SendFunctionCall(finfo, attr); |
5090 | | - pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ); |
5091 | | - pq_sendbytes(buf, VARDATA(outputbytes), |
5092 | | - VARSIZE(outputbytes) - VARHDRSZ); |
5093 | | - } |
5094 | | - } |
5095 | | - |
5096 | | - /* |
5097 | | - * We mustn't call pq_endmessage_reuse(), since that would actually send |
5098 | | - * the data to the client. Just count the data, instead. We can leave |
5099 | | - * the buffer alone; it'll be reset on the next iteration (as would also |
5100 | | - * happen in printtup()). |
5101 | | - */ |
5102 | | - myState->metrics.bytesSent += buf->len; |
5103 | | - |
5104 | | - /* Return to caller's context, and flush row's temporary memory */ |
5105 | | - MemoryContextSwitchTo(oldcontext); |
5106 | | - MemoryContextReset(myState->tmpcontext); |
5107 | | - |
5108 | | - /* Update timing data */ |
5109 | | - if (myState->es->timing) |
5110 | | - { |
5111 | | - INSTR_TIME_SET_CURRENT(end); |
5112 | | - INSTR_TIME_ACCUM_DIFF(myState->metrics.timeSpent, end, start); |
5113 | | - } |
5114 | | - |
5115 | | - /* Update buffer metrics */ |
5116 | | - if (myState->es->buffers) |
5117 | | - BufferUsageAccumDiff(&myState->metrics.bufferUsage, |
5118 | | - &pgBufferUsage, |
5119 | | - &instr_start); |
5120 | | - |
5121 | | - return true; |
5122 | | -} |
5123 | | - |
5124 | | -/* |
5125 | | - * serializeAnalyzeStartup - start up the serializeAnalyze receiver |
5126 | | - */ |
5127 | | -static void |
5128 | | -serializeAnalyzeStartup(DestReceiver *self, int operation, TupleDesc typeinfo) |
5129 | | -{ |
5130 | | - SerializeDestReceiver *receiver = (SerializeDestReceiver *) self; |
5131 | | - |
5132 | | - Assert(receiver->es != NULL); |
5133 | | - |
5134 | | - switch (receiver->es->serialize) |
5135 | | - { |
5136 | | - case EXPLAIN_SERIALIZE_NONE: |
5137 | | - Assert(false); |
5138 | | - break; |
5139 | | - case EXPLAIN_SERIALIZE_TEXT: |
5140 | | - receiver->format = 0; /* wire protocol format text */ |
5141 | | - break; |
5142 | | - case EXPLAIN_SERIALIZE_BINARY: |
5143 | | - receiver->format = 1; /* wire protocol format binary */ |
5144 | | - break; |
5145 | | - } |
5146 | | - |
5147 | | - /* Create per-row temporary memory context */ |
5148 | | - receiver->tmpcontext = AllocSetContextCreate(CurrentMemoryContext, |
5149 | | - "SerializeTupleReceive", |
5150 | | - ALLOCSET_DEFAULT_SIZES); |
5151 | | - |
5152 | | - /* The output buffer is re-used across rows, as in printtup.c */ |
5153 | | - initStringInfo(&receiver->buf); |
5154 | | - |
5155 | | - /* Initialize results counters */ |
5156 | | - memset(&receiver->metrics, 0, sizeof(SerializeMetrics)); |
5157 | | - INSTR_TIME_SET_ZERO(receiver->metrics.timeSpent); |
5158 | | -} |
5159 | | - |
5160 | | -/* |
5161 | | - * serializeAnalyzeShutdown - shut down the serializeAnalyze receiver |
5162 | | - */ |
5163 | | -static void |
5164 | | -serializeAnalyzeShutdown(DestReceiver *self) |
5165 | | -{ |
5166 | | - SerializeDestReceiver *receiver = (SerializeDestReceiver *) self; |
5167 | | - |
5168 | | - if (receiver->finfos) |
5169 | | - pfree(receiver->finfos); |
5170 | | - receiver->finfos = NULL; |
5171 | | - |
5172 | | - if (receiver->buf.data) |
5173 | | - pfree(receiver->buf.data); |
5174 | | - receiver->buf.data = NULL; |
5175 | | - |
5176 | | - if (receiver->tmpcontext) |
5177 | | - MemoryContextDelete(receiver->tmpcontext); |
5178 | | - receiver->tmpcontext = NULL; |
5179 | | -} |
5180 | | - |
5181 | | -/* |
5182 | | - * serializeAnalyzeDestroy - destroy the serializeAnalyze receiver |
5183 | | - */ |
5184 | | -static void |
5185 | | -serializeAnalyzeDestroy(DestReceiver *self) |
5186 | | -{ |
5187 | | - pfree(self); |
5188 | | -} |
5189 | | - |
5190 | | -/* |
5191 | | - * Build a DestReceiver for EXPLAIN (SERIALIZE) instrumentation. |
5192 | | - */ |
5193 | | -DestReceiver * |
5194 | | -CreateExplainSerializeDestReceiver(ExplainState *es) |
5195 | | -{ |
5196 | | - SerializeDestReceiver *self; |
5197 | | - |
5198 | | - self = (SerializeDestReceiver *) palloc0(sizeof(SerializeDestReceiver)); |
5199 | | - |
5200 | | - self->pub.receiveSlot = serializeAnalyzeReceive; |
5201 | | - self->pub.rStartup = serializeAnalyzeStartup; |
5202 | | - self->pub.rShutdown = serializeAnalyzeShutdown; |
5203 | | - self->pub.rDestroy = serializeAnalyzeDestroy; |
5204 | | - self->pub.mydest = DestExplainSerialize; |
5205 | | - |
5206 | | - self->es = es; |
5207 | | - |
5208 | | - return (DestReceiver *) self; |
5209 | | -} |
5210 | | - |
5211 | | -/* |
5212 | | - * GetSerializationMetrics - collect metrics |
5213 | | - * |
5214 | | - * We have to be careful here since the receiver could be an IntoRel |
5215 | | - * receiver if the subject statement is CREATE TABLE AS. In that |
5216 | | - * case, return all-zeroes stats. |
5217 | | - */ |
5218 | | -static SerializeMetrics |
5219 | | -GetSerializationMetrics(DestReceiver *dest) |
5220 | | -{ |
5221 | | - SerializeMetrics empty; |
5222 | | - |
5223 | | - if (dest->mydest == DestExplainSerialize) |
5224 | | - return ((SerializeDestReceiver *) dest)->metrics; |
5225 | | - |
5226 | | - memset(&empty, 0, sizeof(SerializeMetrics)); |
5227 | | - INSTR_TIME_SET_ZERO(empty.timeSpent); |
5228 | | - |
5229 | | - return empty; |
5230 | | -} |
0 commit comments