#include "postgres.h"#include "access/printtup.h"#include "libpq/libpq.h"#include "libpq/pqformat.h"#include "tcop/pquery.h"#include "utils/lsyscache.h"
Go to the source code of this file.
Data Structures | |
| struct | PrinttupAttrInfo |
| struct | DR_printtup |
Functions | |
| static void | printtup_startup (DestReceiver *self, int operation, TupleDesc typeinfo) |
| static void | printtup (TupleTableSlot *slot, DestReceiver *self) |
| static void | printtup_20 (TupleTableSlot *slot, DestReceiver *self) |
| static void | printtup_internal_20 (TupleTableSlot *slot, DestReceiver *self) |
| static void | printtup_shutdown (DestReceiver *self) |
| static void | printtup_destroy (DestReceiver *self) |
| DestReceiver * | printtup_create_DR (CommandDest dest) |
| void | SetRemoteDestReceiverParams (DestReceiver *self, Portal portal) |
| void | SendRowDescriptionMessage (TupleDesc typeinfo, List *targetlist, int16 *formats) |
| static void | printtup_prepare_info (DR_printtup *myState, TupleDesc typeinfo, int numAttrs) |
| static void | printatt (unsigned attributeId, Form_pg_attribute attributeP, char *value) |
| void | debugStartup (DestReceiver *self, int operation, TupleDesc typeinfo) |
| void | debugtup (TupleTableSlot *slot, DestReceiver *self) |
| void debugStartup | ( | DestReceiver * | self, | |
| int | operation, | |||
| TupleDesc | typeinfo | |||
| ) |
Definition at line 497 of file printtup.c.
References tupleDesc::attrs, i, tupleDesc::natts, NULL, and printatt().
| void debugtup | ( | TupleTableSlot * | slot, | |
| DestReceiver * | self | |||
| ) |
Definition at line 516 of file printtup.c.
References tupleDesc::attrs, DatumGetPointer, getTypeOutputInfo(), i, tupleDesc::natts, OidOutputFunctionCall(), pfree(), PG_DETOAST_DATUM, PointerGetDatum, printatt(), slot_getattr(), TupleTableSlot::tts_tupleDescriptor, and value.
Referenced by print_slot().
{
TupleDesc typeinfo = slot->tts_tupleDescriptor;
int natts = typeinfo->natts;
int i;
Datum origattr,
attr;
char *value;
bool isnull;
Oid typoutput;
bool typisvarlena;
for (i = 0; i < natts; ++i)
{
origattr = slot_getattr(slot, i + 1, &isnull);
if (isnull)
continue;
getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
&typoutput, &typisvarlena);
/*
* If we have a toasted datum, forcibly detoast it here to avoid
* memory leakage inside the type's output routine.
*/
if (typisvarlena)
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
else
attr = origattr;
value = OidOutputFunctionCall(typoutput, attr);
printatt((unsigned) i + 1, typeinfo->attrs[i], value);
pfree(value);
/* Clean up detoasted copy, if any */
if (DatumGetPointer(attr) != DatumGetPointer(origattr))
pfree(DatumGetPointer(attr));
}
printf("\t----\n");
}
| static void printatt | ( | unsigned | attributeId, | |
| Form_pg_attribute | attributeP, | |||
| char * | value | |||
| ) | [static] |
Definition at line 476 of file printtup.c.
Referenced by debugStartup(), and debugtup().
{
printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
attributeId,
NameStr(attributeP->attname),
value != NULL ? " = \"" : "",
value != NULL ? value : "",
value != NULL ? "\"" : "",
(unsigned int) (attributeP->atttypid),
attributeP->attlen,
attributeP->atttypmod,
attributeP->attbyval ? 't' : 'f');
}
| static void printtup | ( | TupleTableSlot * | slot, | |
| DestReceiver * | self | |||
| ) | [static] |
Definition at line 287 of file printtup.c.
References DR_printtup::attrinfo, buf, DatumGetPointer, PrinttupAttrInfo::finfo, PrinttupAttrInfo::format, i, DR_printtup::myinfo, DR_printtup::nattrs, tupleDesc::natts, OutputFunctionCall(), pfree(), PG_DETOAST_DATUM, PointerGetDatum, pq_beginmessage(), pq_endmessage(), pq_sendbytes(), pq_sendcountedtext(), pq_sendint(), printtup_prepare_info(), SendFunctionCall(), slot_getallattrs(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, TupleTableSlot::tts_values, PrinttupAttrInfo::typisvarlena, VARDATA, VARHDRSZ, and VARSIZE.
{
TupleDesc typeinfo = slot->tts_tupleDescriptor;
DR_printtup *myState = (DR_printtup *) self;
StringInfoData buf;
int natts = typeinfo->natts;
int i;
/* Set or update my derived attribute info, if needed */
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
printtup_prepare_info(myState, typeinfo, natts);
/* Make sure the tuple is fully deconstructed */
slot_getallattrs(slot);
/*
* Prepare a DataRow message
*/
pq_beginmessage(&buf, 'D');
pq_sendint(&buf, natts, 2);
/*
* send the attributes of this tuple
*/
for (i = 0; i < natts; ++i)
{
PrinttupAttrInfo *thisState = myState->myinfo + i;
Datum origattr = slot->tts_values[i],
attr;
if (slot->tts_isnull[i])
{
pq_sendint(&buf, -1, 4);
continue;
}
/*
* If we have a toasted datum, forcibly detoast it here to avoid
* memory leakage inside the type's output routine.
*/
if (thisState->typisvarlena)
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
else
attr = origattr;
if (thisState->format == 0)
{
/* Text output */
char *outputstr;
outputstr = OutputFunctionCall(&thisState->finfo, attr);
pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
pfree(outputstr);
}
else
{
/* Binary output */
bytea *outputbytes;
outputbytes = SendFunctionCall(&thisState->finfo, attr);
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ);
pfree(outputbytes);
}
/* Clean up detoasted copy, if any */
if (DatumGetPointer(attr) != DatumGetPointer(origattr))
pfree(DatumGetPointer(attr));
}
pq_endmessage(&buf);
}
| static void printtup_20 | ( | TupleTableSlot * | slot, | |
| DestReceiver * | self | |||
| ) | [static] |
Definition at line 367 of file printtup.c.
References Assert, DR_printtup::attrinfo, buf, DatumGetPointer, PrinttupAttrInfo::finfo, PrinttupAttrInfo::format, i, DR_printtup::myinfo, DR_printtup::nattrs, tupleDesc::natts, OutputFunctionCall(), pfree(), PG_DETOAST_DATUM, PointerGetDatum, pq_beginmessage(), pq_endmessage(), pq_sendcountedtext(), pq_sendint(), printtup_prepare_info(), slot_getallattrs(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, TupleTableSlot::tts_values, and PrinttupAttrInfo::typisvarlena.
{
TupleDesc typeinfo = slot->tts_tupleDescriptor;
DR_printtup *myState = (DR_printtup *) self;
StringInfoData buf;
int natts = typeinfo->natts;
int i,
j,
k;
/* Set or update my derived attribute info, if needed */
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
printtup_prepare_info(myState, typeinfo, natts);
/* Make sure the tuple is fully deconstructed */
slot_getallattrs(slot);
/*
* tell the frontend to expect new tuple data (in ASCII style)
*/
pq_beginmessage(&buf, 'D');
/*
* send a bitmap of which attributes are not null
*/
j = 0;
k = 1 << 7;
for (i = 0; i < natts; ++i)
{
if (!slot->tts_isnull[i])
j |= k; /* set bit if not null */
k >>= 1;
if (k == 0) /* end of byte? */
{
pq_sendint(&buf, j, 1);
j = 0;
k = 1 << 7;
}
}
if (k != (1 << 7)) /* flush last partial byte */
pq_sendint(&buf, j, 1);
/*
* send the attributes of this tuple
*/
for (i = 0; i < natts; ++i)
{
PrinttupAttrInfo *thisState = myState->myinfo + i;
Datum origattr = slot->tts_values[i],
attr;
char *outputstr;
if (slot->tts_isnull[i])
continue;
Assert(thisState->format == 0);
/*
* If we have a toasted datum, forcibly detoast it here to avoid
* memory leakage inside the type's output routine.
*/
if (thisState->typisvarlena)
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
else
attr = origattr;
outputstr = OutputFunctionCall(&thisState->finfo, attr);
pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
pfree(outputstr);
/* Clean up detoasted copy, if any */
if (DatumGetPointer(attr) != DatumGetPointer(origattr))
pfree(DatumGetPointer(attr));
}
pq_endmessage(&buf);
}
| DestReceiver* printtup_create_DR | ( | CommandDest | dest | ) |
Definition at line 70 of file printtup.c.
References palloc0().
Referenced by CreateDestReceiver().
{
DR_printtup *self = (DR_printtup *) palloc0(sizeof(DR_printtup));
self->pub.receiveSlot = printtup; /* might get changed later */
self->pub.rStartup = printtup_startup;
self->pub.rShutdown = printtup_shutdown;
self->pub.rDestroy = printtup_destroy;
self->pub.mydest = dest;
/*
* Send T message automatically if DestRemote, but not if
* DestRemoteExecute
*/
self->sendDescrip = (dest == DestRemote);
self->attrinfo = NULL;
self->nattrs = 0;
self->myinfo = NULL;
return (DestReceiver *) self;
}
| static void printtup_destroy | ( | DestReceiver * | self | ) | [static] |
| static void printtup_internal_20 | ( | TupleTableSlot * | slot, | |
| DestReceiver * | self | |||
| ) | [static] |
Definition at line 568 of file printtup.c.
References Assert, DR_printtup::attrinfo, buf, DatumGetPointer, PrinttupAttrInfo::finfo, PrinttupAttrInfo::format, i, DR_printtup::myinfo, DR_printtup::nattrs, tupleDesc::natts, pfree(), PG_DETOAST_DATUM, PointerGetDatum, pq_beginmessage(), pq_endmessage(), pq_sendbytes(), pq_sendint(), printtup_prepare_info(), SendFunctionCall(), slot_getallattrs(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, TupleTableSlot::tts_values, PrinttupAttrInfo::typisvarlena, VARDATA, VARHDRSZ, and VARSIZE.
{
TupleDesc typeinfo = slot->tts_tupleDescriptor;
DR_printtup *myState = (DR_printtup *) self;
StringInfoData buf;
int natts = typeinfo->natts;
int i,
j,
k;
/* Set or update my derived attribute info, if needed */
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
printtup_prepare_info(myState, typeinfo, natts);
/* Make sure the tuple is fully deconstructed */
slot_getallattrs(slot);
/*
* tell the frontend to expect new tuple data (in binary style)
*/
pq_beginmessage(&buf, 'B');
/*
* send a bitmap of which attributes are not null
*/
j = 0;
k = 1 << 7;
for (i = 0; i < natts; ++i)
{
if (!slot->tts_isnull[i])
j |= k; /* set bit if not null */
k >>= 1;
if (k == 0) /* end of byte? */
{
pq_sendint(&buf, j, 1);
j = 0;
k = 1 << 7;
}
}
if (k != (1 << 7)) /* flush last partial byte */
pq_sendint(&buf, j, 1);
/*
* send the attributes of this tuple
*/
for (i = 0; i < natts; ++i)
{
PrinttupAttrInfo *thisState = myState->myinfo + i;
Datum origattr = slot->tts_values[i],
attr;
bytea *outputbytes;
if (slot->tts_isnull[i])
continue;
Assert(thisState->format == 1);
/*
* If we have a toasted datum, forcibly detoast it here to avoid
* memory leakage inside the type's output routine.
*/
if (thisState->typisvarlena)
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
else
attr = origattr;
outputbytes = SendFunctionCall(&thisState->finfo, attr);
/* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ);
pfree(outputbytes);
/* Clean up detoasted copy, if any */
if (DatumGetPointer(attr) != DatumGetPointer(origattr))
pfree(DatumGetPointer(attr));
}
pq_endmessage(&buf);
}
| static void printtup_prepare_info | ( | DR_printtup * | myState, | |
| TupleDesc | typeinfo, | |||
| int | numAttrs | |||
| ) | [static] |
Definition at line 237 of file printtup.c.
References DR_printtup::attrinfo, tupleDesc::attrs, ereport, errcode(), errmsg(), ERROR, PrinttupAttrInfo::finfo, fmgr_info(), PrinttupAttrInfo::format, format, PortalData::formats, getTypeBinaryOutputInfo(), getTypeOutputInfo(), i, DR_printtup::myinfo, DR_printtup::nattrs, palloc0(), pfree(), DR_printtup::portal, PrinttupAttrInfo::typisvarlena, PrinttupAttrInfo::typoutput, and PrinttupAttrInfo::typsend.
Referenced by printtup(), printtup_20(), and printtup_internal_20().
{
int16 *formats = myState->portal->formats;
int i;
/* get rid of any old data */
if (myState->myinfo)
pfree(myState->myinfo);
myState->myinfo = NULL;
myState->attrinfo = typeinfo;
myState->nattrs = numAttrs;
if (numAttrs <= 0)
return;
myState->myinfo = (PrinttupAttrInfo *)
palloc0(numAttrs * sizeof(PrinttupAttrInfo));
for (i = 0; i < numAttrs; i++)
{
PrinttupAttrInfo *thisState = myState->myinfo + i;
int16 format = (formats ? formats[i] : 0);
thisState->format = format;
if (format == 0)
{
getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
&thisState->typoutput,
&thisState->typisvarlena);
fmgr_info(thisState->typoutput, &thisState->finfo);
}
else if (format == 1)
{
getTypeBinaryOutputInfo(typeinfo->attrs[i]->atttypid,
&thisState->typsend,
&thisState->typisvarlena);
fmgr_info(thisState->typsend, &thisState->finfo);
}
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unsupported format code: %d", format)));
}
}
| static void printtup_shutdown | ( | DestReceiver * | self | ) | [static] |
Definition at line 450 of file printtup.c.
References DR_printtup::attrinfo, DR_printtup::myinfo, and pfree().
{
DR_printtup *myState = (DR_printtup *) self;
if (myState->myinfo)
pfree(myState->myinfo);
myState->myinfo = NULL;
myState->attrinfo = NULL;
}
| static void printtup_startup | ( | DestReceiver * | self, | |
| int | operation, | |||
| TupleDesc | typeinfo | |||
| ) | [static] |
Definition at line 121 of file printtup.c.
References FetchPortalTargetList(), PortalData::formats, FrontendProtocol, PortalData::name, NULL, PG_PROTOCOL_MAJOR, DR_printtup::portal, pq_puttextmessage(), DR_printtup::sendDescrip, and SendRowDescriptionMessage().
{
DR_printtup *myState = (DR_printtup *) self;
Portal portal = myState->portal;
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
{
/*
* Send portal name to frontend (obsolete cruft, gone in proto 3.0)
*
* If portal name not specified, use "blank" portal.
*/
const char *portalName = portal->name;
if (portalName == NULL || portalName[0] == '\0')
portalName = "blank";
pq_puttextmessage('P', portalName);
}
/*
* If we are supposed to emit row descriptions, then send the tuple
* descriptor of the tuples.
*/
if (myState->sendDescrip)
SendRowDescriptionMessage(typeinfo,
FetchPortalTargetList(portal),
portal->formats);
/* ----------------
* We could set up the derived attr info at this time, but we postpone it
* until the first call of printtup, for 2 reasons:
* 1. We don't waste time (compared to the old way) if there are no
* tuples at all to output.
* 2. Checking in printtup allows us to handle the case that the tuples
* change type midway through (although this probably can't happen in
* the current executor).
* ----------------
*/
}
Definition at line 174 of file printtup.c.
References tupleDesc::attrs, buf, FrontendProtocol, getBaseTypeAndTypmod(), i, lfirst, list_head(), lnext, NameStr, tupleDesc::natts, PG_PROTOCOL_MAJOR, pq_beginmessage(), pq_endmessage(), pq_sendint(), pq_sendstring(), TargetEntry::resorigcol, and TargetEntry::resorigtbl.
Referenced by exec_describe_portal_message(), exec_describe_statement_message(), and printtup_startup().
{
Form_pg_attribute *attrs = typeinfo->attrs;
int natts = typeinfo->natts;
int proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
int i;
StringInfoData buf;
ListCell *tlist_item = list_head(targetlist);
pq_beginmessage(&buf, 'T'); /* tuple descriptor message type */
pq_sendint(&buf, natts, 2); /* # of attrs in tuples */
for (i = 0; i < natts; ++i)
{
Oid atttypid = attrs[i]->atttypid;
int32 atttypmod = attrs[i]->atttypmod;
pq_sendstring(&buf, NameStr(attrs[i]->attname));
/* column ID info appears in protocol 3.0 and up */
if (proto >= 3)
{
/* Do we have a non-resjunk tlist item? */
while (tlist_item &&
((TargetEntry *) lfirst(tlist_item))->resjunk)
tlist_item = lnext(tlist_item);
if (tlist_item)
{
TargetEntry *tle = (TargetEntry *) lfirst(tlist_item);
pq_sendint(&buf, tle->resorigtbl, 4);
pq_sendint(&buf, tle->resorigcol, 2);
tlist_item = lnext(tlist_item);
}
else
{
/* No info available, so send zeroes */
pq_sendint(&buf, 0, 4);
pq_sendint(&buf, 0, 2);
}
}
/* If column is a domain, send the base type and typmod instead */
atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
pq_sendint(&buf, (int) atttypid, sizeof(atttypid));
pq_sendint(&buf, attrs[i]->attlen, sizeof(attrs[i]->attlen));
/* typmod appears in protocol 2.0 and up */
if (proto >= 2)
pq_sendint(&buf, atttypmod, sizeof(atttypmod));
/* format info appears in protocol 3.0 and up */
if (proto >= 3)
{
if (formats)
pq_sendint(&buf, formats[i], 2);
else
pq_sendint(&buf, 0, 2);
}
}
pq_endmessage(&buf);
}
| void SetRemoteDestReceiverParams | ( | DestReceiver * | self, | |
| Portal | portal | |||
| ) |
Definition at line 97 of file printtup.c.
References Assert, DestRemote, DestRemoteExecute, PortalData::formats, FrontendProtocol, _DestReceiver::mydest, PG_PROTOCOL_MAJOR, DR_printtup::portal, DR_printtup::pub, and _DestReceiver::receiveSlot.
Referenced by exec_execute_message(), and exec_simple_query().
{
DR_printtup *myState = (DR_printtup *) self;
Assert(myState->pub.mydest == DestRemote ||
myState->pub.mydest == DestRemoteExecute);
myState->portal = portal;
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
{
/*
* In protocol 2.0 the Bind message does not exist, so there is no way
* for the columns to have different print formats; it's sufficient to
* look at the first one.
*/
if (portal->formats && portal->formats[0] != 0)
myState->pub.receiveSlot = printtup_internal_20;
else
myState->pub.receiveSlot = printtup_20;
}
}
1.7.1