Header And Logo

PostgreSQL
| The world's most advanced open source database.

plpy_plpymodule.c

Go to the documentation of this file.
00001 /*
00002  * the plpy module
00003  *
00004  * src/pl/plpython/plpy_plpymodule.c
00005  */
00006 
00007 #include "postgres.h"
00008 
00009 #include "mb/pg_wchar.h"
00010 #include "utils/builtins.h"
00011 
00012 #include "plpython.h"
00013 
00014 #include "plpy_plpymodule.h"
00015 
00016 #include "plpy_cursorobject.h"
00017 #include "plpy_elog.h"
00018 #include "plpy_planobject.h"
00019 #include "plpy_resultobject.h"
00020 #include "plpy_spi.h"
00021 #include "plpy_subxactobject.h"
00022 
00023 
00024 HTAB       *PLy_spi_exceptions = NULL;
00025 
00026 
00027 static void PLy_add_exceptions(PyObject *plpy);
00028 static void PLy_generate_spi_exceptions(PyObject *mod, PyObject *base);
00029 
00030 /* module functions */
00031 static PyObject *PLy_debug(PyObject *self, PyObject *args);
00032 static PyObject *PLy_log(PyObject *self, PyObject *args);
00033 static PyObject *PLy_info(PyObject *self, PyObject *args);
00034 static PyObject *PLy_notice(PyObject *self, PyObject *args);
00035 static PyObject *PLy_warning(PyObject *self, PyObject *args);
00036 static PyObject *PLy_error(PyObject *self, PyObject *args);
00037 static PyObject *PLy_fatal(PyObject *self, PyObject *args);
00038 static PyObject *PLy_quote_literal(PyObject *self, PyObject *args);
00039 static PyObject *PLy_quote_nullable(PyObject *self, PyObject *args);
00040 static PyObject *PLy_quote_ident(PyObject *self, PyObject *args);
00041 
00042 
00043 /* A list of all known exceptions, generated from backend/utils/errcodes.txt */
00044 typedef struct ExceptionMap
00045 {
00046     char       *name;
00047     char       *classname;
00048     int         sqlstate;
00049 } ExceptionMap;
00050 
00051 static const ExceptionMap exception_map[] = {
00052 #include "spiexceptions.h"
00053     {NULL, NULL, 0}
00054 };
00055 
00056 static PyMethodDef PLy_methods[] = {
00057     /*
00058      * logging methods
00059      */
00060     {"debug", PLy_debug, METH_VARARGS, NULL},
00061     {"log", PLy_log, METH_VARARGS, NULL},
00062     {"info", PLy_info, METH_VARARGS, NULL},
00063     {"notice", PLy_notice, METH_VARARGS, NULL},
00064     {"warning", PLy_warning, METH_VARARGS, NULL},
00065     {"error", PLy_error, METH_VARARGS, NULL},
00066     {"fatal", PLy_fatal, METH_VARARGS, NULL},
00067 
00068     /*
00069      * create a stored plan
00070      */
00071     {"prepare", PLy_spi_prepare, METH_VARARGS, NULL},
00072 
00073     /*
00074      * execute a plan or query
00075      */
00076     {"execute", PLy_spi_execute, METH_VARARGS, NULL},
00077 
00078     /*
00079      * escaping strings
00080      */
00081     {"quote_literal", PLy_quote_literal, METH_VARARGS, NULL},
00082     {"quote_nullable", PLy_quote_nullable, METH_VARARGS, NULL},
00083     {"quote_ident", PLy_quote_ident, METH_VARARGS, NULL},
00084 
00085     /*
00086      * create the subtransaction context manager
00087      */
00088     {"subtransaction", PLy_subtransaction_new, METH_NOARGS, NULL},
00089 
00090     /*
00091      * create a cursor
00092      */
00093     {"cursor", PLy_cursor, METH_VARARGS, NULL},
00094 
00095     {NULL, NULL, 0, NULL}
00096 };
00097 
00098 static PyMethodDef PLy_exc_methods[] = {
00099     {NULL, NULL, 0, NULL}
00100 };
00101 
00102 #if PY_MAJOR_VERSION >= 3
00103 static PyModuleDef PLy_module = {
00104     PyModuleDef_HEAD_INIT,      /* m_base */
00105     "plpy",                     /* m_name */
00106     NULL,                       /* m_doc */
00107     -1,                         /* m_size */
00108     PLy_methods,                /* m_methods */
00109 };
00110 
00111 static PyModuleDef PLy_exc_module = {
00112     PyModuleDef_HEAD_INIT,      /* m_base */
00113     "spiexceptions",            /* m_name */
00114     NULL,                       /* m_doc */
00115     -1,                         /* m_size */
00116     PLy_exc_methods,            /* m_methods */
00117     NULL,                       /* m_reload */
00118     NULL,                       /* m_traverse */
00119     NULL,                       /* m_clear */
00120     NULL                        /* m_free */
00121 };
00122 
00123 /*
00124  * Must have external linkage, because PyMODINIT_FUNC does dllexport on
00125  * Windows-like platforms.
00126  */
00127 PyMODINIT_FUNC
00128 PyInit_plpy(void)
00129 {
00130     PyObject   *m;
00131 
00132     m = PyModule_Create(&PLy_module);
00133     if (m == NULL)
00134         return NULL;
00135 
00136     PLy_add_exceptions(m);
00137 
00138     return m;
00139 }
00140 #endif   /* PY_MAJOR_VERSION >= 3 */
00141 
00142 void
00143 PLy_init_plpy(void)
00144 {
00145     PyObject   *main_mod,
00146                *main_dict,
00147                *plpy_mod;
00148 
00149 #if PY_MAJOR_VERSION < 3
00150     PyObject   *plpy;
00151 #endif
00152 
00153     /*
00154      * initialize plpy module
00155      */
00156     PLy_plan_init_type();
00157     PLy_result_init_type();
00158     PLy_subtransaction_init_type();
00159     PLy_cursor_init_type();
00160 
00161 #if PY_MAJOR_VERSION >= 3
00162     PyModule_Create(&PLy_module);
00163     /* for Python 3 we initialized the exceptions in PyInit_plpy */
00164 #else
00165     plpy = Py_InitModule("plpy", PLy_methods);
00166     PLy_add_exceptions(plpy);
00167 #endif
00168 
00169     /* PyDict_SetItemString(plpy, "PlanType", (PyObject *) &PLy_PlanType); */
00170 
00171     /*
00172      * initialize main module, and add plpy
00173      */
00174     main_mod = PyImport_AddModule("__main__");
00175     main_dict = PyModule_GetDict(main_mod);
00176     plpy_mod = PyImport_AddModule("plpy");
00177     if (plpy_mod == NULL)
00178         PLy_elog(ERROR, "could not import \"plpy\" module");
00179     PyDict_SetItemString(main_dict, "plpy", plpy_mod);
00180     if (PyErr_Occurred())
00181         PLy_elog(ERROR, "could not import \"plpy\" module");
00182 }
00183 
00184 static void
00185 PLy_add_exceptions(PyObject *plpy)
00186 {
00187     PyObject   *excmod;
00188     HASHCTL     hash_ctl;
00189 
00190 #if PY_MAJOR_VERSION < 3
00191     excmod = Py_InitModule("spiexceptions", PLy_exc_methods);
00192 #else
00193     excmod = PyModule_Create(&PLy_exc_module);
00194 #endif
00195     if (PyModule_AddObject(plpy, "spiexceptions", excmod) < 0)
00196         PLy_elog(ERROR, "could not add the spiexceptions module");
00197 
00198     /*
00199      * XXX it appears that in some circumstances the reference count of the
00200      * spiexceptions module drops to zero causing a Python assert failure when
00201      * the garbage collector visits the module. This has been observed on the
00202      * buildfarm. To fix this, add an additional ref for the module here.
00203      *
00204      * This shouldn't cause a memory leak - we don't want this garbage
00205      * collected, and this function shouldn't be called more than once per
00206      * backend.
00207      */
00208     Py_INCREF(excmod);
00209 
00210     PLy_exc_error = PyErr_NewException("plpy.Error", NULL, NULL);
00211     PLy_exc_fatal = PyErr_NewException("plpy.Fatal", NULL, NULL);
00212     PLy_exc_spi_error = PyErr_NewException("plpy.SPIError", NULL, NULL);
00213 
00214     if (PLy_exc_error == NULL ||
00215         PLy_exc_fatal == NULL ||
00216         PLy_exc_spi_error == NULL)
00217         PLy_elog(ERROR, "could not create the base SPI exceptions");
00218 
00219     Py_INCREF(PLy_exc_error);
00220     PyModule_AddObject(plpy, "Error", PLy_exc_error);
00221     Py_INCREF(PLy_exc_fatal);
00222     PyModule_AddObject(plpy, "Fatal", PLy_exc_fatal);
00223     Py_INCREF(PLy_exc_spi_error);
00224     PyModule_AddObject(plpy, "SPIError", PLy_exc_spi_error);
00225 
00226     memset(&hash_ctl, 0, sizeof(hash_ctl));
00227     hash_ctl.keysize = sizeof(int);
00228     hash_ctl.entrysize = sizeof(PLyExceptionEntry);
00229     hash_ctl.hash = tag_hash;
00230     PLy_spi_exceptions = hash_create("SPI exceptions", 256,
00231                                      &hash_ctl, HASH_ELEM | HASH_FUNCTION);
00232 
00233     PLy_generate_spi_exceptions(excmod, PLy_exc_spi_error);
00234 }
00235 
00236 /*
00237  * Add all the autogenerated exceptions as subclasses of SPIError
00238  */
00239 static void
00240 PLy_generate_spi_exceptions(PyObject *mod, PyObject *base)
00241 {
00242     int         i;
00243 
00244     for (i = 0; exception_map[i].name != NULL; i++)
00245     {
00246         bool        found;
00247         PyObject   *exc;
00248         PLyExceptionEntry *entry;
00249         PyObject   *sqlstate;
00250         PyObject   *dict = PyDict_New();
00251 
00252         if (dict == NULL)
00253             PLy_elog(ERROR, "could not generate SPI exceptions");
00254 
00255         sqlstate = PyString_FromString(unpack_sql_state(exception_map[i].sqlstate));
00256         if (sqlstate == NULL)
00257             PLy_elog(ERROR, "could not generate SPI exceptions");
00258 
00259         PyDict_SetItemString(dict, "sqlstate", sqlstate);
00260         Py_DECREF(sqlstate);
00261         exc = PyErr_NewException(exception_map[i].name, base, dict);
00262         PyModule_AddObject(mod, exception_map[i].classname, exc);
00263         entry = hash_search(PLy_spi_exceptions, &exception_map[i].sqlstate,
00264                             HASH_ENTER, &found);
00265         entry->exc = exc;
00266         Assert(!found);
00267     }
00268 }
00269 
00270 
00271 /*
00272  * the python interface to the elog function
00273  * don't confuse these with PLy_elog
00274  */
00275 static PyObject *PLy_output(volatile int, PyObject *, PyObject *);
00276 
00277 PyObject *
00278 PLy_debug(PyObject *self, PyObject *args)
00279 {
00280     return PLy_output(DEBUG2, self, args);
00281 }
00282 
00283 PyObject *
00284 PLy_log(PyObject *self, PyObject *args)
00285 {
00286     return PLy_output(LOG, self, args);
00287 }
00288 
00289 PyObject *
00290 PLy_info(PyObject *self, PyObject *args)
00291 {
00292     return PLy_output(INFO, self, args);
00293 }
00294 
00295 PyObject *
00296 PLy_notice(PyObject *self, PyObject *args)
00297 {
00298     return PLy_output(NOTICE, self, args);
00299 }
00300 
00301 PyObject *
00302 PLy_warning(PyObject *self, PyObject *args)
00303 {
00304     return PLy_output(WARNING, self, args);
00305 }
00306 
00307 PyObject *
00308 PLy_error(PyObject *self, PyObject *args)
00309 {
00310     return PLy_output(ERROR, self, args);
00311 }
00312 
00313 PyObject *
00314 PLy_fatal(PyObject *self, PyObject *args)
00315 {
00316     return PLy_output(FATAL, self, args);
00317 }
00318 
00319 PyObject *
00320 PLy_quote_literal(PyObject *self, PyObject *args)
00321 {
00322     const char *str;
00323     char       *quoted;
00324     PyObject   *ret;
00325 
00326     if (!PyArg_ParseTuple(args, "s", &str))
00327         return NULL;
00328 
00329     quoted = quote_literal_cstr(str);
00330     ret = PyString_FromString(quoted);
00331     pfree(quoted);
00332 
00333     return ret;
00334 }
00335 
00336 PyObject *
00337 PLy_quote_nullable(PyObject *self, PyObject *args)
00338 {
00339     const char *str;
00340     char       *quoted;
00341     PyObject   *ret;
00342 
00343     if (!PyArg_ParseTuple(args, "z", &str))
00344         return NULL;
00345 
00346     if (str == NULL)
00347         return PyString_FromString("NULL");
00348 
00349     quoted = quote_literal_cstr(str);
00350     ret = PyString_FromString(quoted);
00351     pfree(quoted);
00352 
00353     return ret;
00354 }
00355 
00356 PyObject *
00357 PLy_quote_ident(PyObject *self, PyObject *args)
00358 {
00359     const char *str;
00360     const char *quoted;
00361     PyObject   *ret;
00362 
00363     if (!PyArg_ParseTuple(args, "s", &str))
00364         return NULL;
00365 
00366     quoted = quote_identifier(str);
00367     ret = PyString_FromString(quoted);
00368 
00369     return ret;
00370 }
00371 
00372 static PyObject *
00373 PLy_output(volatile int level, PyObject *self, PyObject *args)
00374 {
00375     PyObject   *volatile so;
00376     char       *volatile sv;
00377     volatile MemoryContext oldcontext;
00378 
00379     if (PyTuple_Size(args) == 1)
00380     {
00381         /*
00382          * Treat single argument specially to avoid undesirable ('tuple',)
00383          * decoration.
00384          */
00385         PyObject   *o;
00386 
00387         if (!PyArg_UnpackTuple(args, "plpy.elog", 1, 1, &o))
00388             PLy_elog(ERROR, "could not unpack arguments in plpy.elog");
00389         so = PyObject_Str(o);
00390     }
00391     else
00392         so = PyObject_Str(args);
00393     if (so == NULL || ((sv = PyString_AsString(so)) == NULL))
00394     {
00395         level = ERROR;
00396         sv = dgettext(TEXTDOMAIN, "could not parse error message in plpy.elog");
00397     }
00398 
00399     oldcontext = CurrentMemoryContext;
00400     PG_TRY();
00401     {
00402         pg_verifymbstr(sv, strlen(sv), false);
00403         elog(level, "%s", sv);
00404     }
00405     PG_CATCH();
00406     {
00407         ErrorData  *edata;
00408 
00409         MemoryContextSwitchTo(oldcontext);
00410         edata = CopyErrorData();
00411         FlushErrorState();
00412 
00413         /*
00414          * Note: If sv came from PyString_AsString(), it points into storage
00415          * owned by so.  So free so after using sv.
00416          */
00417         Py_XDECREF(so);
00418 
00419         /* Make Python raise the exception */
00420         PLy_exception_set(PLy_exc_error, "%s", edata->message);
00421         return NULL;
00422     }
00423     PG_END_TRY();
00424 
00425     Py_XDECREF(so);
00426 
00427     /*
00428      * return a legal object so the interpreter will continue on its merry way
00429      */
00430     Py_INCREF(Py_None);
00431     return Py_None;
00432 }