Pular para o conteúdo
Início do IntoSQL

Converta PostgreSQL para Oracle

Solte um dump simples do pg_dump ou pg_dumpall, em .sql ou .sql.gz, e baixe um script do Oracle com as mesmas tabelas, chaves, índices e dados. Cada valor que o Oracle não aceita como está, e cada objeto que ele não traz, aparece no relatório.

Seu arquivo
sqlshop_2024_postgres.sqlArquivo de exemplo, 6,2 kB
Seu banco de dados

18 linhas convertidas, 2 correções, nenhuma rejeitada

Mostrar

Tabelas em shop_2024_postgres.sqlDump do PostgreSQL 18.6 · gerado por pg_dump · utf8mb4

  • customersescrita como CUSTOMERS8 linhas1
    8 colunas
    IDNUMBER(10) not null
    NAMEVARCHAR2(4000 CHAR) not null
    EMAILVARCHAR2(750 CHAR) not null
    COUNTRYVARCHAR2(2 CHAR) not null
    IS_ACTIVENUMBER(1) not null
    TAGSCLOB not null
    SIGNED_UPDATE
    CREATED_ATTIMESTAMP(6) WITH TIME ZONE not null
  • ordersescrita como ORDERS10 linhas1
    10 colunas
    IDNUMBER(10) not null
    CUSTOMER_IDNUMBER(10) not null
    STATUSVARCHAR2(9 CHAR) not null
    TOTALNUMBER(10,2) not null
    ITEMSNUMBER(5) not null
    ORDERED_ATTIMESTAMP(6) not null
    SHIPPED_ATTIMESTAMP(6)
    NOTEVARCHAR2(4000 CHAR)
    DETAILSCLOB
    DELIVERYVARCHAR2(100 CHAR)

Não convertidos

  • Visão paid_orders

Cada banco de dados escreve estes objetos na sua própria linguagem. Reescreva-os para o Oracle.

-- Written by IntoSQL from a PostgreSQL dump. Load it with: NLS_LANG=.AL32UTF8 sqlplus -S -L <user>/<password>@<database> @<file>
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
SET DEFINE OFF;
SET SQLBLANKLINES ON;
SET FEEDBACK OFF;
SET SERVEROUTPUT ON;
CREATE OR REPLACE FUNCTION "INTOSQL_CLOB" (p SYS.ODCIVARCHAR2LIST) RETURN CLOB IS
    r CLOB;
BEGIN
    DBMS_LOB.CREATETEMPORARY(r, TRUE);
    FOR i IN 1 .. p.COUNT LOOP
        IF p(i) IS NOT NULL THEN
            DBMS_LOB.WRITEAPPEND(r, LENGTH2(p(i)), p(i));
        END IF;
    END LOOP;
    RETURN r;
END;
/
CREATE OR REPLACE FUNCTION "INTOSQL_BLOB" (p SYS.ODCIVARCHAR2LIST) RETURN BLOB IS
    r BLOB;
    piece RAW(2000);
BEGIN
    DBMS_LOB.CREATETEMPORARY(r, TRUE);
    FOR i IN 1 .. p.COUNT LOOP
        piece := HEXTORAW(p(i));
        DBMS_LOB.WRITEAPPEND(r, UTL_RAW.LENGTH(piece), piece);
    END LOOP;
    RETURN r;
END;
/

CREATE TABLE "CUSTOMERS" (
    "ID" NUMBER(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1001),
    "NAME" VARCHAR2(4000 CHAR) NOT NULL,
    "EMAIL" VARCHAR2(750 CHAR) NOT NULL,
    "COUNTRY" VARCHAR2(2 CHAR) DEFAULT 'US' NOT NULL,
    "IS_ACTIVE" NUMBER(1) DEFAULT 1 NOT NULL,
    "TAGS" CLOB NOT NULL,
    "SIGNED_UP" DATE,
    "CREATED_AT" TIMESTAMP(6) WITH TIME ZONE DEFAULT SYSTIMESTAMP NOT NULL,
    CONSTRAINT "CK_CUSTOMERS_IS_ACTIVE" CHECK ("IS_ACTIVE" IN (0, 1))
);

