Skip to content

Commit 0b6c665

Browse files
authored
Refactoring JSON support (#312)
1 parent 4b40c8c commit 0b6c665

File tree

2 files changed

+60
-51
lines changed

2 files changed

+60
-51
lines changed

MySQLdb/_mysql.c

+56-50
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,13 @@ _mysql_ResultObject_Initialize(
302302
long flags = fields[i].flags;
303303
PyObject *fun2=NULL;
304304
int j, n2=PySequence_Size(fun);
305-
if (fields[i].charsetnr != 63) { /* maaagic */
306-
flags &= ~BINARY_FLAG;
307-
} else {
305+
// BINARY_FLAG means ***_bin collation is used.
306+
// To distinguish text and binary, we shoud use charsetnr==63 (binary).
307+
// But we abuse BINARY_FLAG for historical reason.
308+
if (fields[i].charsetnr == 63) {
308309
flags |= BINARY_FLAG;
310+
} else {
311+
flags &= ~BINARY_FLAG;
309312
}
310313
for (j=0; j<n2; j++) {
311314
PyObject *t = PySequence_GetItem(fun, j);
@@ -1098,58 +1101,61 @@ _mysql_field_to_python(
10981101
MYSQL_FIELD *field,
10991102
const char *encoding)
11001103
{
1101-
PyObject *v;
1102-
#ifdef IS_PY3K
1103-
int field_type = field->type;
1104-
// Return bytes for binary and string types.
1105-
int binary = 0;
1106-
if (field_type == FIELD_TYPE_TINY_BLOB ||
1107-
field_type == FIELD_TYPE_MEDIUM_BLOB ||
1108-
field_type == FIELD_TYPE_LONG_BLOB ||
1109-
field_type == FIELD_TYPE_BLOB ||
1110-
field_type == FIELD_TYPE_VAR_STRING ||
1111-
field_type == FIELD_TYPE_STRING ||
1112-
field_type == FIELD_TYPE_GEOMETRY ||
1113-
field_type == FIELD_TYPE_BIT) {
1114-
binary = 1;
1104+
if (rowitem == NULL) {
1105+
Py_RETURN_NONE;
11151106
}
1116-
#endif
1117-
if (rowitem) {
1118-
if (converter == (PyObject*)&PyUnicode_Type) {
1119-
if (encoding == utf8) {
1120-
//fprintf(stderr, "decoding with utf8!\n");
1121-
v = PyUnicode_DecodeUTF8(rowitem, length, NULL);
1122-
} else {
1123-
//fprintf(stderr, "decoding with %s\n", encoding);
1124-
v = PyUnicode_Decode(rowitem, length, encoding, NULL);
1125-
}
1126-
}
1127-
else if (converter == (PyObject*)&PyBytes_Type || converter == Py_None) {
1128-
//fprintf(stderr, "decoding with bytes\n", encoding);
1129-
v = PyBytes_FromStringAndSize(rowitem, length);
1130-
}
1131-
else if (converter == (PyObject*)&PyInt_Type) {
1132-
//fprintf(stderr, "decoding with int\n", encoding);
1133-
v = PyInt_FromString(rowitem, NULL, 10);
1107+
1108+
// Fast paths for int, string and binary.
1109+
if (converter == (PyObject*)&PyUnicode_Type) {
1110+
if (encoding == utf8) {
1111+
//fprintf(stderr, "decoding with utf8!\n");
1112+
return PyUnicode_DecodeUTF8(rowitem, length, NULL);
1113+
} else {
1114+
//fprintf(stderr, "decoding with %s\n", encoding);
1115+
return PyUnicode_Decode(rowitem, length, encoding, NULL);
11341116
}
1135-
else {
1136-
//fprintf(stderr, "decoding with callback\n");
1137-
//PyObject_Print(converter, stderr, 0);
1138-
//fprintf(stderr, "\n");
1139-
v = PyObject_CallFunction(converter,
1117+
}
1118+
if (converter == (PyObject*)&PyBytes_Type || converter == Py_None) {
1119+
//fprintf(stderr, "decoding with bytes\n", encoding);
1120+
return PyBytes_FromStringAndSize(rowitem, length);
1121+
}
1122+
if (converter == (PyObject*)&PyInt_Type) {
1123+
//fprintf(stderr, "decoding with int\n", encoding);
1124+
return PyInt_FromString(rowitem, NULL, 10);
1125+
}
1126+
1127+
//fprintf(stderr, "decoding with callback\n");
1128+
//PyObject_Print(converter, stderr, 0);
1129+
//fprintf(stderr, "\n");
11401130
#ifdef IS_PY3K
1141-
binary ? "y#" : "s#",
1131+
int binary;
1132+
switch (field->type) {
1133+
case FIELD_TYPE_TINY_BLOB:
1134+
case FIELD_TYPE_MEDIUM_BLOB:
1135+
case FIELD_TYPE_LONG_BLOB:
1136+
case FIELD_TYPE_BLOB:
1137+
case FIELD_TYPE_VAR_STRING:
1138+
case FIELD_TYPE_STRING:
1139+
case FIELD_TYPE_GEOMETRY:
1140+
case FIELD_TYPE_BIT:
1141+
#ifdef FIELD_TYPE_JSON
1142+
case FIELD_TYPE_JSON:
11421143
#else
1143-
"s#",
1144+
case 245: // JSON
11441145
#endif
1145-
rowitem,
1146-
(int)length);
1147-
}
1148-
} else {
1149-
Py_INCREF(Py_None);
1150-
v = Py_None;
1146+
// Call converter with bytes
1147+
binary = 1;
1148+
default: // e.g. FIELD_TYPE_DATETIME, etc.
1149+
// Call converter with unicode string
1150+
binary = 0;
11511151
}
1152-
return v;
1152+
return PyObject_CallFunction(converter,
1153+
binary ? "y#" : "s#",
1154+
rowitem, (int)length);
1155+
#else
1156+
return PyObject_CallFunction(converter,
1157+
"s#", rowitem, (int)length);
1158+
#endif
11531159
}
11541160

11551161
static PyObject *
@@ -1226,7 +1232,7 @@ _mysql_row_to_dict_old(
12261232
unsigned int n, i;
12271233
unsigned long *length;
12281234
PyObject *r, *c;
1229-
MYSQL_FIELD *fields;
1235+
MYSQL_FIELD *fields;
12301236

12311237
n = mysql_num_fields(self->result);
12321238
if (!(r = PyDict_New())) return NULL;

MySQLdb/connections.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,11 @@ def unicode_literal(u, dummy=None):
183183

184184
if use_unicode:
185185
for t in (FIELD_TYPE.STRING, FIELD_TYPE.VAR_STRING, FIELD_TYPE.VARCHAR, FIELD_TYPE.TINY_BLOB,
186-
FIELD_TYPE.MEDIUM_BLOB, FIELD_TYPE.LONG_BLOB, FIELD_TYPE.BLOB, FIELD_TYPE.JSON):
186+
FIELD_TYPE.MEDIUM_BLOB, FIELD_TYPE.LONG_BLOB, FIELD_TYPE.BLOB):
187187
self.converter[t] = _bytes_or_str
188+
# Unlike other string/blob types, JSON is always text.
189+
# MySQL may return JSON with charset==binary.
190+
self.converter[FIELD_TYPE.JSON] = unicode
188191

189192
self.encoders[unicode] = unicode_literal
190193
self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS

0 commit comments

Comments
 (0)