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; }
/* Make this datatype available to the postgres system. */ UDT UDT_registerUDT(jclass clazz, Oid typeId, Form_pg_type pgType, TupleDesc td, bool isJavaBasedScalar) { jstring jcn; MemoryContext currCtx; HeapTuple nspTup; Form_pg_namespace nspStruct; TypeClass udtClass; UDT udt; Size signatureLen; jstring sqlTypeName; char* className; char* classSignature; char* sp; const char* cp; const char* tp; char c; Type existing = Type_fromOidCache(typeId); if(existing != 0) { if(existing->typeClass->coerceDatum != _UDT_coerceDatum) { ereport(ERROR, ( errcode(ERRCODE_CANNOT_COERCE), errmsg("Attempt to register UDT with Oid %d failed. Oid appoints a non UDT type", typeId))); } return (UDT)existing; } nspTup = PgObject_getValidTuple(NAMESPACEOID, pgType->typnamespace, "namespace"); nspStruct = (Form_pg_namespace)GETSTRUCT(nspTup); /* Concatenate namespace + '.' + typename */ cp = NameStr(nspStruct->nspname); tp = NameStr(pgType->typname); sp = palloc(strlen(cp) + strlen(tp) + 2); sprintf(sp, "%s.%s", cp, tp); sqlTypeName = String_createJavaStringFromNTS(sp); pfree(sp); ReleaseSysCache(nspTup); /* Create a Java Signature String from the class name */ jcn = JNI_callObjectMethod(clazz, Class_getName); currCtx = MemoryContextSwitchTo(TopMemoryContext); className = String_createNTS(jcn); JNI_deleteLocalRef(jcn); signatureLen = strlen(className) + 2; classSignature = palloc(signatureLen + 1); MemoryContextSwitchTo(currCtx); sp = classSignature; cp = className; *sp++ = 'L'; while((c = *cp++) != 0) { if(c == '.') c = '/'; *sp++ = c; } *sp++ = ';'; *sp = 0; udtClass = TypeClass_alloc2("type.UDT", sizeof(struct TypeClass_), sizeof(struct UDT_)); udtClass->JNISignature = classSignature; udtClass->javaTypeName = className; udtClass->javaClass = JNI_newGlobalRef(clazz); udtClass->canReplaceType = _Type_canReplaceType; udtClass->coerceDatum = _UDT_coerceDatum; udtClass->coerceObject = _UDT_coerceObject; udt = (UDT)TypeClass_allocInstance2(udtClass, typeId, pgType); udt->sqlTypeName = JNI_newGlobalRef(sqlTypeName); JNI_deleteLocalRef(sqlTypeName); udt->init = PgObject_getJavaMethod(clazz, "<init>", "()V"); if(isJavaBasedScalar) { /* A scalar mapping that is implemented in Java will have the static method: * * T parse(String stringRep, String sqlTypeName); * * and a matching: * * String toString(); * * instance method. A pure mapping (i.e. no Java I/O methods) will not have * this. */ udt->toString = PgObject_getJavaMethod(clazz, "toString", "()Ljava/lang/String;"); /* The parse method is a static method on the class with the signature * (Ljava/lang/String;Ljava/lang/String;)<classSignature> */ sp = palloc(signatureLen + 40); strcpy(sp, "(Ljava/lang/String;Ljava/lang/String;)"); strcpy(sp + 38, classSignature); udt->parse = PgObject_getStaticJavaMethod(clazz, "parse", sp); pfree(sp); } else { udt->toString = 0; udt->parse = 0; } udt->tupleDesc = td; udt->readSQL = PgObject_getJavaMethod(clazz, "readSQL", "(Ljava/sql/SQLInput;Ljava/lang/String;)V"); udt->writeSQL = PgObject_getJavaMethod(clazz, "writeSQL", "(Ljava/sql/SQLOutput;)V"); Type_registerType(className, (Type)udt); return udt; }