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 | */ |
30 | void |
31 | printsimple_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 | */ |
58 | bool |
59 | printsimple(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 | |