@@ -212,38 +212,89 @@ conn_get_standard_conforming_strings(PGconn *pgconn)
212212 return equote ;
213213}
214214
215- /* Return a string containing the client_encoding setting .
215+ /* Convert a PostgreSQL encoding to a Python codec .
216216 *
217- * Return a new string allocated by malloc(): use free() to free it.
218- * Return NULL in case of failure .
217+ * Return a new copy of the codec name allocated on the Python heap,
218+ * NULL with exception in case of error .
219219 */
220220static char *
221- conn_get_encoding ( PGconn * pgconn )
221+ conn_encoding_to_codec ( const char * enc )
222222{
223- const char * tmp , * i ;
224- char * encoding , * j ;
223+ char * tmp ;
224+ Py_ssize_t size ;
225+ PyObject * pyenc ;
226+ char * rv = NULL ;
227+
228+ if (!(pyenc = PyDict_GetItemString (psycoEncodings , enc ))) {
229+ PyErr_Format (OperationalError ,
230+ "no Python codec for client encoding '%s'" , enc );
231+ goto exit ;
232+ }
233+ if (-1 == PyString_AsStringAndSize (pyenc , & tmp , & size )) {
234+ goto exit ;
235+ }
236+
237+ /* have our own copy of the python codec name */
238+ rv = psycopg_strdup (tmp , size );
239+
240+ exit :
241+ /* pyenc is borrowed: no decref. */
242+ return rv ;
243+ }
244+
245+ /* Read the client encoding from the connection.
246+ *
247+ * Store the encoding in the pgconn->encoding field and the name of the
248+ * matching python codec in codec. The buffers are allocated on the Python
249+ * heap.
250+ *
251+ * Return 0 on success, else nonzero.
252+ */
253+ static int
254+ conn_read_encoding (connectionObject * self , PGconn * pgconn )
255+ {
256+ char * enc = NULL , * codec = NULL , * j ;
257+ const char * tmp ;
258+ int rv = -1 ;
225259
226260 tmp = PQparameterStatus (pgconn , "client_encoding" );
227261 Dprintf ("conn_connect: client encoding: %s" , tmp ? tmp : "(none)" );
228262 if (!tmp ) {
229263 PyErr_SetString (OperationalError ,
230264 "server didn't return client encoding" );
231- return NULL ;
265+ goto exit ;
232266 }
233267
234- encoding = malloc (strlen (tmp )+ 1 );
235- if (encoding == NULL ) {
268+ if (!(enc = PyMem_Malloc (strlen (tmp )+ 1 ))) {
236269 PyErr_NoMemory ();
237- return NULL ;
270+ goto exit ;
238271 }
239272
240- /* return in uppercase */
241- i = tmp ;
242- j = encoding ;
243- while (* i ) { * j ++ = toupper (* i ++ ); }
273+ /* turn encoding in uppercase */
274+ j = enc ;
275+ while (* tmp ) { * j ++ = toupper (* tmp ++ ); }
244276 * j = '\0' ;
245277
246- return encoding ;
278+ /* Look for this encoding in Python codecs. */
279+ if (!(codec = conn_encoding_to_codec (enc ))) {
280+ goto exit ;
281+ }
282+
283+ /* Good, success: store the encoding/codec in the connection. */
284+ PyMem_Free (self -> encoding );
285+ self -> encoding = enc ;
286+ enc = NULL ;
287+
288+ PyMem_Free (self -> codec );
289+ self -> codec = codec ;
290+ codec = NULL ;
291+
292+ rv = 0 ;
293+
294+ exit :
295+ PyMem_Free (enc );
296+ PyMem_Free (codec );
297+ return rv ;
247298}
248299
249300int
@@ -319,9 +370,8 @@ conn_setup(connectionObject *self, PGconn *pgconn)
319370 PyErr_SetString (InterfaceError , "only protocol 3 supported" );
320371 return -1 ;
321372 }
322- /* conn_get_encoding returns a malloc'd string */
323- self -> encoding = conn_get_encoding (pgconn );
324- if (self -> encoding == NULL ) {
373+
374+ if (conn_read_encoding (self , pgconn )) {
325375 return -1 ;
326376 }
327377
@@ -651,9 +701,7 @@ _conn_poll_setup_async(connectionObject *self)
651701 PyErr_SetString (InterfaceError , "only protocol 3 supported" );
652702 break ;
653703 }
654- /* conn_get_encoding returns a malloc'd string */
655- self -> encoding = conn_get_encoding (self -> pgconn );
656- if (self -> encoding == NULL ) {
704+ if (conn_read_encoding (self , self -> pgconn )) {
657705 break ;
658706 }
659707 self -> cancel = conn_get_cancel (self -> pgconn );
@@ -873,11 +921,15 @@ conn_set_client_encoding(connectionObject *self, const char *enc)
873921 char * error = NULL ;
874922 char query [48 ];
875923 int res = 0 ;
924+ char * codec ;
876925
877926 /* If the current encoding is equal to the requested one we don't
878927 issue any query to the backend */
879928 if (strcmp (self -> encoding , enc ) == 0 ) return 0 ;
880929
930+ /* We must know what python codec this encoding is. */
931+ if (!(codec = conn_encoding_to_codec (enc ))) { return -1 ; }
932+
881933 Py_BEGIN_ALLOW_THREADS ;
882934 pthread_mutex_lock (& self -> lock );
883935
@@ -886,19 +938,29 @@ conn_set_client_encoding(connectionObject *self, const char *enc)
886938
887939 /* abort the current transaction, to set the encoding ouside of
888940 transactions */
889- res = pq_abort_locked (self , & pgres , & error , & _save );
890-
891- if (res == 0 ) {
892- res = pq_execute_command_locked (self , query , & pgres , & error , & _save );
893- if (res == 0 ) {
894- /* no error, we can proceeed and store the new encoding */
895- if (self -> encoding ) free (self -> encoding );
896- self -> encoding = strdup (enc );
897- Dprintf ("conn_set_client_encoding: set encoding to %s" ,
898- self -> encoding );
899- }
941+ if ((res = pq_abort_locked (self , & pgres , & error , & _save ))) {
942+ goto endlock ;
943+ }
944+
945+ if ((res = pq_execute_command_locked (self , query , & pgres , & error , & _save ))) {
946+ goto endlock ;
900947 }
901948
949+ /* no error, we can proceeed and store the new encoding */
950+ PyMem_Free (self -> encoding );
951+ if (!(self -> encoding = psycopg_strdup (enc , 0 ))) {
952+ res = 1 ; /* don't call pq_complete_error below */
953+ goto endlock ;
954+ }
955+
956+ /* Store the python codec too. */
957+ PyMem_Free (self -> codec );
958+ self -> codec = codec ;
959+
960+ Dprintf ("conn_set_client_encoding: set encoding to %s (codec: %s)" ,
961+ self -> encoding , self -> codec );
962+
963+ endlock :
902964
903965 pthread_mutex_unlock (& self -> lock );
904966 Py_END_ALLOW_THREADS ;
0 commit comments