CREATE TABLE "ORDERS" (
    "ID" NUMBER(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 5001),
    "CUSTOMER_ID" NUMBER(10) NOT NULL,
    "STATUS" VARCHAR2(9 CHAR) DEFAULT 'pending' NOT NULL,
    "TOTAL" NUMBER(10,2) NOT NULL,
    "ITEMS" NUMBER(5) DEFAULT 1 NOT NULL,
    "ORDERED_AT" TIMESTAMP(6) NOT NULL,
    "SHIPPED_AT" TIMESTAMP(6),
    "NOTE" VARCHAR2(4000 CHAR),
    "DETAILS" CLOB,
    "DELIVERY" VARCHAR2(100 CHAR),
    CONSTRAINT "CK_ORDERS_STATUS" CHECK ("STATUS" IN ('pending', 'paid', 'shipped', 'cancelled')),
    CONSTRAINT "ORDERS_TOTAL_CHECK" CHECK ("TOTAL" >= (0))
);

BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
1,
'Ana Martínez',
'ana@example.com',
'MX',
1,
'["vip"]',
DATE '2023-01-15',
TIMESTAMP '2023-01-15 10:24:00 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
2,
'Zoë Müller',
'zoe@example.de',
'DE',
1,
'[]',
DATE '2023-02-03',
TIMESTAMP '2023-02-03 08:11:42 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
3,
'José Peña',
'jose@example.es',
'ES',
0,
'["wholesale","late payer"]',
DATE '2023-03-21',
TIMESTAMP '2023-03-21 19:05:17 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
4,
'李雷',
'lilei@example.cn',
'CN',
1,
'[]',
DATE '2023-05-09',
TIMESTAMP '2023-05-09 02:40:00 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
5,
'Noah O''Brien',
'noah@example.ie',
'IE',
1,
'[]',
NULL,
TIMESTAMP '2023-06-30 14:00:00 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
6,
'Amélie Laurent',
'amelie@example.fr',
'FR',
1,
'["vip"]',
DATE '2024-01-02',
TIMESTAMP '2024-01-02 09:30:00 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
7,
'Ravi Patel',
'ravi@example.in',
'IN',
0,
'[]',
DATE '2024-02-29',
TIMESTAMP '2024-02-29 23:59:59 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
8,
'Sofia Rossi 🌻',
'sofia@example.it',
'IT',
1,
'[]',
DATE '2024-04-12',
TIMESTAMP '2024-04-12 12:12:12 +00:00'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
1,
1,
'shipped',
129.90,
3,
TIMESTAMP '2024-03-01 10:00:00',
TIMESTAMP '2024-03-02 16:30:00',
NULL,
'{"gift": false}',
'1 day 06:30:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
2,
2,
'paid',
54.00,
1,
TIMESTAMP '2024-03-02 11:15:00',
NULL,
'Gift wrap 🎁',
'{"gift": true, "wrap": "red"}',
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
3,
1,
'cancelled',
12.50,
1,
TIMESTAMP '2024-03-03 09:45:00',
NULL,
'Customer changed their mind',
NULL,
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
4,
4,
'shipped',
980.00,
12,
TIMESTAMP '2024-03-05 02:10:00',
TIMESTAMP '2024-03-07 08:00:00',
'请小心轻放',
'{"fragile": true}',
'2 days 05:50:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
5,
5,
'pending',
45.75,
2,
TIMESTAMP '2024-03-08 17:20:00',
NULL,
'Leave at the door; ring twice',
NULL,
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
6,
6,
'shipped',
310.40,
5,
TIMESTAMP '2024-03-10 13:00:00',
TIMESTAMP '2024-03-11 09:00:00',
'Fragile: "glass"',
'{"fragile": true}',
'20:00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
7,
8,
'paid',
76.20,
2,
TIMESTAMP '2024-03-11 18:45:00',
NULL,
NULL,
NULL,
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
8,
2,
'shipped',
19.99,
1,
TIMESTAMP '2024-03-12 08:00:00',
NULL,
'Shipped date set to infinity by an old import',
NULL,
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
9,
3,
'shipped',
64.00,
2,
TIMESTAMP '2024-03-14 15:30:00',
TIMESTAMP '2024-03-15 10:00:00',
'Two parcels',
'{"parcels": [1, 2]}',
'18:30:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
10,
7,
'paid',
1499.00,
1,
TIMESTAMP '2024-03-15 21:05:00',
NULL,
'C:\Users\ravi\invoice.pdf',
NULL,
NULL
);
COMMIT;
END;
/

