snowflake

The snowflake plugin allows you to view and read Snowflake data. It supports establishing and closing connections to Snowflake, listing tables and views visible to the current Snowflake role in a specified database or schema, and retrieving column metadata for table schemas or query results. For data reads, the plugin can load Snowflake tables or query results into DolphinDB in-memory tables. It can also write table data or query results in batches to existing DolphinDB tables.

Note:

Prerequisites

  • A valid CA certificate and an RSA private key file must be configured on the server hosting DolphinDB Server.

  • The system clock on the server hosting DolphinDB Server must be accurate. Otherwise, JWT authentication may fail when the token's issue or expiration time is validated.

  • Create a Snowflake organization account, user, warehouse, database, and schema.

  • Generate a public key that matches the RSA private key on the server hosting DolphinDB Server, and configure the public key for the Snowflake user.

    ALTER USER [USERNAME] SET RSA_PUBLIC_KEY = 'RSA public key'

Installation

Version Requirements

DolphinDB Server 2.00.16+ or 3.00.4+, and the package type is Linux x86_64 or Linux x86_64 ABI.

Installation Steps

  1. In a DolphinDB client, use the listRemotePlugins function to view the plugins available for installation.

    login("admin", "123456")
    listRemotePlugins()
  2. Use the installPlugin function to install the plugin.

    installPlugin("snowflake")
  3. Use the loadPlugin function to load the plugin.

    loadPlugin("snowflake")

Method References

connect

Syntax

snowflake::connect(config)

Details

Connects to a Snowflake database and returns a connection handle.

Note:

This method uses JWT for Snowflake key-pair authentication. When establishing a connection, the plugin reads the RSA private key from the local file path specified by "privateKeyPath" and generates a JWT based on "account" and "user". The plugin sends the JWT to Snowflake in the Authorization request header. Snowflake validates the JWT against the RSA public key preconfigured for the corresponding user and authenticates the user if validation succeeds.

Parameters

config is a dictionary (Dictionary<STRING, ANY>) specifying the connection settings. It supports the following key-value pairs:

Key Value Required

"account"

A STRING scalar specifying the account identifier in the Snowflake organization, without specifying the region. The identifier must use the format "organization-account", for example, "WJCYPAV-TD40511".

Yes

"user"

A STRING scalar specifying the user name in the Snowflake account.

Yes

"privateKeyPath"

A STRING scalar specifying the path to the RSA private key file on DolphinDB Server.

Yes

"warehouse"

A STRING scalar specifying the warehouse that provides the compute resources. The default is "warehouse".

Yes

"database"

A STRING scalar specifying the database to access. The default is "database".

Yes

"schema"

A STRING scalar specifying the schema in the database. The default is "schema".

Yes

"role"

A STRING scalar specifying the role used to connect to Snowflake. The default is the role configured for the Snowflake user.

No

"options"

is a dictionary (Dictionary<STRING, ANY>) specifying settings such as the hostname, JWT, polling interval, and timeouts. See the following table for details.

No

The options dictionary supports the following key-value pairs:

Key Value

"host"

A STRING scalar specifying the Snowflake hostname. Enter only the hostname; do not include a protocol such as https://, a port, a path, or URL parameters, including query and fragment components. By default, the account identifier is converted to lowercase and concatenated with .snowflakecomputing.com to form the hostname, for example, "myorg-myaccount.snowflakecomputing.com".

"privateKeyPassphrase"

A STRING scalar specifying the passphrase used to decrypt the RSA private key. Configure this option only when the local RSA private key is encrypted. The default is an empty string.

"jwtLifetimeSeconds"

An integer scalar in the range [1, 3600] specifying the JWT lifetime in seconds. The default is 3600.

"jwtRefreshMarginSeconds"

An integer scalar in the range [0, 3600] specifying how many seconds before expiration the JWT is refreshed. The plugin refreshes the JWT when the remaining time before expiration is less than this value. This value must be less than jwtLifetimeSeconds. The default is 300.

"connectTimeoutSeconds"

A positive integer scalar specifying the timeout, in seconds, for libcurl to establish a TCP/TLS connection. The default is 10.

"requestTimeoutSeconds"

