@@ -2199,8 +2199,9 @@ int databasevm_bind_value (dbvm_t *vm, int index, dbvalue_t *value) {
21992199 // Pass-by-reference: need to copy the actual data
22002200 // Handle variable-length types (typlen == -1) and cstrings (typlen == -2)
22012201 if (typlen == -1 ) {
2202- // Variable-length type (varlena): use datumCopy with correct size
2203- Size len = VARSIZE (DatumGetPointer (v -> datum ));
2202+ // Variable-length type (varlena): use VARSIZE_ANY to handle
2203+ // both short (1-byte) and regular (4-byte) varlena headers
2204+ Size len = VARSIZE_ANY (DatumGetPointer (v -> datum ));
22042205 dcopy = PointerGetDatum (palloc (len ));
22052206 memcpy (DatumGetPointer (dcopy ), DatumGetPointer (v -> datum ), len );
22062207 } else if (typlen == -2 ) {
@@ -2430,8 +2431,10 @@ const void *database_value_blob (dbvalue_t *value) {
24302431 pgvalue_t * v = (pgvalue_t * )value ;
24312432 if (!v || v -> isnull ) return NULL ;
24322433
2433- // Text types reuse blob accessor (pk encode reads text bytes directly)
2434- if (pgvalue_is_text_type (v -> typeid )) {
2434+ // Text types reuse blob accessor (pk encode reads text bytes directly).
2435+ // Exclude JSONB: its internal format is binary, not text —
2436+ // it must go through OidOutputFunctionCall to get the JSON text.
2437+ if (pgvalue_is_text_type (v -> typeid ) && v -> typeid != JSONBOID ) {
24352438 pgvalue_ensure_detoast (v );
24362439 text * txt = (text * )DatumGetPointer (v -> datum );
24372440 return VARDATA_ANY (txt );
@@ -2443,6 +2446,11 @@ const void *database_value_blob (dbvalue_t *value) {
24432446 return VARDATA_ANY (ba );
24442447 }
24452448
2449+ // For unmapped types and JSONB (mapped to DBTYPE_TEXT),
2450+ // convert to text representation via the type's output function
2451+ const char * cstr = database_value_text (value );
2452+ if (cstr ) return cstr ;
2453+
24462454 return NULL ;
24472455}
24482456
@@ -2495,11 +2503,11 @@ const char *database_value_text (dbvalue_t *value) {
24952503 if (!v -> cstring && !v -> owns_cstring ) {
24962504 PG_TRY ();
24972505 {
2498- if (pgvalue_is_text_type (v -> typeid )) {
2506+ if (pgvalue_is_text_type (v -> typeid ) && v -> typeid != JSONBOID ) {
24992507 pgvalue_ensure_detoast (v );
25002508 v -> cstring = text_to_cstring ((text * )DatumGetPointer (v -> datum ));
25012509 } else {
2502- // Fallback to type output function for non-text types
2510+ // Type output function for JSONB and other non-text types
25032511 Oid outfunc ;
25042512 bool isvarlena ;
25052513 getTypeOutputInfo (v -> typeid , & outfunc , & isvarlena );
@@ -2527,7 +2535,8 @@ int database_value_bytes (dbvalue_t *value) {
25272535 pgvalue_t * v = (pgvalue_t * )value ;
25282536 if (!v || v -> isnull ) return 0 ;
25292537
2530- if (pgvalue_is_text_type (v -> typeid )) {
2538+ // Exclude JSONB: binary internal format, must use OidOutputFunctionCall
2539+ if (pgvalue_is_text_type (v -> typeid ) && v -> typeid != JSONBOID ) {
25312540 pgvalue_ensure_detoast (v );
25322541 text * txt = (text * )DatumGetPointer (v -> datum );
25332542 return VARSIZE_ANY_EXHDR (txt );
@@ -2537,6 +2546,9 @@ int database_value_bytes (dbvalue_t *value) {
25372546 bytea * ba = (bytea * )DatumGetPointer (v -> datum );
25382547 return VARSIZE_ANY_EXHDR (ba );
25392548 }
2549+ // For unmapped types and JSONB (mapped to DBTYPE_TEXT),
2550+ // ensure the text representation is materialized
2551+ database_value_text (value );
25402552 if (v -> cstring ) {
25412553 return (int )strlen (v -> cstring );
25422554 }
0 commit comments