Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * libpq-be-fe.h
4 : * Wrapper functions for using libpq in extensions
5 : *
6 : * Code built directly into the backend is not allowed to link to libpq
7 : * directly. Extension code is allowed to use libpq however. One of the
8 : * main risks in doing so is leaking the malloc-allocated structures
9 : * returned by libpq, causing a process-lifespan memory leak.
10 : *
11 : * This file provides wrapper objects to help in building memory-safe code.
12 : * A PGresult object wrapped this way acts much as if it were palloc'd:
13 : * it will go away when the specified context is reset or deleted.
14 : * We might later extend the concept to other objects such as PGconns.
15 : *
16 : * See also the libpq-be-fe-helpers.h file, which provides additional
17 : * facilities built on top of this one.
18 : *
19 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
20 : * Portions Copyright (c) 1994, Regents of the University of California
21 : *
22 : * src/include/libpq/libpq-be-fe.h
23 : *
24 : *-------------------------------------------------------------------------
25 : */
26 : #ifndef LIBPQ_BE_FE_H
27 : #define LIBPQ_BE_FE_H
28 :
29 : /*
30 : * Despite the name, BUILDING_DLL is set only when building code directly part
31 : * of the backend. Which also is where libpq isn't allowed to be
32 : * used. Obviously this doesn't protect against libpq-fe.h getting included
33 : * otherwise, but perhaps still protects against a few mistakes...
34 : */
35 : #ifdef BUILDING_DLL
36 : #error "libpq may not be used in code directly built into the backend"
37 : #endif
38 :
39 : #include "libpq-fe.h"
40 :
41 : /*
42 : * Memory-context-safe wrapper object for a PGresult.
43 : */
44 : typedef struct libpqsrv_PGresult
45 : {
46 : PGresult *res; /* the wrapped PGresult */
47 : MemoryContext ctx; /* the MemoryContext it's attached to */
48 : MemoryContextCallback cb; /* the callback that implements freeing */
49 : } libpqsrv_PGresult;
50 :
51 :
52 : /*
53 : * Wrap the given PGresult in a libpqsrv_PGresult object, so that it will
54 : * go away automatically if the current memory context is reset or deleted.
55 : *
56 : * To avoid potential memory leaks, backend code must always apply this
57 : * immediately to the output of any PGresult-yielding libpq function.
58 : */
59 : static inline libpqsrv_PGresult *
60 49140 : libpqsrv_PQwrap(PGresult *res)
61 : {
62 : libpqsrv_PGresult *bres;
63 49140 : MemoryContext ctx = CurrentMemoryContext;
64 :
65 : /* We pass through a NULL result as-is, since there's nothing to free */
66 49140 : if (res == NULL)
67 23412 : return NULL;
68 : /* Attempt to allocate the wrapper ... this had better not throw error */
69 : bres = (libpqsrv_PGresult *)
70 25728 : MemoryContextAllocExtended(ctx,
71 : sizeof(libpqsrv_PGresult),
72 : MCXT_ALLOC_NO_OOM);
73 : /* If we failed to allocate a wrapper, free the PGresult before failing */
74 25728 : if (bres == NULL)
75 : {
76 0 : PQclear(res);
77 0 : ereport(ERROR,
78 : (errcode(ERRCODE_OUT_OF_MEMORY),
79 : errmsg("out of memory")));
80 : }
81 : /* Okay, set up the wrapper */
82 25728 : bres->res = res;
83 25728 : bres->ctx = ctx;
84 25728 : bres->cb.func = (MemoryContextCallbackFunction) PQclear;
85 25728 : bres->cb.arg = res;
86 25728 : MemoryContextRegisterResetCallback(ctx, &bres->cb);
87 25728 : return bres;
88 : }
89 :
90 : /*
91 : * Free a wrapped PGresult, after detaching it from the memory context.
92 : * Like PQclear(), allow the argument to be NULL.
93 : */
94 : static inline void
95 49828 : libpqsrv_PQclear(libpqsrv_PGresult *bres)
96 : {
97 49828 : if (bres)
98 : {
99 25662 : MemoryContextUnregisterResetCallback(bres->ctx, &bres->cb);
100 25662 : PQclear(bres->res);
101 25662 : pfree(bres);
102 : }
103 49828 : }
104 :
105 : /*
106 : * Move a wrapped PGresult to have a different parent context.
107 : */
108 : static inline libpqsrv_PGresult *
109 134 : libpqsrv_PGresultSetParent(libpqsrv_PGresult *bres, MemoryContext ctx)
110 : {
111 : libpqsrv_PGresult *newres;
112 :
113 : /* We pass through a NULL result as-is */
114 134 : if (bres == NULL)
115 0 : return NULL;
116 : /* Make a new wrapper in the target context, raising error on OOM */
117 : newres = (libpqsrv_PGresult *)
118 134 : MemoryContextAlloc(ctx, sizeof(libpqsrv_PGresult));
119 : /* Okay, set up the new wrapper */
120 134 : newres->res = bres->res;
121 134 : newres->ctx = ctx;
122 134 : newres->cb.func = (MemoryContextCallbackFunction) PQclear;
123 134 : newres->cb.arg = bres->res;
124 134 : MemoryContextRegisterResetCallback(ctx, &newres->cb);
125 : /* Disarm and delete the old wrapper */
126 134 : MemoryContextUnregisterResetCallback(bres->ctx, &bres->cb);
127 134 : pfree(bres);
128 134 : return newres;
129 : }
130 :
131 : /*
132 : * Convenience wrapper for PQgetResult.
133 : *
134 : * We could supply wrappers for other PGresult-returning functions too,
135 : * but at present there's no need.
136 : */
137 : static inline libpqsrv_PGresult *
138 49140 : libpqsrv_PQgetResult(PGconn *conn)
139 : {
140 49140 : return libpqsrv_PQwrap(PQgetResult(conn));
141 : }
142 :
143 : /*
144 : * Accessor functions for libpqsrv_PGresult. While it's not necessary to use
145 : * these, they emulate the behavior of the underlying libpq functions when
146 : * passed a NULL pointer. This is particularly important for PQresultStatus,
147 : * which is often the first check on a result.
148 : */
149 :
150 : static inline ExecStatusType
151 98524 : libpqsrv_PQresultStatus(const libpqsrv_PGresult *res)
152 : {
153 98524 : if (!res)
154 0 : return PGRES_FATAL_ERROR;
155 98524 : return PQresultStatus(res->res);
156 : }
157 :
158 : static inline const char *
159 : libpqsrv_PQresultErrorMessage(const libpqsrv_PGresult *res)
160 : {
161 : if (!res)
162 : return "";
163 : return PQresultErrorMessage(res->res);
164 : }
165 :
166 : static inline char *
167 284 : libpqsrv_PQresultErrorField(const libpqsrv_PGresult *res, int fieldcode)
168 : {
169 284 : if (!res)
170 0 : return NULL;
171 284 : return PQresultErrorField(res->res, fieldcode);
172 : }
173 :
174 : static inline char *
175 48 : libpqsrv_PQcmdStatus(const libpqsrv_PGresult *res)
176 : {
177 48 : if (!res)
178 0 : return NULL;
179 48 : return PQcmdStatus(res->res);
180 : }
181 :
182 : static inline int
183 11912 : libpqsrv_PQntuples(const libpqsrv_PGresult *res)
184 : {
185 11912 : if (!res)
186 0 : return 0;
187 11912 : return PQntuples(res->res);
188 : }
189 :
190 : static inline int
191 180314 : libpqsrv_PQnfields(const libpqsrv_PGresult *res)
192 : {
193 180314 : if (!res)
194 0 : return 0;
195 180314 : return PQnfields(res->res);
196 : }
197 :
198 : static inline char *
199 501474 : libpqsrv_PQgetvalue(const libpqsrv_PGresult *res, int tup_num, int field_num)
200 : {
201 501474 : if (!res)
202 0 : return NULL;
203 501474 : return PQgetvalue(res->res, tup_num, field_num);
204 : }
205 :
206 : static inline int
207 20 : libpqsrv_PQgetlength(const libpqsrv_PGresult *res, int tup_num, int field_num)
208 : {
209 20 : if (!res)
210 0 : return 0;
211 20 : return PQgetlength(res->res, tup_num, field_num);
212 : }
213 :
214 : static inline int
215 499962 : libpqsrv_PQgetisnull(const libpqsrv_PGresult *res, int tup_num, int field_num)
216 : {
217 499962 : if (!res)
218 0 : return 1; /* pretend it is null */
219 499962 : return PQgetisnull(res->res, tup_num, field_num);
220 : }
221 :
222 : static inline char *
223 5566 : libpqsrv_PQfname(const libpqsrv_PGresult *res, int field_num)
224 : {
225 5566 : if (!res)
226 0 : return NULL;
227 5566 : return PQfname(res->res, field_num);
228 : }
229 :
230 : static inline const char *
231 1984 : libpqsrv_PQcmdTuples(const libpqsrv_PGresult *res)
232 : {
233 1984 : if (!res)
234 0 : return "";
235 1984 : return PQcmdTuples(res->res);
236 : }
237 :
238 : /*
239 : * Redefine these libpq entry point names concerned with PGresults so that
240 : * they will operate on libpqsrv_PGresults instead. This avoids needing to
241 : * convert a lot of pre-existing code, and reduces the notational differences
242 : * between frontend and backend libpq-using code.
243 : */
244 : #define PGresult libpqsrv_PGresult
245 : #define PQclear libpqsrv_PQclear
246 : #define PQgetResult libpqsrv_PQgetResult
247 : #define PQresultStatus libpqsrv_PQresultStatus
248 : #define PQresultErrorMessage libpqsrv_PQresultErrorMessage
249 : #define PQresultErrorField libpqsrv_PQresultErrorField
250 : #define PQcmdStatus libpqsrv_PQcmdStatus
251 : #define PQntuples libpqsrv_PQntuples
252 : #define PQnfields libpqsrv_PQnfields
253 : #define PQgetvalue libpqsrv_PQgetvalue
254 : #define PQgetlength libpqsrv_PQgetlength
255 : #define PQgetisnull libpqsrv_PQgetisnull
256 : #define PQfname libpqsrv_PQfname
257 : #define PQcmdTuples libpqsrv_PQcmdTuples
258 :
259 : #endif /* LIBPQ_BE_FE_H */
|