static void setupFunctionParams(Function self, ParseResult info, Form_pg_proc procStruct, PG_FUNCTION_ARGS) { Oid* paramOids; MemoryContext ctx = GetMemoryChunkContext(self); int32 top = (int32)procStruct->pronargs;; self->func.nonudt.numParams = top; self->func.nonudt.isMultiCall = procStruct->proretset; self->func.nonudt.returnType = Type_fromOid(procStruct->prorettype, self->func.nonudt.typeMap); if(top > 0) { int idx; paramOids = PARAM_OIDS(procStruct); self->func.nonudt.paramTypes = (Type*)MemoryContextAlloc(ctx, top * sizeof(Type)); for(idx = 0; idx < top; ++idx) self->func.nonudt.paramTypes[idx] = Type_fromOid(paramOids[idx], self->func.nonudt.typeMap); } else { self->func.nonudt.paramTypes = 0; paramOids = 0; } if(info->parameters != 0) parseParameters(self, paramOids, info->parameters); if(info->returnType != 0) { const char* jtName = Type_getJavaTypeName(self->func.nonudt.returnType); if(strcmp(jtName, info->returnType) != 0) { Type repl = Type_fromJavaType(Type_getOid(self->func.nonudt.returnType), info->returnType); if(!Type_canReplaceType(repl, self->func.nonudt.returnType)) repl = Type_getCoerceOut(repl, self->func.nonudt.returnType); self->func.nonudt.returnType = repl; } } }
/* * Class: org_postgresql_pljava_internal_TupleDesc * Method: _formTuple * Signature: (J[Ljava/lang/Object;)Lorg/postgresql/pljava/internal/Tuple; */ JNIEXPORT jobject JNICALL Java_org_postgresql_pljava_internal_TupleDesc__1formTuple(JNIEnv* env, jclass cls, jlong _this, jobjectArray jvalues) { jobject result = 0; BEGIN_NATIVE Ptr2Long p2l; p2l.longVal = _this; PG_TRY(); { jint idx; HeapTuple tuple; MemoryContext curr; TupleDesc self = (TupleDesc)p2l.ptrVal; int count = self->natts; Datum* values = (Datum*)palloc(count * sizeof(Datum)); char* nulls = palloc(count); jobject typeMap = Invocation_getTypeMap(); memset(values, 0, count * sizeof(Datum)); memset(nulls, 'n', count); /* all values null initially */ for(idx = 0; idx < count; ++idx) { jobject value = JNI_getObjectArrayElement(jvalues, idx); if(value != 0) { Type type = Type_fromOid(SPI_gettypeid(self, idx + 1), typeMap); values[idx] = Type_coerceObject(type, value); nulls[idx] = ' '; } } curr = MemoryContextSwitchTo(JavaMemoryContext); tuple = heap_formtuple(self, values, nulls); result = Tuple_internalCreate(tuple, false); MemoryContextSwitchTo(curr); pfree(values); pfree(nulls); } PG_CATCH(); { Exception_throw_ERROR("heap_formtuple"); } PG_END_TRY(); END_NATIVE return result; }
Type Type_objectTypeFromOid(Oid typeId, jobject typeMap) { Type type = Type_fromOid(typeId, typeMap); Type objectType = type->objectType; return (objectType == 0) ? type : objectType; }
Type Type_fromOid(Oid typeId, jobject typeMap) { CacheEntry ce; HeapTuple typeTup; Form_pg_type typeStruct; Type type = Type_fromOidCache(typeId); if(type != 0) return type; typeTup = PgObject_getValidTuple(TYPEOID, typeId, "type"); typeStruct = (Form_pg_type)GETSTRUCT(typeTup); if(typeStruct->typelem != 0 && typeStruct->typlen == -1) { type = Type_getArrayType(Type_fromOid(typeStruct->typelem, typeMap), typeId); goto finally; } /* For some reason, the anyarray is *not* an array with anyelement as the * element type. We'd like to see it that way though. */ if(typeId == ANYARRAYOID) { type = Type_getArrayType(Type_fromOid(ANYELEMENTOID, typeMap), typeId); goto finally; } if(typeStruct->typbasetype != 0) { /* Domain type, recurse using the base type (which in turn may * also be a domain) */ type = Type_fromOid(typeStruct->typbasetype, typeMap); goto finally; } if(typeMap != 0) { jobject joid = Oid_create(typeId); jclass typeClass = (jclass)JNI_callObjectMethod(typeMap, s_Map_get, joid); JNI_deleteLocalRef(joid); if(typeClass != 0) { TupleDesc tupleDesc = lookup_rowtype_tupdesc_noerror(typeId, -1, true); type = (Type)UDT_registerUDT(typeClass, typeId, typeStruct, tupleDesc, false); JNI_deleteLocalRef(typeClass); goto finally; } } /* Composite and record types will not have a TypeObtainer registered */ if(typeStruct->typtype == 'c' || (typeStruct->typtype == 'p' && typeId == RECORDOID)) { type = Composite_obtain(typeId); goto finally; } ce = (CacheEntry)HashMap_getByOid(s_obtainerByOid, typeId); if(ce == 0) /* * Default to String and standard textin/textout coersion. */ type = String_obtain(typeId); else { type = ce->type; if(type == 0) type = ce->obtainer(typeId); } finally: ReleaseSysCache(typeTup); Type_cacheByOid(typeId, type); return type; }