Datum UDT_output(UDT udt, PG_FUNCTION_ARGS) { char* txt; if(!UDT_isScalar(udt)) ereport(ERROR, ( errcode(ERRCODE_CANNOT_COERCE), errmsg("UDT with Oid %d is not scalar", Type_getOid((Type)udt)))); if(Type_getLength((Type)udt) == -2) { txt = PG_GETARG_CSTRING(0); if(txt != 0) txt = pstrdup(txt); } else { jobject value = _UDT_coerceDatum((Type)udt, PG_GETARG_DATUM(0)).l; jstring jstr = (jstring)JNI_callObjectMethod(value, udt->toString); MemoryContext currCtx = Invocation_switchToUpperContext(); txt = String_createNTS(jstr); MemoryContextSwitchTo(currCtx); JNI_deleteLocalRef(value); JNI_deleteLocalRef(jstr); } PG_RETURN_CSTRING(txt); }
Datum UDT_input(UDT udt, PG_FUNCTION_ARGS) { jstring jstr; jobject obj; char* txt; if(!UDT_isScalar(udt)) ereport(ERROR, ( errcode(ERRCODE_CANNOT_COERCE), errmsg("UDT with Oid %d is not scalar", Type_getOid((Type)udt)))); txt = PG_GETARG_CSTRING(0); if(Type_getLength((Type)udt) == -2) { if(txt != 0) txt = pstrdup(txt); PG_RETURN_CSTRING(txt); } jstr = String_createJavaStringFromNTS(txt); obj = JNI_callStaticObjectMethod(Type_getJavaClass((Type)udt), udt->parse, jstr, udt->sqlTypeName); JNI_deleteLocalRef(jstr); return _UDT_coerceObject((Type)udt, obj); }
Datum UDT_send(UDT udt, PG_FUNCTION_ARGS) { StringInfoData buf; int32 dataLen = Type_getLength((Type)udt); if(!UDT_isScalar(udt)) ereport(ERROR, ( errcode(ERRCODE_CANNOT_COERCE), errmsg("UDT with Oid %d is not scalar", Type_getOid((Type)udt)))); if(dataLen == -1) return byteasend(fcinfo); if(dataLen == -2) return unknownsend(fcinfo); pq_begintypsend(&buf); appendBinaryStringInfo(&buf, PG_GETARG_POINTER(0), dataLen); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); }
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; } } }
static Datum _Array_coerceObject(Type self, jobject objArray) { ArrayType* v; jsize idx; int lowerBound = 1; Type elemType = Type_getElementType(self); int nElems = (int)JNI_getArrayLength((jarray)objArray); Datum* values = (Datum*)palloc(nElems * sizeof(Datum) + nElems * sizeof(bool)); bool* nulls = (bool*)(values + nElems); for(idx = 0; idx < nElems; ++idx) { jobject obj = JNI_getObjectArrayElement(objArray, idx); if(obj == 0) { nulls[idx] = true; values[idx] = 0; } else { nulls[idx] = false; values[idx] = Type_coerceObject(elemType, obj); JNI_deleteLocalRef(obj); } } v = construct_md_array( values, nulls, 1, &nElems, &lowerBound, Type_getOid(elemType), Type_getLength(elemType), Type_isByValue(elemType), Type_getAlign(elemType)); pfree(values); PG_RETURN_ARRAYTYPE_P(v); }
Datum UDT_receive(UDT udt, PG_FUNCTION_ARGS) { StringInfo buf; char* tmp; int32 dataLen = Type_getLength((Type)udt); if(!UDT_isScalar(udt)) ereport(ERROR, ( errcode(ERRCODE_CANNOT_COERCE), errmsg("UDT with Oid %d is not scalar", Type_getOid((Type)udt)))); if(dataLen == -1) return bytearecv(fcinfo); if(dataLen == -2) return unknownrecv(fcinfo); buf = (StringInfo)PG_GETARG_POINTER(0); tmp = palloc(dataLen); pq_copymsgbytes(buf, tmp, dataLen); PG_RETURN_POINTER(tmp); }
/* * Fail openly rather than mysteriously if an INPUT or RECEIVE function is * called with a non-default typmod. It seems possible that, aside from COPY * operations, that doesn't happen much, and values are usually produced as if * with no typmod, then fed through a typmod application cast. So even * without this implemented, there may be usable typmod capability except for * COPY. */ static void noTypmodYet(UDT udt, PG_FUNCTION_ARGS) { Oid toid; int mod; if ( 3 > PG_NARGS() ) return; toid = PG_GETARG_OID(1); mod = PG_GETARG_INT32(2); if ( -1 != mod ) ereport(ERROR, ( errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg( "PL/Java UDT with non-default type modifier not yet supported") )); if ( Type_getOid((Type)udt) != toid ) ereport(ERROR, ( errcode(ERRCODE_INTERNAL_ERROR), errmsg("Unexpected type Oid %d passed to PL/Java UDT", toid))); }
static Datum coerceScalarObject(UDT self, jobject value) { Datum result; int32 dataLen = Type_getLength((Type)self); if(dataLen == -2) { jstring jstr = (jstring)JNI_callObjectMethod(value, self->toString); char* tmp = String_createNTS(jstr); result = CStringGetDatum(tmp); JNI_deleteLocalRef(jstr); } else { jobject outputStream; StringInfoData buffer; bool passByValue = Type_isByValue((Type)self); MemoryContext currCtx = Invocation_switchToUpperContext(); initStringInfo(&buffer); if(dataLen < 0) /* * Reserve space for an int32 at the beginning. We are building * a varlena */ appendBinaryStringInfo(&buffer, (char*)&dataLen, sizeof(int32)); outputStream = SQLOutputToChunk_create(&buffer); JNI_callVoidMethod(value, self->writeSQL, outputStream); SQLOutputToChunk_close(outputStream); MemoryContextSwitchTo(currCtx); if(dataLen < 0) { /* Assign the correct length. */ #if PG_VERSION_NUM < 80300 VARATT_SIZEP(buffer.data) = buffer.len; #else SET_VARSIZE(buffer.data, buffer.len); #endif } else if(dataLen != buffer.len) { ereport(ERROR, ( errcode(ERRCODE_CANNOT_COERCE), errmsg("UDT for Oid %d produced image with incorrect size. Expected %d, was %d", Type_getOid((Type)self), dataLen, buffer.len))); } if (passByValue) { memset(&result, 0, SIZEOF_DATUM); /* pass by value data is stored in the least * significant bits of a Datum. */ #ifdef WORDS_BIGENDIAN memcpy(&result + SIZEOF_DATUM - dataLen, buffer.data, dataLen); #else memcpy(&result, buffer.data, dataLen); #endif } else { result = PointerGetDatum(buffer.data); } } return result; }