Wednesday, December 17, 2025

Federated Tables in ADB-S : Simplifying Cross-Database Data Access

In the past, we have discussed accessing table hyperlinks (also known as PAR URLs) using external tables. This post focuses on a new enhancement in the Autonomous Database – Shared Infrastructure (ADB-S) platform called Federated Tables.

 

Federated Tables automate the creation of table hyperlinks, map them to external tables, and provide read-only SQL access to remote data—without requiring manual PAR URL management.

 



 

In this example, the setup is done between two databases running in OCI:

  • Source (Producer): Oracle Autonomous Database 19c
  • Target (Consumer): Oracle Autonomous Database 26ai

 

Both databases reside within the same OCI compartment. 

Step 1: Grant Scope Registration Privilege on the Source Database 

First, grant the scope registration privilege to the schema that owns the data in the source database.

 admin@ATP19C> exec dbms_data_access_admin.grant_register('DEMO',scope=>'MY$COMPARTMENT');

 PL/SQL procedure successfully completed.

  

This grants the DEMO schema permission to share data at the compartment level.

 


Step 2: Register the Creation Scope for Shared Objects

 

Next, the data owner registers the creation scope for specific objects. This authorizes consumer databases in the same compartment to create table hyperlinks remotely.

demo@ATP19C> begin
  2     dbms_data_access_scope.register_creation_scope(
  3         schema_name => user
  4         , schema_object_list => '["DEPT","BIG_TABLE"]'
  5         , scope=>'MY$COMPARTMENT' );
  6  end;
  7* /

PL/SQL procedure successfully completed.

demo@ATP19C>

 This step explicitly defines which objects can be shared. To make this sharing to happen at schema level (or) for all the (existing/upcoming) objects in the schema we can pass schema_object_list parameter as NULL

 Step 3: Grant Read Access on the Target (Consumer) Database 


On the target database, grant the required privileges to the consumer schema. 

admin@ADB26ai> grant execute on dbms_data_access to DEMO_USER; 

Grant succeeded. 


Then below grant will provide read access to the remote schema and object to the target schema DEMO_USER in the consumer database. 

Step 4: Create the Federated Table on the Consumer Database

admin@ADB26ai> begin
  2     DBMS_DATA_ACCESS_ADMIN.GRANT_READ(
  3         username => 'DEMO_USER'
  4         , remote_schema_name => 'DEMO'
  5         , remote_schema_object_name => 'DEPT' );
  6  end;
  7* / 

PL/SQL procedure successfully completed.
 
Finally, create the federated external table using the CREATE_FEDERATED_TABLE procedure. 

demo-user@ADB26ai> begin
  2     dbms_data_access.create_federated_table(
  3         table_name => 'MY_DEPT_DEMO'
  4         , remote_schema_name =>'DEMO'
  5         , remote_schema_object_name =>'DEPT'
  6         , db_ocids => '[{"region":"IAD","db_ocid":"OCID1.AUTONOMOUSDATABASE.OC1.IAD.ANUWCLJS3CXJV6AALSKNDVN2XUPBL46LP53FXJQYGOOU5K77X7BTIX2GIFKQ"}]' );
  7  end;
  8* / 

PL/SQL procedure successfully completed. 

The region and db_ocid in the above method, refers to the source (producer) database where the data resides. 

Step 5: Query the Federated Table
 
Once created, the federated table can be queried like a regular table.
 
demo-user@ADB26ai> select * from MY_DEPT_DEMO ;
 
   DEPTNO DNAME         LOC
_________ _____________ ___________
       10 ACCOUNTING    NEW YORK
       20 RESEARCH      DALLAS
       30 SALES         CHICAGO
       40 OPERATIONS    BOSTON

 

Inspecting the table metadata shows that the federated table is implemented as an external table backed by a table hyperlink.

 