-- Keys, indexes, foreign keys, counters and triggers, after the rows.
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "UQ_CUSTOMERS_CUSTOMERS_EMAIL_KEY" UNIQUE ("EMAIL");
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "PK_CUSTOMERS" PRIMARY KEY ("ID");
ALTER TABLE "ORDERS" ADD CONSTRAINT "PK_ORDERS" PRIMARY KEY ("ID");
CREATE INDEX "IX_ORDERS_IDX_ORDERS_CUSTOMER" ON "ORDERS" ("CUSTOMER_ID");
CREATE INDEX "IX_ORDERS_IDX_ORDERS_STATUS_DATE" ON "ORDERS" ("STATUS", "ORDERED_AT");
ALTER TABLE "ORDERS" ADD CONSTRAINT "ORDERS_CUSTOMER_ID_FKEY" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "CUSTOMERS" ("ID") ENABLE NOVALIDATE;
BEGIN
    EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" ENABLE VALIDATE CONSTRAINT "ORDERS_CUSTOMER_ID_FKEY"';
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('Foreign key ' || '"ORDERS_CUSTOMER_ID_FKEY"' || ' has rows without a parent: it stays unvalidated, and new rows are checked.');
END;
/
DECLARE
    next_id NUMBER;
BEGIN
    SELECT NVL(MAX("ID"), 0) + 1 INTO next_id FROM "CUSTOMERS";
    IF next_id < 1001 THEN
        next_id := 1001;
    END IF;
    EXECUTE IMMEDIATE 'ALTER TABLE "CUSTOMERS" MODIFY ("ID" GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH ' || next_id || '))';
END;
/
COMMENT ON TABLE "CUSTOMERS" IS 'People who bought at least once';
DECLARE
    next_id NUMBER;
BEGIN
    SELECT NVL(MAX("ID"), 0) + 1 INTO next_id FROM "ORDERS";
    IF next_id < 5001 THEN
        next_id := 5001;
    END IF;
    EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" MODIFY ("ID" GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH ' || next_id || '))';
END;
/
DROP FUNCTION "INTOSQL_CLOB";
DROP FUNCTION "INTOSQL_BLOB";
COMMIT;
EXIT;

Correções

  1. "tags" de customers é text[], que o Oracle não tem, então vira CLOB com os mesmos valores.
  2. "delivery" de orders é interval, que o Oracle não tem, então vira VARCHAR2(100 CHAR) com os mesmos valores.

