SnowConvert AI - Oracle - COLLECTIONS AND RECORDS¶
Translation reference to convert Oracle COLLECTIONS and RECORDS to Snowflake Scripting
Warning
This section is a work in progress, information may change in the future.
General Description¶
PL/SQL lets you define two kinds of composite data types: collection and record, where composite is a data type that stores values that have internal components.
In a collection, the internal components always have the same data type, and are called elements.
In a record, the internal components can have different data types, and are called fields. (Oracle PL/SQL Language Reference COLLECTIONS AND RECORDS)
Note
Please take into account the CREATE TYPE statement translation reference since some workarounds can overlap and may be functional in both scenarios.
Limitations¶
Snowflake doesn’t support user-defined data types, which includes PL Collections and Records, according to its online documentation Unsupported Data Types, but it supports Semi-structured Data Types, which can be used to mimic both the hierarchy-like structure of Record and the element structure of Collection User-defined types. For this reason, there are multiple types of features that have no workaround.
Following are the features for which NO workaround is proposed:
Variable size cannot exceed 16MB¶
Snowflake sets VARIANT, OBJECT, and ARRAY’s maximum size on 16MBs. This means that if a Record, a Collection, or any element of either exceeds this size it will cause a Runtime Error.
Varray capacity cannot be limited¶
Oracle’s varrays offer the capacity to limit the number of elements within them. This is not supported by Snowflake.
Proposed Workaround¶
About Record types definition¶
The proposed workaround is to use an “OBJECT” semi-structured data type to mimic Oracle’s data type.
About Collection types definition¶
There are two different workarounds that depend on the type of collection to be migrated:
Associative Arrays are proposed to be changed into an “OBJECT” semi-structured data type.
Varrays and Nested Table Arrays are proposed to be changed into an “ARRAY” semi-structured data type.
Current SnowConvert AI Support¶
The next table shows a summary of the current support provided by the SnowConvert AI tool. Please keep in mind that translations may still not be final, and more work may be needed.
Sub-Feature |
Current recognition status |
Current translation status |
Has Known Workarounds |
|---|---|---|---|
Recognized. |
Not Translated. |
Yes. |
|
Not Recognized. |
Not Translated. |
Yes. |
|
Recognized. |
Not Translated. |
Yes. |
|
Recognized. |
Not Translated. |
Yes. |
Known Issues¶
1. Associate Arrays are considered a Nested Table¶
As of now, SnowConvert AI doesn’t differentiate between an Associative Array and a Nested Table meaning they are mixed up in the same assessment counts.
Associative Array Type Definition¶
This is a translation reference to convert the Oracle Associative Array Declaration to Snowflake
Warning
This section is a work in progress, information may change in the future.
Note
Some parts in the output code are omitted for clarity reasons.
Description¶
An associative array (formerly called PL/SQL table or index-by table) is a set of key-value pairs. Each key is a unique index, used to locate the associated value with the syntax
variable_name(index).The data type of
indexcan be either a string type (VARCHAR2,VARCHAR,STRING, orLONG) orPLS_INTEGER. Indexes are stored in sort order, not creation order. For string types, sort order is determined by the initialization parametersNLS_SORTandNLS_COMP.
Warning
Not to be confused with the PL/SQL NESTED TABLE Type definition.
For the translation, the type definition is replaced by an OBJECT Semi-structured Data Type and then its usages are changed accordingly across any operations.
To define an Associative Array type, the syntax is as follows:
To declare a variable of this type:
Sample Source Patterns¶
Varchar-indexed Associative Array¶
Oracle¶
Result¶
DBMS OUTPUT |
|---|
1 |
3 |
4 |
2 |
3 |
Snowflake¶
Please note the ‘true’ parameter in the OBJECT_INSERT. This is so that the element is updated if it is already present in the array.
Result¶
DBMS OUTPUT |
|---|
1 |
3 |
4 |
2 |
3 |
Numeric-indexed Associative Array¶
Oracle¶
Result¶
DBMS OUTPUT |
|---|
-1 |
3 |
-4 |
-2 |
-3 |
Snowflake¶
Please note that the numeric value is converted to varchar accordingly when the operation needs it. Additionally, note the ‘true’ parameter in the OBJECT_INSERT. This is so that the element is updated if it is already present in the array.
Result¶
DBMS OUTPUT |
|---|
-1 |
3 |
-4 |
-2 |
-3 |
Record-element Numeric-indexed Associative Array¶
In this case, the associative array is composed of a Record-structure, and this structure needs to be preserved. For this purpose, further operations on insertions were added.
Oracle¶
Result¶
DBMS OUTPUT |
|---|
-1 |
3 |
-4 |
-2 |
-3 |
Snowflake¶
In this scenario, the insertion/update assumes an automatic creation of the record within the associative array and this needs to be taken into account when creating new records.
Result¶
DBMS OUTPUT |
|---|
-1 |
3 |
-4 |
-2 |
-3 |
Known Issues¶
1. They are currently not being recognized¶
SnowConvert AI treats these collections as Nested Table Arrays. There is a work item to fix this.
Related EWIs¶
No related EWIs.
Collection Methods¶
This is a translation reference to convert the Oracle Collection Methods to Snowflake
Warning
This section is a work in progress, information may change in the future
Note
Some parts in the output code are omitted for clarity reasons.
Description¶
A collection method is a PL/SQL subprogram—either a function that returns information about a collection or a procedure that operates on a collection. Collection methods make collections easier to use and your applications easier to maintain.
Some of these methods can be mapped to native Snowflake semi-structured operations. The ones that can’t or have differences will be mapped to a UDF implementation.
Current SnowConvert AI Support¶
The next table shows a summary of the current support provided by the SnowConvert AI tool. Please keep in mind that translations may still not be final, and more work may be needed.
Method |
Current recognition status |
Current translation status |
Mapped to |
|---|---|---|---|
Not Recognized. |
Not Translated. |
UDF |
|
Not Recognized. |
Not Translated. |
UDF (To be defined) |
|
Not Recognized. |
Not Translated. |
UDF |
|
Not Recognized. |
Not Translated. |
||
Not Recognized. |
Not Translated. |
UDF |
|
Not Recognized. |
Not Translated. |
UDF |
|
Not Recognized. |
Not Translated. |
||
Not Recognized. |
Not Translated. |
Not Supported. |
|
Not Recognized. |
Not Translated. |
UDF (To be defined) |
|
Not Recognized. |
Not Translated. |
UDF (To be defined) |
Sample Source Patterns¶
COUNT¶
This method returns the count of “non-undefined” (not to be confused with null) elements within a collection (nested tables can become sparse leaving these elements in between). In associative arrays, it returns the number of keys in the array.
Oracle¶
Result¶
DBMS OUTPUT |
|---|
2 |
3 |
4 |
Snowflake¶
The snowflake equivalent is the ARRAY_SIZE method.
Result¶
DBMS OUTPUT |
|---|
2 |
3 |
4 |
EXISTS¶
This method returns true if the given element is contained within the collection. In associative arrays, it tests if the key is contained.
Oracle¶
Result¶
DBMS OUTPUT |
|---|
2 |
3 |
4 |
Snowflake¶
The snowflake equivalent is the ARRAY_CONTAINS method. Note that, when using Varchar elements, casting to Variant is necessary.
Result¶
DBMS OUTPUT |
|---|
2 |
3 |
4 |
FIRST/LAST¶
These two methods return the First/Last element of the collection, respectively. If the collection is empty it returns null. This operation is mapped to a UDF, which will be added in further revisions.
Oracle¶
Result¶
DBMS OUTPUT |
|---|
abc |
bca |
–These empty spaces are due to it evaluating to null |
1 |
4 |
Snowflake¶
UDFs¶
Result¶
DBMS OUTPUT |
|---|
abc |
bca |
–These empty spaces are due to it evaluating to null |
1 |
4 |
DELETE¶
This method is used to remove elements from a Collection. It has three possible variants:
.DELETE removes all elements.
.DELETE(n) removes the element whose index matches ‘n’.
.DELETE(n, m) removes in the indexes from ‘n’ through ‘m’.
Note
In Oracle, using this operation on Nested Tables causes it to have “undefined” elements within it due to them being sparse.
Warning
Please note that the second and third versions do not apply to Varrays.
Oracle¶
For the sake of simplicity, this sample only checks on the number of elements but may be modified to display the contents of each collection.
Result¶
DBMS OUTPUT |
|---|
0 |
0 |
3 |
2 |
0 |
3 |
1 |
Snowflake¶
Snowflake does not support deletions from an existing ARRAY and for this reason, the only offered workaround is to rebuild a new ARRAY depending on the original parameters of the DELETE.
Note
Note that a UDF was added to implement the functionality for the update of the element.
This UDF will be added in later revisions.
Result¶
DBMS OUTPUT |
|---|
0 |
0 |
3 |
2 |
0 |
3 |
1 |
EXTEND¶
This method is used to append new elements to a Nested Table or a Varray. It has three possible variants:
.EXTEND inserts a null element.
.EXTEND(n) inserts ‘n’ null elements.
.EXTEND(n, i) inserts ‘n’ copies of the element at ‘i’.
Oracle¶
Result¶
DBMS OUTPUT |
|---|
5 |
5 |
5 |
Snowflake¶
Note
Note that a UDF was added to implement the functionality for the update of the element.
This UDF will be added in later revisions.
Result¶
DBMS OUTPUT |
|---|
5 |
5 |
5 |
TRIM¶
This method is used to remove the last elements from a Nested Table or a Varray. It has two possible variants:
.TRIM removes the last element.
.TRIM(n) removes the last ‘n’ elements.
Note
This functionality may be implemented using ARRAY_SLICE
Oracle¶
Result¶
LIMIT¶
This method returns the maximum limit of a Varray.
Danger
This method is not supported in Snowflake.
Oracle¶
Result¶
DBMS OUTPUT |
|---|
5 |
6 |
PRIOR/NEXT¶
This method returns the prior/next index, given an index. If there is not a prior/next then it returns null. It is most frequently used to traverse a collection.
Oracle¶
Result¶
DBMS OUTPUT |
|---|
– Empty spaces are due to null results |
1 |
3 |
abc |
jkl |
jkl |
Known Issues¶
1. Limit method is not supported in Snowflake¶
Snowflake does not have support for limited-space varrays. For this reason, this method is not supported.
Related EWIs¶
No EWIs related.
Nested Table Array Type Definition¶
This is a translation reference to convert the Oracle Nested Table Array Declaration to Snowflake
Warning
This section is a work in progress, information may change in the future.
Note
This section is for the PL/SQL Version of the Nested Table Arrays, for the Standalone Version please see Nested Table Type Definition.
Note
Some parts in the output code are omitted for clarity reasons.
Description¶
In the database, a nested table is a column type that stores an unspecified number of rows in no particular order.
When you retrieve a nested table value from the database into a PL/SQL nested table variable, PL/SQL gives the rows consecutive indexes, starting at 1. Using these indexes, you can access the individual rows of the nested table variable. The syntax is
variable_name(index). The indexes and row order of a nested table might not remain stable as you store and retrieve the nested table from the database.
For the translation, the type definition is replaced by an ARRAY Semi-structured Data Type and then its usages are changed accordingly across any operations. Please note how the translation for Nested Tables and Varrays are the same.
To define a Nested Table Array type, the syntax is as follows:
To declare a variable of this type:
Sample Source Patterns¶
Nested Table Array definitions¶
This illustrates how to create different nested table arrays, and how to migrate the definitions for the variables.
Oracle¶
Snowflake¶
Nested Table iteration¶
Oracle¶
Result¶
DBMS OUTPUT |
|---|
10 |
20 |
30 |
40 |
20 |
30 |
Snowflake¶
Note
Note that a UDF was added to implement the functionality for the update of the element.
This UDF will be added in later revisions.
UDF¶
Result¶
DBMS OUTPUT |
|---|
10 |
20 |
30 |
40 |
20 |
30 |
Known Issues¶
1. They are currently not being converted¶
SnowConvert AI does not support translating these elements.
2. Indexing needs to be modified¶
Oracle’s indexes start at 1, on Snowflake they will begin at 0.
Related EWIs¶
No EWIs related.
Record Type Definition¶
This is a translation reference to convert the Oracle Record Declaration to Snowflake
Warning
This section is a work in progress, information may change in the future.
Note
Some parts in the output code are omitted for clarity reasons.
Description¶
A record variable is a composite variable whose internal components, called fields, can have different data types. The value of a record variable and the values of its fields can change.
You reference an entire record variable by its name. You reference a record field with the syntax
record.field.You can create a record variable in any of these ways:
Define a record type and then declare a variable of that type.
Use
%ROWTYPEto declare a record variable that represents either a full or partial row of a database table or view.Use
%TYPEto declare a record variable of the same type as a previously declared record variable.
For the translation, the type definition is replaced by an OBJECT Semi-structured Data Type and then its usages are changed accordingly across any operations.
To define a Record type, the syntax is as follows:
To declare a variable of this type:
Sample Source Patterns¶
Note
Some parts in the output code are omitted for clarity reasons.
Record initialization and assignment¶
This sample attempts to insert two new rows using a record variable which is reassigned mid-procedure.
Oracle¶
Result¶
COL1 |
COL2 |
|---|---|
1.5 |
1 |
2.5 |
2 |
Snowflake¶
Notice how the reassignments are replaced by an OBJECT_INSERT that updates if the column already exists, and how the VALUES clause is replaced by a SELECT.
Result¶
COL1 |
COL2 |
|---|---|
1.5 |
1 |
2.5 |
2 |
%ROWTYPE Record and Values Record¶
Since the operations are the ones that define the structure, these definitions can be replaced by an OBJECT datatype, but the values of the record need to be decomposed as inserting the record “as-is” is not supported.
Oracle¶
Result¶
COL1 |
COL2 |
COL3 |
|---|---|---|
1 |
“Hello” |
25-DEC-20 |
Snowflake¶
Please note finally how the OBJECT variable needs to be initialized to add the information to it.
Result¶
COL1 |
COL2 |
COL3 |
|---|---|---|
1 |
“Hello” |
25-DEC-20 |
Fetching data into a Record¶
Oracle¶
Result¶
DBMS OUTPUT |
|---|
1 |
Hello |
25-DEC-20 |
Snowflake¶
Please note the additional OBJECT_CONSTRUCT in the Cursor definition, this is what allows to extract an OBJECT, which then can be used to seamlessly migrate the FETCH statement.
Result¶
DBMS OUTPUT |
|---|
1 |
Hello |
25-DEC-20 |
Assigning a Record Variable in a SELECT INTO¶
This transformation consists in taking advantage of the OBJECT_CONTRUCT function to initialize the record using the SELECT columns as the arguments.
Sample auxiliary code¶
Oracle¶
Snowflake¶
Oracle¶
Result¶
COL1 |
COL2 |
|---|---|
SELECT 1 |
NAME 1 |
SELECT 2 |
NAME 2 |
SELECT 3 |
NAME 3 |
SELECT 4 |
NAME 4 |
Snowflake¶
Result¶
COL1 |
COL2 |
|---|---|
SELECT 1 |
NAME 1 |
SELECT 2 |
NAME 2 |
SELECT 3 |
NAME 3 |
SELECT 4 |
NAME 4 |
Known Issues¶
1. The following functionalities are currently not being converted:¶
Fetching data into a Record.
Nested records (Records inside records).
Collections inside records.
Related EWIs¶
SSC-EWI-0036: Data type converted to another data type.
SSC-EWI-0056: Create Type Not Supported
SSC-FDM-0006: Number type column may not behave similarly in Snowflake.
SSC-FDM-OR0042: Date Type Transformed To Timestamp Has A Different Behavior.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE check UDF implementation.
SSC-PRF-0003: Fetch inside a loop is considered a complex pattern, this could degrade Snowflake performance.
Varray Type Definition¶
This is a translation reference to convert the Oracle Varray Declaration to Snowflake
Warning
This section is a work in progress, information may change in the future.
Note
This section is for the PL/SQL Version of the Varrays, for the Standalone Version please see Array Type Definition.
Note
Some parts in the output code are omitted for clarity reasons.
Description¶
A varray (variable-size array) is an array whose number of elements can vary from zero (empty) to the declared maximum size.
To access an element of a varray variable, use the syntax
variable_name(index). The lower bound ofindexis 1; the upper bound is the current number of elements. The upper bound changes as you add or delete elements, but it cannot exceed the maximum size. When you store and retrieve a varray from the database, its indexes and element order remain stable.
For the translation, the type definition is replaced by an ARRAY Semi-structured Data Type and then its usages are changed accordingly across any operations. Please note how the translation for Nested Tables and Varrays are the same.
To define a varray type, the syntax is as follows:
To declare a variable of this type:
Sample Source Patterns¶
Varray definitions¶
This illustrates how three different ways to create a varray, and how to migrate these definitions for the variables.
Oracle¶
Snowflake¶
Varray iteration¶
Oracle¶
Result¶
DBMS OUTPUT |
|---|
10 |
20 |
30 |
40 |
20 |
30 |
Snowflake¶
Note
Note that a UDF was added to implement the functionality for the update of the element.
This UDF will be added in later revisions.
UDF¶
Result¶
DBMS OUTPUT |
|---|
10 |
20 |
30 |
40 |
20 |
30 |
Known Issues¶
1. They are currently not being converted¶
SnowConvert AI does not support translating these elements.
2. Indexing needs to be modified¶
Oracle’s indexes start at 1, on Snowflake they will begin at 0.
3. Array Density may not match the original¶
Since the ARRAY datatype can become sparse, care should be taken when performing additions or deletions of the array. Using ARRAY_COMPACT() after such operations can be helpful if the density is a concern.
Related EWIs¶
SSC-EWI-0058: Functionality is not currently supported by Snowflake Scripting.
SSC-EWI-0062: Custom type usage changed to variant.
SSC-EWI-0073: Pending Functional Equivalence Review.
SSC-EWI-OR0108: The Following Assignment Statement is Not Supported by Snowflake Scripting.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE check UDF implementation.
Collection Bulk Operations¶
This is a translation reference to convert the Oracle Collection Bulk Operations to Snowflake
Warning
This section is a work in progress, information may change in the future
Note
Some parts in the output code are omitted for clarity reasons.
Description¶
The
BULKCOLLECTclause, a feature of bulk SQL, returns results from SQL to PL/SQL in batches rather than one at a time.The
BULKCOLLECTclause can appear in:
SELECTINTOstatement
FETCHstatement
RETURNINGINTOclause of:
DELETEstatement
INSERTstatement
UPDATEstatement
EXECUTEIMMEDIATEstatementWith the
BULKCOLLECTclause, each of the preceding statements retrieves an entire result set and stores it in one or more collection variables in a single operation (which is more efficient than using a loop statement to retrieve one result row at a time).
(Oracle PL/SQL Language Reference BULK COLLECT CLAUSE)
This section has some workarounds for SELECTs and FETCH Cursor with Bulk Clauses.
Sample Source Patterns¶
Source Table¶
Oracle¶
Snowflake¶
Bulk Collect from a Table¶
Oracle¶
Result¶
DBMS OUTPUT |
|---|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
Snowflake¶
Danger
EXECUTE IMMEDIATE with Bulk Collect clause has no workarounds offered.
Note
Please note, that while the FETCH Cursor can be mostly preserved, it is advised to be changed into SELECT statements whenever possible for performance issues.
Result¶
DBMS OUTPUT |
|---|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
– EXECUTE IMMEDIATE NOT EXECUTED, it’s not supported |
SELECT INTO statement case¶
In this case, the translation specification uses RESULTSETs. Review the documentation for WITH, SELECT, and BULK COLLECT INTO statements here:
Known Issues¶
1. Heavy performance issues on FETCH Cursor workaround¶
The workaround for the Fetch cursor has heavy performance requirements due to the Temporary table. It is advised for them to be manually migrated to SELECT statements
2. Execute immediate statements are not transformed¶
They are not supported by SnowConvert AI but may be manually changed to SELECT statements.
Related EWIs¶
SSC-EWI-0058: Functionality is not currently supported by Snowflake Scripting.
SSC-EWI-0062: Custom type usage changed to variant.
SSC-EWI-0073: Pending Functional Equivalence Review
SSC-EWI-OR0036: Types resolution issues, the arithmetic operation may not behave correctly between string and date.
SSC-EWI-OR0108: The Following Assignment Statement is Not Supported by Snowflake Scripting.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE check UDF implementation.
SSC-PRF-0001: This statement has usages of cursor fetch bulk operations.
SSC-EWI-0030: The statement below has usages of dynamic SQL
WITH, SELECT, and BULK COLLECT INTO statements¶
Danger
This section is a translation specification. Information may change in the future.
Note
Some parts in the output code are omitted for clarity reasons.
Description¶
This section is a translation specification for the statement WITH subsequent to a SELECT statement which uses a BULK COLLECT INTO statement. For more information review the following documentation:
Sample Source Patterns¶
Note
Some parts in the output code are omitted for clarity reasons.
The following query is used for the following examples.
Oracle¶
Snowflake¶
1. Inside procedure simple case¶
Danger
This is an approach that uses a resultset data type. User-defined types must be reviewed. Review the following Snowflake documentation to review more information about RESULTSETs.
The following example uses a User-defined type and it is declared indirectly as a table. The translation for this case implements a RESULTSET as a data type in Snowflake. The resultset is stored on a variable which must be returned wrapped on a TABLE() function.
Oracle¶
Result¶
Note
The query does not return results but the expected gathered information would be the IT Salary Information used for the example:
IT_Salary |
|---|
75000 |
80000 |
Danger
One of the limitations of the RESULTSETs is that they cannot be used as tables. E.g.: select * from my_result_set; (This is an error, review the following documentation for more information).
Snowflake¶
Result¶
SALARY |
|---|
77500 |
80000 |
2. Simple case for iterations: FOR LOOP statement¶
The following case is to define a translation for iteration with FOR...LOOP. In this case, the User-defined type is implicitly a table, thus, it is possible to use a cursor to iterate. Review the following documentation to learn more:
Snowflake documentation about Returning a Table for a Cursor.
In this case, there is a need to create a cursor for the iteration. Review the following Cursor Assignment Syntax documentation.
Oracle¶
Result¶
Snowflake¶
Result¶
SIMPLE_PROCEDURE |
|---|
Average Salary for IT Department: 77500 |
Known Issues¶
1. Resulset limitations.¶
There are limitations while using the RESULTSET data type. Review the following Snowflake documentation to learn more. Markable limitations are the following:
Declaring a column of type RESULTSET.
Declaring a parameter of type RESULTSET.
Declaring a stored procedure’s return type as a RESULTSET.
2. Execute statements with Bulk Collect clause are not supported.¶
Review the following documentation.
Related EWIs¶
SSC-EWI-0058: Functionality is not currently supported by Snowflake Scripting.
SSC-EWI-0062: Custom type usage changed to variant.
SSC-EWI-0073: Pending Functional Equivalence Review
SSC-EWI-OR0036: Types resolution issues, the arithmetic operation may not behave correctly between string and date.
SSC-EWI-OR0072: Procedural Member not supported
SSC-EWI-OR0104: Unusable collection variable.
SSC-FDM-0006: Number type column may not behave similarly in Snowflake.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE check UDF implementation.