SnowConvert AI - PostgreSQL Functional Differences¶
Note
SnowConvert AI for PostgreSQL currently supports assessment and translation for TABLES and VIEWS. Although SnowConvert AI can recognize other types of statements, they are not fully supported.
In Snowflake there is not a direct translation for this property, for the following scenarios:
INSERT
UPDATE
DELETE
MERGE
The converted code will be SQLFOUND Snowflake property (Here is the documentation) since it behaves like the PostgreSQL FOUND property.
For the other cases such as:
SELECT INTO
PERFORM
FETCH
The converted code will be a custom UDF (IS_FOUND_UDF) that behaves like the PostgreSQL FOUND property.
This happens because SQLFOUND changes its value only when at least one row is affected by the last executed query, if the last query does not change any row, it does not change.
While the IS_FOUND_UDF only works for statements that returns rows, if no row is returned it, it will return FALSE.
-- Found property used with INSERT statement.CREATE OR REPLACEPROCEDURE FoundUsingInsertProcedure()LANGUAGE plpgsql
AS $$
BEGIN-- Insert into SampleTableINSERTINTO SampleTable (SampleColumn1)VALUES('SampleValue0.1');SELECTFOUND;END;
$$;
-- Found property used with INSERT statement.CREATE OR REPLACEPROCEDURE FoundUsingInsertProcedure ()RETURNSVARCHARLANGUAGESQLAS $$
BEGIN-- Insert into SampleTableINSERTINTO SampleTable (SampleColumn1)VALUES('SampleValue0.1');SELECTSQLFOUND/*** SSC-FDM-PG0001 - FOUND COULD HAVE A DIFFERENT BEHAVIOR IN SNOWFLAKE IN SOME SCENARIOS. ***/;END;
$$;
-- Found property used with UPDATE statement.CREATE OR REPLACEPROCEDURE FoundUsingUpdateProcedure()LANGUAGE plpgsql
AS
$$
BEGINUPDATE SampleTable
SET SampleColumn1 ='SampleValue0.1'WHERE SampleColumn1 ='SampleValue0.1';SELECTFOUND;END;
$$;
-- Found property used with UPDATE statement.CREATE OR REPLACEPROCEDURE FoundUsingUpdateProcedure ()RETURNSVARCHARLANGUAGESQLAS
$$
BEGINUPDATE SampleTable
SET SampleColumn1 ='SampleValue0.1'WHERE SampleColumn1 ='SampleValue0.1';SELECTSQLFOUND/*** SSC-FDM-PG0001 - FOUND COULD HAVE A DIFFERENT BEHAVIOR IN SNOWFLAKE IN SOME SCENARIOS. ***/;END;
$$;
-- Found property used with DELETE statement.CREATE OR REPLACEPROCEDURE FoundUsingDeleteProcedure()LANGUAGE plpgsql
AS
$$
BEGINDELETEFROM SampleTable
WHERE SampleColumn1 ='SampleValue0.1';SELECTFOUND;END;
$$;
-- Found property used with DELETE statement.CREATE OR REPLACEPROCEDURE FoundUsingDeleteProcedure ()RETURNSVARCHARLANGUAGESQLAS
$$
BEGINDELETEFROM
SampleTable
WHERE SampleColumn1 ='SampleValue0.1';SELECTSQLFOUND/*** SSC-FDM-PG0001 - FOUND COULD HAVE A DIFFERENT BEHAVIOR IN SNOWFLAKE IN SOME SCENARIOS. ***/;END;
$$;
-- Found property used with MERGE statement.CREATE OR REPLACEPROCEDURE FoundUsingMergeProcedure()LANGUAGE plpgsql
AS
$$
BEGINMERGEINTO SampleTableB BUSING(SELECT*FROM SampleTableA)AONB.SampleColumn1 =A.SampleColumn2
WHENMATCHEDTHENDELETE;SELECTFOUND;END;
$$;
-- Found property used with MERGE statement.CREATE OR REPLACEPROCEDURE FoundUsingMergeProcedure ()RETURNSVARCHARLANGUAGESQLAS
$$
BEGINMERGEINTO SampleTableB BUSING(SELECT*FROM SampleTableA)AONB.SampleColumn1 =A.SampleColumn2
WHENMATCHEDTHENDELETE!!!RESOLVEEWI!!!/*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'MergeStatement' NODE ***/!!!;SELECTSQLFOUND/*** SSC-FDM-PG0001 - FOUND COULD HAVE A DIFFERENT BEHAVIOR IN SNOWFLAKE IN SOME SCENARIOS. ***/;END;
$$;
-- Found property used with SELECT INTO statement.CREATE OR REPLACEPROCEDURE FoundUsingSelectIntoProcedure()LANGUAGE plpgsql
AS
$$
DECLARE
SampleNumber INTEGER;BEGINSELECT1INTO SampleNumber;SELECTFOUND;END;
$$;
-- Found property used with SELECT INTO statement.CREATE OR REPLACEPROCEDURE FoundUsingSelectIntoProcedure ()RETURNSVARCHARLANGUAGESQLAS
$$
DECLARE
SampleNumber INTEGER;BEGINSELECT1INTO
: SampleNumber;SELECTFOUND_UDF()/*** SSC-FDM-PG0001 - FOUND COULD HAVE A DIFFERENT BEHAVIOR IN SNOWFLAKE IN SOME SCENARIOS. ***/;END;
$$;
-- Found property used with PERFORM statement.CREATE OR REPLACEPROCEDURE FoundUsingPerformProcedure()LANGUAGE plpgsql
AS
$$
BEGINPERFORM1;RETURNFOUND;END;
$$;
-- Found property used with PERFORM statement.CREATE OR REPLACEPROCEDURE FoundUsingPerformProcedure ()RETURNSVARCHARLANGUAGESQLAS
$$
BEGINSELECT1;RETURNFOUND_UDF()/*** SSC-FDM-PG0001 - FOUND COULD HAVE A DIFFERENT BEHAVIOR IN SNOWFLAKE IN SOME SCENARIOS. ***/;END;
$$;
-- Found property used with FETCH statement.CREATE OR REPLACEPROCEDURE FoundUsingFetchProcedure ()LANGUAGE plpgsql
AS
$$
DECLARE
SampleRow VARCHAR;
SampleCursor CURSORFORSELECT EmptyColumn FROM EmptyTable;BEGINOPEN SampleCursor;FETCH SampleCursor;CLOSE SampleCursor;SELECTFOUND;END;
$$;
-- Found property used with FETCH statement.CREATE OR REPLACEPROCEDURE FoundUsingFetchProcedure ()RETURNSVARCHARLANGUAGESQLAS
$$
DECLARE
SampleRow VARCHAR;
SampleCursor CURSORFORSELECT EmptyColumn FROM
EmptyTable;BEGINOPEN SampleCursor;!!!RESOLVEEWI!!!/*** SSC-EWI-PG0015 - FETCH CURSOR WITHOUT TARGET VARIABLES IS NOT SUPPORTED IN SNOWFLAKE ***/!!!FETCH SampleCursor;CLOSE SampleCursor;SELECTFOUND_UDF()/*** SSC-FDM-PG0001 - FOUND COULD HAVE A DIFFERENT BEHAVIOR IN SNOWFLAKE IN SOME SCENARIOS. ***/;END;
$$;
This warning is added because bpchar type (“blank-padded char”) may have some functional equivalence difference compared to the varchar data type in Snowflake. However, both data types can store the values up to the “n” length of characters and consume storage for only the amount of actual data stored. The main difference occurs when there are blanks at the end of the data, where bpchar does not store them but snowflake does.
For this reason, we can use the RTRIM function so that these blanks are not stored. But there may be cases where the functionality is not completely equivalent.
SELECT'Y':: VARCHAR/*** SSC-FDM-PG0002 - BPCHAR CONVERTED TO VARCHAR. THESE TYPES MAY HAVE SOME FUNCTIONAL DIFFERENCES. ***/;SELECTRTRIM('Y '):: VARCHAR(20)/*** SSC-FDM-PG0002 - BPCHAR CONVERTED TO VARCHAR. THESE TYPES MAY HAVE SOME FUNCTIONAL DIFFERENCES. ***/;SELECTRTRIM(COL1):: VARCHAR(20)/*** SSC-FDM-PG0002 - BPCHAR CONVERTED TO VARCHAR. THESE TYPES MAY HAVE SOME FUNCTIONAL DIFFERENCES. ***/FROM
tbl;
The rtrim function can resolve storage differences in case you want those blanks not to be stored. This case is handled in the explicit cast, however, there may be other scenarios where it has to be handled manually. For more information refer to the Snowflake documentation about RTRIM.
CREATETABLE table1 (
dt_update TIMESTAMP_NTZDEFAULTCAST(--** SSC-FDM-PG0004 - THE DATE OUTPUT FORMAT MAY VARY DEPENDING ON THE TIMESTAMP TYPE AND THE TIMESTAMP_OUTPUT_FORMAT BEING USED. **CURRENT_TIMESTAMP()ASTIMESTAMP_NTZ))COMMENT='{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "postgresql", "convertedOn": "09/17/2024" }}';
CREATETABLE sample2 (
platform_id integerNOT NULL,
dt_update TIMESTAMP_TZDEFAULTCAST(--** SSC-FDM-PG0004 - THE DATE OUTPUT FORMAT MAY VARY DEPENDING ON THE TIMESTAMP TYPE AND THE TIMESTAMP_OUTPUT_FORMAT BEING USED. **CURRENT_TIMESTAMP()ASTIMESTAMP_TZ));insertintopostgres.public.sample2 (platform_id)values(1);ALTERSESSIONSETtimestamp_output_format='YYYY-MM-DD HH24:MI:SS.FF';select*,CURRENT_TIMESTAMP(3)frompostgres.public.sample2;
PostgreSQL’s UNLOGGED tables offer a significant speed advantage by skipping write-ahead logging (WAL). However, their data isn’t replicated to mirror instances. Snowflake doesn’t support this functionality, so the UNLOGGED clause will be commented out.
In PostgreSQL the removal of a comment is handled by using the NULL term. However, in Snowflake, a similar method for removing a comment is to assign the value of an empty string '' to provide the same result. This approach ensures that the comment is effectively mapped to an empty string with a similar behavior.
Select Into is not supported by Snowflake, this functionality was emulated with CREATE TABLE AS. In addition, Snowflake always uses transaction logs to protect tables and ensure data integrity and recoverability. Consequently, tables with the UNLOGGED option are not supported by Snowflake.
CREATETABLEIF NOT EXISTS NewTable ASselect column1
-- --** SSC-FDM-PG0008 - SELECT INTO UNLOGGED TABLES ARE NOT SUPPORTED BY SNOWFLAKE. **-- into UNLOGGED NewTablefrom
oldTable;
Snowflake does not guarantee generating sequence numbers without gaps. The generated numbers consistently increase in value (or decrease in value if the step size is negative) but are not necessarily contiguous.
For shift operations involving integer left operands, the MOD function should be applied to the right operand to get equivalent results, as well as using the INTEGER_BITSHIFTLEFT_UDF helper for ensuring the equivalence of the shift left operation on integers. When the datatype of the left operand can not be determined, SnowConvert AI will generate this FDM to warn about the potential functional differences.
CREATETABLE someTable (
intCol INTEGER,
smallIntCol SMALLINT,
varbyteCol BINARY,
incrementValue INTEGER);SELECTPUBLIC.INTEGER_BITSHIFTLEFT_UDF(
intCol,MOD(incrementValue,32),32),BITSHIFTRIGHT(
smallIntCol,MOD(incrementValue,16)),BITSHIFTLEFT(
varbyteCol, incrementValue)FROM
someTable;--** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "missingTable" **SELECT--** SSC-FDM-PG0010 - DATATYPE OF THE LEFT OPERAND COULD NOT BE DETERMINED. RESULTS MAY VARY DUE TO THE BEHAVIOR OF SNOWFLAKE'S BITSHIFTLEFT BITWISE FUNCTION **BITSHIFTLEFT( missingCol, incrementValue)FROM
missingTable;
Ensure the source code you migrate has no missing depedencies, by providing any missing object to SnowConvert AI the operands semantic information should be extracted correctly and this FDM should no longer appear
This message is added when a pattern-matching condition uses arguments with COLLATE specifications, as they are not currently supported in Snowflake’s regular expression function. Consequently, the COLLATE clause must be disabled to use this function, which may result in differences in the results.
CREATETABLE collateTable (
col1 VARCHAR(20)COLLATE'en-ci',
col2 VARCHAR(30)COLLATE'en-cs')COMMENT='{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "postgresql", "convertedOn": "01/16/2025", "domain": "test" }}';INSERTINTO collateTable
values('HELLO WORLD!','HELLO WORLD!');SELECTRLIKE(COLLATE(--** SSC-FDM-PG0011 - THE USE OF THE COLLATE COLUMN CONSTRAINT HAS BEEN DISABLED FOR THIS PATTERN-MATCHING CONDITION. **
col1,''),'Hello.*','s')as ci,RLIKE(COLLATE(--** SSC-FDM-PG0011 - THE USE OF THE COLLATE COLUMN CONSTRAINT HAS BEEN DISABLED FOR THIS PATTERN-MATCHING CONDITION. **
col2,''),'Hello.*','s')as cs
FROM
collateTable;
In PostgreSQL, specifying the NOT NULL constraint ensures that assigning a null value to a variable results in a runtime error. Since this clause does not exist in Snowflake, it is removed during transformation and assigning a NULL to this variable will no longer fail in execution.
CREATE OR REPLACEPROCEDURE variable_Not_Null ()RETURNSVARCHARLANGUAGESQLAS $$
DECLARE--** SSC-FDM-PG0012 - NOT NULL CONSTRAINT HAS BEEN REMOVED. ASSIGNING NULL TO THIS VARIABLE WILL NO LONGER CAUSE A FAILURE. **
v_notnull VARCHARDEFAULT'Test default';BEGIN
v_notnull :=NULL;-- Procedure logicEND;
$$;
This functional difference message indicates that while Snowflake supports the function’s syntax (either directly or through an equivalent mapping), its behavior might be different from the original in some situations.
SELECT--** SSC-FDM-PG0013 - FUNCTION SYNTACTICALLY SUPPORTED BY SNOWFLAKE BUT MAY HAVE FUNCTIONAL DIFFERENCES **LISTAGG(skill)WITHINGROUP(ORDER BY skill)OVER(PARTITION BY
employee_name)AS employee_skills
FROM
employees;
This functional difference message indicates that UNKNOWN Pseudo Type used in PostgreSQL is not supported in Snowflake and is transformed to a Text Type.
SnowConvert AI will add this warning because PostgreSQL supports arrays of any built-in or user-defined base type, enum type, composite type, range type, or domain, whereas Snowflake does not. In Snowflake, each value in a semi-structured array is of type VARIANT.
SnowConvert AI will generate a warning for any function that returns void. This is because functions returning void typically indicate a procedure rather than a value-producing operation, which can sometimes require special handling during conversion.
SnowConvert AI flags ANALYZE statements with a warning and comments them out. While ANALYZE is used in PostgreSQL for collecting table statistics, Snowflake automatically manages this process, making the statement redundant and generally unnecessary post-conversion.