demo-user@ADB26ai> select dbms_metadata.get_ddl('TABLE','MY_DEPT_DEMO') ; 
DBMS_METADATA.GET_DDL('TABLE','MY_DEPT_DEMO')
________________________________________________________________ 
  CREATE TABLE "DEMO_USER"."MY_DEPT_DEMO"
   (    "DEPTNO" NUMBER,
        "DNAME" VARCHAR2(14) COLLATE "USING_NLS_COMP",
        "LOC" VARCHAR2(13) COLLATE "USING_NLS_COMP"
   )  DEFAULT COLLATION "USING_NLS_COMP"
   ORGANIZATION EXTERNAL
    ( TYPE ORACLE_LOADER
      DEFAULT DIRECTORY "DATA_PUMP_DIR"
      ACCESS PARAMETERS
      ( RECORDS ESCAPE CHARACTERSET AL32UTF8 ALLOW MISSING FILES DELIMITED BY NEWLINE NOLOGFILE NOBADFILE NODISCARDFILE READSIZE=10000000
    FIELDS CSV WITHOUT EMBEDDED TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' MISSING FIELD VALUES ARE NULL   NOTRIM )
      LOCATION
       ( 'https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/8ldGfvy2qeSeJzDaZ_rtf2aTjutCJAURrI5yKLrk8z743dvC64fYj4IwkUzp54cw9dsHPKpaPjc/data*')
    )
   REJECT LIMIT 0
  PARALLEL

 

The LOCATION clause points to a secure HTTPS endpoint, which is the generated table hyperlink.

 

The same table hyperlink can be accessed using any REST client (such as curl, Postman, or Insomnia)

 

$ curl --location 'https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/8ldGfvy2qeSeJzDaZ_rtf2aTjutCJAURrI5yKLrk8z743dvC64fYj4IwkUzp54cw9dsHPKpaPjc/data'

{
  "items": [
    {
      "DEPTNO": 10,
      "DNAME": "ACCOUNTING",
      "LOC": "NEW YORK"
    },
    {
      "DEPTNO": 20,
      "DNAME": "RESEARCH",
      "LOC": "DALLAS"
    },
    {
      "DEPTNO": 30,
      "DNAME": "SALES",
      "LOC": "CHICAGO"
    },
    {
      "DEPTNO": 40,
      "DNAME": "OPERATIONS",
      "LOC": "BOSTON"
    }
  ],
  "hasMore": false,
  "limit": 1000,
  "offset": 0,
  "count": 4,
  "links": [
    {
      "rel": "self",
      "href": "https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/8ldGfvy2qeSeJzDaZ_rtf2aTjutCJAURrI5yKLrk8z743dvC64fYj4IwkUzp54cw9dsHPKpaPjc/data"
    }
  ]
}
 
 

Federated Tables in ADB-S provide a secure and streamlined way to:

  • Share data across Autonomous Databases
  • Eliminate manual PAR URL handling
  • Access remote data using standard SQL
  • Consume the same data via REST endpoints 

This feature significantly simplifies cross-database data sharing while maintaining strong access controls. 

 

 


Monday, December 8, 2025

Value LOBs in Oracle 26ai: The End of Chunked LOB Overhead

 
LOBs in Oracle have historically been stored as chunks, with an associated LOB index segment to allow navigation through the LOB structure. Because of this architecture, when a query returns a LOB column, the client historically receives a pointer to the LOB, and only when the client actually requests the LOB value does the database send the data piece-by-piece across the network.
 
This design still makes sense for very large LOBs, but today many modern JSON or text payloads fall into an awkward middle area: 
  • too large for VARCHAR datatypes
  • too small to justify chunking and LOB indexing overhead 
Let’s walk through a simple demonstration.

 
demo@ADB26AI> create table base_table
  2  as
  3  with base_data as (
  4     select rownum id
  5             , 'Text' || rownum as data
  6     from all_objects
  7     where rownum <= 80 )
  8  , one_clob as (
  9             select json_arrayagg(json{*} returning clob) as jdoc
 10             from base_data )
 11  select rownum as pk
 12      , one_clob.jdoc
 13  from one_clob , all_objects
 14  where rownum <= 100;
 
Table created.
 
And we will create a table with clob data type in a standard way and populate it with some source data
 
demo@ADB26AI> create table t_reference_clob( x number, y clob ) ;
 
Table created.
 
demo@ADB26AI>
demo@ADB26AI> insert into t_reference_clob select * from base_table;
 
100 rows created.
 
demo@ADB26AI> commit;
 
Commit complete.
 
Now query the table from a client session far from the database (in my case, Autonomous Database in a remote region):
 
demo@ADB26AI> select * from t_reference_clob;
 
100 rows selected.
 
Elapsed: 00:11:04.73
 
Statistics
----------------------------------------------------------
       1070  recursive calls
         17  db block gets
       5713  consistent gets
       5215  physical reads
       2504  redo size
     943880  bytes sent via SQL*Net to client
     631599  bytes received via SQL*Net from client
       2602  SQL*Net roundtrips to/from client
         59  sorts (memory)
          0  sorts (disk)
        100  rows processed
 
 
This happens because the client presumes the LOB might be arbitrarily large, so it retrieves each row’s LOB in chunks, issuing repeated network requests.
 
From 23ai onward, Oracle lets us tell the database that certain LOBs should be treated like values rather than chunked LOB objects.
 
demo@ADB26AI> create table t_value_clob( x number, y clob )
  2  lob(y) query as value;
 
Table created.
 
demo@ADB26AI> insert into t_value_clob select * from base_table;
 
100 rows created.
 
Now if I rerun the query, notice the improvements in the round trips.
 
demo@ADB26AI> select * from t_value_clob;
 
100 rows selected.
 
Elapsed: 00:00:03.12
 
Statistics
----------------------------------------------------------
         23  recursive calls
         16  db block gets
        137  consistent gets
          0  physical reads
       2796  redo size
     420380  bytes sent via SQL*Net to client
        404  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
        100  rows processed
 
 
This is all good If the Lobs are small, what if there is a mix ? we can also decide on query by query basis on how would the lob data to be retrieved.  Here is our original table query with LOB_VALUE function.
 
demo@ADB26AI> select x,lob_value(y) from t_reference_clob;
 
100 rows selected.
 
Elapsed: 00:00:03.14
 
Statistics
----------------------------------------------------------
         11  recursive calls
          9  db block gets
         16  consistent gets
        112  physical reads
       1552  redo size
     420391  bytes sent via SQL*Net to client
        404  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
        100  rows processed
 
If the data is JSON, then we can also provide the instruction to the database as part of the JSON_SERIALIZE function.
 
demo@ADB26AI> select x,json_serialize(y returning clob value) from t_reference_clob;
 
100 rows selected.
 
Elapsed: 00:00:03.12
 
Statistics
----------------------------------------------------------
         12  recursive calls
         11  db block gets
         16  consistent gets
        100  physical reads
       1700  redo size
     420414  bytes sent via SQL*Net to client
        404  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
        100  rows processed
 
 
Why this matters today. 
  • For most modern JSON use cases:
  • ORDS APIs
  • APEX pages
  • Microservices
  • Autonomous clients
  • Cloud apps 
…the payloads are typically kilobytes, not gigabytes. The default LOB architecture is overkill and causes unnecessarily high network latency.
 
With the new approach, we can treat JSON CLOB as a value, not a chunked object, dramatically reducing network round trips and improving performance—without changing the data model.
 
If your applications plan to leverage Oracle’s modern data types such as JSON or Vector, Oracle Database 26ai will store these values as VALUE LOBs by default. This means Oracle uses the VALUE LOB format internally for optimized retrieval and processing.

 
demo-user@ADB26ai> create table t ( x json ,y vector );
 
Table T created.
 
demo-user@ADB26ai> select column_name, value_based
  2  from user_lobs
  3* where table_name ='T' ;
 
COLUMN_NAME    VALUE_BASED
______________ ______________
X              YES
Y              YES

Monday, December 1, 2025

Talk to Your Oracle Database Using Natural Language in VS Code with SQLcl MCP Server

 
stop writing SQL from scratch — let AI understand your schema and generate SQL for you.
 
Oracle SQLcl 25.2+ introduced one of the most important developer features in years: native MCP (Model Context Protocol) server support. With this, Oracle becomes the first major database platform to offer a standardized way for AI assistants like ChatGPT and Claude to securely understand your schema, generate SQL, and even run queries — all from plain English.
 
In this post, we’ll walk through:
 
  • What MCP is and why it matters
  •  How SQLcl can act as an MCP Server
  • Setting up VS Code to use natural language chat with your database
  • Real demos — from simple queries to advanced analytics
  • How AI can generate reports and dashboards from your Oracle data
 
Let’s get started.
 
What is MCP (Model Context Protocol)?
 
MCP is an open-source standard for connecting AI models to real systems.
 
Just like USB-C gives your devices a universal connector, MCP gives AI a universal connector to databases, filesystems, tools, and workflows
.
 


 
With MCP:
 
  • An AI assistant can inspect your database schema
  • Generate SQL queries
  • Execute them only with your permission
  • Produce dashboards, summaries, or reports
  • Plug into developer tools like VS Code
 
Oracle SQLcl now supports this protocol natively — no separate servers, plugins, or bridges needed.

 
SQLcl as an MCP Server
 
SQLcl 25.2 introduced the new command:

 
sql -mcp
 
Running this transforms SQLcl into a live MCP Server, allowing AI clients to talk to the database through a safe, controlled interface.
 
Example:

 
C:\Users\Rajeshwaran Jeyabal> sql -mcp
---------- MCP SERVER STARTUP ----------
MCP Server started successfully on Fri Nov 28 19:27:09 IST 2025
Press Ctrl+C to stop the server
----------------------------------------
 
This server acts as a secure gateway — the AI can propose SQL, but you must approve execution.
 
 
Prerequisites
 
Before beginning, ensure the following: 
  •  Visual Studio Code v1.101 or later
  • Oracle SQL Developer Extension for VS Code (version 25.2.0+)
  • At least one Oracle Database connection with password saved
 
Once this setup is complete, the chat panel in VS Code will automatically detect the MCP tools exposed by SQLcl.

 
Saving a Database Connection for MCP
 
First create a saved connection in SQLcl — MCP relies on this.

 
C:\Trash> sql /nolog
SQLcl: Release 25.3 Production on Thu Nov 27 20:46:15 2025
idle> conn hr/hr@localhost:1521/ora23ai
Connected.
hr@ORA23AI> connect -savepwd -save hr_local_mcp
Name: hr_local_mcp
Connect String: localhost:1521/ora23ai
User: hr
Password: ******
 
Now the MCP server will be able to use this connection automatically.
 
 
See It in Action — Talking to Your Database in Natural Language
 
Open the Chat Panel in VS Code.
You will notice SQLcl’s MCP tools automatically appear on the left sidebar.
 
This confirms that VS Code + AI Assistant + SQLcl MCP Server are connected.

 


 
 
Example 1 — “Show me all tables with their data volume”
 
You simply ask the AI:
 
Can you connect to the HR database and show me all tables with their data volume?
 
Claude / ChatGPT will: 
  • Check available MCP tools
  • Propose a SQL query
  • Ask for your confirmation
  • Execute it through SQLcl
  • Return a neat table of row counts
This ensures safety — nothing runs without approval.

 

 
Claude always asks permission prior to executing any queries. We can see exactly what it plans to execute before approving.
 


 
 
Example 2 — Analyzing Employees Hired in 2008
 
You ask:

 
Show me employees hired in 2008, grouped by department, with average salary for each group. Also show the highest-paid employee in each department.
 
AI generates a multi-part SQL including:
  • Filtering by hire year
  • GROUP BY analyses
  • JOINs to departments
  • Window functions to identify the highest salary
 
And after you approve, the results come back instantly.

 
 


 
Example 3 — AI-Generated Analytics Dashboard (Markdown Report)
 
Now let’s ask something more advanced:
 
Can you create a comprehensive HR dashboard showing: department headcount, salary ranges, recent hiring trends, and identify any departments that might need attention based on salary distribution or hiring patterns. Create the report as MarkDown
 
The AI will:
 
  • Pull multiple SQL queries
  • Aggregate the results
  • Identify anomalies/trends
 
Generate a clean Markdown report that looks like this:
 
HR Dashboard (Generated by AI)
1. Department Headcount
 
                Sales — 34 employees
                IT — 19 employees
                Marketing — 12 employees
                Finance — 11 employees
 
2. Salary Distribution
 
                IT: Highest variance, indicates mixed seniority
                Sales: Several outliers with high commission-based compensation
                Finance: Narrow salary band → stable structure
 
3. Recent Hiring Trends
 
                Hiring spikes in Q2 and Q4
                Marketing hired heavily last year due to campaign cycle
 
4. Departments Needing Attention
 
                IT — high salary spread
                Marketing — rapid hiring, potential onboarding load

 
 




 
This entire dashboard was produced using: 
  • Your HR schema
  • SQL generated automatically
  • Data analyzed via AI
  • Result formatted into Markdown
 No SQL written manually.
 
Why This Matters
 
This workflow fundamentally changes how developers work with Oracle:
 
  • No need to remember every syntax detail
  • No need to hand-craft queries
  • Faster exploration of schema and data
  • Insightful reports without BI tools
  • Safe execution (AI asks before running SQL)
  • Works locally — no cloud dependency
 
With SQLcl MCP Server, your database becomes conversational.
 
Conclusion
 
Oracle has taken a major step forward by bringing MCP support directly into SQLcl. Combined with VS Code AI chat, developers can now:
 
  • Query databases in plain English
  • Let AI generate complex joins and analytics
  • Approve execution safely
  • Produce dashboards and reports instantly
 
This is the future of database development — not replacing SQL, but removing the friction around writing it.