00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include "access/printtup.h"
00019 #include "libpq/libpq.h"
00020 #include "libpq/pqformat.h"
00021 #include "tcop/pquery.h"
00022 #include "utils/lsyscache.h"
00023
00024
00025 static void printtup_startup(DestReceiver *self, int operation,
00026 TupleDesc typeinfo);
00027 static void printtup(TupleTableSlot *slot, DestReceiver *self);
00028 static void printtup_20(TupleTableSlot *slot, DestReceiver *self);
00029 static void printtup_internal_20(TupleTableSlot *slot, DestReceiver *self);
00030 static void printtup_shutdown(DestReceiver *self);
00031 static void printtup_destroy(DestReceiver *self);
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 typedef struct
00047 {
00048 Oid typoutput;
00049 Oid typsend;
00050 bool typisvarlena;
00051 int16 format;
00052 FmgrInfo finfo;
00053 } PrinttupAttrInfo;
00054
00055 typedef struct
00056 {
00057 DestReceiver pub;
00058 Portal portal;
00059 bool sendDescrip;
00060 TupleDesc attrinfo;
00061 int nattrs;
00062 PrinttupAttrInfo *myinfo;
00063 } DR_printtup;
00064
00065
00066
00067
00068
00069 DestReceiver *
00070 printtup_create_DR(CommandDest dest)
00071 {
00072 DR_printtup *self = (DR_printtup *) palloc0(sizeof(DR_printtup));
00073
00074 self->pub.receiveSlot = printtup;
00075 self->pub.rStartup = printtup_startup;
00076 self->pub.rShutdown = printtup_shutdown;
00077 self->pub.rDestroy = printtup_destroy;
00078 self->pub.mydest = dest;
00079
00080
00081
00082
00083
00084 self->sendDescrip = (dest == DestRemote);
00085
00086 self->attrinfo = NULL;
00087 self->nattrs = 0;
00088 self->myinfo = NULL;
00089
00090 return (DestReceiver *) self;
00091 }
00092
00093
00094
00095
00096 void
00097 SetRemoteDestReceiverParams(DestReceiver *self, Portal portal)
00098 {
00099 DR_printtup *myState = (DR_printtup *) self;
00100
00101 Assert(myState->pub.mydest == DestRemote ||
00102 myState->pub.mydest == DestRemoteExecute);
00103
00104 myState->portal = portal;
00105
00106 if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
00107 {
00108
00109
00110
00111
00112
00113 if (portal->formats && portal->formats[0] != 0)
00114 myState->pub.receiveSlot = printtup_internal_20;
00115 else
00116 myState->pub.receiveSlot = printtup_20;
00117 }
00118 }
00119
00120 static void
00121 printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
00122 {
00123 DR_printtup *myState = (DR_printtup *) self;
00124 Portal portal = myState->portal;
00125
00126 if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
00127 {
00128
00129
00130
00131
00132
00133 const char *portalName = portal->name;
00134
00135 if (portalName == NULL || portalName[0] == '\0')
00136 portalName = "blank";
00137
00138 pq_puttextmessage('P', portalName);
00139 }
00140
00141
00142
00143
00144
00145 if (myState->sendDescrip)
00146 SendRowDescriptionMessage(typeinfo,
00147 FetchPortalTargetList(portal),
00148 portal->formats);
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 void
00174 SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, int16 *formats)
00175 {
00176 Form_pg_attribute *attrs = typeinfo->attrs;
00177 int natts = typeinfo->natts;
00178 int proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
00179 int i;
00180 StringInfoData buf;
00181 ListCell *tlist_item = list_head(targetlist);
00182
00183 pq_beginmessage(&buf, 'T');
00184 pq_sendint(&buf, natts, 2);
00185
00186 for (i = 0; i < natts; ++i)
00187 {
00188 Oid atttypid = attrs[i]->atttypid;
00189 int32 atttypmod = attrs[i]->atttypmod;
00190
00191 pq_sendstring(&buf, NameStr(attrs[i]->attname));
00192
00193 if (proto >= 3)
00194 {
00195
00196 while (tlist_item &&
00197 ((TargetEntry *) lfirst(tlist_item))->resjunk)
00198 tlist_item = lnext(tlist_item);
00199 if (tlist_item)
00200 {
00201 TargetEntry *tle = (TargetEntry *) lfirst(tlist_item);
00202
00203 pq_sendint(&buf, tle->resorigtbl, 4);
00204 pq_sendint(&buf, tle->resorigcol, 2);
00205 tlist_item = lnext(tlist_item);
00206 }
00207 else
00208 {
00209
00210 pq_sendint(&buf, 0, 4);
00211 pq_sendint(&buf, 0, 2);
00212 }
00213 }
00214
00215 atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
00216 pq_sendint(&buf, (int) atttypid, sizeof(atttypid));
00217 pq_sendint(&buf, attrs[i]->attlen, sizeof(attrs[i]->attlen));
00218
00219 if (proto >= 2)
00220 pq_sendint(&buf, atttypmod, sizeof(atttypmod));
00221
00222 if (proto >= 3)
00223 {
00224 if (formats)
00225 pq_sendint(&buf, formats[i], 2);
00226 else
00227 pq_sendint(&buf, 0, 2);
00228 }
00229 }
00230 pq_endmessage(&buf);
00231 }
00232
00233
00234
00235
00236 static void
00237 printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
00238 {
00239 int16 *formats = myState->portal->formats;
00240 int i;
00241
00242
00243 if (myState->myinfo)
00244 pfree(myState->myinfo);
00245 myState->myinfo = NULL;
00246
00247 myState->attrinfo = typeinfo;
00248 myState->nattrs = numAttrs;
00249 if (numAttrs <= 0)
00250 return;
00251
00252 myState->myinfo = (PrinttupAttrInfo *)
00253 palloc0(numAttrs * sizeof(PrinttupAttrInfo));
00254
00255 for (i = 0; i < numAttrs; i++)
00256 {
00257 PrinttupAttrInfo *thisState = myState->myinfo + i;
00258 int16 format = (formats ? formats[i] : 0);
00259
00260 thisState->format = format;
00261 if (format == 0)
00262 {
00263 getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
00264 &thisState->typoutput,
00265 &thisState->typisvarlena);
00266 fmgr_info(thisState->typoutput, &thisState->finfo);
00267 }
00268 else if (format == 1)
00269 {
00270 getTypeBinaryOutputInfo(typeinfo->attrs[i]->atttypid,
00271 &thisState->typsend,
00272 &thisState->typisvarlena);
00273 fmgr_info(thisState->typsend, &thisState->finfo);
00274 }
00275 else
00276 ereport(ERROR,
00277 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00278 errmsg("unsupported format code: %d", format)));
00279 }
00280 }
00281
00282
00283
00284
00285
00286 static void
00287 printtup(TupleTableSlot *slot, DestReceiver *self)
00288 {
00289 TupleDesc typeinfo = slot->tts_tupleDescriptor;
00290 DR_printtup *myState = (DR_printtup *) self;
00291 StringInfoData buf;
00292 int natts = typeinfo->natts;
00293 int i;
00294
00295
00296 if (myState->attrinfo != typeinfo || myState->nattrs != natts)
00297 printtup_prepare_info(myState, typeinfo, natts);
00298
00299
00300 slot_getallattrs(slot);
00301
00302
00303
00304
00305 pq_beginmessage(&buf, 'D');
00306
00307 pq_sendint(&buf, natts, 2);
00308
00309
00310
00311
00312 for (i = 0; i < natts; ++i)
00313 {
00314 PrinttupAttrInfo *thisState = myState->myinfo + i;
00315 Datum origattr = slot->tts_values[i],
00316 attr;
00317
00318 if (slot->tts_isnull[i])
00319 {
00320 pq_sendint(&buf, -1, 4);
00321 continue;
00322 }
00323
00324
00325
00326
00327
00328 if (thisState->typisvarlena)
00329 attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
00330 else
00331 attr = origattr;
00332
00333 if (thisState->format == 0)
00334 {
00335
00336 char *outputstr;
00337
00338 outputstr = OutputFunctionCall(&thisState->finfo, attr);
00339 pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
00340 pfree(outputstr);
00341 }
00342 else
00343 {
00344
00345 bytea *outputbytes;
00346
00347 outputbytes = SendFunctionCall(&thisState->finfo, attr);
00348 pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
00349 pq_sendbytes(&buf, VARDATA(outputbytes),
00350 VARSIZE(outputbytes) - VARHDRSZ);
00351 pfree(outputbytes);
00352 }
00353
00354
00355 if (DatumGetPointer(attr) != DatumGetPointer(origattr))
00356 pfree(DatumGetPointer(attr));
00357 }
00358
00359 pq_endmessage(&buf);
00360 }
00361
00362
00363
00364
00365
00366 static void
00367 printtup_20(TupleTableSlot *slot, DestReceiver *self)
00368 {
00369 TupleDesc typeinfo = slot->tts_tupleDescriptor;
00370 DR_printtup *myState = (DR_printtup *) self;
00371 StringInfoData buf;
00372 int natts = typeinfo->natts;
00373 int i,
00374 j,
00375 k;
00376
00377
00378 if (myState->attrinfo != typeinfo || myState->nattrs != natts)
00379 printtup_prepare_info(myState, typeinfo, natts);
00380
00381
00382 slot_getallattrs(slot);
00383
00384
00385
00386
00387 pq_beginmessage(&buf, 'D');
00388
00389
00390
00391
00392 j = 0;
00393 k = 1 << 7;
00394 for (i = 0; i < natts; ++i)
00395 {
00396 if (!slot->tts_isnull[i])
00397 j |= k;
00398 k >>= 1;
00399 if (k == 0)
00400 {
00401 pq_sendint(&buf, j, 1);
00402 j = 0;
00403 k = 1 << 7;
00404 }
00405 }
00406 if (k != (1 << 7))
00407 pq_sendint(&buf, j, 1);
00408
00409
00410
00411
00412 for (i = 0; i < natts; ++i)
00413 {
00414 PrinttupAttrInfo *thisState = myState->myinfo + i;
00415 Datum origattr = slot->tts_values[i],
00416 attr;
00417 char *outputstr;
00418
00419 if (slot->tts_isnull[i])
00420 continue;
00421
00422 Assert(thisState->format == 0);
00423
00424
00425
00426
00427
00428 if (thisState->typisvarlena)
00429 attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
00430 else
00431 attr = origattr;
00432
00433 outputstr = OutputFunctionCall(&thisState->finfo, attr);
00434 pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
00435 pfree(outputstr);
00436
00437
00438 if (DatumGetPointer(attr) != DatumGetPointer(origattr))
00439 pfree(DatumGetPointer(attr));
00440 }
00441
00442 pq_endmessage(&buf);
00443 }
00444
00445
00446
00447
00448
00449 static void
00450 printtup_shutdown(DestReceiver *self)
00451 {
00452 DR_printtup *myState = (DR_printtup *) self;
00453
00454 if (myState->myinfo)
00455 pfree(myState->myinfo);
00456 myState->myinfo = NULL;
00457
00458 myState->attrinfo = NULL;
00459 }
00460
00461
00462
00463
00464
00465 static void
00466 printtup_destroy(DestReceiver *self)
00467 {
00468 pfree(self);
00469 }
00470
00471
00472
00473
00474
00475 static void
00476 printatt(unsigned attributeId,
00477 Form_pg_attribute attributeP,
00478 char *value)
00479 {
00480 printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
00481 attributeId,
00482 NameStr(attributeP->attname),
00483 value != NULL ? " = \"" : "",
00484 value != NULL ? value : "",
00485 value != NULL ? "\"" : "",
00486 (unsigned int) (attributeP->atttypid),
00487 attributeP->attlen,
00488 attributeP->atttypmod,
00489 attributeP->attbyval ? 't' : 'f');
00490 }
00491
00492
00493
00494
00495
00496 void
00497 debugStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
00498 {
00499 int natts = typeinfo->natts;
00500 Form_pg_attribute *attinfo = typeinfo->attrs;
00501 int i;
00502
00503
00504
00505
00506 for (i = 0; i < natts; ++i)
00507 printatt((unsigned) i + 1, attinfo[i], NULL);
00508 printf("\t----\n");
00509 }
00510
00511
00512
00513
00514
00515 void
00516 debugtup(TupleTableSlot *slot, DestReceiver *self)
00517 {
00518 TupleDesc typeinfo = slot->tts_tupleDescriptor;
00519 int natts = typeinfo->natts;
00520 int i;
00521 Datum origattr,
00522 attr;
00523 char *value;
00524 bool isnull;
00525 Oid typoutput;
00526 bool typisvarlena;
00527
00528 for (i = 0; i < natts; ++i)
00529 {
00530 origattr = slot_getattr(slot, i + 1, &isnull);
00531 if (isnull)
00532 continue;
00533 getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
00534 &typoutput, &typisvarlena);
00535
00536
00537
00538
00539
00540 if (typisvarlena)
00541 attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
00542 else
00543 attr = origattr;
00544
00545 value = OidOutputFunctionCall(typoutput, attr);
00546
00547 printatt((unsigned) i + 1, typeinfo->attrs[i], value);
00548
00549 pfree(value);
00550
00551
00552 if (DatumGetPointer(attr) != DatumGetPointer(origattr))
00553 pfree(DatumGetPointer(attr));
00554 }
00555 printf("\t----\n");
00556 }
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567 static void
00568 printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
00569 {
00570 TupleDesc typeinfo = slot->tts_tupleDescriptor;
00571 DR_printtup *myState = (DR_printtup *) self;
00572 StringInfoData buf;
00573 int natts = typeinfo->natts;
00574 int i,
00575 j,
00576 k;
00577
00578
00579 if (myState->attrinfo != typeinfo || myState->nattrs != natts)
00580 printtup_prepare_info(myState, typeinfo, natts);
00581
00582
00583 slot_getallattrs(slot);
00584
00585
00586
00587
00588 pq_beginmessage(&buf, 'B');
00589
00590
00591
00592
00593 j = 0;
00594 k = 1 << 7;
00595 for (i = 0; i < natts; ++i)
00596 {
00597 if (!slot->tts_isnull[i])
00598 j |= k;
00599 k >>= 1;
00600 if (k == 0)
00601 {
00602 pq_sendint(&buf, j, 1);
00603 j = 0;
00604 k = 1 << 7;
00605 }
00606 }
00607 if (k != (1 << 7))
00608 pq_sendint(&buf, j, 1);
00609
00610
00611
00612
00613 for (i = 0; i < natts; ++i)
00614 {
00615 PrinttupAttrInfo *thisState = myState->myinfo + i;
00616 Datum origattr = slot->tts_values[i],
00617 attr;
00618 bytea *outputbytes;
00619
00620 if (slot->tts_isnull[i])
00621 continue;
00622
00623 Assert(thisState->format == 1);
00624
00625
00626
00627
00628
00629 if (thisState->typisvarlena)
00630 attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
00631 else
00632 attr = origattr;
00633
00634 outputbytes = SendFunctionCall(&thisState->finfo, attr);
00635
00636 pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
00637 pq_sendbytes(&buf, VARDATA(outputbytes),
00638 VARSIZE(outputbytes) - VARHDRSZ);
00639 pfree(outputbytes);
00640
00641
00642 if (DatumGetPointer(attr) != DatumGetPointer(origattr))
00643 pfree(DatumGetPointer(attr));
00644 }
00645
00646 pq_endmessage(&buf);
00647 }