dexsql documentation Open the app

DexSQL accepts read-only SQL with joins, subqueries, CTEs, aggregates, windows and set operations. It follows SQLite semantics within its supported language, with the text rules below. Invalid or unsupported statements return structured errors.

Start with DEX keys and descriptors, the table reference, or query examples. Functions, callers and overrides, annotations, and DEX structure queries cover specific tasks.

Statements and temporary results

SELECT and VALUES read data. CREATE VIEW, CREATE TEMP VIEW and CREATE TEMP TABLE ... AS SELECT ... name intermediate relations. Source data is read-only: INSERT, UPDATE, DELETE, ALTER, transactions and persistent schema changes are not supported.

CREATE TEMP TABLE app_strings AS
SELECT string_pool_id, string_idx, value
FROM strings WHERE value LIKE '%example%';

SELECT DISTINCT method
FROM method_strings
WHERE value IN (SELECT value FROM app_strings);

In a one-shot CLI call, pass each statement as a separate --sql; definitions last for that request. Interactive CLI and MCP datasets retain definitions across submissions until DROP VIEW / DROP TABLE, redefinition or session close. CREATE replaces an existing session definition after validation; IF NOT EXISTS keeps it. All session definitions are lazy, including TEMP TABLE: their rows are read when a query needs them. CLI --cache NAME=SQL follows the same scope rules. These definitions do not create disk cache files.

Text order

Text uses DEX's lexicographic UTF-16 code-unit order consistently in ORDER BY, window ordering, <, <=, >, >=, BETWEEN, and MIN/MAX. This differs from SQLite's UTF-8 BINARY order for some supplementary Unicode characters: U+10000 sorts before U+FFFD. ASCII ordering is unchanged.

BINARY compares exact text; NOCASE first folds ASCII case; RTRIM first removes trailing spaces (U+0020). Numeric conversion, NULL placement, and BLOB byte ordering are unchanged. LIKE and GLOB keep their pattern-matching rules.

Local DEX IDs are not a global text-order key. For values spanning files, request ORDER BY on the text itself; a complete method descriptor also does not necessarily follow method_idx order.

Text values

DEX text retains its original MUTF-8 bytes internally. Query output decodes to UTF-8: C0 80 becomes U+0000 and a valid surrogate pair becomes one Unicode scalar. An isolated surrogate becomes one U+FFFD; other invalid bytes, including each byte of a four-byte UTF-8 sequence, each produce U+FFFD. Distinct raw values can therefore look identical in output; hex(value) exposes their stored bytes. CLI tables escape control characters, and MCP strings use JSON escaping.

U+0000 is an ordinary character: text functions and patterns consume the complete value, including embedded NULs. This differs from SQLite functions that stop at NUL. CAST(text AS BLOB) exposes raw MUTF-8, and CAST(blob AS TEXT) keeps those bytes. For valid DEX text, a surrogate pair counts as one character for length and substr, even though sorting compares UTF-16 code units.

Text matching

Without ESCAPE, % matches any sequence and _ is a literal underscore. For example, LIKE '%SEND_SMS%' looks for that literal substring. An explicit ESCAPE clause enables SQLite-style patterns, including _ as a single-character wildcard unless escaped.

LIKE folds ASCII case; instr and = preserve case. Choose the operation that matches your intent:

Match ASCII case-insensitive Case-sensitive
Contains value LIKE '%x%' instr(value, 'x') > 0
Prefix value LIKE 'x%' instr(value, 'x') = 1
Suffix value LIKE '%x' substr(value, -length('x')) = 'x'
Exact value LIKE 'x' value = 'x'
SELECT 'SEND_SMS' LIKE '%SEND_SMS%';       -- 1
SELECT 'a' LIKE '_';                     -- 0
SELECT 'a' LIKE '_' ESCAPE '!';          -- 1
SELECT 'HTTPS://' LIKE 'https://%';       -- 1

Practical query costs

Select the columns you need, filter before expanding large annotation or reference sets, and reuse a prepared dataset for repeated queries. Result limits in an API cap the response, not necessarily execution work. Some joins and DISTINCT queries can exceed intermediate-result budgets even with a small output limit. Measure the actual SQL with CLI --timing.

For a stable result order, use ORDER BY with a unique tie-breaker, such as file_id, method_idx. A result page may run the query again; keep the SQL and input unchanged when continuing it.


Copyright (c) 2026 LSPosed Developers. Documentation licensed under MIT.