/* * Convert a Python object to a composite Datum, using all supported * conversion methods: composite as a string, as a sequence, as a mapping or * as an object that has __getattr__ support. */ Datum PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv) { Datum datum; if (PyString_Check(plrv) || PyUnicode_Check(plrv)) datum = PLyString_ToComposite(info, desc, plrv); else if (PySequence_Check(plrv)) /* composite type as sequence (tuple, list etc) */ datum = PLySequence_ToComposite(info, desc, plrv); else if (PyMapping_Check(plrv)) /* composite type as mapping (currently only dict) */ datum = PLyMapping_ToComposite(info, desc, plrv); else /* returned as smth, must provide method __getattr__(name) */ datum = PLyGenericObject_ToComposite(info, desc, plrv); return datum; }
/* * Convert a Python object to a composite type. First look up the type's * description, then route the Python object through the conversion function * for obtaining PostgreSQL tuples. */ static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray) { Datum rv; TupleDesc desc; if (plrv == Py_None) { *isnull = true; return (Datum) 0; } *isnull = false; /* * The string conversion case doesn't require a tupdesc, nor per-field * conversion data, so just go for it if that's the case to use. */ if (PyString_Check(plrv) || PyUnicode_Check(plrv)) return PLyString_ToComposite(arg, plrv, inarray); /* * If we're dealing with a named composite type, we must look up the * tupdesc every time, to protect against possible changes to the type. * RECORD types can't change between calls; but we must still be willing * to set up the info the first time, if nobody did yet. */ if (arg->typoid != RECORDOID) { desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod); /* We should have the descriptor of the type's typcache entry */ Assert(desc == arg->u.tuple.typentry->tupDesc); /* Detect change of descriptor, update cache if needed */ if (arg->u.tuple.tupdescseq != arg->u.tuple.typentry->tupDescSeqNo) { PLy_output_setup_tuple(arg, desc, PLy_current_execution_context()->curr_proc); arg->u.tuple.tupdescseq = arg->u.tuple.typentry->tupDescSeqNo; } } else { desc = arg->u.tuple.recdesc; if (desc == NULL) { desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod); arg->u.tuple.recdesc = desc; } else { /* Pin descriptor to match unpin below */ PinTupleDesc(desc); } } /* Simple sanity check on our caching */ Assert(desc->natts == arg->u.tuple.natts); /* * Convert, using the appropriate method depending on the type of the * supplied Python object. */ if (PySequence_Check(plrv)) /* composite type as sequence (tuple, list etc) */ rv = PLySequence_ToComposite(arg, desc, plrv); else if (PyMapping_Check(plrv)) /* composite type as mapping (currently only dict) */ rv = PLyMapping_ToComposite(arg, desc, plrv); else /* returned as smth, must provide method __getattr__(name) */ rv = PLyGenericObject_ToComposite(arg, desc, plrv, inarray); ReleaseTupleDesc(desc); return rv; }