1/*-------------------------------------------------------------------------
2 *
3 * printsimple.c
4 * Routines to print out tuples containing only a limited range of
5 * builtin types without catalog access. This is intended for
6 * backends that don't have catalog access because they are not bound
7 * to a specific database, such as some walsender processes. It
8 * doesn't handle standalone backends or protocol versions other than
9 * 3.0, because we don't need such handling for current applications.
10 *
11 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
13 *
14 * IDENTIFICATION
15 * src/backend/access/common/printsimple.c
16 *
17 *-------------------------------------------------------------------------
18 */
19#include "postgres.h"
20
21#include "access/printsimple.h"
22#include "catalog/pg_type.h"
23#include "fmgr.h"
24#include "libpq/pqformat.h"
25#include "utils/builtins.h"
26
27/*
28 * At startup time, send a RowDescription message.
29 */
30void
31printsimple_startup(DestReceiver *self, int operation, TupleDesc tupdesc)
32{
33 StringInfoData buf;
34 int i;
35
36 pq_beginmessage(&buf, 'T'); /* RowDescription */
37 pq_sendint16(&buf, tupdesc->natts);
38
39 for (i = 0; i < tupdesc->natts; ++i)
40 {
41 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
42
43 pq_sendstring(&buf, NameStr(attr->attname));
44 pq_sendint32(&buf, 0); /* table oid */
45 pq_sendint16(&buf, 0); /* attnum */
46 pq_sendint32(&buf, (int) attr->atttypid);
47 pq_sendint16(&buf, attr->attlen);
48 pq_sendint32(&buf, attr->atttypmod);
49 pq_sendint16(&buf, 0); /* format code */
50 }
51
52 pq_endmessage(&buf);
53}
54
55/*
56 * For each tuple, send a DataRow message.
57 */
58bool
59printsimple(TupleTableSlot *slot, DestReceiver *self)
60{
61 TupleDesc tupdesc = slot->tts_tupleDescriptor;
62 StringInfoData buf;
63 int i;
64
65 /* Make sure the tuple is fully deconstructed */
66 slot_getallattrs(slot);
67
68 /* Prepare and send message */
69 pq_beginmessage(&buf, 'D');
70 pq_sendint16(&buf, tupdesc->natts);
71
72 for (i = 0; i < tupdesc->natts; ++i)
73 {
74 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
75 Datum value;
76
77 if (slot->tts_isnull[i])
78 {
79 pq_sendint32(&buf, -1);
80 continue;
81 }
82
83 value = slot->tts_values[i];
84
85 /*
86 * We can't call the regular type output functions here because we
87 * might not have catalog access. Instead, we must hard-wire
88 * knowledge of the required types.
89 */
90 switch (attr->atttypid)
91 {
92 case TEXTOID:
93 {
94 text *t = DatumGetTextPP(value);
95
96 pq_sendcountedtext(&buf,
97 VARDATA_ANY(t),
98 VARSIZE_ANY_EXHDR(t),
99 false);
100 }
101 break;
102
103 case INT4OID:
104 {
105 int32 num = DatumGetInt32(value);
106 char str[12]; /* sign, 10 digits and '\0' */
107
108 pg_ltoa(num, str);
109 pq_sendcountedtext(&buf, str, strlen(str), false);
110 }
111 break;
112
113 case INT8OID:
114 {
115 int64 num = DatumGetInt64(value);
116 char str[23]; /* sign, 21 digits and '\0' */
117
118 pg_lltoa(num, str);
119 pq_sendcountedtext(&buf, str, strlen(str), false);
120 }
121 break;
122
123 default:
124 elog(ERROR, "unsupported type OID: %u", attr->atttypid);
125 }
126 }
127
128 pq_endmessage(&buf);
129
130 return true;
131}
132