Approximate DNA, IUPAC and ASCII string matching with SIMD Sassy kernels, including CRISPR guide search
Installing and Loading
INSTALL ducksassy FROM community;
LOAD ducksassy;
Example
-- Load the extension
LOAD ducksassy;
-- Find a DNA pattern with up to one edit, on both strands
SELECT unnest(sassy_matches('ACGTAGG', 'TTACGTTGGAA', 1), recursive := true);
-- Fuzzy grep over text: one allowed edit, ASCII alphabet
SELECT * FROM sassy_grep('timeout', 'request timedout; retry timeout', 1);
-- CRISPR guide with its NGG PAM against a sequence column
SELECT name, unnest(sassy_crispr_matches('ACGTNGG', seq, 1), recursive := true)
FROM (VALUES ('target', 'TTACGTAGGTT')) AS t(name, seq);
About ducksassy
Ducksassy brings Sassy, a SIMD approximate string matcher by Rick Beeloo and Ragnar Groot Koerkamp, into DuckDB. Search DNA, IUPAC or ASCII text for patterns with up to k substitutions, insertions or deletions, and get every hit back as rows with edit cost, zero-based half-open coordinates, strand and CIGAR.
Scalar functions search any sequence or text column, so pattern panels, guide libraries and targets compose with joins, filters and aggregates. CRISPR search applies Sassy's exact PAM endpoint filter and N-content limit. Packed BAM-style CIGAR operations are available in SAM forward-reference order.
Pair it with the duckhts community extension to search FASTA, FASTQ and BAM records directly.
Full function reference includes signatures, return types and examples.
Functions included in this extension:
Search
sassy_matches: Return every approximate match of one pattern in a text with at most k edits.alphabetis 'dna', 'iupac' or 'ascii';rcalso searches the reverse complement;all_endpointsreports every qualifying endpoint instead of Sassy's rightmost local minima;cigar_formatis 'text', 'packed' or 'both'.sassy_matches_many: Search a panel of up to 4096 patterns in one text. Each hit carries the zero-basedpattern_idxof the panel entry that produced it, so duplicate patterns stay distinct.sassy_count: Count the matchessassy_matcheswould return, without building CIGAR strings.sassy_count_many: Count the matches of every pattern in a panel, without building CIGAR strings.sassy_contains: Return whether the text contains at least one match of the pattern with at most k edits.sassy_contains_many: Return whether any pattern in the panel matches the text with at most k edits.sassy_grep: Stream the matches of an ASCII pattern in one long text value, scanning overlapping 1 KiB regions and returning all qualifying endpoints. An outerLIMITstops the scan once enough rows are produced.
CRISPR
sassy_crispr_matches: Find guide occurrences with at most k edits over the whole guide, including its trailing PAM. Hits must end in an exact IUPAC PAM match unlessallow_pam_editsis true, and targets whose N fraction exceedsmax_n_fracare dropped. Both strands are searched by default.cigar_formatselects text, packed BAM operations, or both.sassy_crispr_matches_many: Search a guide panel sharing the same PAM suffix; each hit carries the guide's zero-basedpattern_idx. Guides with different PAMs belong in separate rows or calls.cigar_formatselects text, packed BAM operations, or both.
Diagnostics
sassy_backend_info: Report each SIMD backend (scalar, avx2, avx512, neon, wasm128): whether it is compiled into this build, supported by the running CPU, and selected. Selection happens on the first search.
Operational notes:
- Scalar arguments are positional with trailing defaults; the C extension API does not support named scalar arguments. For example
sassy_matches(pattern, text, k, alphabet := 'iupac', rc := true, all_endpoints := false, cigar_format := 'text')is writtensassy_matches(pattern, text, k, 'iupac', true, false, 'text'), and trailing arguments may be omitted. - Every scalar has VARCHAR and BLOB overloads; pattern and text must use the same type.
_manyvariants take aVARCHAR[]orBLOB[]panel and report the zero-basedpattern_idxof each hit. - Coordinates are zero-based and half-open in the input text. Text CIGAR is in pattern direction on reverse-strand hits; packed
cigar_opsuse BAM encoding in forward-reference order with query soft clips. The result struct is fixed across formats: 'text' setscigar_opsto NULL, 'packed' setscigarto NULL, and 'both' populates both fields. sassy_grepstreams one long ASCII value in overlapping 1 KiB regions and returns all qualifying endpoints, so an outerLIMITstops the search early.- The SIMD backend (scalar, AVX2, AVX-512 or NEON) is chosen at runtime; set
SASSY_C_BACKENDbefore the first search to force one.sassy_backend_info()reports what is compiled, supported and selected. - Loading executes no SQL and writes nothing to the database, so read-only databases are supported. MinGW and Rtools x86-64 builds use static Rust/GCC runtimes and Windows system DLLs. MSVC is unsupported. The default DuckDB-Wasm MVP and EH bundles are supported with scalar search and a fail-stop Rust panic ABI; the optional COI/threads bundle remains excluded pending an atomics-enabled Rust standard library.
Added Functions
| function_name | function_type | description | comment | examples |
|---|---|---|---|---|
| sassy_backend_info | table | NULL | NULL | |
| sassy_contains | scalar | NULL | NULL | |
| sassy_contains_many | scalar | NULL | NULL | |
| sassy_count | scalar | NULL | NULL | |
| sassy_count_many | scalar | NULL | NULL | |
| sassy_crispr_matches | scalar | NULL | NULL | |
| sassy_crispr_matches_many | scalar | NULL | NULL | |
| sassy_grep | table | NULL | NULL | |
| sassy_matches | scalar | NULL | NULL | |
| sassy_matches_many | scalar | NULL | NULL |
Overloaded Functions
This extension does not add any function overloads.
Added Types
This extension does not add any types.
Added Settings
This extension does not add any settings.