Примеры использования опций sqlways.ini секции [POSTGRE]
[Usage example]:RETURN_RESULT_FROM_SP_AND_FN
Наборы результатов в PosgreSQL могут быть возвращены следующими способами: с помощью таблицы, типа SETOF и с помощью рефкурсора. Ниже приведены примеры вывода с различными вариантами:
Исходный код (MSSQL Server)
create table test_data(c1 int, c2 varchar(22))
create procedure result_set_pr @p1 Date as
select @p1 as c0, c1, c2 from test_data
Преобразованный код PostgreSQL (RETURN_RESULT_FROM_SP_AND_FN=TABLE, по умолчанию)
CREATE OR REPLACE FUNCTION result_set_pr(v_p1 DATE)
RETURNS table
(
c0 DATE,
c1 INTEGER,
c2 VARCHAR(22)
) LANGUAGE plpgsql
AS $$
BEGIN
return query select v_p1 as c0, c1, c2 from test_data;
END; $$;
Преобразованный код PostgreSQL (RETURN_RESULT_FROM_SP_AND_FN=SETOF)
CREATE TYPE result_set_pr_rs AS(c0 DATE, c1 INTEGER, c2 VARCHAR(22));
CREATE OR REPLACE FUNCTION result_set_pr(v_p1 DATE)
RETURNS SETOF result_set_pr_rs LANGUAGE plpgsql
AS $$
BEGIN
return query select v_p1 as c0, c1, c2 from test_data;
END; $$;
Преобразованный код PostgreSQL (RETURN_RESULT_FROM_SP_AND_FN=REFCURSOR)
CREATE OR REPLACE PROCEDURE result_set_pr(v_p1 DATE, INOUT SWV_RefCur refcursor)
LANGUAGE plpgsql
AS $$
BEGIN
open SWV_RefCur for
select v_p1 as c0, c1, c2 from test_data;
END; $$;
[Usage example]:TABLE_TYPE_CONVERSION
PostgreSQL не поддерживает коллекции, но есть 2 способа имитировать логику Oracle.
По умолчанию табличные типы (TYPE IS TABLE, VARRAYS) преобразуются с помощью массивов. Другой способ - преобразовать табличные типы в массивы в PostgreSQL (используя временные таблицы), как это показано в столбце 2 таблицы. Исходный код (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 (TABLE_TYPE_CONVERSION=Tables)
CREATE TYPE EMPLOYEE AS(id DOUBLE PRECISION,Name VARCHAR(300));
-- CREATE TYPE EMPLOYEES_TAB IS TABLE OF employee;
CREATE OR REPLACE PROCEDURE HIRE(id DOUBLE PRECISION,Name VARCHAR(4000))
LANGUAGE plpgsql
AS $$
BEGIN
create temporary table if not exists SWT_HIRE_NEW_EMPLOYEES
(
SWC_INDEX INTEGER NOT NULL,
ID DOUBLE PRECISION,
NAME VARCHAR(300)
);
DELETE FROM SWT_HIRE_NEW_EMPLOYEES;
FOR i IN COALESCE((SELECT MAX(SWT_HIRE_EMPLOYEES.SWC_INDEX) FROM SWT_HIRE_EMPLOYEES)+1,1) .. COALESCE((SELECT MAX(SWT_HIRE_EMPLOYEES.SWC_INDEX) FROM SWT_HIRE_EMPLOYEES),
0)+1
LOOP
INSERT INTO SWT_HIRE_EMPLOYEES(SWC_Index) VALUES(i);
END LOOP;
IF NOT EXISTS(SELECT 1 FROM SWT_HIRE_EMPLOYEES WHERE SWT_HIRE_EMPLOYEES.SWC_INDEX =(SELECT COUNT(*) FROM SWT_HIRE_EMPLOYEES)) then
INSERT INTO SWT_HIRE_EMPLOYEES VALUES((SELECT COUNT(*) FROM SWT_HIRE_EMPLOYEES),NULL);
END IF;
UPDATE SWT_HIRE_EMPLOYEES SET id = id,Name = Name
WHERE SWT_HIRE_EMPLOYEES.SWC_INDEX =(SELECT COUNT(*) FROM SWT_HIRE_EMPLOYEES);
FOR i IN(SELECT MIN(SWC_INDEX) FROM SWT_HIRE_EMPLOYEES) ..(SELECT MAX(SWC_INDEX) FROM SWT_HIRE_EMPLOYEES)
LOOP
INSERT INTO EMP_TAB values((SELECT SWT_HIRE_EMPLOYEES.ID FROM SWT_HIRE_EMPLOYEES WHERE SWC_INDEX = i), (SELECT
SWT_HIRE_EMPLOYEES.NAME FROM SWT_HIRE_EMPLOYEES WHERE SWC_INDEX = i));
END LOOP;
INSERT INTO EMP_TAB SELECT * FROM EMPLOYEES;
FOR i IN COALESCE((SELECT MAX(SWT_HIRE_NEW_EMPLOYEES.SWC_INDEX) FROM SWT_HIRE_NEW_EMPLOYEES)+1,1) .. COALESCE((SELECT
MAX(SWT_HIRE_NEW_EMPLOYEES.SWC_INDEX) FROM SWT_HIRE_NEW_EMPLOYEES),0)+(SELECT COUNT(*) FROM SWT_HIRE_EMPLOYEES)
LOOP
INSERT INTO SWT_HIRE_NEW_EMPLOYEES(SWC_Index) VALUES(i);
END LOOP;
DELETE FROM SWT_HIRE_NEW_EMPLOYEES;
END; $$;
Преобразованный код PostgreSQL (TABLE_TYPE_CONVERSION=Arrays, по умолчанию)
CREATE TYPE EMPLOYEE AS(id DOUBLE PRECISION,Name VARCHAR(300));
-- CREATE TYPE EMPLOYEES_TAB IS TABLE OF employee;
CREATE OR REPLACE PROCEDURE HIRE(INOUT EMPLOYEES EMPLOYEE[] ,
ID DOUBLE PRECISION, NAME VARCHAR(4000))
LANGUAGE plpgsql
AS $$
DECLARE
EMPLOYEES_REC EMPLOYEE;
NEW_EMPLOYEES EMPLOYEE[] default array[]::EMPLOYEE[] ;
BEGIN
EMPLOYEES[swf_array_length(EMPLOYEES)+1] := null;
EMPLOYEES[swf_array_length(EMPLOYEES)] := row(ID,NAME);
FOR i IN array_lower(EMPLOYEES,1) .. array_upper(EMPLOYEES,1)
LOOP
EMPLOYEES_REC := EMPLOYEES[i];
INSERT INTO EMP_TAB values(EMPLOYEES_REC.ID, EMPLOYEES_REC.NAME);
EMPLOYEES[i] := EMPLOYEES_REC;
END LOOP;
INSERT INTO EMP_TAB SELECT * FROM unnest(EMPLOYEES);
for i in 1 .. swf_array_length(EMPLOYEES) loop
NEW_EMPLOYEES[swf_array_length(NEW_EMPLOYEES)+1] := null;
end loop;
NEW_EMPLOYEES := array[]:: EMPLOYEE[];
END; $$;
[Usage example]:IDENTITY_TO_SERIAL
PostgreSQL позволяет использовать 2 способа автоматической генерации целых чисел: с помощью свойства IDENTITY или с помощью типа псевдоданных SERIAL. Результат использования опции со значениями "No" и "Yes" показан в таблице ниже. Тип данных исходного столбца IDENTITY будет преобразован в соответствующий столбец SERIAL: SMALLINT станет SMALLSERIAL, INTEGER перейдет в SERIAL, а BIGINT в BIGSERIAL соответственно. Исходный код (DB2 LUW)
CREATE TABLE TABIDENTCOLUMN
(
ID INTEGER GENERATED ALWAYS AS IDENTITY
(START WITH 1, INCREMENT BY 1) NOT NULL,
NAME CHAR(5)
);
CREATE TABLE TABIDENTCOLUMN_2
(
ID SMALLINT GENERATED ALWAYS AS IDENTITY
(START WITH 3, INCREMENT BY 1) NOT NULL,
NAME CHAR(5)
)
Преобразованный код PostgreSQL (IDENTITY_TO_SERIAL=No)
CREATE TABLE TABIDENTCOLUMN
(
ID INTEGER GENERATED ALWAYS AS IDENTITY(START 1 INCREMENT 1) NOT NULL,
NAME CHAR(5)
);
CREATE TABLE TABIDENTCOLUMN_2
(
ID SMALLINT GENERATED ALWAYS AS IDENTITY(START 3 INCREMENT 1) NOT NULL,
NAME CHAR(5)
);
Преобразованный код PostgreSQL (IDENTITY_TO_SERIAL=Yes)
CREATE TABLE TABIDENTCOLUMN
(
ID SERIAL,
NAME CHAR(5)
);
CREATE TABLE TABIDENTCOLUMN_2
(
ID SMALLSERIAL,
NAME CHAR(5)
);
ALTER SEQUENCE TABIDENTCOLUMN_2_ID_seq RESTART WITH 3 INCREMENT BY 1;
[Usage example]:IDENTITY_COLUMN_TYPE
В PostgreSQL разрешено указывать различные типы генерации для столбца IDENTITY. Для того чтобы использовать нужный, можно установить опцию IDENTITY_COLUMN_TYPE.
Ниже показано, как опция IDENTITY_COLUMN_TYPE влияет на результат преобразования: в столбце 1 приведен пример исходного кода, в столбце 2 - преобразованный код с установленной опцией «Always» (или с пустой опцией), а в последнем столбце - преобразованный код с установленной опцией «Default». Исходный код (Microsoft SQL Server)
CREATE TABLE ident_table_pg
(
c1 INT IDENTITY,
c2 VARCHAR(22)
);
Преобразованный код PostgreSQL (с опцией IDENTITY_COLUMN_TYPE=ALWAYS, по умолчанию)
CREATE TABLE ident_table_pg
(
c1 INTEGER GENERATED ALWAYS AS IDENTITY(START 1 INCREMENT 1) NOT NULL,
c2 VARCHAR(22)
);
Преобразованный код PostgreSQL (с опцией IDENTITY_COLUMN_TYPE=DEFAULT)
CREATE TABLE ident_table_pg
(
c1 INTEGER GENERATED BY DEFAULT AS IDENTITY(START 1 INCREMENT 1) NOT NULL,
c2 VARCHAR(22)
);
[Usage example]:TRIGGER_RECURSION_LVL
Чтобы избежать выполнения триггеров, которые будут запускать один и тот же триггер или любые другие триггеры бесконечное количество раз, иначе говоря, рекурсии триггеров, можно добавить соответствующий оператор WHEN для проверки уровня вложенности триггеров.
В следующем примере показаны результаты преобразования триггеров в зависимости от значения опции TRIGGER_RECURSION_LVL: в столбце 1 приведен пример исходного кода триггера, в столбце 2 - преобразованная функция и код триггера, когда значение опции не установлено, а в столбце 3 - преобразованный код с установленной опцией TRIGGER_RECURSION_LVL=0. Триггер в столбце 2 приведет к его бесконечному выполнению, которое в итоге завершится ошибкой «ERROR: превышен предел глубины стека». Чтобы решить эту проблему, необходимо добавить проверку с помощью опции - это можно сделать, указав опцию, как показано в столбце 3. Исходный код (Microsoft SQL Server)
CREATE TRIGGER trigOnTab1
ON tab1
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON
update tab1
set c2 = UPPER(i.c2)
from tab1 t
inner join inserted i on i.c1 = t.c1
END
Преобразованный код PostgreSQL (с опцией TRIGGER_RECURSION_LVL= , по умолчанию)
CREATE OR REPLACE FUNCTION trigOnTab1_TrFunc()
RETURNS TRIGGER LANGUAGE plpgsql
AS $$
BEGIN
BEGIN
update tab1 t
set c2 = UPPER(i.c2)
from new_table i WHERE i.c1 = t.c1;
END;
RETURN NULL;
END; $$;
DROP TRIGGER IF EXISTS trigOnTab1 ON tab1;
CREATE TRIGGER trigOnTab1
AFTER UPDATE
ON tab1
REFERENCING NEW TABLE AS new_table
FOR STATEMENT
EXECUTE PROCEDURE trigOnTab1_TrFunc();
Преобразованный код PostgreSQL (с опцией TRIGGER_RECURSION_LVL=0)
CREATE OR REPLACE FUNCTION trigOnTab1_TrFunc()
RETURNS TRIGGER LANGUAGE plpgsql
AS $$
BEGIN
BEGIN
update tab1 t
set c2 = UPPER(i.c2)
from new_table i WHERE i.c1 = t.c1;
END;
RETURN NULL;
END; $$;
DROP TRIGGER IF EXISTS trigOnTab1 ON tab1;
CREATE TRIGGER trigOnTab1
AFTER UPDATE
ON tab1
REFERENCING NEW TABLE AS new_table
FOR STATEMENT
WHEN (pg_trigger_depth() <1)
EXECUTE PROCEDURE trigOnTab1_TrFunc();
[Usage example]:AUTONOMOUS_TRANSACTION_TO_DBLINK
В примере ниже показана разница в результирующей процедуре в обоих случаях. Пожалуйста, сравните:
| Исходный код Oracle | PostgreSQL AUTONOMOUS_TRANSACTION_TO_DBLINK=No | PostgreSQL AUTONOMOUS_TRANSACTION_TO_DBLINK=Yes |
|---|---|---|
CREATE PROCEDURE AUTO_TEST |
CREATE OR REPLACE PROCEDURE AUTO_TEST |
CREATE OR REPLACE PROCEDURE AUTO_TEST |
[Usage example]:SECURITY_DEFINER
В примере ниже показана разница между результирующей процедурой в обоих случаях. Пожалуйста, сравните:
| Исходный код Oracle | По умолчанию преобразованный код PostgreSQL | Преобразованный код PostgreSQL с опцией SECURITY_DEFINER=Yes |
|---|---|---|
CREATE Procedure Pr_Test(p1 int default 0,p2 int, p3 int ) IS BEGIN insert into tab4 (col1, col2, col3) select p1,p2,p3 from dual; END Pr_Test; |
CREATE OR REPLACE Procedure Pr_Test(p1 INTEGER default 0, |
CREATE OR REPLACE Procedure Pr_Test (p1 INTEGER default 0, |
CREATE or replace Procedure Pr_Test(p1 int default 0,p2 int, p3 int ) |
CREATE or replace Procedure Pr_Test(p1 INTEGER default 0, |
CREATE or replace Procedure Pr_Test(p1 INTEGER default 0, |
[Usage example]:TRIG_PROC_SCHEMA_PREFIX and TRIG_PROC_SCHEMA_SUFFIX
В приведенном ниже примере показана разница в результирующей процедуре в обоих случаях.
[POSTGRE]
TRIG_PROC_SCHEMA_PREFIX=Prefix_
TRIG_PROC_SCHEMA_SUFFIX=_Suffix
Пожалуйста, сравните:
| Исходный код Informix | Преобразованный код PostgreSQL (по умолчанию) | Преобразованный код PostgreSQL (с установленными опциями) |
|---|---|---|
create procedure schm.tr_proc_print() referencing new as n for my_table ; DEFINE v_message VARCHAR(255); LET v_message = 'Nailed it!'; end procedure ; create trigger schm.tr_proc insert on schm.my_table referencing new as new for each row (execute procedure schm.tr_proc_print() with trigger references ); |
CREATE OR REPLACE FUNCTION schm.tr_proc_print_trfunc() |
CREATE SCHEMA IF NOT EXISTS Prefix_schm_Suffix; CREATE OR REPLACE FUNCTION Prefix_schm_Suffix.tr_proc_print_trfunc() RETURNS TRIGGER LANGUAGE plpgsql AS $$ DECLARE v_message VARCHAR(255); BEGIN v_message := 'Nailed it!'; RETURN NULL; END; $$; create trigger tr_proc AFTER insert on schm.my_table |
[Usage example]:CONV_ALL_PROC_TO_FUNC
Вот пример использования опции CONV_ALL_PROC_TO_FUNC:
| Исходный код MSSQL | Преобразованный код PostgreSQL (по умолчанию) | Преобразованный код PostgreSQL с опцией CONV_ALL_PROC_TO_FUNC =Yes |
|---|---|---|
create PROCEDURE [dbo].[sp_tab_insert] @id int, @name varchar(10) AS insert into t3 values (@id, @name) |
create or replace PROCEDURE sp_tab_insert(v_id INTEGER, v_name VARCHAR) LANGUAGE plpgsql AS $$ BEGIN insert into T3 values(v_id, v_name); END; $$; |
create or replace FUNCTION sp_tab_insert(v_id INTEGER, v_name VARCHAR) RETURNS VOID LANGUAGE plpgsql AS $$ BEGIN insert into T3 values(v_id, v_name); RETURN; END; $$; |
[Usage example]:CASE_INSENS_DATA
В примере ниже показана разница в результирующей процедуре в случаях DEFAULT и COLLATION. Пожалуйста, сравните:
| Тип / Значение параметра | Примеры кода |
|---|---|
| Исходный код MSSQL | create table tb_collation ( first_name varchar(64), last_name varchar(64) ); create procedure pr_collation @title varchar(20) = 'convertum' as BEGIN declare @title2 varchar(20) = 'CONVERTUM' IF (@title = @title2) begin print 'equal' END IF (@title like @title2 ) begin print 'like' END END |
| PostgreSQL CASE_INSENS_DATA=Default |
create table tb_collation ( first_name VARCHAR(64), last_name VARCHAR(64) ); create or replace PROCEDURE pr_collation
(v_title VARCHAR DEFAULT 'convertum')
LANGUAGE plpgsql
AS $$
DECLARE
v_title2 VARCHAR(20) DEFAULT 'CONVERTUM';
BEGIN
IF (v_title = v_title2) then
RAISE NOTICE 'equal';
end if;
IF (v_title ilike v_title2) then
RAISE NOTICE 'like';
end if;
END; $$; |
| PostgreSQL CASE_INSENS_DATA=Collation |
CREATE COLLATION IF NOT EXISTS swcol_ci_nondet (provider = icu, locale = 'und-u-ks-level2', deterministic = false); CREATE COLLATION IF NOT EXISTS swcol_ci_det (provider = icu, locale = 'und-u-ks-level2', deterministic = true); create table tb_collation ( first_name VARCHAR(64) COLLATE swcol_ci_nondet, last_name VARCHAR(64) COLLATE swcol_ci_nondet ); create or replace PROCEDURE pr_collation(v_title VARCHAR DEFAULT 'ispirer')
LANGUAGE plpgsql
AS $$
DECLARE
v_title2 VARCHAR(20) COLLATE swcol_ci_nondet DEFAULT 'ISPIRER';
BEGIN
IF (v_title COLLATE swcol_ci_nondet = v_title2) then
RAISE NOTICE 'equal';
end if;
IF (v_title ilike v_title2 COLLATE swcol_ci_det) then
RAISE NOTICE 'like';
end if;
END; $$; |
| PostgreSQL CASE_INSENS_DATA=Lower |
create table tb_collation ( first_name VARCHAR(64), last_name VARCHAR(64) ); create or replace PROCEDURE pr_collation(v_title VARCHAR DEFAULT 'ispirer')
LANGUAGE plpgsql
AS $$
DECLARE
v_title2 VARCHAR(20) DEFAULT 'ISPIRER';
BEGIN
IF (LOWER(v_title) = LOWER(v_title2)) then
RAISE NOTICE 'equal';
end if;
IF (v_title ilike v_title2) then
RAISE NOTICE 'like';
end if;
END; $$; |
Если этот вариант не сработал, пожалуйста, свяжитесь с нашей технической службой: support@convertum.ru.
[Usage example]:RESOLVE_PARAMETER_NAME_AMBIGUITY
В примере ниже показана разница в результирующей процедуре в случаях No и Yes. Пожалуйста, сравните:
| Исходный код Informix | PostgreSQL RESOLVE_PARAMETER_NAME_AMBIGUITY =No | PostgreSQL RESOLVE_PARAMETER_NAME_AMBIGUITY =Yes |
|---|---|---|
CREATE PROCEDURE sp_table_ambiguity (col1 integer, col2 integer, col3 integer) DEFINE var_expr1 INTEGER; DEFINE var_expr2 INTEGER; SELECT table1.col1, col3 INTO var_expr1, var_expr2 FROM table1 WHERE table1.col2 = col1 LIMIT 1; END PROCEDURE |
CREATE OR REPLACE PROCEDURE sp_table_ambiguity(col1 INTEGER, col2 INTEGER, col3 INTEGER) LANGUAGE plpgsql AS $$ DECLARE var_expr1 INTEGER; var_expr2 INTEGER; BEGIN SELECT table1.col1, col3 INTO var_expr1,var_expr2 FROM table1 WHERE table1.col2 = col1 LIMIT 1; END; $$; |
CREATE OR REPLACE PROCEDURE sp_table_ambiguity(col1 INTEGER, col2 INTEGER, col3 INTEGER) LANGUAGE plpgsql AS $$ DECLARE var_expr1 INTEGER; var_expr2 INTEGER; BEGIN SELECT table1.col1, sp_table_ambiguity.col3 INTO var_expr1,var_expr2 FROM table1 WHERE table1.col2 = sp_table_ambiguity.col1 LIMIT 1; END; $$; |
Если этот вариант не сработал, пожалуйста, свяжитесь с нашей технической службой: support@convertum.ru.
[Usage example]:USE_CUSTOM_CAST_DATE_INT
В примере ниже показана разница в результирующей процедуре в случаях No и Yes. Пожалуйста, сравните:
| Исходный код Informix | PostgreSQL USE_CUSTOM_CAST_DATE_INT =No | PostgreSQL USE_CUSTOM_CAST_DATE_INT =Yes |
|---|---|---|
create table t_log(id integer, col1 integer, col2 integer); CREATE PROCEDURE sp_date_as_integer (ibuf INTEGERT) DEFINE res date; LET res = ibuf; LET ibuf = res; insert into t_log values (1, ibuf, res); END PROCEDURE; |
create table t_log(id INTEGER, col1 INTEGER, col2 INTEGER); CREATE OR REPLACE PROCEDURE sp_date_as_integer(ibuf INTEGERT) LANGUAGE plpgsql AS $$ DECLARE res DATE; BEGIN res := CAST(ibuf AS DATE); ibuf := EXTRACT(DAY FROM(res):: TIMESTAMP -'1899-12-31':: TIMESTAMP); insert into dbm.alf_log_k values(1, ibuf, EXTRACT(DAY FROM(res):: TIMESTAMP -'1899-12-31':: TIMESTAMP)); END; $$; |
create table t_log(id INTEGER, col1 INTEGER, col2 INTEGER); CREATE OR REPLACE PROCEDURE sp_date_as_integer(ibuf INTEGERT) LANGUAGE plpgsql AS $$ DECLARE res DATE; BEGIN res := CAST(ibuf AS DATE); ibuf := CAST(res AS INTEGER); insert into t_log values(1, ibuf, CAST(res AS INTEGER)); END; $$; |
[Usage example]:ANSINULL
Ниже вы можете увидеть пример исходного кода пользовательской функции с несколькими аргументами. Левый столбец содержит исходный код, второй столбец показывает преобразованный код без опции, а третий столбец демонстрирует результаты преобразования, когда опция ANSINULL установлена в значение OFF .
| Исходный код (Sybase ASE) | Преобразованный код PostgreSQL (без опции ANSINULL или ANSINULL=ON) | Преобразованный код PostgreSQL (с опцией ANSINULL=OFF) |
|---|---|---|
CREATE PROCEDURE sp_ansinull @param1 INT AS BEGIN SELECT 1 WHERE @param1=@param2 END |
CREATE OR REPLACE FUNCTION sp_ansinull(v_param1 INTEGER, v_param2 INTEGER)
RETURNS TABLE
(
col INTEGER
) LANGUAGE plpgsql
AS $$
BEGIN
IF v_param1 = v_param2 then
return query
select 1;
end if;
END; $$; |
CREATE OR REPLACE FUNCTION sp_ansinull(v_param1 INTEGER, v_param2 INTEGER)
RETURNS TABLE
(
col INTEGER
) LANGUAGE plpgsql
AS $$
BEGIN
IF (v_param1 IS NOT DISTINCT FROM v_param2) then
return query
select 1;
end if;
END; $$; |
Как видно, если опция ANSINULL не включена (ANSINULL=OFF), преобразование гарантирует, что поведение обработки NULL в PostgreSQL будет соответствовать поведению Sybase ASE. Это означает, что сравнения с NULL-значениями будут обрабатываться таким образом, чтобы сохранить совместимость с исходной логикой, предотвращая неожиданные результаты из-за различий в поведении базы данных.
Если опция ANSINULL включена (ANSINULL=ON), применяются стандартные правила обработки NULL в PostgreSQL, что может привести к расхождениям в обработке значений NULL при выполнении запросов.
Если этот вариант не сработал, пожалуйста, свяжитесь с нашей технической службой: support@convertum.ru.
[Usage example]:FUNC_MAX_ARGS
Ниже приведен пример исходного кода для пользовательской функции с несколькими аргументами.
Левый столбец содержит исходный код, второй столбец показывает преобразованный код без опции, а третий столбец демонстрирует результаты преобразования, когда опция FUNC_MAX_ARGS установлена в пользовательское значение.
| Исходный код (Sybase ASE) | Преобразованный код PostgreSQL (без опции FUNC_MAX_ARGS или FUNC_MAX_ARGS=100/Пусто) | Преобразованный код PostgreSQL (с опцией FUNC_MAX_ARGS=200) |
|---|---|---|
CREATE PROCEDURE MyProc @param1 INT, @param2 INT, @param3 INT, … @param200 INT AS BEGIN SELECT 1 END |
CREATE TYPE MyProc_PS AS ( v_param1 INTEGER, v_param2 INTEGER, v_param3 INTEGER, -- Add more parameters until param200 v_param200 INTEGER ); CREATE OR REPLACE FUNCTION MyProc(SWP_INPUT MyProc_PS) RETURNS TABLE (col INTEGER) LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT 1; END; $$; |
CREATE OR REPLACE FUNCTION MyProc( v_param1 INTEGER, v_param2 INTEGER, v_param3 INTEGER, -- Add more parameters until param200 v_param200 INTEGER) RETURNS TABLE (col INTEGER) LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT 1; END; $$; |
Как видно, если параметр FUNC_MAX_ARGS не указан, используется значение по умолчанию (100), что позволяет преобразовывать функции и процедуры с числом аргументов до 100 без создания дополнительного типа.
Если опция явно задана, то все функции/процедуры, имеющие более указанного количества параметров, будут преобразованы с использованием дополнительного типа.
Если этот вариант не сработал, пожалуйста, свяжитесь с нашей технической службой: support@convertum.ru.
[Usage example]: RECURSIVE_TRIGGERS_ENABLED
Цель этой статьи - продемонстрировать, как опция RECURSIVE_TRIGGERS_ENABLED влияет на результаты конвертации.
Следующий пример иллюстрирует влияние включения или отключения этой опции при создании триггера:
Левый столбец содержит исходный код, второй столбец показывает преобразованный код без опции, а третий столбец демонстрирует результаты преобразования, когда опция RECURSIVE_TRIGGERS_ENABLED установлена в пользовательское значение.
| Исходный код (MS SQL Server) | Преобразованный код PostgreSQL (без опции RECURSIVE_TRIGGERS_ENABLED илиRECURSIVE_TRIGGERS_ENABLED=No) | Преобразованный код PostgreSQL (с опцией RECURSIVE_TRIGGERS_ENABLED=Yes) |
|---|---|---|
create TRIGGER tr_rec_update
ON tab_for_tr
AFTER UPDATE
AS
BEGIN
update t
set b_col = UPPER(i.b_col)
from tab_for_tr t
inner join inserted i on t.a_col = i.a_col
END |
CREATE TRIGGER tr_rec_update AFTER UPDATE ON tab_for_tr REFERENCING NEW TABLE AS new_table FOR STATEMENT WHEN(pg_trigger_depth() |
CREATE TRIGGER tr_rec_update AFTER UPDATE ON tab_for_tr REFERENCING NEW TABLE AS new_table FOR STATEMENT EXECUTE PROCEDURE tr_rec_update_TrFunc(); |
Параметр RECURSIVE_TRIGGERS_ENABLED служит той же цели, что и параметр „Recursive triggers enabled“ (или RECURSIVE_TRIGGERS) в базе данных MS SQL Server. Она управляет рекурсией для триггеров. Значение по умолчанию - NO, как и OFF в MS SQL Server. Когда опция установлена в NO, все триггеры с прямой рекурсией будут вызываться один раз, а если опция установлена в YES, то рекурсия разрешена.
Если этот вариант не сработал, пожалуйста, свяжитесь с нашей технической службой: support@convertum.ru.
[Usage example]: PACKAGE_VAR_CONVERSION
Цель этой статьи - продемонстрировать, как параметр PACKAGE_VAR_CONVERSION влияет на результаты преобразования.
В примерах ниже показана разница в результирующей процедуре для случаев <пусто>, pg_variables и session_config_params. Пожалуйста, сравните:
Левый столбец содержит исходный код, второй столбец показывает преобразованный код без опции, а третий столбец демонстрирует результаты преобразования, когда опция PACKAGE_VAR_CONVERSION установлена в pg_variables значение.
| Тип / Значение параметра | Примеры кода |
|---|---|
| Исходный код Oracle | CREATE OR REPLACE PACKAGE test_pkg1 IS
g_n1 number := 15;
PROCEDURE proc1;
END;
/
CREATE OR REPLACE PACKAGE BODY test_pkg1 IS
g_n2 CONSTANT NUMBER := 2026;
g_s varchar2(65) := 'ТЕСТ';
PROCEDURE print_global_vars IS
BEGIN
DBMS_OUTPUT.PUT_LINE('g_n1 = '||g_n1);
DBMS_OUTPUT.PUT_LINE('g_n2 = '||g_n2);
DBMS_OUTPUT.PUT_LINE('g_s = '||g_s);
END;
PROCEDURE proc1 IS
v_n NUMBER;
v_v varchar2(65);
BEGIN
v_n := g_n2;
if g_s = 'ТЕСТ1' then
g_s := 'aaa';
g_n1 := 1000;
else
g_s := 'bbb';
g_n1 := 2000;
end if;
v_v := g_s;
DBMS_OUTPUT.PUT_LINE('v_n = '||v_n);
DBMS_OUTPUT.PUT_LINE('v_v = '||v_v);
print_global_vars;
END;
BEGIN
DBMS_OUTPUT.PUT_LINE('Body Initialization Block');
g_s := 'ТЕСТ1';
END;
/ |
| PostgreSQL PACKAGE_VAR_CONVERSION= |
CREATE SCHEMA IF NOT EXISTS TEST_PKG1
;
DROP TYPE IF EXISTS TEST_PKG1.GL_VAR_TYPE CASCADE;
CREATE type TEST_PKG1.GL_VAR_TYPE
as(g_n1 NUMERIC,
g_n2 NUMERIC,
g_s VARCHAR(65));
CREATE OR REPLACE FUNCTION TEST_PKG1.INIT_GL_VAR()
RETURNS VOID LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE;
BEGIN
CREATE TEMPORARY TABLE TEST_PKG1_GL_VAR AS SELECT(15,2026,'ТЕСТ')::TEST_PKG1.GL_VAR_TYPE AS SWV_GL_VAR_VAL;
-- begin Initialization Block
SWV_GL_VAR := TEST_PKG1.GET_GL_VAR();
RAISE NOTICE 'Body Initialization Block';
SWV_GL_VAR.G_S := 'ТЕСТ1';
CALL TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
-- end Initialization Block
RETURN;
EXCEPTION
WHEN SQLSTATE '42P07' THEN
NULL;
END; $$;
CREATE OR REPLACE FUNCTION TEST_PKG1.GET_GL_VAR()
RETURNS TEST_PKG1.GL_VAR_TYPE LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE;
BEGIN
RETURN(select SWV_GL_VAR_VAL:: TEST_PKG1.GL_VAR_TYPE from TEST_PKG1_GL_VAR);
EXCEPTION
WHEN OTHERS THEN
PERFORM TEST_PKG1.INIT_GL_VAR();
RETURN(select SWV_GL_VAR_VAL:: TEST_PKG1.GL_VAR_TYPE from TEST_PKG1_GL_VAR);
END; $$;
CREATE OR REPLACE PROCEDURE TEST_PKG1.SET_GL_VAR(SWP_GLVAR TEST_PKG1.GL_VAR_TYPE)
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE TEST_PKG1_GL_VAR SET SWV_GL_VAR_VAL = SWP_GLVAR;
END; $$;
CREATE OR REPLACE PROCEDURE test_pkg1.PRINT_GLOBAL_VARS()
LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE DEFAULT TEST_PKG1.GET_GL_VAR();
BEGIN
RAISE NOTICE '%',CONCAT('g_n1 = ',SWV_GL_VAR.g_n1);
RAISE NOTICE '%',CONCAT('g_n2 = ',SWV_GL_VAR.g_n2);
RAISE NOTICE '%',CONCAT('g_s = ',SWV_GL_VAR.g_s);
END; $$;
CREATE OR REPLACE PROCEDURE test_pkg1.PROC1()
LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE DEFAULT TEST_PKG1.GET_GL_VAR();
v_n NUMERIC;
v_v VARCHAR(65);
BEGIN
v_n := SWV_GL_VAR.g_n2;
if SWV_GL_VAR.g_s = 'ТЕСТ1' then
SWV_GL_VAR.G_S := 'aaa';
CALL TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
SWV_GL_VAR.G_N1 := 1000;
CALL TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
else
SWV_GL_VAR.G_S := 'bbb';
CALL TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
SWV_GL_VAR.G_N1 := 2000;
CALL TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
end if;
v_v := SWV_GL_VAR.g_s;
RAISE NOTICE '%',CONCAT('v_n = ',v_n);
RAISE NOTICE '%',CONCAT('v_v = ',v_v);
CALL TEST_PKG1.PRINT_GLOBAL_VARS();
SWV_GL_VAR := TEST_PKG1.GET_GL_VAR();
END; $$; |
| PostgreSQL PACKAGE_VAR_CONVERSION=pg_variables |
CREATE SCHEMA IF NOT EXISTS TEST_PKG1
;
DROP TYPE IF EXISTS TEST_PKG1.GL_VAR_TYPE CASCADE;
CREATE type TEST_PKG1.GL_VAR_TYPE
as(g_n1 NUMERIC,
g_n2 NUMERIC,
g_s VARCHAR(65));
CREATE OR REPLACE FUNCTION TEST_PKG1.GET_GL_VAR()
RETURNS TEST_PKG1.GL_VAR_TYPE LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE;
BEGIN
if not pgv_exists('TEST_PKG1','GL_VAR_TYPE') then
perform pgv_set('TEST_PKG1','GL_VAR_TYPE',(15,2026,'ТЕСТ')::TEST_PKG1.GL_VAR_TYPE);
-- begin Initialization Block
SWV_GL_VAR := TEST_PKG1.GET_GL_VAR();
RAISE NOTICE 'Body Initialization Block';
SWV_GL_VAR.G_S := 'ТЕСТ1';
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
-- end Initialization Block
end if;
return(select pgv_get('TEST_PKG1','GL_VAR_TYPE',NULL:: TEST_PKG1.GL_VAR_TYPE));
END; $$;
CREATE OR REPLACE FUNCTION TEST_PKG1.SET_GL_VAR(SWP_GLVAR TEST_PKG1.GL_VAR_TYPE)
RETURNS VOID LANGUAGE plpgsql
AS $$
BEGIN
perform pgv_set('TEST_PKG1','GL_VAR_TYPE',SWP_GLVAR);
END; $$;
CREATE OR REPLACE PROCEDURE test_pkg1.PRINT_GLOBAL_VARS()
LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE DEFAULT TEST_PKG1.GET_GL_VAR();
BEGIN
RAISE NOTICE '%',CONCAT('g_n1 = ',SWV_GL_VAR.g_n1);
RAISE NOTICE '%',CONCAT('g_n2 = ',SWV_GL_VAR.g_n2);
RAISE NOTICE '%',CONCAT('g_s = ',SWV_GL_VAR.g_s);
END; $$;
CREATE OR REPLACE PROCEDURE test_pkg1.PROC1()
LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE DEFAULT TEST_PKG1.GET_GL_VAR();
v_n NUMERIC;
v_v VARCHAR(65);
BEGIN
v_n := SWV_GL_VAR.g_n2;
if SWV_GL_VAR.g_s = 'ТЕСТ1' then
SWV_GL_VAR.G_S := 'aaa';
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
SWV_GL_VAR.G_N1 := 1000;
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
else
SWV_GL_VAR.G_S := 'bbb';
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
SWV_GL_VAR.G_N1 := 2000;
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
end if;
v_v := SWV_GL_VAR.g_s;
RAISE NOTICE '%',CONCAT('v_n = ',v_n);
RAISE NOTICE '%',CONCAT('v_v = ',v_v);
CALL TEST_PKG1.PRINT_GLOBAL_VARS();
SWV_GL_VAR := TEST_PKG1.GET_GL_VAR();
END; $$; |
| PostgreSQL PACKAGE_VAR_CONVERSION= session_config_params |
CREATE SCHEMA IF NOT EXISTS TEST_PKG1
;
DROP TYPE IF EXISTS TEST_PKG1.GL_VAR_TYPE CASCADE;
CREATE type TEST_PKG1.GL_VAR_TYPE
as(g_n1 NUMERIC,
g_n2 NUMERIC,
g_s VARCHAR(65));
CREATE OR REPLACE FUNCTION TEST_PKG1.GET_GL_VAR()
RETURNS TEST_PKG1.GL_VAR_TYPE LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE;
BEGIN
RETURN current_setting('sqlways.TEST_PKG1_GL_VAR'):: TEST_PKG1.GL_VAR_TYPE;
EXCEPTION
WHEN SQLSTATE '42704' THEN
SET sqlways.TEST_PKG1_GL_VAR = DEFAULT;
PERFORM set_config('sqlways.TEST_PKG1_GL_VAR',(15,2026,'ТЕСТ')::TEST_PKG1.GL_VAR_TYPE::text,
false);
-- begin Initialization Block
SWV_GL_VAR := TEST_PKG1.GET_GL_VAR();
RAISE NOTICE 'Body Initialization Block';
SWV_GL_VAR.G_S := 'ТЕСТ1';
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
-- end Initialization Block
RETURN current_setting('sqlways.TEST_PKG1_GL_VAR'):: TEST_PKG1.GL_VAR_TYPE;
END; $$;
CREATE OR REPLACE FUNCTION TEST_PKG1.SET_GL_VAR(SWP_GLVAR TEST_PKG1.GL_VAR_TYPE)
RETURNS VOID LANGUAGE plpgsql
AS $$
BEGIN
perform set_config('sqlways.TEST_PKG1_GL_VAR',SWP_GLVAR::text,false);
END; $$;
CREATE OR REPLACE PROCEDURE test_pkg1.PRINT_GLOBAL_VARS()
LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE DEFAULT TEST_PKG1.GET_GL_VAR();
BEGIN
RAISE NOTICE '%',CONCAT('g_n1 = ',SWV_GL_VAR.g_n1);
RAISE NOTICE '%',CONCAT('g_n2 = ',SWV_GL_VAR.g_n2);
RAISE NOTICE '%',CONCAT('g_s = ',SWV_GL_VAR.g_s);
END; $$;
CREATE OR REPLACE PROCEDURE test_pkg1.PROC1()
LANGUAGE plpgsql
AS $$
DECLARE
SWV_GL_VAR TEST_PKG1.GL_VAR_TYPE DEFAULT TEST_PKG1.GET_GL_VAR();
v_n NUMERIC;
v_v VARCHAR(65);
BEGIN
v_n := SWV_GL_VAR.g_n2;
if SWV_GL_VAR.g_s = 'ТЕСТ1' then
SWV_GL_VAR.G_S := 'aaa';
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
SWV_GL_VAR.G_N1 := 1000;
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
else
SWV_GL_VAR.G_S := 'bbb';
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
SWV_GL_VAR.G_N1 := 2000;
PERFORM TEST_PKG1.SET_GL_VAR(SWV_GL_VAR);
end if;
v_v := SWV_GL_VAR.g_s;
RAISE NOTICE '%',CONCAT('v_n = ',v_n);
RAISE NOTICE '%',CONCAT('v_v = ',v_v);
CALL TEST_PKG1.PRINT_GLOBAL_VARS();
SWV_GL_VAR := TEST_PKG1.GET_GL_VAR();
END; $$; |
Если этот вариант не сработал, пожалуйста, свяжитесь с нашей технической службой: support@convertum.ru.
[Usage example]: AUTO_FUNCTION_VOLATILITY
В приведенном ниже примере показана разница в результирующей функции в обоих случаях. Пожалуйста, сравните и попробуйте:
| Исходный код (Informix) | Преобразованный код PostgreSQL (без опции AUTO_FUNCTION_VOLATILITY или AUTO_FUNCTION_VOLATILITY=No) | Преобразованный код PostgreSQL (с опцией AUTO_FUNCTION_VOLATILITY=Yes) |
|---|---|---|
create function fn_immutable (param int) returning int; return param * 5; end function; create function fn_stable (param int) returning date, char(30); return current year to day, 'The best day'; end function; |
create or replace function fn_immutable(param integer) returns integer language plpgsql as $$ begin return param*5; end; $$; create or replace function fn_stable(param integer) returns table ( unnamed_col_1 date, unnamed_col_2 char(30) ) language plpgsql as $$ begin return query(select current_date,'The best day':: char(30)); end; $$; |
create or replace function fn_immutable(param integer) returns integer IMMUTABLE language plpgsql as $$ begin return param*5; end; $$; create or replace function fn_stable(param integer) returns table ( unnamed_col_1 date, unnamed_col_2 char(30) ) STABLE language plpgsql as $$ begin return query(select current_date,'The best day':: char(30)); end; $$; |
Если этот вариант не сработал, пожалуйста, свяжитесь с нашей технической службой: support@convertum.ru.
[Usage example]: EXPLICIT_COLUMN_OWNERSHIP
В приведенном ниже примере показана разница в результирующей процедуры в обоих случаях. Пожалуйста, сравните и попробуйте:
| Исходный код (Infromix) | Преобразованный код PostgreSQL (без опции EXPLICIT_COLUMN_OWNERSHIP или EXPLICIT_COLUMN_OWNERSHIP=No) | Преобразованный код PostgreSQL (с опцией EXPLICIT_COLUMN_OWNERSHIP=Yes) |
|---|---|---|
CREATE PROCEDURE sp_1 (par1 integer) DEFINE var1, var2 INTEGER; SELECT col1t1, col1t2 INTO var1, var2 FROM table1, OUTER table2 WHERE col1t1 = col1t2 AND col2t1 = par1 LIMIT 1; END PROCEDURE |
CREATE OR REPLACE PROCEDURE sp_1(par1 INTEGER) LANGUAGE plpgsql AS $$ DECLARE var1 INTEGER; var2 INTEGER; BEGIN SELECT col1t1, col1t2 INTO var1,var2 FROM table1 LEFT OUTER JOIN table2 ON col1t1 = col1t2 WHERE col2t1 = par1 LIMIT 1; END; $$; |
CREATE OR REPLACE PROCEDURE sp_1(par1 INTEGER) LANGUAGE plpgsql AS $$ DECLARE var1 INTEGER; var2 INTEGER; BEGIN SELECT table1.col1t1, table2.col1t2 INTO var1,var2 FROM table1 LEFT OUTER JOIN table2 ON table1.col1t1 = table2.col1t2 WHERE table1.col2t1 = par1 LIMIT 1; END; $$; |
Если этот вариант не сработал, пожалуйста, свяжитесь с нашей технической службой: support@convertum.ru.
[Usage example]: ANALYZE_TEMP_STATS
Ниже вы можете увидеть пример исходного кода с временными таблицами и индексами. Левый столбец содержит исходный код Sybase ASE, второй столбец показывает преобразованный код PostgreSQL без опции, а третий столбец демонстрирует результаты преобразования, когда включена опция ANALYZE_TEMP_STATS.
Исходный код Sybase ASE
CREATE PROCEDURE test_proc
AS
BEGIN
CREATE TABLE #temp3 (id INT, name VARCHAR(50))
CREATE INDEX idx_temp3_id ON #temp3 (id)
INSERT INTO #temp3
SELECT id, name
FROM regular_table
WHERE status = 'ACTIVE'
INSERT INTO #temp3 VALUES (101, 'AnotherRow')
INSERT INTO regular_table
SELECT id, name, 'Val6', 'ACTIVE'
FROM #temp3
WHERE id = 1
CREATE INDEX idx_temp3_name ON #temp3 (name)
CREATE UNIQUE INDEX idx_temp3_name ON #temp3 (name)
INSERT INTO #temp3 VALUES (101, 'AnotherRow')
INSERT INTO #temp3 VALUES (102, 'AnotherRow')
INSERT INTO #temp3 VALUES (103, 'AnotherRow')
END
Преобразованный код PostgreSQL (по умолчанию)
CREATE OR REPLACE FUNCTION test_proc()
RETURNS TABLE
(
id INTEGER,
name VARCHAR
) LANGUAGE plpgsql
AS $$
BEGIN
CREATE TEMPORARY TABLE tt_TEMP3
(
id INTEGER,
name VARCHAR(50)
) ON COMMIT DROP;
CREATE INDEX idx_temp3_id ON tt_TEMP3
(id);
INSERT INTO tt_TEMP3
SELECT id, name
FROM regular_table
WHERE status = 'ACTIVE';
INSERT INTO tt_TEMP3 VALUES(101, 'AnotherRow');
INSERT INTO regular_table
SELECT id, name, 'Val6', 'ACTIVE'
FROM tt_TEMP3
WHERE id = 1;
CREATE INDEX idx_temp3_name ON tt_TEMP3
(name);
CREATE UNIQUE INDEX idx_temp3_name ON tt_TEMP3
(name);
INSERT INTO tt_TEMP3 VALUES(101, 'AnotherRow');
INSERT INTO tt_TEMP3 VALUES(102, 'AnotherRow');
INSERT INTO tt_TEMP3 VALUES(103, 'AnotherRow');
RETURN;
END; $$;
Преобразованный код PostgreSQL с опцией ANALYZE_TEMP_STATS=Yes
CREATE OR REPLACE FUNCTION test_proc()
RETURNS TABLE
(
id INTEGER,
name VARCHAR
) LANGUAGE plpgsql
AS $$
BEGIN
CREATE TEMPORARY TABLE tt_TEMP3
(
id INTEGER,
name VARCHAR(50)
) ON COMMIT DROP;
CREATE INDEX idx_temp3_id ON tt_TEMP3
(id);
ANALYZE tt_TEMP3;
INSERT INTO tt_TEMP3
SELECT id, name
FROM regular_table
WHERE status = 'ACTIVE';
INSERT INTO tt_TEMP3 VALUES(101, 'AnotherRow');
ANALYZE tt_TEMP3;
INSERT INTO regular_table
SELECT id, name, 'Val6', 'ACTIVE'
FROM tt_TEMP3
WHERE id = 1;
CREATE INDEX idx_temp3_name ON tt_TEMP3
(name);
CREATE UNIQUE INDEX idx_temp3_name ON tt_TEMP3
(name);
ANALYZE tt_TEMP3;
INSERT INTO tt_TEMP3 VALUES(101, 'AnotherRow');
INSERT INTO tt_TEMP3 VALUES(102, 'AnotherRow');
INSERT INTO tt_TEMP3 VALUES(103, 'AnotherRow');
ANALYZE tt_TEMP3;
RETURN;
END; $$;
Если параметр ANALYZE_TEMP_STATS не указан, используется значение по умолчанию (No), что означает, что в процессе преобразования не добавляются дополнительные инструкции ANALYZE.
Если опция включена явно (Yes), то инструкции ANALYZE будут автоматически вставляться после создания индекса и операций INSERT во временных таблицах, гарантируя, что оптимизатор PostgreSQL будет работать со свежей статистикой при выполнении последующих запросов.
Если этот вариант не сработал, пожалуйста, свяжитесь с нашей технической службой: support@convertum.ru.