PL/SQL20 min readBy Priyanshu Pandey

PL/SQL Masterclass: Working with Large Objects (DBMS_LOB)

Master Oracle LOBs. Learn how to store, slice, search, and manipulate massive character (CLOB) and binary (BLOB) data using the DBMS_LOB package.

Development Guide · PL/SQL Masterclass

Working with Large Objects: Mastering DBMS_LOB

VARCHAR2 stops at 32KB. When you need to store gigabytes of raw JSON, XML, or binary image data, you must turn to LOBs. Learn how to manipulate them efficiently using the DBMS_LOB package.

20 min read📅August 7, 2026✍️Priyanshu Pandey📚PL/SQL Masterclass

The 32KB Limit

In PL/SQL, a VARCHAR2 variable maxes out at 32,767 bytes (and in a SQL table column, it maxes out at 4,000 bytes unless extended string sizes are enabled).

If you are integrating with an external API that returns a 50MB JSON payload, or you need to store high-res product images for an e-commerce platform, VARCHAR2 fails.

You must use LOBs (Large Objects), which can store up to 4 Terabytes (or more, depending on block size) in a single row.

How LOBs Work

LOB Locators vs Values

When you query a VARCHAR2, Oracle returns the actual string value. When you query a CLOB or BLOB, Oracle does not return the 4 Terabyte value (which would instantly crash your application's memory).

Instead, Oracle returns a LOB Locator. A locator is essentially a pointer to the physical location of the LOB data on disk. You use this locator, in conjunction with the DBMS_LOB package, to read or write the data in manageable chunks.

Reading and Writing with DBMS_LOB

Because LOBs are so massive, you generally process them iteratively.

Creating and Writing to a Temporary CLOB

If you need to build a massive string in memory (like generating a giant XML file), you create a Temporary LOB.

PL/SQL
DECLARE
  v_clob CLOB;
  v_text VARCHAR2(32767);
BEGIN
  -- 1. Create a temporary LOB in memory
  DBMS_LOB.CREATETEMPORARY(v_clob, TRUE);
  
  -- 2. Open it for writing
  DBMS_LOB.OPEN(v_clob, DBMS_LOB.LOB_READWRITE);
  
  FOR i IN 1..1000 LOOP
    v_text := 'Building a massive payload. Row: ' || i || CHR(10);
    
    -- 3. Append the varchar chunk to the end of the CLOB
    DBMS_LOB.WRITEAPPEND(v_clob, LENGTH(v_text), v_text);
  END LOOP;
  
  -- 4. Always close and free the LOB to prevent PGA memory leaks!
  DBMS_LOB.CLOSE(v_clob);
  DBMS_LOB.FREETEMPORARY(v_clob);
END;
/

Reading from a CLOB

To read a CLOB, you read it in chunks (e.g., 8000 bytes at a time) using DBMS_LOB.READ.

PL/SQL
DECLARE
  v_clob   CLOB;
  v_buffer VARCHAR2(8000);
  v_amount INTEGER := 8000;
  v_offset INTEGER := 1;
BEGIN
  SELECT payload INTO v_clob FROM api_logs WHERE id = 100;
  
  DBMS_LOB.OPEN(v_clob, DBMS_LOB.LOB_READONLY);
  
  LOOP
    BEGIN
      -- Read 8000 bytes starting at the offset
      DBMS_LOB.READ(v_clob, v_amount, v_offset, v_buffer);
      
      -- Process the chunk (e.g., print it)
      DBMS_OUTPUT.PUT_LINE(v_buffer);
      
      -- Move the offset forward for the next iteration
      v_offset := v_offset + v_amount;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        EXIT; -- End of the LOB reached
    END;
  END LOOP;
  
  DBMS_LOB.CLOSE(v_clob);
END;
/

Searching Inside a CLOB

You cannot easily use standard LIKE operators on massive CLOBs efficiently. Instead, use DBMS_LOB.INSTR to find the exact character position of a substring.

PL/SQL
DECLARE
  v_position INTEGER;
BEGIN
  -- Find the position of 'ERROR_CODE' starting at character 1, 1st occurrence
  v_position := DBMS_LOB.INSTR(v_clob, 'ERROR_CODE', 1, 1);
  
  IF v_position > 0 THEN
    -- Extract 50 characters starting from that position
    DBMS_OUTPUT.PUT_LINE(DBMS_LOB.SUBSTR(v_clob, 50, v_position));
  END IF;
END;
/

Common Gotchas

Important Gotchas

  • !

    If you call DBMS_LOB.CREATETEMPORARY in a loop and forget to call DBMS_LOB.FREETEMPORARY, you will exhaust the database's PGA memory and crash the Oracle instance. Always clean up temporary LOBs, ideally in the EXCEPTION block as well.

  • !

    You can use the || operator to concatenate a VARCHAR2 to a CLOB. However, it creates an implicit temporary LOB under the hood every single time it executes. In a loop, this is incredibly slow. Always use DBMS_LOB.WRITEAPPEND for loops.

Key Takeaways

Key Takeaways

  • Use CLOBs for text > 32KB and BLOBs for raw binary data.
  • Oracle variables hold LOB Locators (pointers), not the full LOB value.
  • Use DBMS_LOB.WRITEAPPEND and DBMS_LOB.READ to process data in manageable chunks.
  • Always free temporary LOBs to prevent catastrophic memory leaks.
RetailCoder
All systems operational
v1.0 Live

RC:OMS

Multi-channel order management with double-entry inventory ledger. Amazon, Flipkart, Shopify, WooCommerce — one source of truth.

Launch demo →
v1.0 Live

RC:Storefront

Self-hosted headless e-commerce. Your server, your data, zero transaction fees. Native RC:OMS inventory sync.

Visit Storefront →
Pipeline

RC:Pulse

AI-powered retail analytics and demand forecasting — built natively on top of your RC:OMS and Storefront data.

Request early access →
Built in India 🇮🇳  ·  Architected by Priyanshu PandeyTalk to an engineer →