19
19
20
20
#include "common/keywords.h"
21
21
#include "fe_utils/string_utils.h"
22
+ #include "mb/pg_wchar.h"
22
23
23
24
static PQExpBuffer defaultGetLocalPQExpBuffer (void );
24
25
25
26
/* Globals exported by this file */
26
27
int quote_all_identifiers = 0 ;
27
28
PQExpBuffer (* getLocalPQExpBuffer ) (void ) = defaultGetLocalPQExpBuffer ;
28
29
30
+ static int fmtIdEncoding = -1 ;
31
+
29
32
30
33
/*
31
34
* Returns a temporary PQExpBuffer, valid until the next call to the function.
@@ -54,14 +57,48 @@ defaultGetLocalPQExpBuffer(void)
54
57
return id_return ;
55
58
}
56
59
60
+ /*
61
+ * Set the encoding that fmtId() and fmtQualifiedId() use.
62
+ *
63
+ * This is not safe against multiple connections having different encodings,
64
+ * but there is no real other way to address the need to know the encoding for
65
+ * fmtId()/fmtQualifiedId() input for safe escaping. Eventually we should get
66
+ * rid of fmtId().
67
+ */
68
+ void
69
+ setFmtEncoding (int encoding )
70
+ {
71
+ fmtIdEncoding = encoding ;
72
+ }
73
+
74
+ /*
75
+ * Return the currently configured encoding for fmtId() and fmtQualifiedId().
76
+ */
77
+ static int
78
+ getFmtEncoding (void )
79
+ {
80
+ if (fmtIdEncoding != -1 )
81
+ return fmtIdEncoding ;
82
+
83
+ /*
84
+ * In assertion builds it seems best to fail hard if the encoding was not
85
+ * set, to make it easier to find places with missing calls. But in
86
+ * production builds that seems like a bad idea, thus we instead just
87
+ * default to UTF-8.
88
+ */
89
+ Assert (fmtIdEncoding != -1 );
90
+
91
+ return PG_UTF8 ;
92
+ }
93
+
57
94
/*
58
95
* Quotes input string if it's not a legitimate SQL identifier as-is.
59
96
*
60
- * Note that the returned string must be used before calling fmtId again,
97
+ * Note that the returned string must be used before calling fmtIdEnc again,
61
98
* since we re-use the same return buffer each time.
62
99
*/
63
100
const char *
64
- fmtId (const char * rawid )
101
+ fmtIdEnc (const char * rawid , int encoding )
65
102
{
66
103
PQExpBuffer id_return = getLocalPQExpBuffer ();
67
104
@@ -134,25 +171,42 @@ fmtId(const char *rawid)
134
171
}
135
172
136
173
/*
137
- * fmtQualifiedId - construct a schema-qualified name, with quoting as needed.
174
+ * Quotes input string if it's not a legitimate SQL identifier as-is.
175
+ *
176
+ * Note that the returned string must be used before calling fmtId again,
177
+ * since we re-use the same return buffer each time.
178
+ *
179
+ * NB: This assumes setFmtEncoding() previously has been called to configure
180
+ * the encoding of rawid. It is preferable to use fmtIdEnc() with an
181
+ * explicit encoding.
182
+ */
183
+ const char *
184
+ fmtId (const char * rawid )
185
+ {
186
+ return fmtIdEnc (rawid , getFmtEncoding ());
187
+ }
188
+
189
+ /*
190
+ * fmtQualifiedIdEnc - construct a schema-qualified name, with quoting as
191
+ * needed.
138
192
*
139
193
* Like fmtId, use the result before calling again.
140
194
*
141
195
* Since we call fmtId and it also uses getLocalPQExpBuffer() we cannot
142
196
* use that buffer until we're finished with calling fmtId().
143
197
*/
144
198
const char *
145
- fmtQualifiedId (const char * schema , const char * id )
199
+ fmtQualifiedIdEnc (const char * schema , const char * id , int encoding )
146
200
{
147
201
PQExpBuffer id_return ;
148
202
PQExpBuffer lcl_pqexp = createPQExpBuffer ();
149
203
150
204
/* Some callers might fail to provide a schema name */
151
205
if (schema && * schema )
152
206
{
153
- appendPQExpBuffer (lcl_pqexp , "%s." , fmtId (schema ));
207
+ appendPQExpBuffer (lcl_pqexp , "%s." , fmtIdEnc (schema , encoding ));
154
208
}
155
- appendPQExpBufferStr (lcl_pqexp , fmtId (id ));
209
+ appendPQExpBufferStr (lcl_pqexp , fmtIdEnc (id , encoding ));
156
210
157
211
id_return = getLocalPQExpBuffer ();
158
212
@@ -162,6 +216,24 @@ fmtQualifiedId(const char *schema, const char *id)
162
216
return id_return -> data ;
163
217
}
164
218
219
+ /*
220
+ * fmtQualifiedId - construct a schema-qualified name, with quoting as needed.
221
+ *
222
+ * Like fmtId, use the result before calling again.
223
+ *
224
+ * Since we call fmtId and it also uses getLocalPQExpBuffer() we cannot
225
+ * use that buffer until we're finished with calling fmtId().
226
+ *
227
+ * NB: This assumes setFmtEncoding() previously has been called to configure
228
+ * the encoding of schema/id. It is preferable to use fmtQualifiedIdEnc()
229
+ * with an explicit encoding.
230
+ */
231
+ const char *
232
+ fmtQualifiedId (const char * schema , const char * id )
233
+ {
234
+ return fmtQualifiedIdEnc (schema , id , getFmtEncoding ());
235
+ }
236
+
165
237
166
238
/*
167
239
* Format a Postgres version number (in the PG_VERSION_NUM integer format
0 commit comments