static void PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes) { Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); Oid element_type; Oid base_type; Oid funcid; /* Get the type's conversion information */ perm_fmgr_info(typeStruct->typoutput, &arg->typfunc); arg->typoid = HeapTupleGetOid(typeTup); arg->typmod = -1; arg->typioparam = getTypeIOParam(typeTup); arg->typbyval = typeStruct->typbyval; arg->typlen = typeStruct->typlen; arg->typalign = typeStruct->typalign; /* Determine which kind of Python object we will convert to */ element_type = get_base_element_type(typeOid); base_type = getBaseType(element_type ? element_type : typeOid); if ((funcid = get_transform_fromsql(base_type, langid, trftypes))) { arg->func = PLyObject_FromTransform; perm_fmgr_info(funcid, &arg->typtransform); } else switch (base_type) { case BOOLOID: arg->func = PLyBool_FromBool; break; case FLOAT4OID: arg->func = PLyFloat_FromFloat4; break; case FLOAT8OID: arg->func = PLyFloat_FromFloat8; break; case NUMERICOID: arg->func = PLyDecimal_FromNumeric; break; case INT2OID: arg->func = PLyInt_FromInt16; break; case INT4OID: arg->func = PLyInt_FromInt32; break; case INT8OID: arg->func = PLyLong_FromInt64; break; case OIDOID: arg->func = PLyLong_FromOid; break; case BYTEAOID: arg->func = PLyBytes_FromBytea; break; default: arg->func = PLyString_FromDatum; break; } if (element_type) { char dummy_delim; Oid funcid; arg->elm = PLy_malloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->elm->typtransform = arg->typtransform; arg->func = PLyList_FromArray; arg->elm->typoid = element_type; arg->elm->typmod = -1; get_type_io_data(element_type, IOFunc_output, &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 PLyDatumToOb structure(s) needed to construct * a Python value from a SQL value of the specified typeOid/typmod. * (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_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc) { TypeCacheEntry *typentry; char typtype; Oid trfuncid; Oid typoutput; bool typisvarlena; /* 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 --- we don't care, just recurse down to the base type */ PLy_input_setup_func(arg, 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 = PLyList_FromArray; /* Recursively set up conversion info for the element type */ arg->u.array.elm = (PLyDatumToOb *) MemoryContextAllocZero(arg_mcxt, sizeof(PLyDatumToOb)); PLy_input_setup_func(arg->u.array.elm, arg_mcxt, typentry->typelem, typmod, proc); } else if ((trfuncid = get_transform_fromsql(typeOid, proc->langid, proc->trftypes))) { arg->func = PLyObject_FromTransform; fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt); } else if (typtype == TYPTYPE_COMPOSITE) { /* Named composite type, or RECORD */ arg->func = PLyDict_FromComposite; /* 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; } else { /* Scalar type, but we have a couple of special cases */ switch (typeOid) { case BOOLOID: arg->func = PLyBool_FromBool; break; case FLOAT4OID: arg->func = PLyFloat_FromFloat4; break; case FLOAT8OID: arg->func = PLyFloat_FromFloat8; break; case NUMERICOID: arg->func = PLyDecimal_FromNumeric; break; case INT2OID: arg->func = PLyInt_FromInt16; break; case INT4OID: arg->func = PLyInt_FromInt32; break; case INT8OID: arg->func = PLyLong_FromInt64; break; case OIDOID: arg->func = PLyLong_FromOid; break; case BYTEAOID: arg->func = PLyBytes_FromBytea; break; default: arg->func = PLyString_FromScalar; getTypeOutputInfo(typeOid, &typoutput, &typisvarlena); fmgr_info_cxt(typoutput, &arg->u.scalar.typfunc, arg_mcxt); break; } } }