Changeset 817 for trunk/pgmodule.c


Ignore:
Timestamp:
Feb 4, 2016, 3:18:08 PM (4 years ago)
Author:
cito
Message:

Support the hstore data type

Added adaptation and typecasting of the hstore type as Python dictionaries.
For the typecasting, a fast parser has been added to the C extension.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/pgmodule.c

    r814 r817  
    10771077}
    10781078
     1079/* Cast string s with size and encoding to a Python dictionary.
     1080   using the input and output syntax for hstore values. */
     1081
     1082static PyObject *
     1083cast_hstore(char *s, Py_ssize_t size, int encoding)
     1084{
     1085        PyObject   *result;
     1086        char       *end = s + size;
     1087
     1088    result = PyDict_New();
     1089
     1090        /* everything is set up, start parsing the record */
     1091        while (s != end)
     1092        {
     1093                char       *key, *val;
     1094                PyObject   *key_obj, *val_obj;
     1095                Py_ssize_t      key_esc = 0, val_esc = 0, size;
     1096                int                     quoted;
     1097
     1098                while (s != end && *s == ' ') ++s;
     1099                if (s == end) break;
     1100                quoted = *s == '"';
     1101                if (quoted)
     1102                {
     1103                        key = ++s;
     1104                        while (s != end)
     1105                        {
     1106                                if (*s == '"') break;
     1107                                if (*s == '\\')
     1108                                {
     1109                                        if (++s == end) break;
     1110                                        ++key_esc;
     1111                                }
     1112                                ++s;
     1113                        }
     1114                        if (s == end)
     1115                        {
     1116                                PyErr_SetString(PyExc_ValueError, "Unterminated quote");
     1117                                Py_DECREF(result); return NULL;
     1118                        }
     1119                }
     1120                else
     1121                {
     1122                        key = s;
     1123                        while (s != end)
     1124                        {
     1125                                if (*s == '=' || *s == ' ') break;
     1126                                if (*s == '\\')
     1127                                {
     1128                                        if (++s == end) break;
     1129                                        ++key_esc;
     1130                                }
     1131                                ++s;
     1132                        }
     1133                        if (s == key)
     1134                        {
     1135                                PyErr_SetString(PyExc_ValueError, "Missing key");
     1136                                Py_DECREF(result); return NULL;
     1137                        }
     1138                }
     1139                size = s - key - key_esc;
     1140                if (key_esc)
     1141                {
     1142                        char *r = key, *t;
     1143                        key = (char *) PyMem_Malloc(size);
     1144                        if (!key)
     1145                        {
     1146                                Py_DECREF(result); return PyErr_NoMemory();
     1147                        }
     1148                        t = key;
     1149                        while (r != s)
     1150                        {
     1151                                if (*r == '\\')
     1152                                {
     1153                                        ++r; if (r == s) break;
     1154                                }
     1155                                *t++ = *r++;
     1156                        }
     1157                }
     1158                key_obj = cast_sized_text(key, size, encoding, PYGRES_TEXT);
     1159                if (key_esc) PyMem_Free(key);
     1160                if (!key_obj)
     1161                {
     1162                        Py_DECREF(result); return NULL;
     1163                }
     1164                if (quoted) ++s;
     1165                while (s != end && *s == ' ') ++s;
     1166                if (s == end || *s++ != '=' || s == end || *s++ != '>')
     1167                {
     1168                        PyErr_SetString(PyExc_ValueError, "Invalid characters after key");
     1169                        Py_DECREF(key_obj); Py_DECREF(result); return NULL;
     1170                }
     1171                while (s != end && *s == ' ') ++s;
     1172                quoted = *s == '"';
     1173                if (quoted)
     1174                {
     1175                        val = ++s;
     1176                        while (s != end)
     1177                        {
     1178                                if (*s == '"') break;
     1179                                if (*s == '\\')
     1180                                {
     1181                                        if (++s == end) break;
     1182                                        ++val_esc;
     1183                                }
     1184                                ++s;
     1185                        }
     1186                        if (s == end)
     1187                        {
     1188                                PyErr_SetString(PyExc_ValueError, "Unterminated quote");
     1189                                Py_DECREF(result); return NULL;
     1190                        }
     1191                }
     1192                else
     1193                {
     1194                        val = s;
     1195                        while (s != end)
     1196                        {
     1197                                if (*s == ',' || *s == ' ') break;
     1198                                if (*s == '\\')
     1199                                {
     1200                                        if (++s == end) break;
     1201                                        ++val_esc;
     1202                                }
     1203                                ++s;
     1204                        }
     1205                        if (s == val)
     1206                        {
     1207                                PyErr_SetString(PyExc_ValueError, "Missing value");
     1208                                Py_DECREF(key_obj); Py_DECREF(result); return NULL;
     1209                        }
     1210                        if (STR_IS_NULL(val, s - val))
     1211                                val = NULL;
     1212                }
     1213                if (val)
     1214                {
     1215                        size = s - val - val_esc;
     1216                        if (val_esc)
     1217                        {
     1218                                char *r = val, *t;
     1219                                val = (char *) PyMem_Malloc(size);
     1220                                if (!val)
     1221                                {
     1222                                        Py_DECREF(key_obj); Py_DECREF(result);
     1223                                        return PyErr_NoMemory();
     1224                                }
     1225                                t = val;
     1226                                while (r != s)
     1227                                {
     1228                                        if (*r == '\\')
     1229                                        {
     1230                                                ++r; if (r == s) break;
     1231                                        }
     1232                                        *t++ = *r++;
     1233                                }
     1234                        }
     1235                        val_obj = cast_sized_text(val, size, encoding, PYGRES_TEXT);
     1236                        if (val_esc) PyMem_Free(val);
     1237                        if (!val_obj)
     1238                        {
     1239                                Py_DECREF(key_obj); Py_DECREF(result); return NULL;
     1240                        }
     1241                }
     1242                else
     1243                {
     1244                        Py_INCREF(Py_None); val_obj = Py_None;
     1245                }
     1246                if (quoted) ++s;
     1247                while (s != end && *s == ' ') ++s;
     1248                if (s != end)
     1249                {
     1250                        if (*s++ != ',')
     1251                        {
     1252                                PyErr_SetString(PyExc_ValueError,
     1253                                        "Invalid characters after val");
     1254                                Py_DECREF(key_obj); Py_DECREF(val_obj);
     1255                                Py_DECREF(result); return NULL;
     1256                        }
     1257                        while (s != end && *s == ' ') ++s;
     1258                        if (s == end)
     1259                        {
     1260                                PyErr_SetString(PyExc_ValueError, "Missing entry");
     1261                                Py_DECREF(key_obj); Py_DECREF(val_obj);
     1262                                Py_DECREF(result); return NULL;
     1263                        }
     1264                }
     1265                PyDict_SetItem(result, key_obj, val_obj);
     1266                Py_DECREF(key_obj); Py_DECREF(val_obj);
     1267        }
     1268        return result;
     1269}
     1270
    10791271/* internal wrapper for the notice receiver callback */
    10801272static void
     
    54215613        if (PyBytes_Check(string_obj))
    54225614        {
    5423                 encoding = pg_encoding_ascii;
    54245615                PyBytes_AsStringAndSize(string_obj, &string, &size);
    54255616                string_obj = NULL;
     5617                encoding = pg_encoding_ascii;
    54265618        }
    54275619        else if (PyUnicode_Check(string_obj))
    54285620        {
    5429                 encoding = pg_encoding_utf8;
    5430                 string_obj = get_encoded_string(string_obj, encoding);
     5621                string_obj = PyUnicode_AsUTF8String(string_obj);
    54315622                if (!string_obj) return NULL; /* pass the UnicodeEncodeError */
    54325623                PyBytes_AsStringAndSize(string_obj, &string, &size);
     5624                encoding = pg_encoding_utf8;
    54335625        }
    54345626        else
     
    54795671        if (PyBytes_Check(string_obj))
    54805672        {
    5481                 encoding = pg_encoding_ascii;
    54825673                PyBytes_AsStringAndSize(string_obj, &string, &size);
    54835674                string_obj = NULL;
     5675                encoding = pg_encoding_ascii;
    54845676        }
    54855677        else if (PyUnicode_Check(string_obj))
    54865678        {
    5487                 encoding = pg_encoding_utf8;
    5488                 string_obj = get_encoded_string(string_obj, encoding);
     5679                string_obj = PyUnicode_AsUTF8String(string_obj);
    54895680                if (!string_obj) return NULL; /* pass the UnicodeEncodeError */
    54905681                PyBytes_AsStringAndSize(string_obj, &string, &size);
     5682                encoding = pg_encoding_utf8;
    54915683        }
    54925684        else
     
    55285720}
    55295721
     5722/* cast a string with a text representation of an hstore to a dict */
     5723static char pgCastHStore__doc__[] =
     5724"cast_hstore(string) -- cast a string as an hstore";
     5725
     5726PyObject *
     5727pgCastHStore(PyObject *self, PyObject *string)
     5728{
     5729        PyObject   *tmp_obj = NULL, *ret;
     5730        char       *s;
     5731        Py_ssize_t      size;
     5732        int                     encoding;
     5733
     5734        if (PyBytes_Check(string))
     5735        {
     5736                PyBytes_AsStringAndSize(string, &s, &size);
     5737                encoding = pg_encoding_ascii;
     5738        }
     5739        else if (PyUnicode_Check(string))
     5740        {
     5741                tmp_obj = PyUnicode_AsUTF8String(string);
     5742                if (!tmp_obj) return NULL; /* pass the UnicodeEncodeError */
     5743                PyBytes_AsStringAndSize(tmp_obj, &s, &size);
     5744                encoding = pg_encoding_utf8;
     5745        }
     5746        else
     5747        {
     5748                PyErr_SetString(PyExc_TypeError,
     5749                        "Function cast_hstore() expects a string as first argument");
     5750                return NULL;
     5751        }
     5752
     5753        ret = cast_hstore(s, size, encoding);
     5754
     5755        Py_XDECREF(tmp_obj);
     5756
     5757        return ret;
     5758}
    55305759
    55315760/* List of functions defined in the module */
     
    55725801        {"cast_record", (PyCFunction) pgCastRecord, METH_VARARGS|METH_KEYWORDS,
    55735802                        pgCastRecord__doc__},
     5803        {"cast_hstore", (PyCFunction) pgCastHStore, METH_O, pgCastHStore__doc__},
    55745804
    55755805#ifdef DEFAULT_VARS
Note: See TracChangeset for help on using the changeset viewer.