A positive integer scalar specifying the timeout, in seconds, for a Snowflake statement request. This parameter sets only the timeout in the request body; it does not specify the total timeout for the entire libcurl HTTP request. The default is 60.

"pollIntervalMillis"

A positive integer scalar specifying the polling interval, in milliseconds, after the SQL API returns 202. The default is 500.

"maxPollSeconds"

A positive integer scalar specifying the maximum polling time for an asynchronous statement, in seconds. The default is 3600.

"maxRetry"

A nonnegative integer scalar specifying the number of retries for 429, 500, 502, 503, 504, and libcurl request errors; the total number of attempts is limited to maxRetry + 1. The default is 3.

"proxy"

A STRING scalar specifying the HTTP/HTTPS proxy to use with libcurl. The default is an empty string, indicating that no proxy is configured.

Returns

A connection handle.

Example

// Basic configuration
config = dict(STRING, ANY)
config["account"] = "myorg-myaccount"
config["user"] = "DDB_READER"
config["privateKeyPath"] = "/opt/dolphindb/keys/snowflake_rsa_key.p8"
config["warehouse"] = "DDB_WH"
config["database"] = "SALES_DB"
config["schema"] = "PUBLIC"
config["role"] = "DDB_READER_ROLE"

// Set the private key passphrase and timeout through the options dictionary
connOptions = dict(STRING, ANY)
connOptions["privateKeyPassphrase"] = "<PRIVATE_KEY_PASSPHRASE>"
connOptions["connectTimeoutSeconds"] = 20
connOptions["requestTimeoutSeconds"] = 120
connOptions["pollIntervalMillis"] = 1000
connOptions["maxPollSeconds"] = 1800
connOptions["maxRetry"] = 5
config["options"] = connOptions

conn = snowflake::connect(config)

close

Syntax

snowflake::close(conn)

Details

Closes the specified connection. After the connection is closed, passing its handle to any plugin method causes the method to return the following error: Invalid connection object.

Parameters

conn is a connection handle created by connect.

Returns

The string "Connection is closed."

showTables

Syntax

snowflake::showTables(conn, [database], [schema])

Details

Shows the tables or views visible to the current Snowflake user.

Parameters

conn is a connection handle created by connect.

database is a STRING scalar specifying the database to query. The default is the database specified when the corresponding connection handle was created.

schema is a STRING scalar specifying the schema to query. The default is the schema specified when the corresponding connection handle was created.

Returns

A table containing the following columns, or an empty table if no visible objects are found:

Column Name Data Type Description

database

STRING

Snowflake database.

schema

STRING

The schema of the Snowflake database.

name

STRING

The name of a Snowflake table or view.

kind

STRING

The type of the Snowflake database object, such as BASE TABLE or VIEW.

Example

// Query the connection's default database and schema
objects = snowflake::showTables(conn)

// Specify the database while using the connection's default schema
objects = snowflake::showTables(conn, "ARCHIVE_DB")

// Specify both the database and schema
objects = snowflake::showTables(conn, "ARCHIVE_DB", "REPORTING")

// Specify only the schema; set the database parameter to NULL
objects = snowflake::showTables(conn, NULL, "REPORTING")

extractTableSchema

Syntax

snowflake::extractTableSchema(conn, sourceTableName)

Details

Obtains the schema of a Snowflake table.

Parameters

conn is a connection handle created by connect.

sourceTableName is a STRING scalar specifying the Snowflake table name. Table names can use one-, two-, or three-part formats: TABLE_NAME, SCHEMA_NAME.TABLE_NAME, or DATABASE_NAME.SCHEMA_NAME.TABLE_NAME.

Returns

A table containing the following columns:

Column Name Data Type Description

name

STRING

The normalized DolphinDB column name. Column names are normalized according to the following rules:

  • Empty column names are converted to col_1, col_2, and so on.

  • Characters other than letters, digits, or underscores are replaced with underscores.

  • If the first character of a column name is not a letter or underscore, the prefix col_ is added.

  • To ensure uniqueness, the suffixes _2, _3, and so on are appended to columns whose names are duplicated after normalization.

type

STRING

The DolphinDB data type automatically mapped from the Snowflake data type.

