O AnalyticDB for PostgreSQL é compatível com a sintaxe Oracle. Este tópico aborda tudo o que você precisa para migrar uma aplicação Oracle: como avaliar o escopo da migração com o Ora2Pg, configure o modo de compatibilidade, usar funções compatíveis com Oracle por meio da extensão Orafce e converter construções PL/SQL para PL/pgSQL.
Principais diferenças em resumo
Analise estas diferenças de alto nível antes de se aprofundar nas regras específicas de conversão. Elas afetam os problemas de migração mais comuns:
|
Área |
Comportamento do Oracle |
Comportamento do AnalyticDB for PostgreSQL |
||
|
Concatenação com |
|
NULL` retorna |
Retorna |
|
|
|
Pseudocoluna |
Use |
||
|
Tabela |
Tabela virtual exigida por algumas consultas |
Remova |
||
|
|
Consulta hierárquica nativa |
Sem equivalente direto; reescreva como uma função PL/pgSQL |
||
|
Pacotes |
|
Sem suporte a pacotes; converta para schemas + funções |
||
|
|
Diretivas de compilação |
Não suportado; exclua todas as instruções PRAGMA |
||
|
Controle de transação em funções |
|
Não suportado; mova o controle de transação para fora das funções |
||
|
|
|
Use a sintaxe padrão |
||
|
FOR LOOP REVERSE |
Conta regressivamente do 2º número para o 1º |
Conta regressivamente do 1º número para o 2º; inverta os limites |
||
|
Funções com argumentos |
Ambos permitidos simultaneamente |
Não suportado; converta |
||
|
Arrays associativos |
Suportado |
Sem equivalente; requer redesenho |
||
|
Funções definidas pelo usuário em |
Podem conter instruções SQL |
Não podem conter instruções SQL; reescreva como subconsultas |
Automatize a conversão de schema com o Ora2Pg
O Ora2Pg é uma ferramenta open source que converte instruções DDL do Oracle para tabelas, views e pacotes em sintaxe compatível com PostgreSQL.
Avalie o escopo da migração primeiro
Antes de executar uma conversão completa, gere um relatório de avaliação de migração para identificar quais objetos não podem ser convertidos automaticamente:
ora2pg -t SHOW_REPORT
O relatório lista todos os objetos do banco de dados, suas quantidades e quais exigem trabalho manual. Utilize-o para estimar o escopo antes de iniciar a migração.
O que o Ora2Pg trata automaticamente
DDL de tabelas e views
Estrutura de pacotes (convertida para schemas)
Sintaxe básica de PL/SQL para PL/pgSQL
O que exige correção manual
Após executar o Ora2Pg, revise e corrija a saída para estes problemas antes de executá-la na sua instância:
Os scripts convertidos podem ter como alvo uma versão de sintaxe do PostgreSQL posterior à versão secundária do mecanismo da sua instância
As regras de conversão podem estar incompletas ou incorretas para construções complexas de PL/SQL
Todas as construções listadas na seção Conversão de PL/SQL abaixo
Configure o modo de compatibilidade
O parâmetro adb_compatibility_mode controla como o AnalyticDB for PostgreSQL lida com sintaxes que se comportam de maneira diferente entre bancos de dados.
|
Parâmetro |
Valores válidos |
Padrão |
|
|
|
|
Verifique o valor atual antes de fazer alterações:
SHOW adb_compatibility_mode;
Para alterar o parâmetro no nível da instância, envie um ticket.Envie um ticket
Concatenação de strings com NULL
A expressão 'abc' || NULL comporta-se de forma diferente dependendo do modo de compatibilidade:
Modo PostgreSQL (padrão): retorna
NULLModo Oracle: retorna
'abc'(o Oracle trataNULLcomo uma string vazia)
Antes de usar concatenação de strings no modo de compatibilidade Oracle, desative o mecanismo Laser:
SET laser.enable = off;
Inferência de tipo de string constante
O AnalyticDB for PostgreSQL reconhece automaticamente strings constantes como o tipo TEXT (não UNKNOWN) em instruções como CREATE TABLE AS SELECT. Esse comportamento não exige nenhuma configuração de modo de compatibilidade.
Use a extensão Orafce
A extensão Orafce fornece funções compatíveis com Oracle que você pode usar no AnalyticDB for PostgreSQL sem modificá-las ou convertê-las.
Instale o Orafce uma vez por banco de dados:
CREATE EXTENSION orafce;
O Orafce também adiciona suporte ao tipo de dados VARCHAR2 do Oracle.
Funções de data e hora
|
Função |
Descrição |
Exemplo |
|
|
Adiciona meses a uma data |
|
|
|
Retorna o último dia do mês |
|
|
|
Retorna a próxima ocorrência de um dia da semana |
|
|
|
Dia da semana como inteiro: 1=Domingo, 2=Segunda, ..., 7=Sábado |
|
|
|
Retorna o número de meses entre duas datas (positivo se date1 > date2) |
|
Truncamento e arredondamento de timestamp
|
Função |
Descrição |
Exemplo |
|
|
Trunca para ano ( |
|
|
|
Trunca horas, minutos e segundos |
|
|
|
Trunca uma data |
|
|
|
Arredonda para o valor mais próximo por unidade (semana, dia, etc.) |
|
|
|
Arredonda para o dia mais próximo |
|
|
|
Retorna uma data arredondada |
|
|
|
Retorna uma data arredondada |
|
Funções de tratamento de NULL
|
Função |
Descrição |
Exemplo |
|
|
Retorna o segundo argumento se o primeiro for nulo; caso contrário, retorna o primeiro. Ambos os argumentos devem ser do mesmo tipo. |
|
|
|
Retorna o terceiro argumento se o primeiro for nulo; caso contrário, retorna o segundo |
|
|
|
Retorna |
|
|
|
Retorna o segundo argumento se o primeiro for |
|
Funções de string
Função | Descrição |
| Retorna a posição da enésima ocorrência de |
| Retorna a posição da primeira ocorrência a partir de |
| Pesquisa desde o início da string |
| Retorna a substring começando em |
| Retorna uma substring; |
| Retorna uma substring de uma string |
| Retorna uma substring de uma string |
| Retorna a contagem de bytes de uma string |
| Preenche uma string à esquerda até o comprimento especificado. Nota O PostgreSQL remove espaços à direita de valores |
| Preenche à esquerda com espaços |
| Une duas strings |
| Une valores do mesmo tipo ou de tipos diferentes |
| Ordena dados em uma ordem específica de localidade (ex.: |
| Inverte caracteres de |
| Inverte de |
| Inverte a string inteira |
Funções de agregação
|
Função |
Descrição |
Exemplo |
|
|
Concatena valores em uma única string |
|
|
|
Concatena com um separador |
|
|
|
AND bit a bit em dois valores inteiros |
|
Funções de diagnóstico
|
Função |
Descrição |
Exemplo |
|
|
Retorna código de tipo, comprimento em bytes e representação interna |
|
|
|
Especifica o formato de saída: |
|
Funções de expressão regular
Todas as funções regex abaixo aceitam um argumento flags com estes valores: 'i' (insensível a maiúsculas/minúsculas), 'c' (sensível a maiúsculas/minúsculas), 'n' (. corresponde a nova linha), 'm' (multilinha), 'x' (ignorar espaços em branco).
|
Função |
Descrição |
|
|
Retorna o número de vezes que |
|
|
Conta ocorrências a partir de |
|
|
Conta com flags de correspondência personalizadas |
|
|
Retorna a posição inicial do padrão; retorna 0 se não for encontrado |
|
|
Assinatura completa: |
|
|
Retorna |
|
|
Retorna |
|
|
Retorna a primeira substring correspondente |
|
|
Retorna a substring correspondente para a ocorrência especificada a partir de |
Funções suportadas sem Orafce
Estas funções compatíveis com Oracle estão disponíveis nativamente no AnalyticDB for PostgreSQL sem a instalação do Orafce:
|
Função |
Descrição |
Exemplo |
|
|
Seno hiperbólico |
|
|
|
Tangente hiperbólica |
|
|
|
Cosseno hiperbólico |
|
|
|
Retorna o valor correspondente ou o padrão se não houver correspondência |
Visualize o exemplo abaixo |
-- Create sample table
CREATE TABLE t1(id int, name varchar(20));
INSERT INTO t1 values(1,'alibaba');
INSERT INTO t1 values(2,'adb4pg');
-- decode: returns 'alibaba' for id=1, 'adb4pg' for id=2
SELECT decode(id, 1, 'alibaba', 2, 'adb4pg', 'not found') FROM t1;
Mapeamentos de tipos de dados
|
Tipo Oracle |
Tipo AnalyticDB for PostgreSQL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mapeamentos de funções
|
Função Oracle |
Equivalente no AnalyticDB for PostgreSQL |
|
|
|
|
|
|
|
|
Instrução |
|
|
|
|
|
|
Conversão de dados em PL/SQL
PL/SQL (Procedural Language/SQL) corresponde a PL/pgSQL no AnalyticDB for PostgreSQL. As seções abaixo abordam as regras de conversão para cada construção PL/SQL.
Pacotes
O PL/pgSQL não suporta pacotes. Converta cada pacote em um schema e converta todos os procedimentos e funções dentro do pacote em funções independentes nesse schema.
Oracle:
CREATE OR REPLACE PACKAGE pkg IS
...
END;
AnalyticDB for PostgreSQL:
-- Package becomes a schema
CREATE SCHEMA pkg;
Regras de conversão para conteúdo de pacotes:
Variáveis locais em procedimentos e funções: nenhuma alteração necessária
Variáveis globais: armazene em uma tabela temporária (visualize Variáveis globais abaixo)
Blocos de inicialização de pacote: remova-os. Se a lógica não puder ser removida, encapsule-a em uma função e chame a função explicitamente quando necessário.
Procedimentos e funções: converta para funções no schema correspondente. Cada função deve ter o prefixo do nome do schema.
Exemplo — função dentro de um pacote:
Oracle:
FUNCTION test_func (args int) RETURN int is
var number := 10;
BEGIN
...
END;
AnalyticDB for PostgreSQL:
-- RETURN -> RETURNS; IS/AS -> AS $$...$$; add LANGUAGE clause
CREATE OR REPLACE FUNCTION pkg.test_func(args int) RETURNS int AS
$$
...
$$
LANGUAGE plpgsql;
Procedimentos e funções
Converta procedimentos e funções do Oracle para funções PL/pgSQL. As principais mudanças são:
RETURN(na assinatura da função) ->RETURNSEnvolva o corpo da função em
$$...$$Adicione uma cláusula
LANGUAGE plpgsqlConverta subprocedimentos em funções independentes
Exemplo:
Oracle:
CREATE OR REPLACE FUNCTION test_func (v_name varchar2, v_version varchar2)
RETURN varchar2 IS
ret varchar(32);
BEGIN
IF v_version IS NULL THEN
ret := v_name;
ELSE
ret := v_name || '/' || v_version;
END IF;
RETURN ret;
END;
AnalyticDB for PostgreSQL:
-- Changes: varchar2 -> varchar; RETURN -> RETURNS; IS -> AS; body wrapped in $$...$$
CREATE OR REPLACE FUNCTION test_func (v_name varchar, v_version varchar)
RETURNS varchar AS
$$
DECLARE
ret varchar(32);
BEGIN
IF v_version IS NULL THEN
ret := v_name;
ELSE
ret := v_name || '/' || v_version;
END IF;
RETURN ret;
END;
$$
LANGUAGE plpgsql;
Instruções PL
FOR LOOP com REVERSE
PL/SQL e PL/pgSQL tratam a palavra-chave REVERSE de forma diferente:
PL/SQL:
FOR i IN REVERSE 1..3conta regressivamente de 3 a 1PL/pgSQL:
FOR i IN REVERSE 1..3conta regressivamente de 1 a 3 (direção oposta)
Inverta os limites do loop ao converter:
Oracle:
FOR i IN REVERSE 1..3 LOOP
DBMS_OUTPUT.PUT_LINE(TO_CHAR(i));
END LOOP;
AnalyticDB for PostgreSQL:
-- Boundaries swapped: 1..3 -> 3..1; DBMS_OUTPUT.PUT_LINE -> RAISE
FOR i IN REVERSE 3..1 LOOP
RAISE '%', i;
END LOOP;
Instruções PRAGMA
Instruções PRAGMA não são suportadas. Exclua todas as instruções PRAGMA.
Controle de transação
Funções no AnalyticDB for PostgreSQL não suportam BEGIN, COMMIT ou ROLLBACK dentro do corpo da função. Aplique uma destas estratégias:
Exclua as instruções de controle de transação do corpo da função e inclua-as fora da chamada da função.
Divida a função em cada limite de
COMMITouROLLBACKem funções separadas.
EXECUTE (SQL dinâmico)
O AnalyticDB for PostgreSQL suporta SQL dinâmico, mas com estas diferenças em relação ao Oracle:
A sintaxe
USINGnão é suportada. Concatene parâmetros diretamente nas strings SQL.Envolva identificadores de banco de dados com
quote_idente valores de string comquote_literal.
Oracle:
EXECUTE 'UPDATE employees_temp SET commission_pct = :x' USING a_null;
AnalyticDB for PostgreSQL:
-- USING replaced with string concatenation using quote_literal
EXECUTE 'UPDATE employees_temp SET commission_pct = ' || quote_literal(a_null);
Funções PIPE ROW
Substitua funções PIPE ROW por funções de tabela usando RETURNS SETOF <type> e RETURN NEXT.
Oracle:
TYPE pair IS RECORD(a int, b int);
TYPE numset_t IS TABLE OF pair;
FUNCTION f1(x int) RETURN numset_t PIPELINED IS
DECLARE
v_p pair;
BEGIN
FOR i IN 1..x LOOP
v_p.a := i;
v_p.b := i+10;
PIPE ROW(v_p);
END LOOP;
RETURN;
END;
SELECT * FROM f1(10);
AnalyticDB for PostgreSQL:
-- RECORD type -> CREATE TYPE; PIPE ROW -> RETURN NEXT; PIPELINED -> RETURNS SETOF
CREATE TYPE pair AS (a int, b int);
CREATE OR REPLACE FUNCTION f1(x int) RETURNS SETOF pair AS
$$
DECLARE
rec pair;
BEGIN
FOR i IN 1..x LOOP
rec := row(i, i+10);
RETURN NEXT rec;
END LOOP;
RETURN;
END
$$
LANGUAGE plpgsql;
SELECT * FROM f1(10);
Tratamento de exceções
Use a instrução
RAISEpara lançar exceções.Após capturar uma exceção, a transação não pode ser revertida dentro da função. O rollback só é permitido fora de funções definidas pelo usuário.
Para códigos de erro suportados, consulte a referência de códigos de erro do PostgreSQL.
Funções com argumentos RETURN e OUT
Uma função não pode usar simultaneamente um argumento RETURN e um argumento OUT. Converta o argumento RETURN em um argumento OUT adicional e recupere os valores de retorno usando SELECT * FROM test_func(...) INTO rec.
Oracle:
CREATE OR REPLACE FUNCTION test_func(id int, name varchar(10), out_id out int) RETURNS varchar(10)
AS $body$
BEGIN
out_id := id + 1;
RETURN name;
END
$body$
LANGUAGE PLPGSQL;
AnalyticDB for PostgreSQL:
-- RETURN value converted to an OUT argument (out_name)
CREATE OR REPLACE FUNCTION test_func(id int, name varchar(10), out_id out int, out_name out varchar(10))
AS $body$
BEGIN
out_id := id + 1;
out_name := name;
END
$body$
LANGUAGE PLPGSQL;
-- Retrieve both output values
SELECT * FROM test_func(1, '1') INTO rec;
Aspas simples na concatenação de strings SQL dinâmicas
Quando uma variável string contém aspas simples (ex.: adb'-'pg), a concatenação direta causa um erro de análise porque hífens são interpretados como operadores. Use quote_literal para incorporar o valor com segurança.
Oracle:
sql_str := 'SELECT * FROM test1 WHERE col1 = ' || param1 || ' AND col2 = ''' || param2 || ''' AND col3 = 3';
AnalyticDB for PostgreSQL:
-- quote_literal wraps param2 safely, handling embedded quotes
sql_str := 'SELECT * FROM test1 WHERE col1 = ' || param1 || ' AND col2 = ' || quote_literal(param2) || ' AND col3 = 3';
Dias entre dois timestamps
Oracle:
SELECT to_date('2019-06-30 16:16:16') - to_date('2019-06-29 15:15:15') + 1 INTO v_days FROM dual;
AnalyticDB for PostgreSQL:
-- Use extract() to get integer day count from an interval
SELECT extract('days' FROM '2019-06-30 16:16:16'::timestamp - '2019-06-29 15:15:15'::timestamp + '1 days'::interval)::int INTO v_days;
Tipos de dados PL
Tipo RECORD
Converta tipos RECORD do Oracle para tipos compostos:
Oracle:
TYPE rec IS RECORD (a int, b int);
AnalyticDB for PostgreSQL:
CREATE TYPE rec AS (a int, b int);
Tabelas aninhadas e arrays de tamanho variável
Como variáveis PL, tanto NESTED TABLE quanto VARRAY mapeiam para o tipo ARRAY do PostgreSQL.
Oracle:
DECLARE
TYPE Roster IS TABLE OF VARCHAR2(15);
names Roster := Roster('D Caruso', 'J Hamil', 'D Piro', 'R Singh');
BEGIN
FOR i IN names.FIRST .. names.LAST LOOP
IF names(i) = 'J Hamil' THEN
DBMS_OUTPUT.PUT_LINE(names(i));
END IF;
END LOOP;
END;
AnalyticDB for PostgreSQL:
-- TABLE OF -> varchar[]; array indexing: names(i) -> names[i]; FIRST..LAST -> 1..array_length
CREATE OR REPLACE FUNCTION f1() RETURNS VOID AS
$$
DECLARE
names varchar(15)[] := '{"D Caruso", "J Hamil", "D Piro", "R Singh"}';
len int := array_length(names, 1);
BEGIN
FOR i IN 1..len LOOP
IF names[i] = 'J Hamil' THEN
RAISE NOTICE '%', names[i];
END IF;
END LOOP;
RETURN;
END
$$
LANGUAGE plpgsql;
SELECT f1();
Se a tabela aninhada for usada como valor de retorno de função, use uma função de tabela (RETURNS SETOF <type>) em vez disso.
Arrays associativos
Não há substituto para arrays associativos do Oracle no AnalyticDB for PostgreSQL. Esta construção exige redesenho.
Variáveis globais
O AnalyticDB for PostgreSQL não suporta variáveis globais. Armazene variáveis globais de nível de pacote em uma tabela temporária e defina funções de acesso.
-- Store global variables in a temporary table
-- Note: The id column is the distribution key and cannot be modified
CREATE TEMPORARY TABLE global_variables (
id int,
g_count int,
g_set_id varchar(50),
g_err_code varchar(100)
);
INSERT INTO global_variables VALUES(0, 1, null, null);
-- Getter function
CREATE OR REPLACE FUNCTION get_variable() RETURNS SETOF global_variables AS
$$
DECLARE
rec global_variables%rowtype;
BEGIN
EXECUTE 'SELECT * FROM global_variables' INTO rec;
RETURN NEXT rec;
END;
$$
LANGUAGE plpgsql;
-- Setter function
CREATE OR REPLACE FUNCTION set_variable(IN param varchar(50), IN value anyelement) RETURNS void AS
$$
BEGIN
EXECUTE 'UPDATE global_variables SET ' || quote_ident(param) || ' = ' || quote_literal(value);
END;
$$
LANGUAGE plpgsql;
Para modificar uma variável global:
-- Declare tmp_rec record; in the calling function
SELECT * FROM set_variable('g_err_code', 'error'::varchar) INTO tmp_rec;
Para ler uma variável global:
SELECT * FROM get_variable() INTO tmp_rec;
error_code := tmp_rec.g_err_code;
Conversões SQL
CONNECT BY
A cláusula CONNECT BY para consultas hierárquicas não tem equivalente SQL direto no AnalyticDB for PostgreSQL. Reescreva-a como uma função PL/pgSQL que percorre a hierarquia iterativamente.
Oracle:
SELECT emp_id, lead_id, emp_name, PRIOR emp_name AS lead_name, salary
FROM employee
START WITH lead_id = 0
CONNECT BY PRIOR emp_id = lead_id;
AnalyticDB for PostgreSQL (função de percurso iterativo):
CREATE OR REPLACE FUNCTION f1(tablename text, lead_id int, nocycle boolean) RETURNS SETOF employee AS
$$
DECLARE
idx int := 0;
res_tbl varchar(265) := 'result_table';
prev_tbl varchar(265) := 'tmp_prev';
curr_tbl varchar(256) := 'tmp_curr';
current_result_sql varchar(4000);
tbl_count int;
rec record;
BEGIN
EXECUTE 'TRUNCATE ' || prev_tbl;
EXECUTE 'TRUNCATE ' || curr_tbl;
EXECUTE 'TRUNCATE ' || res_tbl;
LOOP
-- Query the current hierarchy level and insert into tmp_curr
current_result_sql := 'INSERT INTO ' || curr_tbl || ' SELECT t1.* FROM ' || tablename || ' t1';
IF idx > 0 THEN
current_result_sql := current_result_sql || ', ' || prev_tbl || ' t2 WHERE t1.lead_id = t2.emp_id';
ELSE
current_result_sql := current_result_sql || ' WHERE t1.lead_id = ' || lead_id;
END IF;
EXECUTE current_result_sql;
-- If nocycle is false, remove already-traversed rows
IF nocycle IS FALSE THEN
EXECUTE 'DELETE FROM ' || curr_tbl || ' WHERE (lead_id, emp_id) IN (SELECT lead_id, emp_id FROM ' || res_tbl || ')';
END IF;
-- Exit when no more rows
EXECUTE 'SELECT count(*) FROM ' || curr_tbl INTO tbl_count;
EXIT WHEN tbl_count = 0;
-- Promote current results to result and prev tables
EXECUTE 'INSERT INTO ' || res_tbl || ' SELECT * FROM ' || curr_tbl;
EXECUTE 'TRUNCATE ' || prev_tbl;
EXECUTE 'INSERT INTO ' || prev_tbl || ' SELECT * FROM ' || curr_tbl;
EXECUTE 'TRUNCATE ' || curr_tbl;
idx := idx + 1;
END LOOP;
FOR rec IN EXECUTE 'SELECT * FROM ' || res_tbl LOOP
RETURN NEXT rec;
END LOOP;
RETURN;
END
$$
LANGUAGE plpgsql;
ROWNUM
Limitar tamanho do resultado:
Oracle:
SELECT * FROM t WHERE rownum < 10;
AnalyticDB for PostgreSQL:
SELECT * FROM t LIMIT 10;
Gerar números de linha:
Oracle:
SELECT rownum, * FROM t;
AnalyticDB for PostgreSQL:
SELECT row_number() OVER() AS rownum, * FROM t;
Tabela DUAL
Opção 1 — Remover FROM DUAL:
Oracle:
SELECT sysdate FROM dual;
AnalyticDB for PostgreSQL:
SELECT current_timestamp;
Opção 2 — Criar uma tabela dual:
CREATE TABLE dual (dummy varchar(1));
INSERT INTO dual VALUES ('X');
Funções definidas pelo usuário em instruções SELECT
O AnalyticDB for PostgreSQL não permite chamar funções definidas pelo usuário que contenham instruções SQL dentro de SELECT. Fazer isso causa um erro de segmento:
ERROR: function cannot execute on segment because it accesses relation "public.t2"
Converta tais funções em expressões SQL ou subconsultas.
Oracle:
CREATE OR REPLACE FUNCTION f1(arg int) RETURN int IS
v int;
BEGIN
SELECT b INTO v FROM t2 WHERE a = arg;
RETURN v;
END;
SELECT a, f1(b) FROM t1;
AnalyticDB for PostgreSQL:
-- Inline the function logic as a join
SELECT t1.a, t2.b FROM t1, t2 WHERE t1.b = t2.a;
OUTER JOIN (+)
Outer join de duas tabelas:
Oracle:
SELECT * FROM a, b WHERE a.id = b.id(+);
AnalyticDB for PostgreSQL:
SELECT * FROM a LEFT JOIN b ON a.id = b.id;
Outer join de três tabelas:
Use uma Common Table Expression (CTE) para unir duas tabelas primeiro e aplique RIGHT OUTER JOIN com coalesce.
Oracle:
SELECT * FROM test1 t1, test2 t2, test3 t3
WHERE t1.col1(+) BETWEEN NVL(t2.col1, t3.col1) AND NVL(t3.col1, t2.col1);
AnalyticDB for PostgreSQL:
WITH cte AS (
SELECT t2.col1 AS low, t2.col2, t3.col1 AS high, t3.col2 AS c2
FROM t2, t3
)
SELECT * FROM t1
RIGHT OUTER JOIN cte ON t1.col1 BETWEEN coalesce(cte.low, cte.high) AND coalesce(cte.high, cte.low);
MERGE INTO
Na maioria dos casos, substitua MERGE INTO por INSERT ON CONFLICT. Para casos que INSERT ON CONFLICT não consegue cobrir, use stored procedures.
Sequências
Oracle:
CREATE SEQUENCE seq1;
SELECT seq1.nextval FROM dual;
AnalyticDB for PostgreSQL:
CREATE SEQUENCE seq1;
SELECT nextval('seq1');
Cursores
O percurso básico de cursor é suportado. Use o padrão OPEN/FETCH/CLOSE:
Oracle:
FUNCTION test_func() IS
CURSOR data_cursor IS SELECT * FROM test1;
BEGIN
FOR i IN data_cursor LOOP
-- process i
END LOOP;
END;
AnalyticDB for PostgreSQL:
CREATE OR REPLACE FUNCTION test_func()
AS $body$
DECLARE
data_cursor CURSOR FOR SELECT * FROM test1;
i record;
BEGIN
OPEN data_cursor;
LOOP
FETCH data_cursor INTO i;
IF NOT FOUND THEN
EXIT;
END IF;
-- process i
END LOOP;
CLOSE data_cursor;
END;
$body$
LANGUAGE PLPGSQL;
Cursores com o mesmo nome em funções recursivas não são suportados. Substitua por FOR i IN <query>:
Oracle:
FUNCTION test_func(level IN number) IS
CURSOR data_cursor IS SELECT * FROM test1;
BEGIN
IF level > 5 THEN RETURN; END IF;
FOR i IN data_cursor LOOP
-- process i
test_func(level + 1);
END LOOP;
END;
AnalyticDB for PostgreSQL:
-- Named cursor removed; inline query used instead to support recursion
CREATE OR REPLACE FUNCTION test_func(level int) RETURNS void
AS $body$
DECLARE
i record;
BEGIN
IF level > 5 THEN
RETURN;
END IF;
FOR i IN SELECT * FROM test1 LOOP
-- process i
PERFORM test_func(level + 1);
END LOOP;
END;
$body$
LANGUAGE PLPGSQL;
Armadilhas comuns
Essas diferenças de comportamento em tempo de execução são a fonte mais frequente de bugs após a migração. Revise-as antes de testar seu código convertido.
|
Armadilha |
Comportamento do Oracle |
Comportamento do AnalyticDB for PostgreSQL |
Ação |
||
|
NULL na concatenação de strings |
|
NULL` -> |
Retorna |
Mude para o modo de compatibilidade Oracle ou reescreva usando |
|
|
Direção do FOR LOOP REVERSE |
Conta regressivamente do 2º para o 1º número |
Conta regressivamente do 1º para o 2º |
Inverta os limites do loop |
||
|
Controle de transação em funções |
|
Não suportado |
Mova para fora da função ou divida a função |
||
|
SQL dinâmico com |
|
|
Concatene com |
||
|
Funções com |
Ambos permitidos |
Não suportado |
Converta |
||
|
Funções definidas pelo usuário em |
Podem consultar tabelas |
Não podem consultar tabelas |
Reescreva como subconsulta ou join |
||
|
Arrays associativos |
Suportado |
Sem equivalente |
Requer redesenho |
||
|
Cursores com o mesmo nome em recursão |
Suportado |
Não suportado |
Use |