static void PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup, Oid langid, List *trftypes) { Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); Oid element_type; Oid base_type; Oid funcid; perm_fmgr_info(typeStruct->typinput, &arg->typfunc); arg->typoid = HeapTupleGetOid(typeTup); arg->typmod = -1; arg->typioparam = getTypeIOParam(typeTup); arg->typbyval = typeStruct->typbyval; element_type = get_base_element_type(arg->typoid); base_type = getBaseType(element_type ? element_type : arg->typoid); /* * Select a conversion function to convert Python objects to PostgreSQL * datums. */ if ((funcid = get_transform_tosql(base_type, langid, trftypes))) { arg->func = PLyObject_ToTransform; perm_fmgr_info(funcid, &arg->typtransform); } else if (typeStruct->typtype == TYPTYPE_COMPOSITE) { arg->func = PLyObject_ToComposite; } else switch (base_type) { case BOOLOID: arg->func = PLyObject_ToBool; break; case BYTEAOID: arg->func = PLyObject_ToBytea; break; default: arg->func = PLyObject_ToDatum; break; } if (element_type) { char dummy_delim; Oid funcid; if (type_is_rowtype(element_type)) arg->func = PLyObject_ToComposite; arg->elm = PLy_malloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->elm->typtransform = arg->typtransform; arg->func = PLySequence_ToArray; arg->elm->typoid = element_type; arg->elm->typmod = -1; get_type_io_data(element_type, IOFunc_input, &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim, &arg->elm->typioparam, &funcid); perm_fmgr_info(funcid, &arg->elm->typfunc); } }
/* * Recursively initialize the PLyObToDatum structure(s) needed to construct * a SQL value of the specified typeOid/typmod from a Python value. * (But note that at this point we may have RECORDOID/-1, ie, an indeterminate * record type.) * proc is used to look up transform functions. */ void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc) { TypeCacheEntry *typentry; char typtype; Oid trfuncid; Oid typinput; /* Since this is recursive, it could theoretically be driven to overflow */ check_stack_depth(); arg->typoid = typeOid; arg->typmod = typmod; arg->mcxt = arg_mcxt; /* * Fetch typcache entry for the target type, asking for whatever info * we'll need later. RECORD is a special case: just treat it as composite * without bothering with the typcache entry. */ if (typeOid != RECORDOID) { typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO); typtype = typentry->typtype; arg->typbyval = typentry->typbyval; arg->typlen = typentry->typlen; arg->typalign = typentry->typalign; } else { typentry = NULL; typtype = TYPTYPE_COMPOSITE; /* hard-wired knowledge about type RECORD: */ arg->typbyval = false; arg->typlen = -1; arg->typalign = 'd'; } /* * Choose conversion method. Note that transform functions are checked * for composite and scalar types, but not for arrays or domains. This is * somewhat historical, but we'd have a problem allowing them on domains, * since we drill down through all levels of a domain nest without looking * at the intermediate levels at all. */ if (typtype == TYPTYPE_DOMAIN) { /* Domain */ arg->func = PLyObject_ToDomain; arg->u.domain.domain_info = NULL; /* Recursively set up conversion info for the element type */ arg->u.domain.base = (PLyObToDatum *) MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum)); PLy_output_setup_func(arg->u.domain.base, arg_mcxt, typentry->domainBaseType, typentry->domainBaseTypmod, proc); } else if (typentry && OidIsValid(typentry->typelem) && typentry->typlen == -1) { /* Standard varlena array (cf. get_element_type) */ arg->func = PLySequence_ToArray; /* Get base type OID to insert into constructed array */ /* (note this might not be the same as the immediate child type) */ arg->u.array.elmbasetype = getBaseType(typentry->typelem); /* Recursively set up conversion info for the element type */ arg->u.array.elm = (PLyObToDatum *) MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum)); PLy_output_setup_func(arg->u.array.elm, arg_mcxt, typentry->typelem, typmod, proc); } else if ((trfuncid = get_transform_tosql(typeOid, proc->langid, proc->trftypes))) { arg->func = PLyObject_ToTransform; fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt); } else if (typtype == TYPTYPE_COMPOSITE) { /* Named composite type, or RECORD */ arg->func = PLyObject_ToComposite; /* We'll set up the per-field data later */ arg->u.tuple.recdesc = NULL; arg->u.tuple.typentry = typentry; arg->u.tuple.tupdescseq = typentry ? typentry->tupDescSeqNo - 1 : 0; arg->u.tuple.atts = NULL; arg->u.tuple.natts = 0; /* Mark this invalid till needed, too */ arg->u.tuple.recinfunc.fn_oid = InvalidOid; } else { /* Scalar type, but we have a couple of special cases */ switch (typeOid) { case BOOLOID: arg->func = PLyObject_ToBool; break; case BYTEAOID: arg->func = PLyObject_ToBytea; break; default: arg->func = PLyObject_ToScalar; getTypeInputInfo(typeOid, &typinput, &arg->u.scalar.typioparam); fmgr_info_cxt(typinput, &arg->u.scalar.typfunc, arg_mcxt); break; } } }