1000+ companies including Fortune 500 and Global 2000 use Ispirer solutions. Join the champions.
Migration opportunities with Ispirer
Ispirer Ecosystem automates your migration routine to enable quick and smart transformation of any database. Double the migration speed with our comprehensive solutions.
Our modernization and migration approach
We select the right conversion approach based on business specifics, project scope, complexity, and risk profile.
-
Rule-Based
Deterministic conversion
Engine
SQLWays, CodeWays
Automation & coverage
~70–80% automated coverage out of the box, with the option to reach up to 90% through manual refinement, refactoring, validation, and QA
What you get
Predictable scope and timeline, stable and repeatable output
Best for
Well-defined, structured migrations
-
Recommended
Hybrid
Rules + AI-assisted refinement
Engine
SQLWays, CodeWays + AI
Automation & coverage
~70–80% automated coverage, up to 90% with AI, reducing manual conversion, validation, and testing
What you get
Predictability of the rule-based engine + speed of AI, backed by the Ispirer expert framework
Best for
Complex or partially undocumented systems
-
AI-Driven
AI-led analysis and delivery
Engine
AI engine
Automation & coverage
AI-led code and business logic extraction by Ispirer Migration Experts
What you get
AI-assisted refactoring, code generation and documentation, human-led QA, insights into undocumented logic and target design
Best for
Iterative modernization and innovation-driven transformation
The approach is defined during the Discovery Phase, based on business specifics, source system complexity, target state, timeline, and expected business value.
Ispirer Ecosystem for automated migration
Ispirer Toolkit is a solution for automated heterogeneous database migration. Using it, you can transfer tables and data, stored procedures, functions, packages, views, and triggers. This solution is based on an intelligent proprietary algorithm that analyzes data types, relationships between objects, reserved words, and code structures that do not have equivalents in a target technology.
AI-powered SQLWays
Ispirer Systems is an ISO/IEC 27001 certified organization. We adhere to the highest international standards of information security.
Oracle to PostgreSQL migration steps
A proven end-to-end approach that turns complex Oracle-to-PostgreSQL migration into a clear, manageable process.
Ispirer Toolkit converts the full database schema: tables, indexes, constraints, views, sequences, triggers, stored procedures, functions, and packages. PL/SQL is automatically converted to PL/pgSQL. Oracle-specific constructs — including hierarchical queries (CONNECT BY), dynamic SQL, collections, and native packages — are handled by the toolkit's rule engine.
Where automation hits a limit, Ispirer engineers add custom conversion rules, typically within 3–5 business days.
Migrate Smarter. Evolve Faster
Over 150 migration directions- PostgreSQL
- Oracle
- AlloyDB
- SQL Server
- Informix
- MySQL
- DB2
- MariaDB
- Sybase ASE
- PostgreSQL
- Oracle
- AlloyDB
- SQL Server
- Informix
- MySQL
- DB2
- MariaDB
- Sybase ASE
- MSSQL
- COBOL
- Azure
- Progress 4GL
- SAP
- PowerBulder
- .NET
- Delphi
- MSSQL
- COBOL
- Azure
- Progress 4GL
- SAP
- PowerBulder
- .NET
- Delphi
Designed for continuity
Every old system carries years of decisions inside it, some good, some made under pressure nobody remembers anymore. My team's job is to understand that history well enough to carry forward what actually works, instead of throwing it out and starting over. That's what I find genuinely interesting about this work: nothing gets lost just because it's old, it either keeps running or turns into something better.
Cloud migration software
Ispirer Toolkit facilitates seamless database migration to both on-premises and cloud environments. This includes Oracle to PostgreSQL migration, with full support for Google Cloud SQL, Amazon RDS, Oracle Cloud Infrastructure, and Azure Database.
Gooole Cloud
Take advantage of the Google Cloud Database Modernization Program
AWS
Discover our tool-driven methodology to move your data infrastructure to AWS
Oracle Cloud
Unlock a streamlined path to modernize databases on Oracle Cloud
Azure
Modernize your systems on Microsoft Azure with seamless migration
Move your migration project to the next level. Migrate logic from database to application
Ispirer has a solution to unlock the full potential of your database. Our team helps you to move business logic to an application layer seamlessly to advance the database performance.
Source Database
- Oracle
ODBC
Files With Business Logic SQL Code
- Oracle
Seamless integration, limitless possibilities!
Application Target Code
- Java
- JDBC
- Spring
- Hibernate
Unlock agility: shift your database logic to the application layer!
Transform faster, scale smarter—see how moving from database to application layer drives real results. Let’s modernize it together.
The world’s most innovative companies are building their next big thing with Ispirer
Magnit, CardinalHealth, Worldline and more have adopted SQLWays to boost their innovation life-cycle accelerate and manage their end-to-end innovation lifecycle
All testimonialsMigration details overview
Ispirer Toolkit automates the entire migration of database objects from Oracle to PostgreSQL.
-
Two ways to migrate your database
1Ispirer Toolkit automates the entire migration of database objects from Oracle to PostgreSQL.
recommended2Convert files containing Oracle PL/SQL scripts without connecting directly to the source database.
-
Ispirer Toolkit migrates the following objects
views tables functions triggers procedures sequences packages collection and object typesAs a result, each separate database object is converted to its equivalent in PostgreSQL.
If you have your own applications, the embedded SQL and database APIs can be converted using either Ispirer Toolkit or Ispirer Service. They will be able to work with your new PostgreSQL database.
Migration demo
Check out how Ispirer Toolkit migrates databases efficiently, minimizing the need for manual corrections
Migrate your data without limits!
Need migrations with near-zero downtime and reliable recovery?
Our automated migration service handles everything — without middleware, without altering your source database, and without requiring unique columns.
Oracle Database to PostgreSQL Migration Challenges and How Ispirer Toolkit Overcomes Them
| Aspect | Oracle Database | PostgreSQL | Ispirer |
|---|---|---|---|
| Licensing | Enterprise Edition per processor, Standard Edition per processor. Annual support costs | Completely free and open source under PostgreSQL License with no licensing fees or usage limitations | Provides project-based or time-boxed licenses |
| Ownership | Owned by Oracle Corporation as a proprietary commercial product | Open source project maintained by PostgreSQL Global Development Group | Ispirer Systems, LLC |
| SQL Language | Uses PL/SQL (Procedural Language/SQL) with robust procedural capabilities and proprietary extensions | Uses standard SQL with PL/pgSQL procedural language and supports multiple procedural languages including PL/Python, PL/Perl, and PL/Tcl | Converts SQL code to PL/pgSQL automatically, including packages, stored procedures, functions, and triggers; handles Oracle-specific constructs and syntax differences |
| Basic Data Types | Uses NUMBER with precision and scale for numeric data; DATE for dates; XMLTYPE for XML; supports FLOAT as NUMBER subtype, string datatypes | Extensive data types including NUMERIC, INTEGER variants, native arrays, JSON, JSONB, UUID, geometric types, and custom user-defined types | Provides global and local data type mapping engines; automatically maps Oracle types (NUMBER, DATE, XMLTYPE, etc.) to optimal PostgreSQL equivalents (NUMERIC, TIMESTAMP, XML, etc.) and others |
| Indexing Options | B-tree (default), bitmap indexes for low-cardinality columns, function-based indexes, domain indexes, reverse key indexes | B-tree (default), GIN, GiST, BRIN, SP-GiST indexes; supports partial/conditional indexes and specialized indexing for various data types | Automatically recreates indexes during migration; translates Oracle index structures to PostgreSQL equivalents; drops unsupported Oracle-specific options |
6 undeniable facts to choose conversion with Ispirer
-
Reduced costs
Migrating to a more efficient PostgreSQL database can lower operational costs by reducing hardware and software maintenance requirements, optimizing resource utilization, and lowering licensing fees.
-
Modernization & innovation
Migrating to PostgreSQL can enable the adoption of new technologies and features, unlocking new business opportunities and driving innovation. It also creates room for future growth.
-
Added AI precision
An AI-driven migration toolkit can automate complex tasks, reduce errors, optimize workflows, and accelerate the process, ensuring smoother transitions while minimizing costly system downtime.
-
Enhanced security
Newer databases often incorporate advanced security features like encryption, access controls, and threat detection mechanisms, providing better protection against data breaches and cyberattacks.
-
Legacy transformation
Migrating legacy databases to modern systems can upgrade your database, making it easier to maintain, update, and extend in the long run. This creates a more flexible foundation for future growth.
-
No need for documentation
We perform the migration using the source code. There is no need for detailed documentation to begin the migration as there is in development. Our tools analyze the source code and database structure automatically.
Conversion Samples of Oracle to PostgreSQL
Ispirer Toolkit analyzes all object dependencies during the conversion process and provides not only line-by-line conversion, but resolves type conversions as well. The software understands and transforms the necessary inheritance dependencies. It parses the entire source code, builds an internal tree with all the information about the objects, and uses it in the migration process.
Oracle Collections conversion
-
Oracle
- CREATE TYPE employee AS OBJECT (
- id NUMBER,
- Name VARCHAR(300)
- );
- CREATE TYPE employees_tab IS TABLE OF employee;
- CREATE OR REPLACE PROCEDURE hire(EMPLOYEES in out employees_tab, id NUMBER, Name VARCHAR) AS
- NEW_EMPLOYEES employees_tab := employees_tab();
- BEGIN
- EMPLOYEES.Extend(1);
- EMPLOYEES(EMPLOYEES.count) := employee(id, Name);
- FOR i IN EMPLOYEES.first..EMPLOYEES.last
- LOOP
- INSERT INTO emp_tab values (EMPLOYEES(i).id, EMPLOYEES(i).Name);
- END LOOP;
- INSERT INTO EMP_TAB SELECT * FROM TABLE(EMPLOYEES);
- NEW_EMPLOYEES.Extend(EMPLOYEES.count);
- NEW_EMPLOYEES.Delete;
- END;
→ PostgreSQL
- CREATE TYPE employee AS(id NUMERIC,Name VARCHAR(300));
- -- CREATE TYPE employees_tab IS TABLE OF employee;
- CREATE OR REPLACE PROCEDURE hire(INOUT EMPLOYEES employee[] , id NUMERIC, Name VARCHAR)
- LANGUAGE plpgsql
- AS $$
- DECLARE
- NEW_EMPLOYEES employee[] default array[]:: employee[];
- BEGIN
- EMPLOYEES[coalesce(array_length(EMPLOYEES,1),0)+1] := null;
- EMPLOYEES[coalesce(array_length(EMPLOYEES,1),0)] := row(id,Name);
- FOR i IN array_lower(EMPLOYEES,1) .. array_upper(EMPLOYEES,1)
- LOOP
- INSERT INTO emp_tab values(EMPLOYEES[i].id, EMPLOYEES[i].Name);
- END LOOP;
- INSERT INTO EMP_TAB SELECT * FROM UNNEST(EMPLOYEES);
- for i in 1 .. coalesce(array_length(EMPLOYEES,1),0) loop
- NEW_EMPLOYEES[coalesce(array_length(NEW_EMPLOYEES,1),0)+1] := null;
- end loop;
- NEW_EMPLOYEES := array[]:: employee[];
- END; $$;
Package objects transformation
-
Oracle
- CREATE OR REPLACE EDITIONABLE PACKAGE BODY "COMMON_PKG" AS
- CUSTOMER_ID NUMBER(10,0);
- TYPE VARCHAR2_AARAY IS TABLE OF VARCHAR2(50) INDEX BY PLS_INTEGER;
- ADDRES_LST VARCHAR2_AARAY;
- PROCEDURE PREPARE_CUSTOMER_ADRESSS_BY_ID(CITY_NAME VARCHAR2, CUSTTYPE_ID VARCHAR2)
- IS
- CUR_ADDR VARCHAR2(500);
- CUSTM_ID NUMBER;
- v_int number;
- V_RES DBMS_UTILITY.lname_array;
- l_clob clob;
- cursor cus_addr(cur_id number) is select address from customer where cust_id = cur_id or cust_id <5;
- BEGIN
- l_clob := '';
- select CUST_ID into CUSTM_ID
- from customer
- where CITY = CITY_NAME and CUST_TYPE_CD = CUSTTYPE_ID and ROWNUM <= 1;
- open cus_addr(CUSTM_ID);
- fetch cus_addr into CUR_ADDR;
- WHILE(cus_addr%found)
- loop
- l_clob := l_clob || CUR_ADDR||',';
- fetch cus_addr into CUR_ADDR;
- end loop;
- if cus_addr%isopen then
- close cus_addr;
- end if;
- dbms_output.put_line( rtrim(l_clob,',') );
- END;
- PROCEDURE GET_FIST_NAME_OF_EMPLOYEE_BY_START_DATE(STRT_DATE DATE) is
- EMPLOYEE_REC EMPLOYEE%ROWTYPE;
- cursor cur_start_date is select * from EMPLOYEE;
- BEGIN
- open cur_start_date;
- fetch cur_start_date into EMPLOYEE_REC;
- WHILE(cur_start_date%found)
- loop
- if EMPLOYEE_REC.START_DATE < STRT_DATE THEN
- goto loop_again;
- end if;
- DBMS_OUTPUT.PUT_LINE(EMPLOYEE_REC.FIRST_NAME || ' ' ||EMPLOYEE_REC.LAST_NAME );
- <<loop_again>>
- fetch cur_start_date into EMPLOYEE_REC;
- end loop;
- if cur_start_date%isopen then
- close cur_start_date;
- end if;
- END;
- END COMMON_PKG;
→ PostgreSQL
- CREATE SCHEMA IF NOT EXISTS COMMON_PKG;
- -- TYPE VARCHAR2_AARAY IS TABLE OF VARCHAR2(50) INDEX BY PLS_INTEGER;
- DROP TYPE IF EXISTS COMMON_PKG.GL_VAR_TYPE CASCADE;
- CREATE type COMMON_PKG.GL_VAR_TYPE
- as(CUSTOMER_ID BIGINT,
- ADDRES_LST VARCHAR(50)[]);
- CREATE OR REPLACE FUNCTION COMMON_PKG.INIT_GL_VAR()
- RETURNS VOID LANGUAGE plpgsql
- AS $$
- BEGIN
- CREATE TEMPORARY TABLE COMMON_PKG_GL_VAR AS SELECT(array[]:: VARCHAR(50)[]):: COMMON_PKG.GL_VAR_TYPE AS SWV_GL_VAR_VAL;
- RETURN;
- EXCEPTION
- WHEN SQLSTATE '42P07' THEN
- NULL;
- END; $$;
- CREATE OR REPLACE FUNCTION COMMON_PKG.GET_GL_VAR()
- RETURNS COMMON_PKG.GL_VAR_TYPE LANGUAGE plpgsql
- AS $$
- DECLARE
- SWV_GL_VAR COMMON_PKG.GL_VAR_TYPE;
- BEGIN
- RETURN(select SWV_GL_VAR_VAL:: COMMON_PKG.GL_VAR_TYPE from COMMON_PKG_GL_VAR);
- EXCEPTION
- WHEN OTHERS THEN
- PERFORM COMMON_PKG.INIT_GL_VAR();
- RETURN(select SWV_GL_VAR_VAL:: COMMON_PKG.GL_VAR_TYPE from COMMON_PKG_GL_VAR);
- END; $$;
- CREATE OR REPLACE PROCEDURE COMMON_PKG.SET_GL_VAR(SWP_GLVAR COMMON_PKG.GL_VAR_TYPE)
- LANGUAGE plpgsql
- AS $$
- BEGIN
- UPDATE COMMON_PKG_GL_VAR SET SWV_GL_VAR_VAL = SWP_GLVAR;
- END; $$;
- CREATE OR REPLACE PROCEDURE COMMON_PKG.GET_CUSTID_BY_PARAMS(CITY_NAME VARCHAR,
- CUST_ID_CD VARCHAR,
- OUT CUST_ID NUMERIC)
- LANGUAGE plpgsql
- AS $$
- DECLARE
- SWV_GL_VAR COMMON_PKG.GL_VAR_TYPE DEFAULT COMMON_PKG.GET_GL_VAR();
- IN_ID BIGINT;
- BEGIN
- select CUST_ID into STRICT IN_ID
- from CUSTOMER
- where CITY = CITY_NAME and CUST_TYPE_CD = CUST_ID_CD LIMIT 1;
- CUST_ID := IN_ID;
- END; $$;
- CREATE OR REPLACE PROCEDURE COMMON_PKG.PREPARE_CUSTOMER_ADRESSS_BY_ID(CITY_NAME VARCHAR, CUSTTYPE_ID VARCHAR)
- LANGUAGE plpgsql
- AS $$
- DECLARE
- SWV_GL_VAR COMMON_PKG.GL_VAR_TYPE DEFAULT COMMON_PKG.GET_GL_VAR();
- CUR_ADDR VARCHAR(500);
- CUSTM_ID NUMERIC;
- v_int NUMERIC;
- V_RES VARCHAR(4000)[] default array[]:: VARCHAR(4000)[];
- l_clob TEXT;
- CUS_ADDR cursor(cur_id NUMERIC) FOR select ADDRESS from CUSTOMER where cust_id = cur_id or cust_id < 5;
- BEGIN
- l_clob := '';
- select CUST_ID into STRICT CUSTM_ID
- from CUSTOMER
- where CITY = CITY_NAME and CUST_TYPE_CD = CUSTTYPE_ID LIMIT 1;
- open CUS_ADDR(CUSTM_ID);
- fetch CUS_ADDR into CUR_ADDR;
- WHILE FOUND
- loop
- l_clob := CONCAT(l_clob,CUR_ADDR,',');
- fetch CUS_ADDR into CUR_ADDR;
- end loop;
- if EXISTS(SELECT 1 FROM pg_cursors WHERE NAME ilike 'CUS_ADDR') then
- close CUS_ADDR;
- end if;
- RAISE NOTICE '%',NULLIF(rtrim(l_clob,','),'');
- END; $$;
- CREATE OR REPLACE PROCEDURE COMMON_PKG.GET_FIST_NAME_OF_EMPLOYEE_BY_START_DATE(STRT_DATE TIMESTAMP)
- LANGUAGE plpgsql
- AS $$
- DECLARE
- SWV_GL_VAR COMMON_PKG.GL_VAR_TYPE DEFAULT COMMON_PKG.GET_GL_VAR();
- EMPLOYEE_REC EMPLOYEE%ROWTYPE;
- CUR_START_DATE cursor FOR select * from EMPLOYEE;
- BEGIN
- open CUR_START_DATE;
- fetch CUR_START_DATE into EMPLOYEE_REC;
- WHILE FOUND
- loop
- << loop_again >>
- BEGIN
- if EMPLOYEE_REC.START_DATE < STRT_DATE THEN
- EXIT loop_again;
- end if;
- RAISE NOTICE '%',CONCAT(EMPLOYEE_REC.FIRST_NAME,' ',EMPLOYEE_REC.LAST_NAME);
- END;
- fetch CUR_START_DATE into EMPLOYEE_REC;
- end loop;
- if EXISTS(SELECT 1 FROM pg_cursors WHERE NAME ilike 'CUR_START_DATE') then
- close CUR_START_DATE;
- end if;
- END; $$;
Hierarchical query conversion
-
Oracle
- create or replace Procedure sp_hier_with_cte_and_rownum (configList IN varchar2)
- IS
- refcur sys_refcursor;
- BEGIN
- FOR refcur IN (
- with test as
- (select configList from dual)
- select regexp_substr(configList, '[^;]+', 1, rownum) config
- from test
- connect by level <= length (regexp_replace(configList, '[^;]+')) +1
- )
- LOOP
- dbms_output.put_line('config= '||refcur.config);
- END LOOP;
- END;
→ PostgreSQL
- create or replace Procedure sp_hier_with_cte_and_rownum(IN configList VARCHAR)
- LANGUAGE plpgsql
- AS $$
- DECLARE
- refcur REFCURSOR;
- SWV_REFCUR_rec RECORD;
- BEGIN
- FOR SWV_REFCUR_rec IN(
- WITH RECURSIVE
- test as(select configList),
- TabAl_cte AS(SELECT 1 AS LEVEL
- UNION ALL
- SELECT TabAl_cte.LEVEL+1 AS LEVEL
- FROM TabAl_cte, test
- WHERE(TabAl_cte.LEVEL+1) <= length(regexp_replace(test.configList,'[^;]+','','g'))+1)
- SELECT SWF_REGEXP_SUBSTR(test.configList,'[^;]+',1,row_number() over()) AS config
- FROM TabAl_cte,test)
- LOOP
- RAISE NOTICE '%',CONCAT('config= ',SWV_REFCUR_rec.config);
- END LOOP;
- END; $$;
Dynamic code conversion
-
Oracle
- CREATE OR REPLACE PROCEDURE DYNAMIC_DELETE
- AS
- TAB_NAME VARCHAR2(15):='FOR_TYPE';
- TAB_COL VARCHAR2(12):='COL1';
- TAB_COL2 VARCHAR2(12):='COL2';
- COL_VALUE INTEGER:=2000;
- SQL_DELETE VARCHAR2(200);
- BEGIN
- SQL_DELETE:='DELETE '||TAB_NAME||' WHERE ' || TAB_COL2 || '=SYSDATE+5 AND ' ||TAB_COL||' < :value ';
- EXECUTE IMMEDIATE SQL_DELETE USING COL_VALUE;
- EXECUTE IMMEDIATE 'begin EXAMPLE_PROC; end;';
- END;
→ PostgreSQL
- CREATE OR REPLACE PROCEDURE DYNAMIC_DELETE()
- LANGUAGE plpgsql
- AS $$
- DECLARE
- TAB_NAME VARCHAR(15) DEFAULT 'FOR_TYPE';
- TAB_COL VARCHAR(12) DEFAULT 'COL1';
- TAB_COL2 VARCHAR(12) DEFAULT 'COL2';
- COL_VALUE INTEGER DEFAULT 2000;
- SQL_DELETE VARCHAR(200);
- BEGIN
- SQL_DELETE := 'DELETE FROM ' || TAB_NAME || ' WHERE ' || TAB_COL2 || '= LOCALTIMESTAMP+INTERVAL ''5 day'' AND ' || TAB_COL || ' <%1$L ';
- EXECUTE format(SQL_DELETE,COL_VALUE);
- EXECUTE 'DO LANGUAGE plpgsql $anonymous_block$ BEGIN CALL EXAMPLE_PROC(); END; $anonymous_block$';
- END; $$;
PRAGMA AUTONOMOUS_TRANSACTION conversion
-
Oracle
- CREATE PROCEDURE AUTO_TEST (id_value number, text_value varchar2)
- IS
- PRAGMA AUTONOMOUS_TRANSACTION;
- BEGIN
- INSERT INTO AUTONOMOUS_EVENT (id, value)
- VALUES(id_value, text_value);
- COMMIT;
- END AUTO_TEST;
→ PostgreSQL
- CREATE EXTENSION IF NOT EXISTS dblink;
- --use superuser to run this script
- CREATE SERVER SWL_targetDBname_link FOREIGN DATA WRAPPER dblink_fdw
- OPTIONS (hostaddr '127.0.0.1', dbname 'targetDBname');
- CREATE USER MAPPING FOR targetUser SERVER SWL_targetDBname_link
- OPTIONS (user 'targetUser', password 'pass');
- GRANT USAGE ON FOREIGN ERVER SWL_targetDBname_link TO targetUser;
- -- procedure code
- CREATE OR REPLACE PROCEDURE AUTO_TEST(id_value DOUBLE PRECISION, text_value VARCHAR,IN is_recursive BOOLEAN DEFAULT false)
- LANGUAGE plpgsql
- AS $$
- DECLARE
- v_sql text;
- BEGIN
- IF is_recursive = FALSE THEN
- BEGIN
- IF NOT EXISTS(SELECT 1 FROM DBLINK_GET_CONNECTIONS()
- WHERE dblink_get_connections@> '{myconn}') THEN
- PERFORM DBLINK_CONNECT('myconn','SWL_targetDBname_link');
- END IF;
- v_sql := FORMAT('CALL AUTO_TEST( id_value => %L, text_value => %L, is_recursive => TRUE )',id_value,text_value);
- PERFORM DBLINK('myconn',v_sql);
- END;
- ELSE
- --procedure body
- INSERT INTO AUTONOMOUS_EVENT(ID, VALUE)
- VALUES(id_value, text_value);
- COMMIT;
- END IF;
- END; $$;
XML functions conversion
-
Oracle
- with demo1 as(
- select XMLType(
- '<hello-world>
- <word seq="1">Hello</word>
- <word seq="2">world</word>
- </hello-world>
- ') XML
- from dual
- )
- select
- t.xml.extract('//word[@seq=1]/text()').getStringVal() col1
- , decode(t.xml.extract('//word[@seq=1]/text()').getStringVal(), 'Hello', 'Hell', 'END') col2
- from demo1 t
→ PostgreSQL
- with demo1 as(select '<hello-world>
- <word seq="1">Hello</word>
- <word seq="2">world</word>
- </hello-world>
- ':: xml AS XML)
- select(trim(replace(xpath('//word[@seq=1]/text()',T.XML):: text,',',''),'{}'):: xml):: text AS COL1
- , CASE(trim(replace(xpath('//word[@seq=1]/text()',T.XML):: text,',',''),'{}'):: xml):: text WHEN 'Hello' THEN 'Hell' ELSE 'END' END AS COL2
- from demo1 T;
Get a free sample code of our Oracle to PostgreSQL conversion
Ispirer Toolkit automatically converts not only a single piece of code, but an entire database. Complex code will require customization of the toolkit
Useful articles about database migration
Take control of your database migration now
Consult with our expert to better organize for you migration flow.
Frequently Asked Questions
Get answers to the most common questions about database migration.
Want more details?
Request a consultation with our expert
How does the migration tool handle complex Oracle PL/SQL packages and stored procedures?
Ispirer Toolkit parses the full source code of each Oracle package — both specification and body — and builds an internal dependency tree. Package-level variables and constants are migrated to tables with getter/setter functions. Procedures and functions are converted to PL/pgSQL equivalents. Where Oracle constructs have no direct PostgreSQL equivalent, the toolkit generates user-defined functions that replicate the original behavior.
Oracle-specific features like PRAGMA AUTONOMOUS_TRANSACTION, UTL_FILE, and DBMS_LOB are handled through dblink extensions and custom conversion rules.
What is the free tool for Oracle to PostgreSQL migration?
Ispirer offers InsightWays — a free assessment tool that connects to your Oracle database, analyzes all objects and structures, and produces a complexity and scope report before you commit to migration. The Ispirer Toolkit itself is also available for a free trial with no payment required.
Why Oracle to PostgreSQL migration?
Oracle's licensing model creates a substantial financial burden — per processor, per edition, with annual support costs. PostgreSQL is open source and free to use. Moving from Oracle to PostgreSQL eliminates vendor lock-in, reduces infrastructure costs, opens access to modern extensions without additional cost, and improves cloud readiness across AWS, GCP, and Azure.
How to load data from Oracle to PostgreSQL?
Ispirer handles data migration directly — without middleware, without altering the source database, and without requiring unique columns. It supports parallel migration threads, custom data type mapping, BLOB migration at full speed, and Change Data Capture (CDC) for near-zero downtime scenarios.
How to export data from Oracle to PostgreSQL?
The recommended approach is a live connection from Ispirer Toolkit to the source Oracle database via ODBC — this gives the tool full visibility into object dependencies and data types. Alternatively, files containing PL/SQL scripts can be converted without a live connection. Ispirer tools read from Oracle in read-only mode with no changes made to the source system.
Is PostgreSQL slower than Oracle?
Not inherently. Performance differences typically arise from configuration and query optimization rather than the database engine itself. Code optimized for Oracle needs to be reviewed and tuned for PostgreSQL after migration — this is a standard step in every Ispirer migration project.
Does Oracle support PostgreSQL?
Oracle Corporation does not provide tools or support for migrating to PostgreSQL. Ispirer Toolkit specifically bridges this gap with a 20,000+ rule engine that handles Oracle-specific constructs, data types, and procedural language differences.
Can you export all of your data from Oracle?
Yes. Ispirer Data Migrator supports migration of all Oracle data types, including BLOB, CLOB, RAW, LONG, XMLType, and spatial data. The tool reads from Oracle in read-only mode with no dependency on unique columns or specific table structures.
How to migrate from Oracle to PostgreSQL using Ora2Pg?
Ora2Pg is a free open-source Oracle to Postgres migration tool that handles basic schema migration and data export. It requires significant manual effort for complex PL/SQL, Oracle packages, hierarchical queries, and dynamic SQL. For large-scale or complex migrations, automated tools like Ispirer Toolkit offer significantly higher automation rates and dedicated expert support.
What percentage of Oracle-specific code can be automatically converted to PostgreSQL's PL/pgSQL?
Automation rates depend heavily on code complexity. For straightforward schema and simple stored procedures, automation routinely exceeds 90%. For codebases heavy in Oracle-specific features, rates vary and are assessed during pre-migration analysis. Ispirer's InsightWays tool provides a complexity index per object so you can estimate manual effort before the project begins. Customization of the toolkit can further increase automation — up to 95% as demonstrated in the Magnit Global project.
How are Oracle-specific data types, such as NUMBER, VARCHAR2, and RAW, mapped to PostgreSQL?
Ispirer Toolkit includes both global and local data type mapping engines. Oracle NUMBER maps to NUMERIC, VARCHAR2 to VARCHAR, DATE to TIMESTAMP, XMLTYPE to XML, RAW to BYTEA. Users can override default mappings at the object or column level where project requirements differ.
Does the automated solution support the migration of partitioned tables and advanced indexing?
Yes. Ispirer Toolkit migrates partitioned tables, translating Oracle's partitioning syntax to PostgreSQL's native declarative partitioning. Oracle index types are translated to their PostgreSQL equivalents — B-tree, GIN, GiST, BRIN, partial indexes. Oracle-specific index options with no PostgreSQL equivalent are dropped with logged warnings.
What strategies are used to handle Oracle's global temporary tables in a PostgreSQL environment?
Ispirer converts Oracle global temporary tables to PostgreSQL temporary tables using ON COMMIT DELETE ROWS or ON COMMIT PRESERVE ROWS behavior depending on the Oracle table's configuration, and adjusts any code that references them accordingly.
Can the tool migrate hierarchical queries (e.g., CONNECT BY) to PostgreSQL's Common Table Expressions (CTE)?
Yes. Oracle CONNECT BY hierarchical queries are converted to PostgreSQL WITH RECURSIVE CTEs. The toolkit handles CONNECT BY LEVEL, CONNECT BY PRIOR, START WITH, and NOCYCLE clauses. A direct before/after example is available in the code samples section above.
How is data integrity validated between the source Oracle database and the target PostgreSQL instance?
Ispirer performs data integrity testing using snapshots of the source database. Migrated data in PostgreSQL is compared against source Oracle data using automated checks and scenario-based testing derived from the source application's actual usage patterns. Discrepancies are logged, analyzed, and corrected before production cutover.
Does the migration process support near-zero downtime for high-availability production environments?
Yes. Ispirer uses Change Data Capture (CDC) to replicate ongoing data changes from Oracle to PostgreSQL while the source remains live. Preliminary cold-data migration is performed in advance for large datasets, reducing the final cutover window significantly. The 12 TB in 12 hours case study above demonstrates this approach in production.
How are Oracle sequences, triggers, and views transformed during the automated migration?
Oracle sequences are migrated to PostgreSQL sequences with matching start values and increment settings. Triggers are converted to PostgreSQL trigger functions plus a trigger definition that calls the function. Views are converted directly to PostgreSQL view syntax. All three object types are included in the full automated migration run.
What are the primary performance considerations when moving large-scale Oracle workloads to PostgreSQL?
The main areas to address are query plan differences, index strategy, connection pooling, VACUUM and autovacuum configuration for write-heavy tables, and partitioning design. Ispirer's post-migration optimization step addresses these systematically.
How does the Ispirer Toolkit automate the conversion of Oracle PL/SQL to PostgreSQL PL/pgSQL?
The toolkit parses each Oracle object's source code, builds a full syntax tree including type information and inter-object dependencies, and applies its rule engine (20,000+ rules) to produce PL/pgSQL output. It handles data type resolution, cursor behavior, exception handling, GOTO statement transformation, and built-in function substitution.
What specific Oracle features (e.g., Packages, Triggers, Sequences) can the tool convert automatically?
Ispirer Toolkit converts: tables and all constraints, indexes, views, sequences, functions, stored procedures, packages (specification and body), triggers, collection types (associative arrays, nested tables, varrays), object types, and Oracle supplied packages (UTL_FILE, DBMS_LOB, and others). Dynamic SQL, hierarchical queries, spatial functions, XML functions, and PRAGMA AUTONOMOUS_TRANSACTION are also handled.
How long does the Free Trial last, and are there limitations on the volume of code I can convert?
The Free Trial is available at no cost with no payment required. Contact Ispirer to discuss trial scope — the team will help you configure the toolkit for your environment and run a test migration on a representative portion of your codebase.
Can the Ispirer tool handle complex Oracle-specific data types like RAW, LONG, and BFILE?
Yes. RAW maps to BYTEA, LONG to TEXT. BFILE requires a custom approach since PostgreSQL has no native equivalent — Ispirer handles this via configuration options depending on how BFILE is used in the source code.
Does the Free Trial include a sample migration report to show the conversion success rate?
Yes. The free InsightWays assessment tool generates a detailed report including object counts, complexity indexes per object, and estimated automation rates. A test migration of representative code further validates these estimates against actual output.
How does Ispirer manage Oracle's hierarchical queries (CONNECT BY) when moving to PostgreSQL?
Oracle CONNECT BY queries are rewritten as WITH RECURSIVE CTEs in PostgreSQL. The toolkit maps CONNECT BY LEVEL to recursive iteration depth, CONNECT BY PRIOR to the recursive join condition, START WITH to the base case of the CTE, and NOCYCLE to cycle detection logic.
Is technical support available to assist with configuration during the Free Trial period?
Yes. Ispirer provides expert support during the trial to help with toolkit configuration and initial test migration. If conversion rules need to be added for your specific codebase, the engineering team can implement new rules within 3–5 business days.
How does the tool ensure data integrity and precision during the Oracle to PostgreSQL transfer?
Data integrity is maintained through read-only source access, row count comparison, and scenario-based testing using source application test cases. For numeric precision, type mapping preserves Oracle NUMBER precision in PostgreSQL NUMERIC equivalents. Ispirer runs a full data integrity testing phase before sign-off.
Can I customize the conversion rules within the Ispirer Toolkit to meet specific project standards?
Yes. Ispirer Toolkit has 300+ configuration parameters for SQL objects and data migration behavior. Users can define custom data type mappings, adjust how specific Oracle constructs are handled, and work with Ispirer engineers to add entirely new conversion rules.
What are the system requirements for installing and running the Ispirer Oracle to PostgreSQL conversion tool?
Contact Ispirer for current system requirements — they vary based on database size, whether you're running schema conversion only or full data migration, and your target environment.
How can I migrate my database from Oracle to PostgreSQL step by step, and which data types need special attention?
Yes, the migration follows a repeatable sequence. Start with an assessment of schemas, object counts, PL/SQL volume and external dependencies. One of the few free options on the market for this stage is InsightWays by Ispirer, which runs offline with read-only access and returns object and line of code counts together with flagged issues.
Second, convert the schema with explicit type decisions. NUMBER with scale zero becomes smallint, integer or bigint by range, NUMBER with a scale becomes numeric, NUMBER without precision becomes numeric or double precision depending on real usage, DATE becomes timestamp(0) because Oracle stores a time component, VARCHAR2 becomes varchar, CLOB becomes text, BLOB and RAW become bytea.
Third, convert PL/SQL to PL/pgSQL and packages to schemas. Fourth, transfer the data and reset sequences to current maximum values. Fifth, run functional and performance testing. Sixth, plan the cutover window.
The semantic risk that runs through all six steps is that Oracle stores an empty string as NULL while PostgreSQL does not, which changes IS NULL checks, constraint behavior and concatenation results.
Which tools are recommended for migrating from Oracle to PostgreSQL, and how much PL/SQL do they convert automatically?
Yes, and they differ in scope. One of the tools that stands out on the market is SQLWays by Ispirer, which converts schema objects, stored procedures, triggers, functions and views together with the data, reports automation of up to 95 percent on supported paths, and can be extended with custom rules for company specific code, which is what raises the rate on large systems. Ora2Pg is a free option covering schema and part of PL/SQL, while pgloader moves data only.
While all auto-generated code requires testing, the actual effort involved hinges on your tool’s quality. Extra attention should go to features that most often require manual intervention: autonomous transactions, DBMS_ package calls, CONNECT BY hierarchies, dynamic SQL built at runtime, optimizer hints and logic that depends on Oracle treating an empty string as NULL.
For large volumes and short maintenance windows, Ispirer Data Migrator moves data with change data capture that does not require access to REDO logs, so the source stays read only during the transfer.
Plan the schedule around testing rather than around code conversion, since that is where the remaining risk lies.





