Overview
Turbo pipelines SQL transforms are powered by Apache DataFusion and include custom functions designed specifically for blockchain and Web3 data processing. These functions extend standard SQL with capabilities for:- Decoding EVM logs and Solana instructions
- Working with 256-bit integers common in smart contracts
- Processing blockchain-specific data formats
- Advanced array and JSON manipulation
- Cryptographic operations
All standard DataFusion SQL functions are also available. This reference
focuses on Turbo-specific custom functions.
EVM & Ethereum Functions
evm_log_decode
Decodes an EVM event log using an ABI definition. Aliases:evm_decode_log, _gs_log_decode
Signature:
Returns: A struct with two fields:
event_signature(string): the event name (e.g."Transfer")event_params(array of strings): decoded parameter values in positional order
Parameters are returned by position, not by name. To access the third parameter, use
decoded.event_params[3], not decoded['paramName']._gs_fetch_abi for dynamic ABI lookup
Instead of hardcoding the ABI JSON, fetch it at runtime from Etherscan:
evm_trace_decode
Decodes EVM trace (call) data using an ABI definition, the trace counterpart ofevm_log_decode.
Aliases: evm_decode_trace, _gs_trace_decode
Signature:
Returns: A struct with three fields:
function_signature(string): the matched function nameinputs(array of strings): decoded input values in positional orderoutputs(array of strings): decoded output values in positional order
NULL.
Example: Decode traces
_gs_fetch_abi
Fetches an ABI JSON from a URL. Results are cached for the lifetime of the pipeline. Signature:
Returns: ABI JSON string that can be passed to
evm_decode_log or _gs_decode_instruction_data
Example: Fetch ABI from Etherscan
_gs_eth_call
Performs aneth_call JSON-RPC request against an EVM node, ABI-encoding the inputs and ABI-decoding the outputs. Use this to enrich streaming rows with on-chain state at a specific block (token balances, totalSupply, oracle prices, contract metadata) without standing up a separate fetcher service.
Signature:
Returns: An
ARRAY<VARCHAR> of decoded output values, one element per declared output type. Index with [1] for the first return value. Returns NULL for any row whose call fails (bad signature, revert, RPC error, decode error); failures never tear down the batch.
Example: Enrich ERC-20 transfers with totalSupply at the transfer’s block
_gs_evm_get_balances
Reads native token balances (ETH on Ethereum, the native asset on any EVM chain) for a list of addresses at a given block, usingeth_getBalance against an RPC endpoint you provide. Use it to fetch exact balances for addresses that just moved value, instead of polling every address every block. See the native balances guide for a complete pipeline.
Signature:
Returns: One element per input address, in input order.
address is the address as you passed it; balance is the balance in wei as a 256-bit integer, the same type as the amount column of the native transfers dataset. Use CAST(balance AS TEXT) to render it and standard operators for arithmetic. A failed lookup (RPC error, timeout, malformed response) leaves that element’s balance as NULL and logs a warning; it never fails the row or the batch. An empty or NULL address list returns an empty list.
Example: balances of both parties after each transfer
Element access such as [1].balance is not supported on this list; use UNNEST in a subquery and read the struct fields from the outer query.
_gs_keccak256
Compute Keccak256 hash (same as Solidity’skeccak256).
Signature:
input- String to hash. A0x-prefixed input is hex-decoded first and the resulting bytes are hashed; any other string is hashed as UTF-8 text.
NULL if a 0x-prefixed input is not valid hex.
Example: Compute Event Signatures
_gs_hex_to_byte / _gs_byte_to_hex
Convert between hex strings and bytes. Signatures:_gs_hex_to_byte accepts input with or without a 0x prefix; invalid or NULL input returns an empty byte array, not NULL. _gs_byte_to_hex returns a bare hex string (no 0x prefix).to_checksum_address
Converts a hex address to its EIP-55 checksummed form (mixed-case encoding). Optionally accepts a chain ID for EIP-1191 chain-specific checksums. Signature:
Returns: A
0x-prefixed checksummed address, or NULL for invalid input.
Example:
reverse_bytes32
Reverses the byte order of a 32-byte value. Useful for endianness conversion of blockchain hashes and 256-bit integers. Signature:
Returns: The same 32 bytes in reversed order.
NULL is passed through.
Example:
Solana Functions
Turbo pipelines include specialized functions for decoding Solana program instructions and analyzing transaction data. Many of the below are already used in our defaultsolana.instructions dataset and other datasets.
_gs_decode_instruction_data (IDL Decode)
Decode Solana program instruction or event data using an IDL (Interface Definition Language) specification. This is the most flexible Solana decoding function - it works with any custom Solana program that has an IDL. Signature:idl_json- IDL specification as JSON string (can be fetched with_gs_fetch_abi())data- Base58-encoded instruction data
name- Instruction or event name (e.g., “initialize”, “swap”, “transfer”)value- JSON string with decoded parameter values
- Parses the IDL JSON specification
- Attempts to decode as an instruction first
- Falls back to event decoding if instruction decoding fails
- Returns both the name and decoded values
When to use:
- Custom Solana programs with available IDL specifications
- Decoding instructions from DEXes, DeFi protocols, NFT marketplaces
- Any program where you need flexible, schema-driven decoding
- Solana system programs (Token, System, Stake, Vote, etc.) - use
_gs_solana_decode_*functions below - Better performance for known programs with hardcoded decoders
_gs_solana_decode_token_program_instruction
Decode Solana Token Program (SPL Token) instructions. Signature:data: Base58-encoded instruction dataaccounts: List of account public keys for the instruction
_gs_solana_decode_system_program_instruction
Decode Solana System Program instructions (transfers, account creation, etc.). No IDL required. Signature:data: Base58-encoded instruction dataaccounts: List of account public keys for the instruction
_gs_solana_get_accounts
Build a unified list of accounts for a Solana transaction, annotated with source, writable, and signer flags. This is the same logic used to produce theaccounts column on solana.instructions.
Signature:
account_keys-LIST<VARCHAR>of account pubkeys from the message headerloaded_readonly-LIST<VARCHAR>of readonly pubkeys loaded via address lookup tablesloaded_writable-LIST<VARCHAR>of writable pubkeys loaded via address lookup tablesnum_required_signatures-UINT8header fieldnum_readonly_signed_accounts-UINT8header fieldnum_readonly_unsigned_accounts-UINT8header fieldsource-VARCHARtag stored on each resulting account record
_gs_solana_get_balance_changes
Pair a transaction’s unified account list with itspreBalances / postBalances arrays to produce per-account SOL balance changes.
Signature:
accounts-LIST<STRUCT<pubkey, source, writable, signer>>(typically the output of_gs_solana_get_accounts)pre_balances-LIST<UINT64>of lamport balances before the transactionpost_balances-LIST<UINT64>of lamport balances after the transaction
Other Solana Decoders
All program-specific decoders take(data, accounts) and follow the same pattern:
_gs_solana_decode_associated_token_program_instruction(data, accounts)- Decode ATA program_gs_solana_decode_stake_program_instruction(data, accounts)- Decode staking operations_gs_solana_decode_vote_program_instruction(data, accounts)- Decode vote program_gs_solana_decode_bpf_loader_instruction(data, accounts)- Decode BPF loader_gs_solana_decode_bpf_upgradeable_loader_instruction(data, accounts)- Decode upgradeable programs_gs_solana_decode_address_lookup_table_instruction(data, accounts)- Decode address lookup tables
_gs_from_base58
Decode Base58 strings (common in Solana for addresses and signatures). Signature:NULL input returns an empty byte array, not NULL.
Example:
_gs_solana_base58
Base58-encode raw Solana bytes. Strings that are already base58 are passed through unchanged, so the same expression works for raw and pinned schemas. Signature:_gs_solana_pin_token_balances
Normalize apreTokenBalances / postTokenBalances array from the raw block schema into the pinned schema, base58-encoding raw mint, owner and programId bytes. Already-pinned values pass through.
Signature:
_gs_flatten_balances
Flatten a pinned token-balance array by liftinguiTokenAmount.amount and uiTokenAmount.decimals onto each entry.
Signature:
amount is a VARCHAR and decimals a UINT8. A NULL input list produces an empty list.
Example:
_gs_decode_log_message
Decode Solana program log messages (e.g. Anchor events) using an IDL. Signature:
Returns: Parallel lists of decoded event names, values (JSON text) and emitting program IDs.
Example:
_gs_solana_get_leader_info
Extract the block leader from a block’s rewards: the pubkey and lamports of the firstFee reward.
Signature:
NULL when the block has no Fee reward. rewards must be an array column.
Example:
Large Numbers (256-bit integers and wide decimals)
Smart contracts use 256-bit integers for token amounts and balances. Turbo stores these values, and anyDECIMAL(p, s) with a precision above 76, as an arbitrary-precision decimal type, decimal_arb. Wide-integer dataset columns such as amount in erc20_transfers and native_transfers, and the balance returned by _gs_evm_get_balances, already have this type. You work with them using standard SQL operators and CAST; no conversion functions are needed.
Working with 256-bit values
- Convert in.
CAST(x AS DECIMAL(78, 0))turns a decimal string, an integer, or an existing 256-bit column into a 256-bit integer. Signed values are fine. A string that isn’t a number fails the query;TRY_CAST(x AS DECIMAL(78, 0))returnsNULLinstead. - Calculate.
+,-,*,/,%, unary-, comparisons,ABS,COALESCEandGREATEST/LEASTall work directly on 256-bit values. A numeric literal next to one is exact however many digits it has, soamount / 1000000000000000000andamount > 1000000000000000000000000need no quoting. - Convert out.
CAST(x AS TEXT)renders the value as a decimal string. To get a native number, go through text, for exampleCAST(CAST(x AS TEXT) AS BIGINT), or usedecimal_arb_to_decimal128for aDECIMAL(38, s). A directCAST(x AS BIGINT),CAST(x AS DOUBLE)orCAST(x AS DECIMAL(38, s))fails withUnsupported CAST from LargeBinary. - NULLs. A
NULLinput or operand givesNULL. It does not raise an error.
When a ClickHouse sink creates a table, it stores a 256-bit column as
UInt256. Results derived from these columns, including a - b, keep that type, so a negative value fails the write. If a column can go negative, set it to Int256 in the sink’s schema_override.decimal_arb functions
Operators and casts cover most needs. These functions handle explicit precision and scale, and conversions to and from other numeric types. Precision and scale arguments must be integer literals, with1 <= precision <= 65535 and 0 <= scale <= precision. A NULL value gives NULL.
The operators are rewritten to
decimal_arb_add, decimal_arb_sub, decimal_arb_mul, decimal_arb_div, decimal_arb_mod, decimal_arb_neg, decimal_arb_abs, decimal_arb_eq, decimal_arb_neq, decimal_arb_lt, decimal_arb_lte, decimal_arb_gt and decimal_arb_gte. You can call these directly, but the operators are clearer. SUM, MIN, MAX and AVG also accept decimal_arb, but streaming SQL transforms don’t run aggregates. Use the PostgreSQL aggregation sink to sum values instead.
Example:
coalesce_meta
Return the first non-null argument per row, likeCOALESCE, preserving the first argument’s field metadata. It only works on values in the old 256-bit format. For 256-bit columns, use COALESCE.
Signature:
Array Processing Functions
make_array
Build an array from individual values. Use it to pass several columns to a function that takes a list, such as_gs_evm_get_balances.
Signature:
ARRAY[value1, value2] is an equivalent literal form.
Example:
array_filter_in
Filter array elements where a struct field matches any value in a provided list. This is particularly useful for preventing overflow panics when processing large nested arrays by filtering before unnesting. Signature:array- Array of structs to filterfield_name- Name of the struct field to match against (Utf8 string)values_list- Array of values to match (supports Utf8 and Int64 types)
ListArray. When the total number of rows after unnesting exceeds ~2.1 billion, buffer offset calculations overflow.
By filtering arrays before unnesting, you reduce both memory usage and processing time while avoiding these overflow issues.
Example: Filter Stellar ledger entry changes
to_large_list
Convert a List array (i32 offsets) to a LargeList array (i64 offsets). This allows processing arrays that would otherwise overflow the i32 offset limit during operations like unnest. Signature:array- List, LargeList, or FixedSizeList array to convert
to_large_list when you need ALL elements from an array but the arrays might be extremely large. This changes the offset type from i32 (~2.1B max) to i64, preventing overflow in Arrow’s take function.
Example: Process large arrays safely
array_filter
Filter array elements based on field value. Signature:array- Array of structs to filterfield_name- Name of field to matchvalue- Value to match against
array_filter_first
Likearray_filter but returns only the first matching element.
Signature:
array_enumerate
Add index to each array element. Signature:array_struct_field
Project one string field out of every struct in an array, producing an array of strings with the same shape.NULL struct elements become NULL strings.
Signature:
_gs_map_to_array_struct
Convert aMAP<VARCHAR, VARCHAR> into an array of key/value structs, for example to unnest the params map returned by the Solana program decoders.
Signature:
VARCHAR keys and values.
Example:
_gs_generate_series
Generate an array of integers fromstart to stop, inclusive of both endpoints. Combine with CROSS JOIN UNNEST for one-to-many row expansion, for example emitting one row per element of a decoded batch.
Signature:
step is optional and defaults to 1. A negative step counts down (e.g. _gs_generate_series(5, 1, -2) returns [5, 3, 1]). A step of 0 raises an error, and a step pointing away from stop returns an empty array.
Example: Expand one row per block in a range
_gs_zip_arrays
Combine multiple arrays element-wise. Signature:String & Encoding Functions
string_to_array
Split string into array by delimiter. Signature:_gs_split_string_to_array / _gs_split_string_by
Split a string into an array by a separator._gs_split_string_by is an alias of _gs_split_string_to_array.
Signatures:
separator argument is optional and defaults to a single space.
Example: Split a decoded batch parameter
SPLIT_INDEX
Split a string by a delimiter and return the element at a given index. This is particularly useful for extracting individual topics from thetopics field in raw_logs datasets, which is a comma-separated string.
Signature:
string- The string to splitdelimiter- The delimiter to split onindex- 0-based index of the element to return
NULL if the index is out of bounds.
Example: Extract event signature from raw logs
Regular Expression Functions
Turbo pipelines include Flink-compatible regex functions: regexp_extract - Extract regex match groups$1 / \1 group references are not expanded, and there is no flags argument.
regexp_count - Count regex matches
NULL from all of these functions.
Example: Extract Address from Log Message
URL Functions
parse_url - Extract URL components_gs_conv_base
Convert a number written as a string between bases 2–36. Signature:number as VARCHAR; from_base and to_base must both be INT32 columns or both be VARCHAR. Returns NULL for an invalid number or a base outside 2–36.
Example:
base32_to_hex
Decode an RFC 4648 base32 string (padding optional) into a lowercase0x-prefixed hex string.
Signature:
NULL for invalid or blank input.
Example:
bytes_to_hex_string
Convert a list of bytes into a lowercase0x-prefixed hex string.
Signature:
LIST<UINT8>, or LIST<VARCHAR> of decimal byte strings ('0'–'255').
Returns: The hex string, or NULL for a NULL or empty list, a NULL element, or an invalid decimal byte.
Example:
gs_ss58_decode / gs_ss58_encode
Convert between Substrate/Polkadot SS58 addresses and 32-byte AccountId32 public keys. Signatures:
Returns:
gs_ss58_decode returns the 0x-prefixed 32-byte key; gs_ss58_encode returns the SS58 address. Both return NULL for invalid input.
Example:
Arweave Tag Functions
Decode and index Arweave transaction tags. Signatures:_gs_arweave_tags_decodetakes a JSON array of base64url-encoded{"name", "value"}pairs and returns the decoded name/value structs._gs_arweave_string_arraytakes the decoded tag list and returns each tag as URL-escapedname#valuetext, which is convenient for searching.
Other String Functions
bin(number)- Convert to binary representationtranslate(string, from_chars, to_chars)- Character translationelt(index, string1, string2, ...)- Return element at index (1-based)locate(substring, string[, start])- Find substring position (1-based; 0 if not found)instr(string, substring[, start[, occurrence]])- Find the position of the nth occurrence (1-based; a negativestartsearches from the end)split(string, delimiter)- Split into an array, keeping empty tokensunhex(hex_string)- Decode hex string
lower, upper, trim, substring, concat, replace, reverse, etc.
JSON Functions
Turbo pipelines have comprehensive JSON support compatible with Flink SQL.json_query
Return the JSON object or array at a path, as JSON text. Signature:$, .key, [n] and ['key'] steps only; wildcards, recursive descent ($..) and filters are not supported.
Example: Extract NFT Metadata
json_value
Extract scalar value from JSON. Signature:parse_json / try_parse_json
Parse JSON string to validate or convert. Signatures:is_json
Check if string is valid JSON. Signature:json_object / json_array
Construct JSON objects and arrays. Signatures:json_object_absent_on_null- Omit null fieldsjson_array_absent_on_null- Omit null elements
Other JSON Functions
json_quote(string)- Quote and escape a string as a JSON string literaljson_unquote(string)- Unescape a double-quoted JSON string; other text is returned unchangedjson(string)- Validate JSON text and re-serialize it compactly (errors on invalid JSON)json_arrayagg_null_on_null(value)/json_arrayagg_absent_on_null(value)- Aggregate a group’s values into a JSON array, keeping or omitting NULLsjson_objectagg_null_on_null(key, value)/json_objectagg_absent_on_null(key, value)- Aggregate a group’s key/value pairs into a JSON object; NULL or duplicate keys raise an error
json_exists
Check if JSON path exists. Signature:json_string
Converts any value to its JSON-encoded string representation. Primitives are quoted; structs and arrays are serialized to JSON objects/arrays. Signature:
Returns: A JSON string.
NULL input is passed through.
Example:
_gs_json_objects_to_clickhouse_tuples
Format selected keys from a JSON array of objects as ClickHouse tuple literals, for example to load nested rows into a ClickHouseArray(Tuple(...)) column.
Signature:
Example:
Time Functions
now / current_time / current_date
Get current timestamp, time, or date. Signatures:date_part
Extract part of a timestamp. Signature:to_timestamp / to_timestamp_micros
Convert Unix timestamp to TIMESTAMP. Signatures:Hash & ID Functions
_gs_xxhash
Fast non-cryptographic hash function (XXH3 128-bit). Returns a 32-character hex string. Signature:uuid7
Generates a UUIDv7, a time-ordered UUID that embeds the current timestamp. Useful as a primary key when you want inserts to be monotonically sorted by time. Signature:018f2a5c-1234-7abc-8def-0123456789ab). Called once per row, so every row gets a distinct value.
Example:
Dynamic Table Functions
dynamic_table_check
Check if a value exists in a dynamic table (async function). Signature:table_name- Reference name of the dynamic table (from your pipeline config). An unknown name fails at execution.value- Value to check for existence: a string, or an array of strings (LIST<VARCHAR>)
true if the value exists in the table, false otherwise, and NULL for a NULL value. For an array, true if any non-null element exists in the table; an empty array returns false.
See the Dynamic Tables documentation for complete details.
Example:
Function Composition
Functions can be composed to build complex transformations. Example: Decode Log and Convert ValuePerformance Considerations
Function Caching
Function Caching
Some functions use internal caching for performance:
evm_decode_logcaches ABI decoders (reuse the same ABI string)- Regex functions cache compiled patterns
- For best performance, use literal strings for patterns/ABIs when possible
Async Functions
Async Functions
dynamic_table_check is async and may perform I/O operations (database
lookups). Use it strategically: - Good: Filter with WHERE clause using dynamic
table - Avoid: Using in complex calculations or deeply nested expressions256-bit Operations
256-bit Operations
256-bit arithmetic is more expensive than native integers:
- Use
DECIMAL(78, 0)only for values that need it, such as token amounts - Do as much filtering as possible before 256-bit operations
- Convert to text once, at the end:
CAST(a / b AS TEXT), not arithmetic on text values
Array Operations
Array Operations
Array processing can be expensive on large arrays:
- Filter arrays early in the pipeline
- Use
array_filter_firstinstead ofarray_filterwhen you only need one element - Consider if SQL filtering can reduce array size before processing
Best Practices
1
Use type-specific functions
Use 256-bit integers (
DECIMAL(78, 0)) for token amounts, regular INT for counters and IDs2
Validate data
Use
try_parse_json instead of parse_json when data quality is uncertain3
Minimize function calls
Store function results in CTEs when used multiple times:
sql WITH decoded AS ( SELECT id, evm_decode_log(abi, topics, data) as evt FROM logs ) SELECT evt.event_signature, evt.event_params[1], evt.event_params[2] FROM decoded 4
Handle NULLs
Many blockchain fields can be NULL - use COALESCE or NULL checks
5
Use appropriate hash functions
_gs_keccak256for EVM-compatible hashing (event signatures, etc.)_gs_xxhashfor fast non-cryptographic hashing (IDs, deduplication)