Esempio n. 1
0
/*
 *	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;
}
Esempio n. 2
0
/*
 * 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;
}