static PyObj func_new(PyTypeObject *subtype, PyObj args, PyObj kw) { char *words[] = {"oid", NULL}; Oid fn_oid = InvalidOid; PyObj source = NULL, lo, so, rob; if (DB_IS_NOT_READY()) return(NULL); if (!PyArg_ParseTupleAndKeywords(args, kw, "O", words, &source)) return(NULL); if (Oid_FromPyObject(source, &fn_oid)) return(NULL); lo = PyLong_FromUnsignedLong(fn_oid); if (lo == NULL) return(NULL); so = PyObject_Str(lo); if (so == NULL) { Py_DECREF(lo); return(NULL); } rob = func_new_from_oid(subtype, fn_oid, lo, so); Py_DECREF(lo); Py_DECREF(so); return(rob); }
static PyObj statement_load_rows(PyObj self, PyObj args, PyObj kw) { char *words[] = {"rows_iter", NULL}; PyObj row_iter, rob; uint32 total = 0; if (PyPgStatement_GetParameters(self) != Py_None) { PyErr_SetString(PyExc_TypeError, "cannot use load_rows with constant parameters"); return(NULL); } if (!PyArg_ParseTupleAndKeywords(args, kw, "O:load_rows", words, &row_iter)) return(NULL); if (DB_IS_NOT_READY()) return(NULL); row_iter = PyObject_GetIter(row_iter); if (row_iter == NULL) return(NULL); if (load_rows(self, row_iter, &total)) rob = NULL; else rob = PyLong_FromUnsignedLong(total); Py_DECREF(row_iter); return(rob); }
static PyObj statement_clone(PyObj self) { if (DB_IS_NOT_READY()) return(NULL); return(PyPgStatement_NEW( Py_TYPE(self), PyPgStatement_GetString(self), PyPgStatement_GetParameters(self) )); }
static PyObj statement_load_chunks(PyObj self, PyObj args, PyObj kw) { char *words[] = {"chunks_iter", NULL}; PyObj chunk_iter, ob; uint32 total = 0; if (PyPgStatement_GetParameters(self) != Py_None) { PyErr_SetString(PyExc_TypeError, "cannot use load_rows with constant parameters"); return(NULL); } if (!PyArg_ParseTupleAndKeywords(args, kw, "O:load_chunks", words, &chunk_iter)) return(NULL); if (DB_IS_NOT_READY()) return(NULL); chunk_iter = PyObject_GetIter(chunk_iter); if (chunk_iter == NULL) return(NULL); while ((ob = PyIter_Next(chunk_iter))) { PyObj row_iter; int r; row_iter = PyObject_GetIter(ob); Py_DECREF(ob); if (row_iter == NULL) { Py_DECREF(chunk_iter); return(NULL); } r = load_rows(self, row_iter, &total); Py_DECREF(row_iter); if (r) { Py_DECREF(chunk_iter); return(NULL); } } Py_DECREF(chunk_iter); return(PyLong_FromUnsignedLong(total)); }
static PyObj statement_declare(PyObj self, PyObj args, PyObj kw) { if (DB_IS_NOT_READY()) return(NULL); if (!PyPgStatement_ReturnsRows(self)) { PyErr_SetString(PyExc_TypeError, "statement does not return rows"); return(NULL); } if (resolve_parameters(self, &args, &kw)) return(NULL); return(PyPgCursor_New(self, args, kw, CUR_SCROLL_FORWARD)); }
PyObj PyPgObject_Operate(const char *op, PyObj fst, PyObj snd) { PyObj rob; MemoryContext former; if (DB_IS_NOT_READY()) return(NULL); former = CurrentMemoryContext; if (snd == NULL) rob = unary_operate(op, fst); else rob = binary_operate(op, fst, snd); MemoryContextSwitchTo(former); return(rob); }
static PyObj obj_new(PyTypeObject *subtype, PyObj args, PyObj kw) { static char *words[] = {"source", "mod", NULL}; PyObj src = NULL, mod = NULL, rob = NULL, typmodin_ob = NULL; Datum d; bool isnull = true; int32 typmod = -1; if (DB_IS_NOT_READY()) return(NULL); /* * The type *must* be a PyPgType instance. * Use CheckExact for speed. * Subclassing PyPgType_Type is not supported. */ if (PyPgObjectType_Require(subtype)) return(NULL); /* * Grab a single "source" argument and an * optional "mod" from the args and kw. */ if (!PyArg_ParseTupleAndKeywords(args, kw, "O|O", words, &src, &mod)) return(NULL); if (mod != NULL && mod != Py_None) { PyObj lo; if (!PyList_CheckExact(mod)) { lo = Py_Call((PyObj) &PyList_Type, mod); if (lo == NULL) { PyErr_SetString(PyExc_ValueError, "'mod' keyword must be a sequence"); return(NULL); } } else { Py_INCREF(mod); lo = mod; } typmodin_ob = Py_Call(PyPg_cstring_Array_Type, lo); Py_DECREF(lo); if (typmodin_ob == NULL) { PyErr_SetString(PyExc_ValueError, "invalid typmod object"); return(NULL); } } else if (Py_TYPE(src) == subtype) { /* * Exact type and no typmod. */ rob = src; Py_INCREF(rob); return(rob); } PG_TRY(); { if (typmodin_ob != NULL) { typmod = PyPgType_modin((PyObj) subtype, typmodin_ob); } if (src == Py_None) { d = 0; isnull = true; } else { PyPgType_DatumNew((PyObj) subtype, src, typmod, &d, &isnull); } if (isnull) { rob = Py_None; Py_INCREF(rob); } else { rob = PyPgObject_New(subtype, d); if (PyPgType_ShouldFree(subtype)) { Datum fd = d; d = 0; isnull = true; /* * If it fails to pfree, don't try it again in * the catch. */ pfree(DatumGetPointer(fd)); } } } PG_CATCH(); { Py_XDECREF(rob); rob = NULL; if (!isnull && PyPgType_ShouldFree(subtype)) pfree(DatumGetPointer(d)); PyErr_SetPgError(false); } PG_END_TRY(); Py_XDECREF(typmodin_ob); return(rob); }
/* * XXX: If type methods ever come along, hopefully this will be implemented * using a more generalized function. */ static PyObj obj_absolute(PyObj self) { MemoryContext former; Oid typoid; volatile PyObj rob = NULL; if (DB_IS_NOT_READY() || PyPgObjectType_Require(Py_TYPE(self))) return(NULL); typoid = PyPgType_GetOid(Py_TYPE(self)); former = CurrentMemoryContext; PG_TRY(); { HeapTuple procTuple; Datum rd = 0; Oid procoid, roid; List *qnl; qnl = stringToQualifiedNameList("abs"); procoid = LookupFuncName(qnl, 1, &(typoid), true); list_free(qnl); if (procoid == InvalidOid) { PyErr_Format(PyExc_LookupError, "no such function named 'abs' for type %u", typoid); return(NULL); } procTuple = SearchSysCache(PROCOID, procoid, 0, 0, 0); if (procTuple == NULL) { PyErr_Format(PyExc_LookupError, "no procedure with Oid %u", procoid); return(NULL); } roid = ((Form_pg_proc) GETSTRUCT(procTuple))->prorettype; ReleaseSysCache(procTuple); rd = OidFunctionCall1(procoid, PyPgObject_GetDatum(self)); rob = PyPgObject_FromTypeOidAndDatum(roid, rd); if (PyPgType_ShouldFree(Py_TYPE(rob))) { /* * That's our datum... */ if (PyPgObject_GetDatum(self) != rd) pfree(DatumGetPointer(rd)); } } PG_CATCH(); { Py_XDECREF(rob); PyErr_SetPgError(false); return(NULL); } PG_END_TRY(); return(rob); }
static PyObj func_call(PyObj self, PyObj args, PyObj kw) { MemoryContext former = CurrentMemoryContext; PyObj fn_input, fn_output, input, rob = NULL; TupleDesc td; FmgrInfo flinfo; FunctionCallInfoData fcinfo; volatile Datum datum = 0; /* * Disallow execution of "anonymous" functions. */ flinfo.fn_addr = PyPgFunction_GetPGFunction(self); flinfo.fn_oid = PyPgFunction_GetOid(self); flinfo.fn_retset = PyPgFunction_GetReturnsSet(self); if (flinfo.fn_addr == NULL || flinfo.fn_oid == InvalidOid) { PyErr_SetString(PyExc_TypeError, "internal functions are not directly callable"); return(NULL); } if (flinfo.fn_retset) { PyErr_SetString(PyExc_NotImplementedError, "cannot directly execute set returning functions"); return(NULL); } fn_input = PyPgFunction_GetInput(self); fn_output = PyPgFunction_GetOutput(self); if (PyPgTupleDesc_IsPolymorphic(fn_input) || PyPgType_IsPolymorphic(fn_output)) { PyErr_SetString(PyExc_NotImplementedError, "cannot directly execute polymorphic functions"); return(NULL); } if (PyPgType_GetOid(fn_output) == TRIGGEROID) { PyErr_SetString(PyExc_NotImplementedError, "cannot directly execute TRIGGER returning functions"); return(NULL); } /* No access if failed transaction */ if (DB_IS_NOT_READY()) return(NULL); td = PyPgTupleDesc_GetTupleDesc(fn_input); /* * Normalize the parameters. */ input = PyTuple_FromTupleDescAndParameters(td, args, kw); if (input == NULL) return(NULL); flinfo.fn_nargs = td->natts; flinfo.fn_extra = NULL; flinfo.fn_mcxt = CurrentMemoryContext; flinfo.fn_expr = NULL; fcinfo.flinfo = &flinfo; fcinfo.context = NULL; fcinfo.resultinfo = NULL; fcinfo.isnull = false; /* * Custom built descriptor; no dropped attributes. */ fcinfo.nargs = td->natts; SPI_push(); PG_TRY(); { Py_BuildDatumsAndNulls(td, PyPgTupleDesc_GetTypesTuple(fn_input), input, fcinfo.arg, fcinfo.argnull); datum = FunctionCallInvoke(&fcinfo); /* * Special casing void to avoid the singleton. */ if (fcinfo.isnull || PyPgType_GetOid(fn_output) == VOIDOID) { rob = Py_None; Py_INCREF(rob); } else { /* * Some functions will return a parameter that its given. * This is problematic if we are going to free the output * after re-allocating as a Postgres.Object. */ if (PyPgType_ShouldFree(fn_output)) { int i; /* * Scan for !typbyval parameters. * When one is found, compare the datum to the result datum. */ for (i = 0; i < PyTuple_GET_SIZE(input); ++i) { PyObj param = PyTuple_GET_ITEM(input, i); /* * It's tempting to check the types first, but in situations * of functions doing binary compatible coercion, it would be a * mistake. */ if (PyPgType_ShouldFree(Py_TYPE(param))) { if (PyPgObject_GetDatum(param) == datum) { /* * It's the same Datum of an argument, * inc the ref and return the param. */ if (fn_output == (PyObj) Py_TYPE(param)) { rob = param; Py_INCREF(rob); } else { /* * It's the same Datum, but a different type. * Make a Copy. */ rob = PyPgObject_New(fn_output, datum); } break; } } } /* * It's a newly allocated result? (not an argument) */ if (rob == NULL) { /* * New result, Datum is copied into the PythonMemoryContext */ rob = PyPgObject_New(fn_output, datum); /* * Cleanup. */ pfree(DatumGetPointer(datum)); } } else { /* Not pfree'ing typbyval, so no need to check parameters. */ rob = PyPgObject_New(fn_output, datum); } } } PG_CATCH(); { Py_XDECREF(rob); rob = NULL; PyErr_SetPgError(false); } PG_END_TRY(); SPI_pop(); Py_DECREF(input); MemoryContextSwitchTo(former); return(rob); }
static PyObj statement_first(PyObj self, PyObj args, PyObj kw) { MemoryContext former = CurrentMemoryContext; PyObj c, rob = NULL; if (resolve_parameters(self, &args, &kw)) return(NULL); if (DB_IS_NOT_READY()) return(NULL); if (PyPgStatement_ReturnsRows(self)) { c = PyPgCursor_New(self, args, kw, CUR_ROWS(1)); if (c != NULL) { PyObj r; r = PyIter_Next(c); if (!PyErr_Occurred() && r == NULL) { r = Py_None; Py_INCREF(r); } if (PyPgCursor_Close(c)) { Py_DECREF(c); Py_XDECREF(r); return(NULL); } if (r != NULL) { if (r == Py_None) rob = r; else { Py_ssize_t s = PySequence_Size(r); if (s == -1) rob = NULL; else if (s == 1) { rob = PySequence_GetItem(r, 0); Py_DECREF(r); } else { /* * It has multiple columns, so return the first row. */ rob = r; } } } Py_DECREF(c); } } else { SPIPlanPtr plan; PyObj tdo = PyPgStatement_GetInput(self); TupleDesc td = PyPgTupleDesc_GetTupleDesc(tdo); PyObj pargs; plan = PyPgStatement_GetPlan(self); if (plan == NULL) return(NULL); pargs = Py_NormalizeRow( PyPgTupleDesc_GetNatts(tdo), td, PyPgTupleDesc_GetNameMap(tdo), args ); if (pargs == NULL) return(NULL); PG_TRY(); { int r; Datum *datums; bool *nulls; char *cnulls; int *freemap = PyPgTupleDesc_GetFreeMap(tdo); datums = palloc(sizeof(Datum) * td->natts); nulls = palloc(sizeof(bool) * td->natts); cnulls = palloc(sizeof(char) * td->natts); Py_BuildDatumsAndNulls( td, PyPgTupleDesc_GetTypesTuple(tdo), pargs, datums, nulls ); for (r = 0; r < td->natts; ++r) { cnulls[r] = nulls[r] ? 'n' : ' '; } r = SPI_execute_plan(plan, datums, cnulls, PL_FN_READONLY(), 1); if (r < 0) raise_spi_error(r); rob = PyLong_FromUnsignedLong(SPI_processed); FreeDatumsAndNulls(freemap, datums, nulls); pfree(cnulls); } PG_CATCH(); { PyErr_SetPgError(false); Py_XDECREF(rob); rob = NULL; } PG_END_TRY(); Py_DECREF(pargs); } MemoryContextSwitchTo(former); return(rob); }