snowflakeType

STRING

The raw data type returned by the Snowflake SQL API.

precision

INT

The precision in Snowflake metadata. If it is not provided in the metadata, -1 is returned.

scale

INT

The number of decimal places in Snowflake metadata. If it is not provided in the metadata, 0 is returned.

nullable

BOOL

Indicates whether the column allows NULL values. The value is taken from Snowflake metadata.

extractQuerySchema

Syntax

snowflake::extractQuerySchema(conn, sql)

Details

Executes the specified SELECT statement against a Snowflake table to obtain the schema of the query result.

Parameters

conn is a connection handle created by connect.

sql is a STRING scalar specifying the query SQL statement. The plugin removes the trailing semicolon from the SQL statement and wraps the query in a statement similar to the following:

SELECT *
FROM (<sql>) AS SNOWFLAKE_PLUGIN_SCHEMA
WHERE 1 = 0

Therefore, sql must be a SELECT statement that can be used as a subquery. Do not pass DDL or DML statements to this method.

Returns

A table containing the following columns:

Column Name Data Type Description

name

STRING

The normalized DolphinDB column name. Column names are normalized according to the following rules:

  • Empty column names are converted to col_1, col_2, and so on.

  • Characters other than letters, digits, or underscores are replaced with underscores.

  • If the first character of a column name is not a letter or underscore, the prefix col_ is added.

  • To ensure uniqueness, the suffixes _2, _3, and so on are appended to columns whose names are duplicated after normalization.

type

STRING

The DolphinDB data type automatically mapped from the Snowflake data type.

snowflakeType

STRING

The raw data type returned by the Snowflake SQL API.

precision

INT

The precision in Snowflake metadata. If it is not provided in the metadata, -1 is returned.

scale

INT

The number of decimal places in Snowflake metadata. If it is not provided in the metadata, 0 is returned.

nullable

BOOL

Indicates whether the column allows NULL values. The value is taken from Snowflake metadata.

loadTable

Syntax

snowflake::loadTable(conn, sourceTableName, [options])

Details

Loads data from a Snowflake table and returns it as a DolphinDB in-memory table.

Parameters

conn is a connection handle created by connect.

sourceTableName is a STRING scalar specifying the Snowflake table name. Table names can use one-, two-, or three-part formats: TABLE_NAME, SCHEMA_NAME.TABLE_NAME, or DATABASE_NAME.SCHEMA_NAME.TABLE_NAME.

options (optional) is a dictionary (Dictionary<STRING, ANY>) supporting the keys "columnSchema", "offset", "limit", and "allowEmptyResult". For details, see Common Parameter for Data Query Methods.

Returns

A DolphinDB in-memory table.

Example

// Do not specify additional options
orders = snowflake::loadTable(conn, "SALES_DB.PUBLIC.ORDERS")

// Return data in pages
options = dict(STRING, ANY)
options["offset"] = 1000
options["limit"] = 500
options["allowEmptyResult"] = true

ordersPage = snowflake::loadTable(
    conn,
    "SALES_DB.PUBLIC.ORDERS",
    options
)

// User-defined column types
columnSchema = table(
    ["order_id", "customer", "amount"] as name,
    ["LONG", "STRING", "DOUBLE"] as type
)

options = dict(STRING, ANY)
options["columnSchema"] = columnSchema

orders = snowflake::loadTable(
    conn,
    "SALES_DB.PUBLIC.ORDER_SUMMARY",
    options
)

query

Syntax

snowflake::query(conn, sql, [options])

Details

Executes the specified SELECT statement on a Snowflake table and returns the query results as a DolphinDB in-memory table.

Parameters

conn is a connection handle created by connect.

sql is a STRING scalar specifying the query SQL statement. The plugin removes the trailing semicolon from the SQL statement and wraps the query in a statement similar to the following:

SELECT *
FROM (<sql>) AS SNOWFLAKE_PLUGIN_SCHEMA
WHERE 1 = 0

Therefore, sql must be a SELECT statement that can be used as a subquery. Do not pass DDL or DML statements to this method.

options (optional) is a dictionary (Dictionary<STRING, ANY>) supporting the keys "columnSchema" and "allowEmptyResult". For details, see Common Parameter for Data Query Methods.

