@@ -201,6 +201,7 @@ ensure_lines_capacity(void)
201201 *
202202 * Add a completed line to the buffer.
203203 * Checks for buffer overflow based on byte usage (Oracle behavior).
204+ * NULL lines are stored as NULL pointers (Oracle behavior).
204205 */
205206static void
206207add_line_to_buffer (const char * line )
@@ -210,7 +211,8 @@ add_line_to_buffer(const char *line)
210211 char * line_copy ;
211212
212213 /* Calculate bytes for this line (Oracle counts actual bytes) */
213- line_bytes = strlen (line );
214+ /* NULL lines count as 0 bytes */
215+ line_bytes = (line != NULL ) ? strlen (line ) : 0 ;
214216
215217 /* Check buffer overflow BEFORE adding (Oracle behavior) */
216218 if (output_buffer -> buffer_used + line_bytes > output_buffer -> buffer_size )
@@ -224,7 +226,8 @@ add_line_to_buffer(const char *line)
224226
225227 /* Store line in buffer memory context */
226228 oldcontext = MemoryContextSwitchTo (output_buffer -> buffer_mcxt );
227- line_copy = pstrdup (line );
229+ /* Store NULL as NULL pointer, not as empty string */
230+ line_copy = (line != NULL ) ? pstrdup (line ) : NULL ;
228231 output_buffer -> lines [output_buffer -> line_count ++ ] = line_copy ;
229232 output_buffer -> buffer_used += line_bytes ;
230233 MemoryContextSwitchTo (oldcontext );
@@ -307,20 +310,24 @@ ora_dbms_output_disable(PG_FUNCTION_ARGS)
307310 *
308311 * Output a line to the buffer (with newline).
309312 * If there's pending PUT text, append it first (Oracle behavior).
310- * Oracle behavior: NULL is treated as empty string.
313+ * Oracle behavior: NULL stores actual NULL in buffer (not empty string) .
311314 */
312315Datum
313316ora_dbms_output_put_line (PG_FUNCTION_ARGS )
314317{
315318 char * line_str ;
319+ bool is_null = false;
316320
317321 /* Silently discard if buffer not enabled (Oracle behavior) */
318322 if (output_buffer == NULL || !output_buffer -> enabled )
319323 PG_RETURN_VOID ();
320324
321- /* Handle NULL argument - treat as empty string (Oracle behavior) */
325+ /* Handle NULL argument - Oracle stores actual NULL */
322326 if (PG_ARGISNULL (0 ))
323- line_str = "" ;
327+ {
328+ line_str = NULL ;
329+ is_null = true;
330+ }
324331 else
325332 {
326333 text * line_text = PG_GETARG_TEXT_PP (0 );
@@ -330,13 +337,15 @@ ora_dbms_output_put_line(PG_FUNCTION_ARGS)
330337 /* If there's pending PUT text, append it first (Oracle behavior) */
331338 if (output_buffer -> current_line -> len > 0 )
332339 {
333- appendStringInfoString (output_buffer -> current_line , line_str );
340+ /* Append non-NULL text to current line */
341+ if (!is_null )
342+ appendStringInfoString (output_buffer -> current_line , line_str );
334343 add_line_to_buffer (output_buffer -> current_line -> data );
335344 resetStringInfo (output_buffer -> current_line );
336345 }
337346 else
338347 {
339- /* No pending PUT text, just add the line */
348+ /* No pending PUT text, just add the line (may be NULL) */
340349 add_line_to_buffer (line_str );
341350 }
342351
@@ -439,7 +448,16 @@ ora_dbms_output_get_line(PG_FUNCTION_ARGS)
439448 /* Return next line */
440449 char * line = output_buffer -> lines [output_buffer -> read_position ++ ];
441450
442- values [0 ] = CStringGetTextDatum (line );
451+ /* Handle NULL lines (Oracle behavior: PUT_LINE(NULL) stores actual NULL) */
452+ if (line == NULL )
453+ {
454+ nulls [0 ] = true;
455+ values [0 ] = (Datum ) 0 ;
456+ }
457+ else
458+ {
459+ values [0 ] = CStringGetTextDatum (line );
460+ }
443461 values [1 ] = Int32GetDatum (0 ); /* status = 0 (success) */
444462 }
445463
@@ -493,17 +511,33 @@ ora_dbms_output_get_lines(PG_FUNCTION_ARGS)
493511
494512 if (actual_lines > 0 )
495513 {
514+ bool * line_nulls ;
515+ int lbound = 1 ; /* 1-based array indexing */
516+
496517 line_datums = (Datum * ) palloc (sizeof (Datum ) * actual_lines );
518+ line_nulls = (bool * ) palloc (sizeof (bool ) * actual_lines );
497519
498520 for (i = 0 ; i < actual_lines ; i ++ )
499521 {
500522 char * line = output_buffer -> lines [output_buffer -> read_position ++ ];
501523
502- line_datums [i ] = CStringGetTextDatum (line );
524+ /* Handle NULL lines (Oracle behavior) */
525+ if (line == NULL )
526+ {
527+ line_nulls [i ] = true;
528+ line_datums [i ] = (Datum ) 0 ;
529+ }
530+ else
531+ {
532+ line_nulls [i ] = false;
533+ line_datums [i ] = CStringGetTextDatum (line );
534+ }
503535 }
504536
505- lines_array = construct_array (line_datums , actual_lines , TEXTOID , -1 , false, TYPALIGN_INT );
537+ lines_array = construct_md_array (line_datums , line_nulls , 1 , & actual_lines , & lbound ,
538+ TEXTOID , -1 , false, TYPALIGN_INT );
506539 pfree (line_datums );
540+ pfree (line_nulls );
507541 }
508542 else
509543 {
0 commit comments