aboutsummaryrefslogtreecommitdiff
path: root/src/pl/plpython/plpy_util.c
blob: bf2953226f49275b022d4222c93f7754c0e403d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
 * utility functions
 *
 * src/pl/plpython/plpy_util.c
 */

#include "postgres.h"

#include "mb/pg_wchar.h"
#include "utils/memutils.h"
#include "utils/palloc.h"

#include "plpython.h"

#include "plpy_util.h"

#include "plpy_elog.h"


void *
PLy_malloc(size_t bytes)
{
	/* We need our allocations to be long-lived, so use TopMemoryContext */
	return MemoryContextAlloc(TopMemoryContext, bytes);
}

void *
PLy_malloc0(size_t bytes)
{
	void	   *ptr = PLy_malloc(bytes);

	MemSet(ptr, 0, bytes);
	return ptr;
}

char *
PLy_strdup(const char *str)
{
	char	   *result;
	size_t		len;

	len = strlen(str) + 1;
	result = PLy_malloc(len);
	memcpy(result, str, len);

	return result;
}

/* define this away */
void
PLy_free(void *ptr)
{
	pfree(ptr);
}

/*
 * Convert a Python unicode object to a Python string/bytes object in
 * PostgreSQL server encoding.	Reference ownership is passed to the
 * caller.
 */
PyObject *
PLyUnicode_Bytes(PyObject *unicode)
{
	PyObject   *rv;
	const char *serverenc;

	/*
	 * Map PostgreSQL encoding to a Python encoding name.
	 */
	switch (GetDatabaseEncoding())
	{
		case PG_SQL_ASCII:
			/*
			 * Mapping SQL_ASCII to Python's 'ascii' is a bit bogus. Python's
			 * 'ascii' means true 7-bit only ASCII, while PostgreSQL's
			 * SQL_ASCII means that anything is allowed, and the system doesn't
			 * try to interpret the bytes in any way. But not sure what else
			 * to do, and we haven't heard any complaints...
			 */
			serverenc = "ascii";
			break;
		case PG_WIN1250:
			serverenc = "cp1250";
			break;
		case PG_WIN1251:
			serverenc = "cp1251";
			break;
		case PG_WIN1252:
			serverenc = "cp1252";
			break;
		case PG_WIN1253:
			serverenc = "cp1253";
			break;
		case PG_WIN1254:
			serverenc = "cp1254";
			break;
		case PG_WIN1255:
			serverenc = "cp1255";
			break;
		case PG_WIN1256:
			serverenc = "cp1256";
			break;
		case PG_WIN1257:
			serverenc = "cp1257";
			break;
		case PG_WIN1258:
			serverenc = "cp1258";
			break;
		case PG_WIN866:
			serverenc = "cp866";
			break;
		case PG_WIN874:
			serverenc = "cp874";
			break;
		default:
			/* Other encodings have the same name in Python. */
			serverenc = GetDatabaseEncodingName();
			break;
	}

	rv = PyUnicode_AsEncodedString(unicode, serverenc, "strict");
	if (rv == NULL)
	{
		/*
		 * Use a plain ereport instead of PLy_elog to avoid recursion, if
		 * the traceback formatting functions try to do unicode to bytes
		 * conversion again.
		 */
		ereport(ERROR,
				(errcode(ERRCODE_INTERNAL_ERROR),
				 errmsg("could not convert Python Unicode object to PostgreSQL server encoding")));
	}
	return rv;
}

/*
 * Convert a Python unicode object to a C string in PostgreSQL server
 * encoding.  No Python object reference is passed out of this
 * function.  The result is palloc'ed.
 *
 * Note that this function is disguised as PyString_AsString() when
 * using Python 3.	That function retuns a pointer into the internal
 * memory of the argument, which isn't exactly the interface of this
 * function.  But in either case you get a rather short-lived
 * reference that you ought to better leave alone.
 */
char *
PLyUnicode_AsString(PyObject *unicode)
{
	PyObject   *o = PLyUnicode_Bytes(unicode);
	char	   *rv = pstrdup(PyBytes_AsString(o));

	Py_XDECREF(o);
	return rv;
}

#if PY_MAJOR_VERSION >= 3
/*
 * Convert a C string in the PostgreSQL server encoding to a Python
 * unicode object.	Reference ownership is passed to the caller.
 */
PyObject *
PLyUnicode_FromString(const char *s)
{
	char	   *utf8string;
	PyObject   *o;

	utf8string = (char *) pg_do_encoding_conversion((unsigned char *) s,
													strlen(s),
													GetDatabaseEncoding(),
													PG_UTF8);

	o = PyUnicode_FromString(utf8string);

	if (utf8string != s)
		pfree(utf8string);

	return o;
}

#endif   /* PY_MAJOR_VERSION >= 3 */