Note:

query does not support "offset" or "limit" in options. Specify LIMIT, OFFSET, and ORDER BY directly in the SQL statement.

Returns

A DolphinDB in-memory table.

Example

// Do not specify additional options
sql = "SELECT ORDER_ID, AMOUNT FROM SALES_DB.PUBLIC.ORDERS WHERE AMOUNT > 100 ORDER BY ORDER_ID"
result = snowflake::query(conn, sql)

// Return data in pages
sql = "SELECT ORDER_ID, AMOUNT FROM SALES_DB.PUBLIC.ORDERS ORDER BY ORDER_ID LIMIT 500 OFFSET 1000"

options = dict(STRING, ANY)
options["allowEmptyResult"] = true

result = snowflake::query(conn, sql, options)

loadTableInto

Syntax

snowflake::loadTableInto(conn, sourceTableName, targetTable, [options])

Details

Loads data from a Snowflake table and writes it to a DolphinDB table.

Note:

Writes are not guaranteed to be transactionally atomic. Partitions are written sequentially. If a later partition fails after earlier partitions have been written successfully, the previously written data is not rolled back automatically. To ensure atomicity, first write the data to a temporary table. After validating the data, use a script to replace the production table with the temporary table.

Parameters

conn is a connection handle created by connect.

sourceTableName is a STRING scalar specifying the Snowflake table name. Table names can use one-, two-, or three-part formats: TABLE_NAME, SCHEMA_NAME.TABLE_NAME, or DATABASE_NAME.SCHEMA_NAME.TABLE_NAME.

targetTable is a DolphinDB in-memory table or DFS table.

options (optional) is a dictionary (Dictionary<STRING, ANY>) supporting the keys "columnSchema", "offset", "limit", and "batchTransform". For details, see Common Parameter for Data Query Methods.

Returns

None.

Example

// Write to a DolphinDB in-memory table
target = table(
    100000:0,
    `order_id`customer`amount,
    [LONG, STRING, DOUBLE]
)

writtenRows = snowflake::loadTableInto(
    conn,
    "SALES_DB.PUBLIC.ORDER_SUMMARY",
    target
)

// Limit the number of rows read
options = dict(STRING, ANY)
options["limit"] = 10000

writtenRows = snowflake::loadTableInto(
    conn,
    "SALES_DB.PUBLIC.ORDER_SUMMARY",
    target,
    options
)

queryInto

Syntax

snowflake::queryInto(conn, sql, targetTable, [options])

Details

Executes the specified SELECT statement on a Snowflake table and writes the query results to a DolphinDB table.

Note:

Writes are not guaranteed to be transactionally atomic. Partitions are written sequentially. If a later partition fails after earlier partitions have been written successfully, the previously written data is not rolled back automatically. To ensure atomicity, first write the data to a temporary table. After validating the data, use a script to replace the production table with the temporary table.

Parameters

conn is a connection handle created by connect.

sql is a STRING scalar specifying the query SQL statement. The plugin removes the trailing semicolon from the SQL statement and wraps the query in a statement similar to the following:

SELECT *
FROM (<sql>) AS SNOWFLAKE_PLUGIN_SCHEMA
WHERE 1 = 0

Therefore, sql must be a SELECT statement that can be used as a subquery. Do not pass DDL or DML statements to this method.

targetTable is a DolphinDB in-memory table or DFS table.

options (optional) is a dictionary (Dictionary<STRING, ANY>) supporting the keys "columnSchema" and "batchTransform". For details, see Common Parameter for Data Query Methods.

Note:

queryInto does not support "offset" or "limit" in options. Specify LIMIT, OFFSET, and ORDER BY directly in the SQL statement.

Returns

None.

Example

// Write to a DolphinDB in-memory table
target = table(
    100000:0,
    `order_id`customer`amount,
    [LONG, STRING, DOUBLE]
)

sql = "SELECT ORDER_ID, CUSTOMER, AMOUNT FROM SALES_DB.PUBLIC.ORDERS ORDER BY ORDER_ID"
writtenRows = snowflake::queryInto(conn, sql, target)

