/* * TupleDesc_GetPyPgTypes - Create a PyTupleObject of PyPgType's * * For each attribute in the TupleDesc, lookup the PyPgType corresponding * with the attribute's atttypid and place it in the new PyTupleObject at the * corresponding offset. * * NOTE: * This includes all attributes in the returned tuple object. * Dropped attributes are represented with Py_None. */ PyObj TupleDesc_GetPyPgTypes(TupleDesc td) { PyObj rob; Form_pg_attribute *att; int i; rob = PyTuple_New(td->natts); if (rob == NULL) return(NULL); att = td->attrs; for (i = 0; i < td->natts; ++i) { if (att[i]->attisdropped) { PyTuple_SET_ITEM(rob, i, Py_None); Py_INCREF(Py_None); } else { PyObj typob = PyPgType_FromOid(att[i]->atttypid); if (typob == NULL) { Py_DECREF(rob); Assert(PyErr_Occurred()); return(NULL); } PyTuple_SET_ITEM(rob, i, typob); } } return(rob); }
PyObj PyPgObject_FromTypeOidAndDatum(Oid typeoid, Datum d) { PyObj typ, rob; typ = PyPgType_FromOid(typeoid); if (typ == NULL) return(NULL); rob = PyPgObject_New(typ, d); Py_DECREF(typ); return(rob); }
PyObj PyPgObject_FromTypeOidAndPyObject(Oid typeoid, PyObj ob) { PyObj typ, args, rob; typ = PyPgType_FromOid(typeoid); if (typ == NULL) return(NULL); args = PyTuple_New(1); PyTuple_SET_ITEM(args, 0, ob); Py_INCREF(ob); rob = PyObject_CallObject(typ, args); Py_DECREF(args); Py_DECREF(typ); return(rob); }
/* * Python only supports prefix unary operators. */ static PyObj unary_operate(const char *op, PyObj right) { PyObj rob = NULL; Datum dright = PyPgObject_GetDatum(right); Oid right_oid = PyPgType_GetOid(Py_TYPE(right)); Py_ALLOCATE_OWNER(); { PyObj rtype; Operator opt; volatile Datum rd = 0; List * volatile namelist = NULL; PG_TRY(); { struct FmgrInfo flinfo = {0,}; struct FunctionCallInfoData fcinfo = {0,}; Form_pg_operator ops; Oid declared, result_type, fn_oid; namelist = stringToQualifiedNameList(op); opt = oper(NULL, (List *) namelist, InvalidOid, right_oid, false, 1); ops = (Form_pg_operator) GETSTRUCT(opt); fn_oid = ops->oprcode; declared = ops->oprright; result_type = ops->oprresult; ReleaseSysCache((HeapTuple) opt); result_type = enforce_generic_type_consistency( &right_oid, &declared, 1, result_type, true); rtype = PyPgType_FromOid(result_type); Py_XACQUIRE(rtype); list_free((List *) namelist); namelist = NULL; if (rtype == NULL) elog(ERROR, "operator result type could not be created"); fmgr_info(fn_oid, &flinfo); fcinfo.flinfo = &flinfo; fcinfo.nargs = 1; fcinfo.arg[0] = dright; fcinfo.argnull[0] = false; rd = FunctionCallInvoke(&fcinfo); if (fcinfo.isnull) { rob = Py_None; Py_INCREF(rob); Py_ACQUIRE(rob); } else { rob = PyPgObject_New(rtype, rd); Py_XACQUIRE(rob); if (PyPgType_ShouldFree(rtype)) pfree(DatumGetPointer(rd)); } } PG_CATCH(); { PyErr_SetPgError(false); rob = NULL; } PG_END_TRY(); Py_XINCREF(rob); } Py_DEALLOCATE_OWNER(); return(rob); }
static PyObj binary_operate(const char *op, PyObj left, PyObj right) { PyObj base = PyPgObject_Check(left) ? left : right; PyObj rob = NULL; Datum dleft, dright; Datum dcoerce; bool lisnull = false, risnull = false, coerce_isnull = true; Oid left_oid, right_oid; Py_ALLOCATE_OWNER(); { volatile Datum rd = 0; List * volatile namelist = NULL; PyObj rtype; PyObj coerce = NULL; PG_TRY(); { struct FmgrInfo flinfo = {0,}; struct FunctionCallInfoData fcinfo = {0,}; Operator opt; Form_pg_operator ops; Oid actual[2]; Oid declared[2]; Oid result_type, fn_oid; /* * base and coerce are used to manage preliminary coercion. * If either side of the operator is not a PyPgObject, convert the * object to the type of the other side. */ if (base == left) { if (!PyPgObject_Check(right)) coerce = right; } else coerce = left; if (coerce != NULL) { PyPgType_DatumNew((PyObj) Py_TYPE(base), coerce, -1, &dcoerce, &coerce_isnull); if (base == left) { dleft = PyPgObject_GetDatum(left); lisnull = false; dright = dcoerce; risnull = coerce_isnull; } else { dleft = dcoerce; lisnull = coerce_isnull; dright = PyPgObject_GetDatum(right); risnull = false; } /* * Both are the same type as base due to coercion. */ left_oid = right_oid = PyPgType_GetOid(Py_TYPE(base)); } else { /* * Both objects are PyPgObjects. */ dleft = PyPgObject_GetDatum(left); left_oid = PyPgType_GetOid(Py_TYPE(left)); dright = PyPgObject_GetDatum(right); right_oid = PyPgType_GetOid(Py_TYPE(right)); } namelist = stringToQualifiedNameList(op); opt = oper(NULL, (List *) namelist, left_oid, right_oid, false, 1); ops = (Form_pg_operator) GETSTRUCT(opt); fn_oid = ops->oprcode; declared[0] = ops->oprleft; declared[1] = ops->oprright; actual[0] = left_oid; actual[1] = right_oid; result_type = ops->oprresult; ReleaseSysCache((HeapTuple) opt); result_type = enforce_generic_type_consistency( actual, declared, 2, result_type, true); rtype = PyPgType_FromOid(result_type); rtype = Py_XACQUIRE(rtype); list_free((List *) namelist); namelist = NULL; if (rtype == NULL) PyErr_RelayException(); fmgr_info(fn_oid, &flinfo); fcinfo.flinfo = &flinfo; fcinfo.nargs = 2; fcinfo.arg[0] = dleft; fcinfo.argnull[0] = lisnull; fcinfo.arg[1] = dright; fcinfo.argnull[1] = risnull; rd = FunctionCallInvoke(&fcinfo); if (fcinfo.isnull) rob = Py_None; else { rob = PyPgObject_New(rtype, rd); Py_XACQUIRE(rob); if (PyPgType_ShouldFree(rtype)) pfree(DatumGetPointer(rd)); } if (!coerce_isnull && PyPgType_ShouldFree(Py_TYPE(base))) pfree(DatumGetPointer(dcoerce)); } PG_CATCH(); { PyErr_SetPgError(false); rob = NULL; } PG_END_TRY(); Py_XINCREF(rob); } Py_DEALLOCATE_OWNER(); return(rob); }
static PyObj func_new_from_oid(PyTypeObject *subtype, Oid fn_oid, PyObj fn_oid_int, PyObj fn_oid_str) { volatile HeapTuple ht = NULL; volatile PyObj rob = NULL; Assert(OidIsValid(fn_oid)); Assert(fn_oid_int != NULL); Assert(fn_oid_str != NULL); rob = subtype->tp_alloc(subtype, 0); if (rob == NULL) return(NULL); PyPgFunction_SetOid(rob, fn_oid); PyPgFunction_SetStateful(rob, false); Py_INCREF(fn_oid_int); Py_INCREF(fn_oid_str); PyPgFunction_SetPyLongOid(rob, fn_oid_int); PyPgFunction_SetPyUnicodeOid(rob, fn_oid_str); /* * Collect the Function information from the system cache */ PG_TRY(); { Form_pg_proc ps; Form_pg_namespace ns; FmgrInfo flinfo; text *prosrc; Datum prosrc_datum; bool isnull = true; const char *filename = NULL, *nspname, *q_nspname; TupleDesc argdesc = NULL, result_desc = NULL; Oid prorettype = InvalidOid; PyObj id_str_ob = NULL, nspname_str_ob = NULL; PyObj filename_str_ob = NULL, q_nspname_str_ob = NULL; PyObj output = NULL, src = NULL; PyObj input; ht = SearchSysCache(PROCOID, fn_oid, 0, 0, 0); if (!HeapTupleIsValid(ht)) { ereport(ERROR,( errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("failed to find function at oid %d", fn_oid) )); } PyPgFunction_SetXMin(rob, HeapTupleHeaderGetXmin(ht->t_data)); PyPgFunction_SetItemPointer(rob, &(ht->t_self)); ps = (Form_pg_proc) GETSTRUCT(ht); PyPgFunction_SetNamespace(rob, ps->pronamespace); PyPgFunction_SetLanguage(rob, ps->prolang); PyPgFunction_SetReturnsSet(rob, ps->proretset); PyPgFunction_SetVolatile(rob, ps->provolatile); prorettype = ps->prorettype; prosrc_datum = SysCacheGetAttr( PROCOID, ht, Anum_pg_proc_prosrc, &isnull); if (!isnull) { prosrc = DatumGetTextPCopy(prosrc_datum); src = PyUnicode_FromTEXT(prosrc); PyPgFunction_SetSource(rob, src); pfree(prosrc); prosrc = NULL; } else { src = Py_None; Py_INCREF(src); PyPgFunction_SetSource(rob, src); } if (src == NULL) PyErr_RelayException(); /* * Get the function's address. */ fmgr_info(fn_oid, &flinfo); PyPgFunction_SetPGFunction(rob, flinfo.fn_addr); /* * Build function parameters TupleDesc */ if (ps->pronargs > 0) { argdesc = TupleDesc_From_pg_proc_arginfo(ht); input = PyPgTupleDesc_FromCopy(argdesc); if (input == NULL) PyErr_RelayException(); PyPgFunction_SetInput(rob, input); FreeTupleDesc(argdesc); } else { Py_INCREF(EmptyPyPgTupleDesc); PyPgFunction_SetInput(rob, EmptyPyPgTupleDesc); } /* * If it's a registered composite, * PyPgType_FromOid will resolve that below. */ if (prorettype == RECORDOID) { /* * Otherwise, build out a function result tupdesc. */ result_desc = build_function_result_tupdesc_t(ht); if (result_desc != NULL) { /* * Anonymous composite returned by function. */ output = PyPgType_FromTupleDesc(result_desc); PyPgFunction_SetOutput(rob, output); FreeTupleDesc(result_desc); /* * We will certainly be using it, so bless it right now iff * it's *not* polymorphic. */ if (output && !PyPgType_IsPolymorphic(output)) BlessTupleDesc(PyPgType_GetTupleDesc(output)); } else { /* * ew.. */ goto lookup_output_type; } } else { lookup_output_type: output = PyPgType_FromOid(prorettype); if (output == NULL) PyErr_RelayException(); PyPgFunction_SetOutput(rob, output); } RELEASESYSCACHE(&ht); /* * Don't worry *too* much about leaking memory. */ filename = format_procedure(fn_oid); Assert(filename != NULL); ht = SearchSysCache(NAMESPACEOID, PyPgFunction_GetNamespace(rob), 0, 0, 0); if (!HeapTupleIsValid(ht)) { pfree((char *) filename); elog(ERROR, "function %u namespace %u does not exist", fn_oid, PyPgFunction_GetNamespace(rob)); } ns = (Form_pg_namespace) GETSTRUCT(ht); nspname = pstrdup(NameStr(ns->nspname)); RELEASESYSCACHE(&ht); /* * Build the filename string. */ q_nspname = quote_identifier(nspname); nspname_str_ob = PyUnicode_FromCString(nspname); PyPgFunction_SetNamespaceName(rob, nspname_str_ob); if (nspname_str_ob == NULL) { /* * Invalid encoded string? */ if (nspname != q_nspname) pfree((char *) q_nspname); pfree((char *) nspname); PyErr_RelayException(); } q_nspname_str_ob = PyUnicode_FromCString(q_nspname); if (nspname != q_nspname) pfree((char *) q_nspname); pfree((char *) nspname); /* * Ignore the potential exception for a moment. */ id_str_ob = PyUnicode_FromCString(filename); /* * Skip the filename_str_ob if either of the above failed. */ if (id_str_ob != NULL && q_nspname_str_ob != NULL) { if (FunctionIsVisible(fn_oid)) filename_str_ob = PyUnicode_FromFormat("%U.%U", q_nspname_str_ob, id_str_ob); else { filename_str_ob = id_str_ob; Py_INCREF(id_str_ob); } } PyPgFunction_SetFilename(rob, filename_str_ob); Py_XDECREF(q_nspname_str_ob); Py_XDECREF(id_str_ob); pfree((char *) filename); if (filename_str_ob == NULL) PyErr_RelayException(); } PG_CATCH(); { Py_XDECREF(rob); rob = NULL; PyErr_SetPgError(false); if (ht != NULL) ReleaseSysCache(ht); } PG_END_TRY(); return(rob); }