| UNION queries |
UNION ALL and UNION DISTINCT through resolver/planner/executor pipeline |
| Dup key error mapping |
Raft duplicate key errors mapped to MySQL ER_DUP_ENTRY (1062) |
| Integer overflow detection |
Proper BIGINT overflow for negation, add, sub, DIV of large numbers |
| Empty INSERT defaults |
INSERT INTO t1 () VALUES () fills all columns with defaults |
| BIT_LENGTH/OCTET_LENGTH |
String length functions in bits and bytes |
| CONCAT_WS |
Concatenate with separator, skipping NULLs |
| Full ALTER TABLE |
ADD/DROP/MODIFY/CHANGE COLUMN, ADD/DROP PK/FK/INDEX, RENAME, Raft persistence |
| Lazy row padding |
TableScan pads rows with defaults after ALTER TABLE ADD COLUMN |
| NOT NULL enforcement |
Error 1048 for NULL into NOT NULL; multi-row converts to default |
| Parenthesized queries |
(SELECT ... LIMIT n) ORDER BY ... LIMIT m |
| ORDER BY aliases |
SELECT aliases usable in ORDER BY clause |
| DDL type validation |
FLOAT precision, CHAR/VARCHAR length limits, TEXT promotion |
| Conditional comments |
/*!NNNNN code*/ pre-processing with version check |
| Post-aggregate arithmetic |
max(x)-1 rewrites aggregate refs in expression trees |
| System variable prefixes |
@@global.var, @@session.var parsed |
| Infix MOD operator |
expr MOD expr works for any expression type |
| Native DECIMAL |
DECIMAL(M,D) with i128 exact arithmetic (38-digit precision) |
| Shift operators |
<<, >> bitwise shifts |
| Integer division |
DIV operator |
| Expression headers |
Column names reconstructed from expression trees |
| String→number coercion |
Implicit conversion in arithmetic contexts |
| BIGINT UNSIGNED |
Full u64 range support |
| INSERT IGNORE |
Suppress errors during INSERT, skip bad rows |
| INSERT ... SELECT |
Insert rows from a source query into a table |
| ABS overflow detection |
ABS(i64::MIN) returns ER_DATA_OUT_OF_RANGE; Decimal + UnsignedInt arms |
| Negation overflow |
checked_neg for Int; UnsignedInt overflow returns error not Decimal |
| Log function sql_mode |
ER_INVALID_ARGUMENT_FOR_LOGARITHM (3020) in DML with ERROR_FOR_DIVISION_BY_ZERO |
| GET_FORMAT resolver |
GET_FORMAT type inference + keyword-as-argument fallback |
| HAVING alias resolution |
HAVING clause resolves SELECT aliases (e.g., HAVING s <> 0) |
| DO statement |
DO expr evaluates expression and discards result |
| ORDER BY aggregate alias |
ORDER BY resolves aggregate aliases via transform_to_output_columns |
| FLOAT/DOUBLE scale validation |
ER_TOO_BIG_SCALE (1427) for D>M; scale max 30; display width max 255 |
| WEIGHT_STRING stub |
Stub returns input bytes; sufficient for DO context |
| LTRIM/RTRIM functions |
Standalone LTRIM()/RTRIM() in eval.rs (resolver already had type inference) |
| DATE_ADD/DATE_SUB |
Full interval arithmetic: DAY, MONTH, YEAR, HOUR, MINUTE, SECOND, etc. |
| EXTRACT() |
EXTRACT(unit FROM expr) for all standard date/time fields |
| GROUP BY ordinal |
GROUP BY 1, ORDER BY 2 — numeric position references |
| DELETE ORDER BY LIMIT |
Full pipeline: resolver → planner → executor with sort + truncate |
| INSERT...SELECT column_map |
Partial column list mapping for INSERT...SELECT |
| INSERT IGNORE...SELECT |
ignore_duplicates propagated through Raft layer |
| DEFAULT for partial INSERT |
Column DEFAULT values applied for unspecified columns |
| Hex literal coercion |
0xNN bytes auto-converted to u64 in arithmetic/bitwise contexts |
| Trigger SET @var |
SET @var = expr and SET @var = NEW.col in trigger bodies |
| Multi-variable SET |
SET @a=1, @b=2, @c=3 sets all variables |
| IN with NULL semantics |
IN list returns NULL when value not found and NULL in list |
| BIT type improvements |
UnsignedInt cast to BIT, BIT/Bool comparison |
| LPAD/RPAD edge cases |
Negative length returns NULL, NULL padstr returns NULL |
| VIEW ORDER BY LIMIT |
Views and derived tables preserve ORDER BY + LIMIT from definition |
| Bool arithmetic coercion |
TRUE/FALSE convert to 1/0 in arithmetic contexts |
| UPDATE type coercion |
UPDATE calls coerce_to_column_type, matching INSERT behavior |
| INSERT DEFAULT keyword |
DEFAULT in VALUES clause uses column's actual default value |
| Exact decimal literals |
0.7 parsed as Decimal(7,1) not Float — 0.7+0.1=0.8 exact |
| Decimal-to-Float cast |
Decimal values inserted into FLOAT/DOUBLE columns convert correctly |
| Scalar subqueries |
(SELECT MAX(a) FROM t2) in SELECT, WHERE, HAVING, ORDER BY |
| IN subqueries |
WHERE col [NOT] IN (SELECT col FROM t2) with NULL handling |
| Nested subqueries |
Subqueries inside subqueries — recursive materialization |
| EXISTS/NOT EXISTS |
WHERE [NOT] EXISTS (SELECT ...) — materialized to boolean |
| LTRIM/RTRIM custom char |
LTRIM/RTRIM accept optional second argument for custom trim character |
| MySQL RAND(seed) |
Deterministic LCG matching MySQL's algorithm; thread-local state |
| B'...' bit string literals |
B'10101' parsed as unsigned integer from binary |
| CAST signed overflow |
CAST(float AS SIGNED) returns ER_DATA_OUT_OF_RANGE when value >= 2^63 |
| Scalar-wrapping aggregates |
CRC32(SUM(a)), FUNC(AGG(...)) in SELECT, HAVING, ORDER BY |
| HAVING with non-SELECT aggregates |
HAVING clause can reference aggregates not in SELECT list |
| CREATE VIEW / DROP VIEW |
Raft-persisted views via system.views; survive restart; SHOW CREATE TABLE; SHOW TABLES includes views; JOIN with views; circular view guard (depth 32); query validation at CREATE time |
| Boolean negation |
-(TRUE) returns -1; -(1 NOT IN (0)) works correctly |
| CREATE TRIGGER / DROP TRIGGER |
BEFORE/AFTER INSERT triggers; body stored as parsed AST; NEW.col substitution; fires via full SQL pipeline |
| Geometry types |
POINT, LINESTRING, POLYGON, MULTILINESTRING, MULTIPOLYGON column types; stored as WKB binary |
| ST_GeomFromText |
WKT parser (POINT, LINESTRING, POLYGON, MULTILINESTRING, MULTIPOLYGON) → WKB |
| ST_X, ST_Y |
Extract X/Y coordinates from POINT geometry |
| ST_NumPoints |
Count points in LINESTRING |
| ST_Length |
Compute Euclidean length of LINESTRING/MULTILINESTRING |
| ST_Area |
Compute area of POLYGON/MULTIPOLYGON via shoelace formula |
| FROM DUAL |
SELECT expr FROM DUAL works (MySQL pseudo-table, equivalent to no FROM) |
| INSERT overflow detection |
String-to-int overflow in INSERT raises ER_WARN_DATA_OUT_OF_RANGE (1264) |
| ER_WRONG_VALUE_COUNT_ON_ROW |
INSERT column/value count mismatch returns MySQL error 1136 |
| CASE with CONVERT |
CASE/WHEN with CONVERT(val, CHAR) + CREATE TABLE SELECT |
| COALESCE/IFNULL BIGINT UNSIGNED |
CAST(COALESCE(nullable_col, -1) AS UNSIGNED) returns correct u64 |
| ROUND integer arithmetic |
ROUND with negative decimals uses integer division for BIGINT/UNSIGNED |
| SET timestamp |
SET timestamp=UNIX_TIMESTAMP(...) accepted; NOW()/TIMEDIFF()/engine=innodb work |
| CREATE TABLE SELECT DIV |
Type resolution for DIV with integer/decimal/string/CAST operands |
| --TRUE double negation |
--TRUE parsed as -(-(TRUE)) = 1 (not as SQL comment) |
| DO statement silent |
DO evaluates expression but discards result; propagates errors |
| CEIL/FLOOR BIGINT UNSIGNED |
Returns UnsignedInt for values > i64::MAX; integer passthrough |
| ENUM/SET columns |
Stored as Text; CRC32 computes on string representation |
| PREPARE/EXECUTE text protocol |
Full cycle including parameter binding with USING @var |
| FLOOR/CEIL DECIMAL support |
Decimal(i128, scale) handled in FLOOR/CEIL; values > u64 stay as Decimal |
| RAND seed algorithm fix |
Fixed seed2 (no +55555555) and u32 wrapping to match MySQL's seed_random() |
| CAST column names |
CAST(x AS UNSIGNED) displays as "unsigned" not "BigIntUnsigned" in column headers |
| CAST float rounding |
CAST(float AS UNSIGNED/SIGNED) uses round() not truncation, matching MySQL's rint() |
| NULL expression type check |
1/NULL etc. skip type checking (evaluates to NULL at runtime); fixes NOT NULL inserts |
| FROM_DAYS |
Inverse of TO_DAYS — converts MySQL day number back to date string |
| SUBSTRING_INDEX |
Extract substring before/after Nth delimiter occurrence |
| MAKE_SET |
Build comma-separated string from bitmask-selected arguments |
| TIMESTAMPDIFF |
Integer difference between two datetimes in specified unit (DAY, MONTH, etc.) |
| TIMESTAMPADD |
Add interval to datetime — supports DAY, MONTH, YEAR, HOUR, MINUTE, SECOND |
| GROUP_CONCAT |
Aggregate that concatenates string values with SEPARATOR, DISTINCT support |
| ANY_VALUE |
Aggregate returning arbitrary non-NULL value from group |
| Multi-table DELETE fix |
DELETE t1 FROM t1 JOIN t2 ON cond correctly deletes only matched rows |
| UTC_DATE/UTC_TIME/UTC_TIMESTAMP |
UTC-based date/time functions (no local timezone offset) |
| WEEKOFYEAR |
ISO week number (equivalent to WEEK(date, 3)) |
| ADDTIME/SUBTIME |
Add/subtract time from datetime or time values, with cross-midnight rollover |
| CONVERT_TZ |
Timezone conversion with +HH:MM offset format and UTC/SYSTEM named zones |
| TO_SECONDS |
Total seconds since year 0 (TO_DAYS * 86400 + time-of-day seconds) |
| MD5 |
MD5 hash → 32-char lowercase hex string |
| SHA / SHA1 |
SHA-1 hash → 40-char lowercase hex string |
| SHA2 |
SHA-224/256/384/512 hash; hash_length 0 = SHA-256 |
| TO_BASE64 / FROM_BASE64 |
Base64 encode/decode with standard alphabet |
| AES_ENCRYPT / AES_DECRYPT |
AES-128-ECB with MySQL key schedule and PKCS7 padding |
| RANDOM_BYTES |
Cryptographically random bytes (1-1024 length) |
| COMPRESS / UNCOMPRESS |
Zlib compression with 4-byte LE length prefix (MySQL format) |
| UNCOMPRESSED_LENGTH |
Read 4-byte LE length prefix from compressed data |
| QUOTE |
Escape and single-quote a string; QUOTE(NULL) returns 'NULL' string |
| EXPORT_SET |
Build string from bitmask: on/off per bit with separator |
| IS_IPV4 / IS_IPV6 |
Validate IP address format; returns 0 for NULL (not NULL) |
| UUID |
UUID v4 generation (random, proper version/variant bits) |
| UUID_SHORT |
Random 64-bit unsigned integer |
| BENCHMARK |
MySQL compat, returns 0 (args eagerly evaluated) |
| 3+ way UNION fix |
A UNION B UNION C now correctly returns all operands (was dropping middle) |
| Parenthesized UNION fix |
(SELECT a UNION SELECT b) no longer drops right side |
| CONNECTION_ID() |
Returns real connection ID from session (was hardcoded 0) |
| USER()/CURRENT_USER() |
Returns authenticated user from session (was hardcoded root@localhost) |
| DATABASE()/SCHEMA() |
Returns current database from session, synced on USE (was hardcoded "test") |
| LAST_INSERT_ID() |
Returns last auto_increment ID from INSERT; LAST_INSERT_ID(expr) sets+returns |
| ROW_COUNT() |
Returns affected rows from last DML statement (was hardcoded 0) |
| FOUND_ROWS() |
Returns row count from last SELECT (was hardcoded 0) |
| ALTER TABLE error |
Unknown ALTER TABLE operations now return error (was silent success) |
| get_expr_type fix |
GROUP BY type inference uses data_type() for all expr types (was fallback Int) |
| INSERT ON DUPLICATE KEY UPDATE |
Full ODKU: detect PK duplicate via storage lookup, apply UPDATE assignments to existing row |
| UPDATE with JOIN |
UPDATE t1 JOIN t2 ON cond SET t1.b = val — rewrite JOIN to IN-subquery filter |
| CTEs (WITH...AS) |
Common Table Expressions — resolve CTE body, inject as derived table into main query |
| Window functions |
Full pipeline: resolver → planner → executor. ROW_NUMBER, RANK, DENSE_RANK, SUM/COUNT/AVG/MIN/MAX OVER, LEAD, LAG, FIRST_VALUE, LAST_VALUE, NTILE with PARTITION BY and ORDER BY |
| Correlated subqueries |
Outer scope chain in resolver (is_outer_ref), per-row substitution + inline execution via thread-local engine context. EXISTS, NOT EXISTS, scalar subqueries. |
| Multi-column IN tuples |
(a,b) IN ((1,2),(3,4)) rewritten to (a=1 AND b=2) OR (a=3 AND b=4) |
| UNION in IN subquery |
a IN (SELECT 1 UNION SELECT 2) — resolver uses resolve_query for subquery body |
| JSON in WHERE |
JSON type allowed in boolean contexts; JSON_EXTRACT comparison works |
| INTERVAL + operator |
expr + INTERVAL 1 DAY rewritten to DATE_ADD; expr - INTERVAL to DATE_SUB |
| Hex = integer comparison |
0x41 = 65 returns true; hex bytes coerced to integer in comparisons |
| SET/TEXT column defaults |
Relaxed MySQL 8.0+ default restriction; SET columns accept default values |
| Correlated subquery aggregates |
Correlated subqueries with AVG/SUM/COUNT/MIN/MAX now use full planner pipeline |