// Write to a DolphinDB DFS table
target = loadTable("dfs://sales", `orders)

sql = "SELECT ORDER_ID, CUSTOMER, AMOUNT FROM SALES_DB.PUBLIC.ORDERS"
writtenRows = snowflake::queryInto(conn, sql, target)

Common Parameter for Data Query Methods

loadTable, query, loadTableInto, and queryInto all support the options parameter. The supported key-value pairs are listed in the following table. The set of supported keys varies by method. Passing an unsupported key causes the method call to fail.

Key Value Methods Supporting This Key

"columnSchema"

A table used to override result column names and target data types. The table must meet the following conditions:

  • It must have at least two columns, and the plugin reads only the first two.

  • The first column contains column names. Its type must be STRING or SYMBOL, and the column names cannot be empty.

  • The second column contains type names. Its type must be STRING or SYMBOL. Type names are case-insensitive and may include the DT_ prefix.

  • The number of rows must exactly match the number of columns in the Snowflake result.

  • Snowflake data can currently be converted only to the following types: BOOL, INT, LONG, DOUBLE, STRING, and SYMBOL. An error is raised if coercion fails.

loadTable, query, loadTableInto, queryInto

"offset"

"offset" specifies the number of rows to skip before returning data, and "limit" specifies the maximum number of rows to return.

  • "offset" and "limit" must be non-negative integer scalars.

  • When "offset" > 0, "limit" must also be specified.

  • Setting "limit" generates a LIMIT <limit> clause. When "offset" > 0, an OFFSET <offset> clause is generated.

  • Specifying "offset" and "limit" does not guarantee the order in which rows are read from the table. For consistent pagination in a specified order, use query/queryInto and include ORDER BY in the SQL statement.

loadTable, loadTableInto

"limit"

"allowEmptyResult"

A BOOL scalar that specifies whether an empty table can be returned. The default is false.

  • By default, a result with 0 rows causes an error: Snowflake query returned an empty table.

  • When set to true, an empty DolphinDB table with the original column structure can be returned.

loadTable, query

"batchTransform"

A user-defined DolphinDB function that processes batches of data.

  • The function's input and output must all be tables.

  • If a zero-row table is returned, tableInsert is not called for this batch.

  • A non-empty table returned by the function must have the same number of columns as targetTable, and the corresponding columns must have the same DolphinDB data types.

  • Any error thrown by the function is returned directly to the caller.

loadTableInto, queryInto

Supported Data Types

Snowflake and DolphinDB Data Type Mapping

The plugin maps types based on thetype, precision, and scale in the metadata returned by the Snowflake SQL API, rather than determining them solely from the type names used in the table-creation DDL.

Snowflake Metadata Type Condition Automatically Mapped DolphinDB Type

fixed, number, decimal, numeric

scale = 0 and 0 <= precision <= 9

INT

scale = 0 and either precision < 0 or 9 < precision <= 18

LONG

scale = 0 and precision > 18

STRING

scale != 0

DOUBLE

real, float, double

Any

DOUBLE

boolean, bool

Any

BOOL

All other metadata types

Any

STRING

The following Snowflake data types are currently mapped to STRING:

  • CHAR, VARCHAR, TEXT

  • DATE, TIME

  • TIMESTAMP_NTZ, TIMESTAMP_LTZ, TIMESTAMP_TZ

  • BINARY, VARBINARY

  • ARRAY, OBJECT, VARIANT

  • GEOGRAPHY, GEOMETRY, VECTOR

  • All other types not listed in the mapping rules above

For types mapped to STRING, the returned value is the textual representation of the value returned by the Snowflake SQL API. In particular, do not currently assume that the return values for DATE, TIME, or TIMESTAMP are native DolphinDB temporal types.

Target Types Supported by columnSchema

columnSchema supports the following target types and aliases. Type names are case-insensitive.

Type Name Available Aliases Accepted Non-NULL Text

BOOL

BOOLEAN, DT_BOOL, DT_BOOLEAN

true, false, 1, or 0; case-insensitive

INT

DT_INT

A decimal integer that can be parsed in full and whose value falls within the range representable by DolphinDB INT.

LONG

DT_LONG

A decimal integer that can be parsed in full and whose value falls within the range representable by DolphinDB LONG.

DOUBLE

DT_DOUBLE

Text that can be fully parsed as a DolphinDB DOUBLE.

STRING

DT_STRING

Any non-empty text.

SYMBOL

DT_SYMBOL

Any non-empty text.

Non-NULL text refers to the textual representation of a non-NULL field value returned by the Snowflake SQL API.

If columnSchema specifies a type not included in the list above, the API returns the following error: schema type ... is not supported yet

NULL Values and Type Conversion

When requesting data from the Snowflake SQL API, the plugin sets nullable=true and processes the returned values according to the following rules:

  • Snowflake SQL NULL: Returned as JSON null and converted to the NULL value of the corresponding DolphinDB type.

  • The string "null": Treats it as an ordinary string rather than NULL.

  • Non-NULL empty string: DolphinDB uses an empty string to represent NULL. Consequently, directly converting a non-NULL empty string from Snowflake would incorrectly interpret it as NULL, so the plugin blocks the conversion and reports an error.

  • Non-NULL numeric value: If a non-NULL numeric value returned by Snowflake equals the NULL representation of the corresponding DolphinDB type, directly converting it would incorrectly interpret it as NULL. To prevent data errors, the plugin blocks the conversion and reports an error. For example, the minimum INT value returned by Snowflake, the minimum LONG value, and any numeric value equal to the DolphinDB DOUBLE NULL representation cannot be converted as non-NULL values.

  • Numeric conversion: Numeric text must be fully parsed as the target type. A conversion error is returned if the text contains extra characters or exceeds the range representable by the target type.

  • NUMBER/DECIMAL: When scale != 0, the value is mapped to DOUBLE by default, which may result in floating-point precision loss. To preserve the original numeric text exactly, specify the column as STRING through columnSchema.

Complete Example

Example 1: The following example demonstrates the complete workflow: loading the plugin, establishing a connection, viewing objects, retrieving the schema, querying data, writing data to a target table, and closing the connection.

// 1. Load the plugin
loadPlugin("snowflake")

// 2. Create a connection
config = dict(STRING, ANY)
config["account"] = "myorg-myaccount"
config["user"] = "DDB_READER"
config["privateKeyPath"] = "/opt/dolphindb/keys/snowflake_rsa_key.p8"
config["warehouse"] = "DDB_WH"

config["database"] = "SALES_DB"
config["schema"] = "PUBLIC"
config["role"] = "DDB_READER_ROLE"

conn = snowflake::connect(config)

// 3. List visible objects
objects = snowflake::showTables(conn)

// 4. Inspect the query result schema
sql = "SELECT ORDER_ID, CUSTOMER, AMOUNT FROM SALES_DB.PUBLIC.ORDERS ORDER BY ORDER_ID"
sourceSchema = snowflake::extractQuerySchema(conn, sql)

// 5. Return a small result directly as an in-memory table
options = dict(STRING, ANY)
options["allowEmptyResult"] = true
preview = snowflake::query(conn, sql + " LIMIT 100", options)

// 6. Write a large result to an existing target table in batches
target = table(
    100000:0,
    `order_id`customer`amount,
    [LONG, STRING, DOUBLE]
)

columnSchema = table(
    ["order_id", "customer", "amount"] as name,
    ["LONG", "STRING", "DOUBLE"] as type
)

writeOptions = dict(STRING, ANY)
writeOptions["columnSchema"] = columnSchema

writtenRows = snowflake::queryInto(conn, sql, target, writeOptions)

// 7. Close the connection when finished
snowflake::close(conn)

Example 2: Use columnSchema to explicitly specify target types.

columnSchema = table(
    ["order_id", "customer", "amount"] as name,
    ["LONG", "STRING", "DOUBLE"] as type
)

options = dict(STRING, ANY)
options["columnSchema"] = columnSchema

target = table(
    100000:0,
    `order_id`customer`amount,
    [LONG, STRING, DOUBLE]
)

sql = "SELECT ORDER_ID, CUSTOMER, AMOUNT FROM SALES_DB.PUBLIC.ORDERS"
writtenRows = snowflake::queryInto(conn, sql, target, options)