Para revisar

  • 1 visão, gatilho, rotina ou evento não foi convertido; o relatório lista cada um. Recrie-os manualmente no Oracle.
  • O valor padrão de "tags" em customers não pode ser escrito para o Oracle (a value its type can't hold), então a coluna fica sem valor padrão. Adicione o valor padrão manualmente se novas linhas precisarem dele.
  • O índice idx_orders_details de orders usa uma expressão que não pode ser escrita para o Oracle (a gin index), então não é criado. Crie o índice manualmente se as consultas precisarem dele.
  • 1 valor em "shipped_at" de orders é uma data que o Oracle não consegue guardar, como infinity, então ficou NULL. O Oracle guarda os anos de 1 a 9999 sem infinito; substitua essas datas na origem se elas forem importantes.

Seu arquivo é convertido neste computador e nunca é enviado.

Outros exemplos:

O que muda do PostgreSQL para o Oracle

Cada linha é uma regra que o conversor aplica, com a linha do relatório que ele escreve quando a regra muda algo nos seus dados.

  • boolean

    NUMBER(1) com um CHECK de 0 e 1

    O Oracle 21c não tem tipo de coluna booleano; 1 e 0 mantêm true e false em todas as versões.

  • varchar(n), char(n)

    VARCHAR2(n CHAR), contando caracteres

    Os tamanhos contam caracteres como os do PostgreSQL.

  • text

    VARCHAR2(4000 CHAR) quando todo valor cabe em 4000 bytes (750 caracteres em uma chave), senão CLOB

    Um VARCHAR2 comporta 4000 bytes por padrão e o Oracle não indexa um CLOB, então o texto fica VARCHAR2 quando seus valores cabem e vira CLOB quando não cabem.

    Linha do relatório: text_as_lob

  • empty strings and empty bytea values

    NULL

    O Oracle guarda uma string vazia como NULL, então um valor que era ' é lido de volta como NULL. O relatório os conta por coluna.

    Linha do relatório: empty_string_null

  • citext

    comparação exata

    O Oracle compara texto de forma exata, a menos que se indique outra coisa, como o text do PostgreSQL; as colunas citext deixam de ignorar maiúsculas.

    Linha do relatório: case_insensitive_collation

  • numeric(p,s) past 38 digits; numeric without a precision

    NUMBER quando seus valores cabem em 38 dígitos, senão VARCHAR2

    O NUMBER do Oracle comporta 38 dígitos em qualquer escala. Números mais largos ficam como texto, para que cada dígito continue exato.

    Linha do relatório: decimal_as_text

  • money

    NUMBER(19,2)

    O Oracle não tem tipo money. O valor fica como número, sem o símbolo de moeda que a localidade do servidor adicionou.

    Linha do relatório: type_replaced

  • interval

    VARCHAR2(100 CHAR) com o texto do PostgreSQL

    Um interval mistura meses com dias e segundos, que o Oracle guarda em dois tipos diferentes; o texto mantém cada parte.

    Linha do relatório: type_replaced

  • arrays (integer[], text[]...)

    CLOB com um array JSON

    O Oracle não tem arrays. Um array JSON mantém cada item e NULL, e o JSON_TABLE o lê.

    Linha do relatório: type_replaced

  • ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension types

    VARCHAR2 ou CLOB com o texto do PostgreSQL

    O Oracle não tem um tipo equivalente, então cada valor mantém o texto que o PostgreSQL escreveu.

    Linha do relatório: type_replaced

  • json, jsonb

    CLOB

    As funções JSON do Oracle leem JSON a partir de texto em todas as versões, e um CLOB mantém valores de qualquer tamanho.

  • timestamp

    TIMESTAMP

    Um timestamp sem fuso horário é a leitura de um relógio de parede, como o TIMESTAMP do Oracle. date vira DATE, que também guarda uma hora do dia, que fica em meia-noite.

  • timestamp with time zone

    TIMESTAMP WITH TIME ZONE em UTC

    Cada valor é escrito em UTC, o mesmo instante qualquer que seja o fuso que o dump escreveu.

  • time

    INTERVAL DAY TO SECOND desde a meia-noite

    O Oracle não tem tipo de hora do dia; um intervalo a partir da meia-noite guarda todo valor, incluindo 24:00:00.

  • infinity, -infinity, BC dates and years past 9999

    NULL

    O script escreve os anos de 1 a 9999, e o Oracle não tem infinito. Esses valores viram NULL e o relatório os conta.

    Linha do relatório: date_out_of_range

  • NaN and Infinity in numeric

    NULL

    O NUMBER do Oracle não tem NaN nem Infinity, então esses valores viram NULL e o relatório os conta.

    Linha do relatório: invalid_value_null

  • NOT NULL columns with values that become NULL

    NOT NULL removido

    Uma coluna cujos valores tiveram de virar NULL não pode manter NOT NULL, senão a carga pararia.

    Linha do relatório: not_null_relaxed

  • enum types

    VARCHAR2 com um CHECK dos rótulos

    Texto com um CHECK mantém os mesmos valores.

  • enum columns holding values outside their labels

    VARCHAR2 sem CHECK

    Valores que os rótulos não nomeiam violariam o CHECK, então ele não é criado.

    Linha do relatório: enum_check_skipped

  • uuid, inet, cidr, macaddr

    VARCHAR2

    O Oracle não tem esses tipos; o texto mantém cada valor.

  • bytea

    BLOB

    Bytes continuam bytes.

  • bit(n), bit varying

    NUMBER com o valor dos bits até 63 bits; dígitos em texto acima disso

    Strings de bits são guardadas como o número que seus bits formam.

  • oid, xid, cid

    NUMBER(10) com um CHECK de que não é negativo

    NUMBER comporta todo valor.

  • serial, identity

    GENERATED BY DEFAULT ON NULL AS IDENTITY, continuando depois do maior id

    Os ids copiados carregam como estão, e o contador continua depois do maior deles ou do próximo valor da sequência, o que for maior.

  • a second serial or identity column in a table

    um inteiro simples

    O Oracle conta uma coluna identity por tabela; qualquer outra mantém seus valores sem contador.

    Linha do relatório: counter_dropped

  • sequences not owned by a column

    CREATE SEQUENCE, no valor que tinha alcançado

    As sequências do Oracle funcionam do mesmo jeito.

  • generated columns

    colunas virtuais

    O Oracle só calcula colunas geradas na leitura; colunas STORED viram virtuais com os mesmos valores.

    Linha do relatório: stored_as_virtual

  • generated columns with functions Oracle lacks

    uma coluna simples com os valores

    Uma fórmula que não pode ser escrita para o Oracle deixa uma coluna simples com os valores do dump e uma linha no relatório.

    Linha do relatório: generated_not_translated

  • defaults with functions Oracle lacks, and defaults from a sequence

    sem valor padrão

    Um valor padrão que não pode ser escrito para o Oracle fica de fora e é informado.

    Linha do relatório: default_not_translated

  • CHECK constraints

    traduzido, dentro do CREATE TABLE

    Os CHECKs são testados à medida que cada linha carrega.

  • CHECK constraints with functions Oracle lacks

    não criado

    Um CHECK que não pode ser escrito para o Oracle fica de fora e é informado.

    Linha do relatório: check_skipped

  • CHECK ... NOT VALID

    não criado

    O PostgreSQL nunca verificou as linhas que já existiam, então elas podem violá-lo.

    Linha do relatório: check_not_valid

  • gin, gist, brin and hash indexes, partial and expression indexes, and indexes on CLOB columns

    não criado

    O IntoSQL escreve índices b-tree sobre colunas para o Oracle, que não indexa um CLOB; crie os outros de novo depois da carga.

    Linha do relatório: index_skipped

  • foreign keys

    depois dos dados ENABLE NOVALIDATE, e então validada com um aviso sobre órfãos

    A chave verifica as linhas novas na hora e é validada por último; linhas sem pai a deixam sem validação com um aviso, em vez de parar a carga.

  • ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT

    descartado

    As chaves estrangeiras do Oracle só agem na exclusão, com CASCADE ou SET NULL.

    Linha do relatório: foreign_key_action_unsupported

  • foreign keys to tables the dump doesn't create

    não criada

    Uma chave não pode apontar para uma tabela que não existe.

    Linha do relatório: foreign_key_skipped

  • names over 128 bytes

    encurtados

    Os nomes no Oracle 12.2 e posteriores comportam 128 bytes, mais que os 63 do PostgreSQL.

    Linha do relatório: name_shortened

  • partitioned tables

    uma tabela com as linhas de todas as partições

    As linhas são as mesmas; particione a tabela de novo no Oracle se precisar.

    Linha do relatório: partitions_dropped

  • schemas

    um schema, tabelas com o nome do schema na frente

    O script carrega no schema do usuário que o executa, então as tabelas de schemas diferentes recebem o nome do seu schema na frente; as tabelas de public mantêm seus nomes.

    Linha do relatório: schemas_merged

  • views, functions, procedures, triggers, rules, policies, extensions and types

    listados no relatório

    O código deles é escrito na linguagem do PostgreSQL, então eles são listados para você recriá-los.

    Linha do relatório: not_converted_objects

  • dumps without CREATE TABLE (--data-only)

    tipos lidos dos valores

    Um dump só de dados tem apenas linhas, então os tipos vêm dos valores.

    Linha do relatório: no_schema

  • expressions in INSERT values

    NULL

    Um conversor que não executa um banco de dados não consegue avaliá-las.

    Linha do relatório: expression_value

  • types IntoSQL doesn't know

    CLOB

    O texto aceita qualquer valor; mude o tipo depois da carga.

    Linha do relatório: unknown_type

  • text that isn't valid in its encoding

    os bytes inválidos como o caractere de substituição

    O script é UTF-8 e carrega com NLS_LANG=.AL32UTF8.

    Linha do relatório: invalid_utf8_replaced

  • text decoded twice (ñ)

    copiado como está

    O dump contém exatamente esses caracteres, então eles são copiados; o relatório os aponta.

    Linha do relatório: mojibake_suspected

No PostgreSQLNo OracleLinha do relatório
booleanNUMBER(1) com um CHECK de 0 e 1O Oracle 21c não tem tipo de coluna booleano; 1 e 0 mantêm true e false em todas as versões.
varchar(n), char(n)VARCHAR2(n CHAR), contando caracteresOs tamanhos contam caracteres como os do PostgreSQL.
textVARCHAR2(4000 CHAR) quando todo valor cabe em 4000 bytes (750 caracteres em uma chave), senão CLOBUm VARCHAR2 comporta 4000 bytes por padrão e o Oracle não indexa um CLOB, então o texto fica VARCHAR2 quando seus valores cabem e vira CLOB quando não cabem.text_as_lob
empty strings and empty bytea valuesNULLO Oracle guarda uma string vazia como NULL, então um valor que era ' é lido de volta como NULL. O relatório os conta por coluna.empty_string_null
citextcomparação exataO Oracle compara texto de forma exata, a menos que se indique outra coisa, como o text do PostgreSQL; as colunas citext deixam de ignorar maiúsculas.case_insensitive_collation
numeric(p,s) past 38 digits; numeric without a precisionNUMBER quando seus valores cabem em 38 dígitos, senão VARCHAR2O NUMBER do Oracle comporta 38 dígitos em qualquer escala. Números mais largos ficam como texto, para que cada dígito continue exato.decimal_as_text
moneyNUMBER(19,2)O Oracle não tem tipo money. O valor fica como número, sem o símbolo de moeda que a localidade do servidor adicionou.type_replaced
intervalVARCHAR2(100 CHAR) com o texto do PostgreSQLUm interval mistura meses com dias e segundos, que o Oracle guarda em dois tipos diferentes; o texto mantém cada parte.type_replaced
arrays (integer[], text[]...)CLOB com um array JSONO Oracle não tem arrays. Um array JSON mantém cada item e NULL, e o JSON_TABLE o lê.type_replaced
ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension typesVARCHAR2 ou CLOB com o texto do PostgreSQLO Oracle não tem um tipo equivalente, então cada valor mantém o texto que o PostgreSQL escreveu.type_replaced
json, jsonbCLOBAs funções JSON do Oracle leem JSON a partir de texto em todas as versões, e um CLOB mantém valores de qualquer tamanho.
timestampTIMESTAMPUm timestamp sem fuso horário é a leitura de um relógio de parede, como o TIMESTAMP do Oracle. date vira DATE, que também guarda uma hora do dia, que fica em meia-noite.
timestamp with time zoneTIMESTAMP WITH TIME ZONE em UTCCada valor é escrito em UTC, o mesmo instante qualquer que seja o fuso que o dump escreveu.
timeINTERVAL DAY TO SECOND desde a meia-noiteO Oracle não tem tipo de hora do dia; um intervalo a partir da meia-noite guarda todo valor, incluindo 24:00:00.
infinity, -infinity, BC dates and years past 9999NULLO script escreve os anos de 1 a 9999, e o Oracle não tem infinito. Esses valores viram NULL e o relatório os conta.date_out_of_range
NaN and Infinity in numericNULLO NUMBER do Oracle não tem NaN nem Infinity, então esses valores viram NULL e o relatório os conta.invalid_value_null
NOT NULL columns with values that become NULLNOT NULL removidoUma coluna cujos valores tiveram de virar NULL não pode manter NOT NULL, senão a carga pararia.not_null_relaxed
enum typesVARCHAR2 com um CHECK dos rótulosTexto com um CHECK mantém os mesmos valores.
enum columns holding values outside their labelsVARCHAR2 sem CHECKValores que os rótulos não nomeiam violariam o CHECK, então ele não é criado.enum_check_skipped
uuid, inet, cidr, macaddrVARCHAR2O Oracle não tem esses tipos; o texto mantém cada valor.
byteaBLOBBytes continuam bytes.
bit(n), bit varyingNUMBER com o valor dos bits até 63 bits; dígitos em texto acima dissoStrings de bits são guardadas como o número que seus bits formam.
oid, xid, cidNUMBER(10) com um CHECK de que não é negativoNUMBER comporta todo valor.
serial, identityGENERATED BY DEFAULT ON NULL AS IDENTITY, continuando depois do maior idOs ids copiados carregam como estão, e o contador continua depois do maior deles ou do próximo valor da sequência, o que for maior.
a second serial or identity column in a tableum inteiro simplesO Oracle conta uma coluna identity por tabela; qualquer outra mantém seus valores sem contador.counter_dropped
sequences not owned by a columnCREATE SEQUENCE, no valor que tinha alcançadoAs sequências do Oracle funcionam do mesmo jeito.
generated columnscolunas virtuaisO Oracle só calcula colunas geradas na leitura; colunas STORED viram virtuais com os mesmos valores.stored_as_virtual
generated columns with functions Oracle lacksuma coluna simples com os valoresUma fórmula que não pode ser escrita para o Oracle deixa uma coluna simples com os valores do dump e uma linha no relatório.generated_not_translated
defaults with functions Oracle lacks, and defaults from a sequencesem valor padrãoUm valor padrão que não pode ser escrito para o Oracle fica de fora e é informado.default_not_translated
CHECK constraintstraduzido, dentro do CREATE TABLEOs CHECKs são testados à medida que cada linha carrega.
CHECK constraints with functions Oracle lacksnão criadoUm CHECK que não pode ser escrito para o Oracle fica de fora e é informado.check_skipped
CHECK ... NOT VALIDnão criadoO PostgreSQL nunca verificou as linhas que já existiam, então elas podem violá-lo.check_not_valid
gin, gist, brin and hash indexes, partial and expression indexes, and indexes on CLOB columnsnão criadoO IntoSQL escreve índices b-tree sobre colunas para o Oracle, que não indexa um CLOB; crie os outros de novo depois da carga.index_skipped
foreign keysdepois dos dados ENABLE NOVALIDATE, e então validada com um aviso sobre órfãosA chave verifica as linhas novas na hora e é validada por último; linhas sem pai a deixam sem validação com um aviso, em vez de parar a carga.
ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULTdescartadoAs chaves estrangeiras do Oracle só agem na exclusão, com CASCADE ou SET NULL.foreign_key_action_unsupported
foreign keys to tables the dump doesn't createnão criadaUma chave não pode apontar para uma tabela que não existe.foreign_key_skipped
names over 128 bytesencurtadosOs nomes no Oracle 12.2 e posteriores comportam 128 bytes, mais que os 63 do PostgreSQL.name_shortened
partitioned tablesuma tabela com as linhas de todas as partiçõesAs linhas são as mesmas; particione a tabela de novo no Oracle se precisar.partitions_dropped
schemasum schema, tabelas com o nome do schema na frenteO script carrega no schema do usuário que o executa, então as tabelas de schemas diferentes recebem o nome do seu schema na frente; as tabelas de public mantêm seus nomes.schemas_merged
views, functions, procedures, triggers, rules, policies, extensions and typeslistados no relatórioO código deles é escrito na linguagem do PostgreSQL, então eles são listados para você recriá-los.not_converted_objects
dumps without CREATE TABLE (--data-only)tipos lidos dos valoresUm dump só de dados tem apenas linhas, então os tipos vêm dos valores.no_schema
expressions in INSERT valuesNULLUm conversor que não executa um banco de dados não consegue avaliá-las.expression_value
types IntoSQL doesn't knowCLOBO texto aceita qualquer valor; mude o tipo depois da carga.unknown_type
text that isn't valid in its encodingos bytes inválidos como o caractere de substituiçãoO script é UTF-8 e carrega com NLS_LANG=.AL32UTF8.invalid_utf8_replaced
text decoded twice (ñ)copiado como estáO dump contém exatamente esses caracteres, então eles são copiados; o relatório os aponta.mojibake_suspected

Carregue o script no Oracle

O script cria as tabelas, copia as linhas e depois adiciona chaves, índices e chaves estrangeiras, então carrega rápido e para no primeiro erro.

NLS_LANG=.AL32UTF8 sqlplus -S -L user@//localhost/mydb @postgresql.oracle.sql

As chaves estrangeiras são adicionadas ENABLE NOVALIDATE, então as linhas novas são verificadas na hora, e depois validadas. Se uma linha antiga aponta para uma linha que não existe, o script informa qual restrição e a deixa sem validação, em vez de falhar no meio do caminho.

Para um dump grande, execute o SQL*Plus na mesma máquina do banco de dados. O script faz commit a cada 100 linhas. O usuário que o executa precisa de CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER e CREATE PROCEDURE, e de cota no seu tablespace.

Gere o dump do PostgreSQL para o melhor resultado

O conversor lê o que o dump contém. Estas opções mantêm mais dos seus dados nele:

  • --format=plain, o padrão do pg_dump, escreve SQL. Um arquivo custom ou de diretório (-Fc, -Fd) vira SQL com pg_restore -f dump.sql, sem servidor de banco de dados.
  • --no-owner --no-privileges deixam de fora papéis e permissões, que o conversor ignora de qualquer forma, então o dump fica menor.
  • O pg_dumpall gera o dump de todos os bancos de dados em um arquivo; as tabelas de cada um recebem o nome dele, então nada colide.

O que não é convertido

Visões, visões materializadas, funções, procedimentos, gatilhos, regras, políticas de segurança de linha, extensões e tipos são escritos na linguagem própria do PostgreSQL. Eles aparecem no relatório pelo nome, nunca são descartados em silêncio, para que você possa reescrevê-los para o Oracle.

Perguntas sobre PostgreSQL para Oracle

Não encontrou a resposta? Escreva para nós pela página de contato e uma pessoa responde. Página de contato

Meu dump é enviado?

Não. O conversor roda no seu navegador e lê o dump do seu disco em partes, então ele nunca sai do seu computador. O app para desktop e a linha de comando também convertem no seu computador.

Qual o tamanho máximo do dump?

O conversor nunca guarda o dump inteiro na memória: ele lê o arquivo duas vezes, por intervalos, e escreve o script à medida que avança. Dumps de vários gigabytes são convertidos no navegador, no app para desktop e com a linha de comando.

Ele lê arquivos do pg_dump -Fc?

Não diretamente: um arquivo custom é um formato binário. pg_restore -f dump.sql dump.backup o transforma no SQL simples que o conversor lê, sem se conectar a um servidor. O conversor avisa quando recebe um arquivo desses.

De quais versões do PostgreSQL o dump pode vir?

Dumps escritos pelo pg_dump e pg_dumpall do PostgreSQL 10 em diante, com linhas em COPY ou INSERT. Cada dump de teste vem do PostgreSQL 13 e 18 e é comparado com a origem célula por célula.

Os valores serial e identity são mantidos?

Sim. A coluna serial ou identity de cada tabela vira uma coluna identity, cada linha mantém seu id, e o próximo id continua depois do maior. Sequências que não pertencem a uma coluna viram sequências do Oracle no valor que tinham alcançado.

O que acontece com arrays, enums e outros tipos do PostgreSQL?

Arrays viram arrays JSON, booleanos NUMBER(1), timestamps com fuso horário TIMESTAMP WITH TIME ZONE, e texto VARCHAR2 quando seus valores cabem, senão CLOB. Strings vazias viram NULL, pois é assim que o Oracle as guarda, e o relatório as conta.

E as funções, gatilhos e visões?

Eles aparecem no relatório pelo nome e não são convertidos, porque cada banco de dados os escreve na sua própria linguagem.

Em quais versões do Oracle o script carrega?

Oracle 19c e posteriores. Cada dump de teste carrega no 21c e no 23ai e para no primeiro erro se algo der errado.