executor_test.go 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773
  1. package executor
  2. import (
  3. "fmt"
  4. "testing"
  5. "time"
  6. "github.com/danfragoso/pizzasql-next/pkg/lexer"
  7. "github.com/danfragoso/pizzasql-next/pkg/parser"
  8. "github.com/danfragoso/pizzasql-next/pkg/storage"
  9. "github.com/danfragoso/pizzasql-next/pkg/version"
  10. )
  11. func parse(t *testing.T, sql string) parser.Statement {
  12. t.Helper()
  13. l := lexer.New(sql)
  14. p := parser.New(l)
  15. stmt, err := p.Parse()
  16. if err != nil {
  17. t.Fatalf("parse error: %v", err)
  18. }
  19. return stmt
  20. }
  21. // execSQL parses and executes a SQL string, used by benchmarks
  22. func execSQL(exec *Executor, sql string) (*Result, error) {
  23. l := lexer.New(sql)
  24. p := parser.New(l)
  25. stmt, err := p.Parse()
  26. if err != nil {
  27. return nil, fmt.Errorf("parse error: %w", err)
  28. }
  29. return exec.Execute(stmt)
  30. }
  31. // Test expression evaluation without database
  32. func TestEvalLiteral(t *testing.T) {
  33. exec := &Executor{}
  34. tests := []struct {
  35. input string
  36. expected interface{}
  37. }{
  38. {"42", int64(42)},
  39. {"3.14", 3.14},
  40. {"'hello'", "hello"},
  41. {"TRUE", true},
  42. {"FALSE", false},
  43. }
  44. for _, tt := range tests {
  45. t.Run(tt.input, func(t *testing.T) {
  46. stmt := parse(t, "SELECT "+tt.input)
  47. sel := stmt.(*parser.SelectStmt)
  48. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  49. if err != nil {
  50. t.Errorf("evalExpr error: %v", err)
  51. return
  52. }
  53. if val != tt.expected {
  54. t.Errorf("expected %v (%T), got %v (%T)", tt.expected, tt.expected, val, val)
  55. }
  56. })
  57. }
  58. }
  59. func TestEvalArithmetic(t *testing.T) {
  60. exec := &Executor{}
  61. tests := []struct {
  62. input string
  63. expected float64
  64. }{
  65. {"1 + 2", 3},
  66. {"5 - 3", 2},
  67. {"4 * 3", 12},
  68. {"10 / 2", 5},
  69. {"1 + 2 * 3", 7},
  70. {"(1 + 2) * 3", 9},
  71. {"-5", -5},
  72. {"10 % 3", 1},
  73. }
  74. for _, tt := range tests {
  75. t.Run(tt.input, func(t *testing.T) {
  76. stmt := parse(t, "SELECT "+tt.input)
  77. sel := stmt.(*parser.SelectStmt)
  78. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  79. if err != nil {
  80. t.Errorf("evalExpr error: %v", err)
  81. return
  82. }
  83. if toFloat(val) != tt.expected {
  84. t.Errorf("expected %v, got %v", tt.expected, val)
  85. }
  86. })
  87. }
  88. }
  89. func TestEvalConstantWhereClause(t *testing.T) {
  90. // Test constant WHERE clauses that don't reference any columns
  91. tests := []struct {
  92. name string
  93. expr string
  94. expected bool
  95. }{
  96. {"NULL IS NULL", "NULL IS NULL", true},
  97. {"NULL IS NOT NULL", "NULL IS NOT NULL", false},
  98. {"NOT NULL IS NOT NULL", "NOT NULL IS NOT NULL", true},
  99. {"79 IS NOT NULL", "79 IS NOT NULL", true},
  100. {"79 IS NULL", "79 IS NULL", false},
  101. {"+ 79 IS NOT NULL", "+ 79 IS NOT NULL", true},
  102. {"- 78 IS NOT NULL", "- 78 IS NOT NULL", true},
  103. }
  104. exec := &Executor{}
  105. for _, tt := range tests {
  106. t.Run(tt.name, func(t *testing.T) {
  107. stmt := parse(t, "SELECT 1 WHERE "+tt.expr)
  108. sel := stmt.(*parser.SelectStmt)
  109. val, err := exec.evalExpr(sel.Where, nil)
  110. if err != nil {
  111. t.Fatalf("evalExpr error: %v", err)
  112. }
  113. result := toBool(val)
  114. if result != tt.expected {
  115. t.Errorf("expected %v, got %v", tt.expected, result)
  116. }
  117. })
  118. }
  119. }
  120. func TestConstantWhereClauseWithTable(t *testing.T) {
  121. // This test requires a real database connection
  122. // Skip if not available
  123. tests := []struct {
  124. name string
  125. whereClause string
  126. expectAllRows bool
  127. expectNoRows bool
  128. }{
  129. {"WHERE NULL IS NULL", "NULL IS NULL", true, false},
  130. {"WHERE NULL IS NOT NULL", "NULL IS NOT NULL", false, true},
  131. {"WHERE NOT NULL IS NOT NULL", "NOT NULL IS NOT NULL", true, false},
  132. {"WHERE 79 IS NOT NULL", "79 IS NOT NULL", true, false},
  133. {"WHERE 79 IS NULL", "79 IS NULL", false, true},
  134. {"WHERE + 79 IS NOT NULL", "+ 79 IS NOT NULL", true, false},
  135. {"WHERE - 78 IS NOT NULL", "- 78 IS NOT NULL", true, false},
  136. {"WHERE 1 = 1", "1 = 1", true, false},
  137. {"WHERE 1 = 0", "1 = 0", false, true},
  138. {"WHERE TRUE", "TRUE", true, false},
  139. {"WHERE FALSE", "FALSE", false, true},
  140. }
  141. for _, tt := range tests {
  142. t.Run(tt.name, func(t *testing.T) {
  143. // Parse the WHERE clause
  144. stmt := parse(t, "SELECT col0 FROM test WHERE "+tt.whereClause)
  145. sel := stmt.(*parser.SelectStmt)
  146. // Check that the WHERE clause doesn't reference any columns
  147. refs := collectColumnRefs(sel.Where)
  148. if len(refs) != 0 {
  149. t.Errorf("expected constant WHERE clause (no column refs), got %d refs", len(refs))
  150. }
  151. // Create a minimal executor to test constant evaluation
  152. exec := &Executor{}
  153. val, err := exec.evalExpr(sel.Where, nil)
  154. if err != nil {
  155. t.Fatalf("evalExpr error: %v", err)
  156. }
  157. result := toBool(val)
  158. if tt.expectAllRows && !result {
  159. t.Errorf("expected WHERE to evaluate to TRUE (select all rows), got FALSE")
  160. }
  161. if tt.expectNoRows && result {
  162. t.Errorf("expected WHERE to evaluate to FALSE (select no rows), got TRUE")
  163. }
  164. })
  165. }
  166. }
  167. func TestComparison(t *testing.T) {
  168. exec := &Executor{}
  169. tests := []struct {
  170. input string
  171. expected bool
  172. }{
  173. {"1 = 1", true},
  174. {"1 = 2", false},
  175. {"1 <> 2", true},
  176. {"1 < 2", true},
  177. {"2 > 1", true},
  178. {"1 <= 1", true},
  179. {"1 >= 1", true},
  180. {"'a' = 'a'", true},
  181. {"'a' < 'b'", true},
  182. }
  183. for _, tt := range tests {
  184. t.Run(tt.input, func(t *testing.T) {
  185. stmt := parse(t, "SELECT "+tt.input)
  186. sel := stmt.(*parser.SelectStmt)
  187. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  188. if err != nil {
  189. t.Errorf("evalExpr error: %v", err)
  190. return
  191. }
  192. if toBool(val) != tt.expected {
  193. t.Errorf("expected %v, got %v", tt.expected, val)
  194. }
  195. })
  196. }
  197. }
  198. func TestEvalLogical(t *testing.T) {
  199. exec := &Executor{}
  200. tests := []struct {
  201. input string
  202. expected bool
  203. }{
  204. {"TRUE AND TRUE", true},
  205. {"TRUE AND FALSE", false},
  206. {"TRUE OR FALSE", true},
  207. {"FALSE OR FALSE", false},
  208. {"NOT TRUE", false},
  209. {"NOT FALSE", true},
  210. {"1 = 1 AND 2 = 2", true},
  211. {"1 = 1 OR 1 = 2", true},
  212. }
  213. for _, tt := range tests {
  214. t.Run(tt.input, func(t *testing.T) {
  215. stmt := parse(t, "SELECT "+tt.input)
  216. sel := stmt.(*parser.SelectStmt)
  217. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  218. if err != nil {
  219. t.Errorf("evalExpr error: %v", err)
  220. return
  221. }
  222. if toBool(val) != tt.expected {
  223. t.Errorf("expected %v, got %v", tt.expected, val)
  224. }
  225. })
  226. }
  227. }
  228. func TestEvalFunctions(t *testing.T) {
  229. exec := &Executor{}
  230. tests := []struct {
  231. input string
  232. expected interface{}
  233. }{
  234. {"UPPER('hello')", "HELLO"},
  235. {"LOWER('HELLO')", "hello"},
  236. {"LENGTH('hello')", int64(5)},
  237. {"ABS(-5)", float64(5)},
  238. {"COALESCE(NULL, 'default')", "default"},
  239. {"COALESCE('value', 'default')", "value"},
  240. {"NULLIF(1, 1)", nil},
  241. {"NULLIF(1, 2)", int64(1)},
  242. {"IFNULL(NULL, 'default')", "default"},
  243. {"IFNULL('value', 'default')", "value"},
  244. {"TYPEOF(42)", "integer"},
  245. {"TYPEOF(3.14)", "real"},
  246. {"TYPEOF('hello')", "text"},
  247. {"TYPEOF(NULL)", "null"},
  248. {"TRIM(' hello ')", "hello"},
  249. {"SUBSTR('hello', 2, 3)", "ell"},
  250. {"REPLACE('hello', 'l', 'L')", "heLLo"},
  251. }
  252. for _, tt := range tests {
  253. t.Run(tt.input, func(t *testing.T) {
  254. stmt := parse(t, "SELECT "+tt.input)
  255. sel := stmt.(*parser.SelectStmt)
  256. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  257. if err != nil {
  258. t.Errorf("evalExpr error: %v", err)
  259. return
  260. }
  261. if val != tt.expected {
  262. t.Errorf("expected %v (%T), got %v (%T)", tt.expected, tt.expected, val, val)
  263. }
  264. })
  265. }
  266. }
  267. func TestEvalCase(t *testing.T) {
  268. exec := &Executor{}
  269. tests := []struct {
  270. input string
  271. expected interface{}
  272. }{
  273. {"CASE WHEN TRUE THEN 'yes' ELSE 'no' END", "yes"},
  274. {"CASE WHEN FALSE THEN 'yes' ELSE 'no' END", "no"},
  275. {"CASE WHEN 1 = 1 THEN 'one' WHEN 1 = 2 THEN 'two' ELSE 'other' END", "one"},
  276. {"CASE 1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'other' END", "one"},
  277. {"CASE 2 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'other' END", "two"},
  278. }
  279. for _, tt := range tests {
  280. t.Run(tt.input, func(t *testing.T) {
  281. stmt := parse(t, "SELECT "+tt.input)
  282. sel := stmt.(*parser.SelectStmt)
  283. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  284. if err != nil {
  285. t.Errorf("evalExpr error: %v", err)
  286. return
  287. }
  288. if val != tt.expected {
  289. t.Errorf("expected %v, got %v", tt.expected, val)
  290. }
  291. })
  292. }
  293. }
  294. func TestEvalIn(t *testing.T) {
  295. exec := &Executor{}
  296. tests := []struct {
  297. input string
  298. expected bool
  299. }{
  300. {"1 IN (1, 2, 3)", true},
  301. {"4 IN (1, 2, 3)", false},
  302. {"1 NOT IN (1, 2, 3)", false},
  303. {"4 NOT IN (1, 2, 3)", true},
  304. {"'a' IN ('a', 'b', 'c')", true},
  305. }
  306. for _, tt := range tests {
  307. t.Run(tt.input, func(t *testing.T) {
  308. stmt := parse(t, "SELECT "+tt.input)
  309. sel := stmt.(*parser.SelectStmt)
  310. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  311. if err != nil {
  312. t.Errorf("evalExpr error: %v", err)
  313. return
  314. }
  315. if toBool(val) != tt.expected {
  316. t.Errorf("expected %v, got %v", tt.expected, val)
  317. }
  318. })
  319. }
  320. }
  321. func TestEvalBetween(t *testing.T) {
  322. exec := &Executor{}
  323. tests := []struct {
  324. input string
  325. expected bool
  326. }{
  327. {"5 BETWEEN 1 AND 10", true},
  328. {"0 BETWEEN 1 AND 10", false},
  329. {"11 BETWEEN 1 AND 10", false},
  330. {"5 NOT BETWEEN 1 AND 10", false},
  331. {"0 NOT BETWEEN 1 AND 10", true},
  332. }
  333. for _, tt := range tests {
  334. t.Run(tt.input, func(t *testing.T) {
  335. stmt := parse(t, "SELECT "+tt.input)
  336. sel := stmt.(*parser.SelectStmt)
  337. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  338. if err != nil {
  339. t.Errorf("evalExpr error: %v", err)
  340. return
  341. }
  342. if toBool(val) != tt.expected {
  343. t.Errorf("expected %v, got %v", tt.expected, val)
  344. }
  345. })
  346. }
  347. }
  348. func TestEvalLike(t *testing.T) {
  349. exec := &Executor{}
  350. tests := []struct {
  351. input string
  352. expected bool
  353. }{
  354. {"'hello' LIKE 'hello'", true},
  355. {"'hello' LIKE 'h%'", true},
  356. {"'hello' LIKE '%o'", true},
  357. {"'hello' LIKE '%ll%'", true},
  358. {"'hello' LIKE 'h_llo'", true},
  359. {"'hello' LIKE 'world'", false},
  360. {"'hello' NOT LIKE 'world'", true},
  361. }
  362. for _, tt := range tests {
  363. t.Run(tt.input, func(t *testing.T) {
  364. stmt := parse(t, "SELECT "+tt.input)
  365. sel := stmt.(*parser.SelectStmt)
  366. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  367. if err != nil {
  368. t.Errorf("evalExpr error: %v", err)
  369. return
  370. }
  371. if toBool(val) != tt.expected {
  372. t.Errorf("expected %v, got %v", tt.expected, val)
  373. }
  374. })
  375. }
  376. }
  377. func TestEvalIsNull(t *testing.T) {
  378. exec := &Executor{}
  379. tests := []struct {
  380. input string
  381. expected bool
  382. }{
  383. {"NULL IS NULL", true},
  384. {"1 IS NULL", false},
  385. {"NULL IS NOT NULL", false},
  386. {"1 IS NOT NULL", true},
  387. }
  388. for _, tt := range tests {
  389. t.Run(tt.input, func(t *testing.T) {
  390. stmt := parse(t, "SELECT "+tt.input)
  391. sel := stmt.(*parser.SelectStmt)
  392. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  393. if err != nil {
  394. t.Errorf("evalExpr error: %v", err)
  395. return
  396. }
  397. if toBool(val) != tt.expected {
  398. t.Errorf("expected %v, got %v", tt.expected, val)
  399. }
  400. })
  401. }
  402. }
  403. func TestEvalCast(t *testing.T) {
  404. exec := &Executor{}
  405. tests := []struct {
  406. input string
  407. expected interface{}
  408. }{
  409. {"CAST(3.14 AS INTEGER)", int64(3)},
  410. {"CAST(42 AS REAL)", float64(42)},
  411. {"CAST(123 AS TEXT)", "123"},
  412. }
  413. for _, tt := range tests {
  414. t.Run(tt.input, func(t *testing.T) {
  415. stmt := parse(t, "SELECT "+tt.input)
  416. sel := stmt.(*parser.SelectStmt)
  417. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  418. if err != nil {
  419. t.Errorf("evalExpr error: %v", err)
  420. return
  421. }
  422. if val != tt.expected {
  423. t.Errorf("expected %v (%T), got %v (%T)", tt.expected, tt.expected, val, val)
  424. }
  425. })
  426. }
  427. }
  428. func TestEvalWithRow(t *testing.T) {
  429. exec := &Executor{}
  430. row := map[string]interface{}{
  431. "id": int64(1),
  432. "name": "John",
  433. "age": 30,
  434. "active": true,
  435. }
  436. tests := []struct {
  437. input string
  438. expected interface{}
  439. }{
  440. {"id", int64(1)},
  441. {"name", "John"},
  442. {"age", 30},
  443. {"active", true},
  444. {"id + 1", float64(2)},
  445. {"age * 2", float64(60)},
  446. {"name = 'John'", true},
  447. {"age > 25", true},
  448. {"active AND age > 20", true},
  449. }
  450. for _, tt := range tests {
  451. t.Run(tt.input, func(t *testing.T) {
  452. stmt := parse(t, "SELECT "+tt.input)
  453. sel := stmt.(*parser.SelectStmt)
  454. val, err := exec.evalExpr(sel.Columns[0].Expr, row)
  455. if err != nil {
  456. t.Errorf("evalExpr error: %v", err)
  457. return
  458. }
  459. // Handle numeric comparisons
  460. if expected, ok := tt.expected.(float64); ok {
  461. if toFloat(val) != expected {
  462. t.Errorf("expected %v, got %v", tt.expected, val)
  463. }
  464. } else if val != tt.expected {
  465. t.Errorf("expected %v (%T), got %v (%T)", tt.expected, tt.expected, val, val)
  466. }
  467. })
  468. }
  469. }
  470. func TestResultString(t *testing.T) {
  471. result := NewResult("SELECT")
  472. result.AddColumn("id")
  473. result.AddColumn("name")
  474. result.AddRow(int64(1), "Alice")
  475. result.AddRow(int64(2), "Bob")
  476. output := result.String()
  477. // Check that output contains expected elements
  478. if output == "" {
  479. t.Error("expected non-empty output")
  480. }
  481. if result.RowCount != 2 {
  482. t.Errorf("expected 2 rows, got %d", result.RowCount)
  483. }
  484. }
  485. func TestMatchLike(t *testing.T) {
  486. tests := []struct {
  487. s string
  488. pattern string
  489. expected bool
  490. }{
  491. {"hello", "hello", true},
  492. {"hello", "h%", true},
  493. {"hello", "%o", true},
  494. {"hello", "%ll%", true},
  495. {"hello", "h_llo", true},
  496. {"hello", "H%", true}, // case insensitive
  497. {"hello", "world", false},
  498. {"", "%", true},
  499. {"abc", "a%c", true},
  500. {"abc", "a_c", true},
  501. {"abc", "__c", true},
  502. {"abc", "___", true},
  503. {"abc", "____", false},
  504. }
  505. for _, tt := range tests {
  506. t.Run(tt.s+"_"+tt.pattern, func(t *testing.T) {
  507. got := matchLike(tt.s, tt.pattern)
  508. if got != tt.expected {
  509. t.Errorf("matchLike(%q, %q) = %v, want %v", tt.s, tt.pattern, got, tt.expected)
  510. }
  511. })
  512. }
  513. }
  514. // Phase 4: SQLite function tests
  515. func TestEvalSQLiteFunctions(t *testing.T) {
  516. exec := &Executor{}
  517. tests := []struct {
  518. input string
  519. expected interface{}
  520. isInt bool // for RANDOM which returns int64
  521. }{
  522. // PRINTF
  523. {"PRINTF('%d', 42)", "42", false},
  524. {"PRINTF('%s', 'hello')", "hello", false},
  525. {"PRINTF('%d + %d = %d', 1, 2, 3)", "1 + 2 = 3", false},
  526. // HEX
  527. {"HEX('ABC')", "414243", false},
  528. {"HEX('hello')", "68656C6C6F", false},
  529. // INSTR
  530. {"INSTR('hello world', 'world')", int64(7), false},
  531. {"INSTR('hello', 'x')", int64(0), false},
  532. {"INSTR('hello', 'l')", int64(3), false},
  533. // ROUND
  534. {"ROUND(3.14159)", float64(3), false},
  535. {"ROUND(3.14159, 2)", float64(3.14), false},
  536. {"ROUND(3.5)", float64(4), false},
  537. // CONCAT
  538. {"CONCAT('hello', ' ', 'world')", "hello world", false},
  539. {"CONCAT('a', 'b', 'c')", "abc", false},
  540. {"PIZZASQL_VERSION()", version.String(), false},
  541. // MAX/MIN (scalar versions)
  542. {"MAX(1, 5, 3)", int64(5), false},
  543. {"MIN(1, 5, 3)", int64(1), false},
  544. {"MAX('a', 'c', 'b')", "c", false},
  545. }
  546. for _, tt := range tests {
  547. t.Run(tt.input, func(t *testing.T) {
  548. stmt := parse(t, "SELECT "+tt.input)
  549. sel := stmt.(*parser.SelectStmt)
  550. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  551. if err != nil {
  552. t.Errorf("evalExpr error: %v", err)
  553. return
  554. }
  555. if val != tt.expected {
  556. t.Errorf("expected %v (%T), got %v (%T)", tt.expected, tt.expected, val, val)
  557. }
  558. })
  559. }
  560. }
  561. func TestEvalRandom(t *testing.T) {
  562. exec := &Executor{}
  563. stmt := parse(t, "SELECT RANDOM()")
  564. sel := stmt.(*parser.SelectStmt)
  565. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  566. if err != nil {
  567. t.Fatalf("evalExpr error: %v", err)
  568. }
  569. // RANDOM() should return an int64
  570. if _, ok := val.(int64); !ok {
  571. t.Errorf("RANDOM() should return int64, got %T", val)
  572. }
  573. }
  574. func TestEvalGlob(t *testing.T) {
  575. exec := &Executor{}
  576. tests := []struct {
  577. input string
  578. expected bool
  579. }{
  580. {"GLOB('*.txt', 'file.txt')", true},
  581. {"GLOB('*.txt', 'file.doc')", false},
  582. {"GLOB('hello*', 'hello world')", true},
  583. {"GLOB('h?llo', 'hello')", true},
  584. {"GLOB('h?llo', 'hallo')", true},
  585. {"GLOB('[abc]*', 'apple')", true},
  586. {"GLOB('[abc]*', 'dog')", false},
  587. }
  588. for _, tt := range tests {
  589. t.Run(tt.input, func(t *testing.T) {
  590. stmt := parse(t, "SELECT "+tt.input)
  591. sel := stmt.(*parser.SelectStmt)
  592. val, err := exec.evalExpr(sel.Columns[0].Expr, nil)
  593. if err != nil {
  594. t.Errorf("evalExpr error: %v", err)
  595. return
  596. }
  597. if toBool(val) != tt.expected {
  598. t.Errorf("expected %v, got %v", tt.expected, val)
  599. }
  600. })
  601. }
  602. }
  603. func TestMatchGlob(t *testing.T) {
  604. tests := []struct {
  605. pattern string
  606. s string
  607. expected bool
  608. }{
  609. {"*", "anything", true},
  610. {"*", "", true},
  611. {"?", "a", true},
  612. {"?", "ab", false},
  613. {"a*b", "ab", true},
  614. {"a*b", "aXXXb", true},
  615. {"a*b", "aXXXc", false},
  616. {"[abc]", "a", true},
  617. {"[abc]", "d", false},
  618. {"[^abc]", "d", true},
  619. {"[^abc]", "a", false},
  620. {"*.go", "main.go", true},
  621. {"*.go", "main.txt", false},
  622. }
  623. for _, tt := range tests {
  624. t.Run(tt.pattern+"_"+tt.s, func(t *testing.T) {
  625. got := matchGlob(tt.pattern, tt.s)
  626. if got != tt.expected {
  627. t.Errorf("matchGlob(%q, %q) = %v, want %v", tt.pattern, tt.s, got, tt.expected)
  628. }
  629. })
  630. }
  631. }
  632. // Test subquery expressions
  633. func TestEvalSubqueryExpr(t *testing.T) {
  634. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  635. if err != nil {
  636. t.Skip("PizzaKV not available, skipping subquery tests")
  637. }
  638. defer pool.Close()
  639. schema := storage.NewSchemaManager(pool, "test_subquery_db")
  640. table := storage.NewTableManager(pool, schema, "test_subquery_db")
  641. exec := New(schema, table)
  642. // Setup test tables
  643. execSQL(exec, "DROP TABLE IF EXISTS products")
  644. execSQL(exec, "DROP TABLE IF EXISTS categories")
  645. _, err = execSQL(exec, "CREATE TABLE categories (id INTEGER PRIMARY KEY, name TEXT)")
  646. if err != nil {
  647. t.Fatalf("failed to create categories: %v", err)
  648. }
  649. _, err = execSQL(exec, "CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, category_id INTEGER, price REAL)")
  650. if err != nil {
  651. t.Fatalf("failed to create products: %v", err)
  652. }
  653. // Insert test data
  654. execSQL(exec, "INSERT INTO categories VALUES (1, 'Electronics')")
  655. execSQL(exec, "INSERT INTO categories VALUES (2, 'Books')")
  656. execSQL(exec, "INSERT INTO categories VALUES (3, 'Clothing')")
  657. execSQL(exec, "INSERT INTO products VALUES (1, 'Laptop', 1, 999.99)")
  658. execSQL(exec, "INSERT INTO products VALUES (2, 'Phone', 1, 599.99)")
  659. execSQL(exec, "INSERT INTO products VALUES (3, 'Novel', 2, 19.99)")
  660. execSQL(exec, "INSERT INTO products VALUES (4, 'T-Shirt', 3, 29.99)")
  661. // Test scalar subquery
  662. t.Run("scalar_subquery", func(t *testing.T) {
  663. result, err := execSQL(exec, "SELECT (SELECT MAX(price) FROM products)")
  664. if err != nil {
  665. t.Fatalf("query failed: %v", err)
  666. }
  667. if result.RowCount != 1 {
  668. t.Errorf("expected 1 row, got %d", result.RowCount)
  669. }
  670. if result.Rows[0][0] != 999.99 {
  671. t.Errorf("expected 999.99, got %v", result.Rows[0][0])
  672. }
  673. })
  674. // Test IN subquery
  675. t.Run("in_subquery", func(t *testing.T) {
  676. result, err := execSQL(exec, "SELECT name FROM products WHERE category_id IN (SELECT id FROM categories WHERE name = 'Electronics')")
  677. if err != nil {
  678. t.Fatalf("query failed: %v", err)
  679. }
  680. if result.RowCount != 2 {
  681. t.Errorf("expected 2 rows, got %d", result.RowCount)
  682. }
  683. })
  684. // Test NOT IN subquery
  685. t.Run("not_in_subquery", func(t *testing.T) {
  686. result, err := execSQL(exec, "SELECT name FROM products WHERE category_id NOT IN (SELECT id FROM categories WHERE name = 'Electronics')")
  687. if err != nil {
  688. t.Fatalf("query failed: %v", err)
  689. }
  690. if result.RowCount != 2 {
  691. t.Errorf("expected 2 rows, got %d", result.RowCount)
  692. }
  693. })
  694. // Test EXISTS subquery
  695. t.Run("exists_subquery", func(t *testing.T) {
  696. result, err := execSQL(exec, "SELECT EXISTS (SELECT 1 FROM products WHERE price > 500)")
  697. if err != nil {
  698. t.Fatalf("query failed: %v", err)
  699. }
  700. if result.RowCount != 1 {
  701. t.Errorf("expected 1 row, got %d", result.RowCount)
  702. }
  703. if result.Rows[0][0] != true {
  704. t.Errorf("expected true, got %v", result.Rows[0][0])
  705. }
  706. })
  707. // Test EXISTS with no matches
  708. t.Run("exists_no_match", func(t *testing.T) {
  709. result, err := execSQL(exec, "SELECT EXISTS (SELECT 1 FROM products WHERE price > 10000)")
  710. if err != nil {
  711. t.Fatalf("query failed: %v", err)
  712. }
  713. if result.Rows[0][0] != false {
  714. t.Errorf("expected false, got %v", result.Rows[0][0])
  715. }
  716. })
  717. // Cleanup
  718. execSQL(exec, "DROP TABLE IF EXISTS products")
  719. execSQL(exec, "DROP TABLE IF EXISTS categories")
  720. }
  721. func TestChainedJoinCanHashAgainstEarlierTable(t *testing.T) {
  722. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  723. if err != nil {
  724. t.Skipf("PizzaKV not available: %v", err)
  725. }
  726. defer pool.Close()
  727. schema := storage.NewSchemaManager(pool, "test_chained_join_hash_db")
  728. table := storage.NewTableManager(pool, schema, "test_chained_join_hash_db")
  729. exec := New(schema, table)
  730. for _, sql := range []string{
  731. "DROP TABLE IF EXISTS order_items",
  732. "DROP TABLE IF EXISTS orders",
  733. "DROP TABLE IF EXISTS addresses",
  734. "CREATE TABLE orders (id INTEGER PRIMARY KEY, shipping_address_id INTEGER)",
  735. "CREATE TABLE addresses (id INTEGER PRIMARY KEY, state TEXT)",
  736. "CREATE TABLE order_items (id INTEGER PRIMARY KEY, order_id INTEGER, line_total REAL)",
  737. "INSERT INTO addresses VALUES (1, 'CA')",
  738. "INSERT INTO addresses VALUES (2, 'NY')",
  739. "INSERT INTO orders VALUES (10, 1)",
  740. "INSERT INTO orders VALUES (11, 2)",
  741. "INSERT INTO order_items VALUES (100, 10, 25.0)",
  742. "INSERT INTO order_items VALUES (101, 10, 30.0)",
  743. "INSERT INTO order_items VALUES (102, 11, 10.0)",
  744. } {
  745. if _, err := execSQL(exec, sql); err != nil {
  746. t.Fatalf("%s: %v", sql, err)
  747. }
  748. }
  749. defer execSQL(exec, "DROP TABLE IF EXISTS order_items")
  750. defer execSQL(exec, "DROP TABLE IF EXISTS orders")
  751. defer execSQL(exec, "DROP TABLE IF EXISTS addresses")
  752. result, err := execSQL(exec, `
  753. SELECT a.state, COUNT(oi.id) AS lines, SUM(oi.line_total) AS revenue
  754. FROM orders o
  755. JOIN addresses a ON o.shipping_address_id = a.id
  756. JOIN order_items oi ON oi.order_id = o.id
  757. GROUP BY a.state
  758. ORDER BY a.state
  759. `)
  760. if err != nil {
  761. t.Fatalf("query failed: %v", err)
  762. }
  763. if len(result.Rows) != 2 {
  764. t.Fatalf("expected 2 rows, got %d: %#v", len(result.Rows), result.Rows)
  765. }
  766. if result.Rows[0][0] != "CA" || result.Rows[0][1] != int64(2) {
  767. t.Fatalf("unexpected CA row: %#v", result.Rows[0])
  768. }
  769. if result.Rows[1][0] != "NY" || result.Rows[1][1] != int64(1) {
  770. t.Fatalf("unexpected NY row: %#v", result.Rows[1])
  771. }
  772. }
  773. func TestCorrelatedAggregateSubqueryUsesGroupedResult(t *testing.T) {
  774. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  775. if err != nil {
  776. t.Skipf("PizzaKV not available: %v", err)
  777. }
  778. defer pool.Close()
  779. schema := storage.NewSchemaManager(pool, "test_correlated_agg_cache_db")
  780. table := storage.NewTableManager(pool, schema, "test_correlated_agg_cache_db")
  781. exec := New(schema, table)
  782. for _, sql := range []string{
  783. "DROP TABLE IF EXISTS orders",
  784. "DROP TABLE IF EXISTS users",
  785. "CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT)",
  786. "CREATE TABLE orders (id INTEGER PRIMARY KEY, user_id INTEGER)",
  787. "INSERT INTO users VALUES (1, 'a@example.com')",
  788. "INSERT INTO users VALUES (2, 'b@example.com')",
  789. "INSERT INTO users VALUES (3, 'c@example.com')",
  790. "INSERT INTO orders VALUES (10, 1)",
  791. "INSERT INTO orders VALUES (11, 1)",
  792. "INSERT INTO orders VALUES (12, 3)",
  793. "INSERT INTO orders VALUES (13, 3)",
  794. "INSERT INTO orders VALUES (14, 3)",
  795. } {
  796. if _, err := execSQL(exec, sql); err != nil {
  797. t.Fatalf("%s: %v", sql, err)
  798. }
  799. }
  800. defer execSQL(exec, "DROP TABLE IF EXISTS orders")
  801. defer execSQL(exec, "DROP TABLE IF EXISTS users")
  802. result, err := execSQL(exec, `
  803. SELECT u.id, u.email
  804. FROM users u
  805. WHERE (
  806. SELECT COUNT(*)
  807. FROM orders o
  808. WHERE o.user_id = u.id
  809. ) >= 2
  810. ORDER BY u.id
  811. `)
  812. if err != nil {
  813. t.Fatalf("query failed: %v", err)
  814. }
  815. if len(result.Rows) != 2 {
  816. t.Fatalf("expected 2 rows, got %d: %#v", len(result.Rows), result.Rows)
  817. }
  818. if result.Rows[0][0] != int64(1) || result.Rows[1][0] != int64(3) {
  819. t.Fatalf("unexpected result rows: %#v", result.Rows)
  820. }
  821. }
  822. // Benchmark
  823. func BenchmarkEvalExpr(b *testing.B) {
  824. exec := &Executor{}
  825. stmt := parse(&testing.T{}, "SELECT (1 + 2) * 3 - 4 / 2")
  826. sel := stmt.(*parser.SelectStmt)
  827. expr := sel.Columns[0].Expr
  828. b.ResetTimer()
  829. for i := 0; i < b.N; i++ {
  830. exec.evalExpr(expr, nil)
  831. }
  832. }
  833. // BenchmarkIndexVsNoIndex compares query performance with and without indexes.
  834. // Requires a running PizzaKV instance at localhost:8085.
  835. func BenchmarkIndexVsNoIndex(b *testing.B) {
  836. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  837. if err != nil {
  838. b.Skip("PizzaKV not available, skipping index benchmark")
  839. }
  840. defer pool.Close()
  841. schema := storage.NewSchemaManager(pool, "bench_db")
  842. table := storage.NewTableManager(pool, schema, "bench_db")
  843. exec := New(schema, table)
  844. // Cleanup first to ensure fresh state
  845. execSQL(exec, "DROP INDEX IF EXISTS idx_bench_status")
  846. execSQL(exec, "DROP TABLE IF EXISTS bench_users")
  847. _, err = execSQL(exec, "CREATE TABLE bench_users (id INTEGER PRIMARY KEY, name TEXT, email TEXT, status TEXT)")
  848. if err != nil {
  849. b.Fatalf("failed to create table: %v", err)
  850. }
  851. // Insert 1000 rows
  852. statuses := []string{"active", "inactive", "pending", "suspended"}
  853. for i := 1; i <= 1000; i++ {
  854. status := statuses[i%len(statuses)]
  855. _, err := execSQL(exec, fmt.Sprintf("INSERT INTO bench_users (id, name, email, status) VALUES (%d, 'User%d', 'user%d@test.com', '%s')", i, i, i, status))
  856. if err != nil {
  857. b.Fatalf("failed to insert row %d: %v", i, err)
  858. }
  859. }
  860. // Benchmark WITHOUT index
  861. b.Run("NoIndex", func(b *testing.B) {
  862. for i := 0; i < b.N; i++ {
  863. _, err := execSQL(exec, "SELECT * FROM bench_users WHERE status = 'active'")
  864. if err != nil {
  865. b.Fatalf("query failed: %v", err)
  866. }
  867. }
  868. })
  869. // Create index on status column
  870. _, err = execSQL(exec, "CREATE INDEX idx_bench_status ON bench_users (status)")
  871. if err != nil {
  872. b.Fatalf("failed to create index: %v", err)
  873. }
  874. // Benchmark WITH index
  875. b.Run("WithIndex", func(b *testing.B) {
  876. for i := 0; i < b.N; i++ {
  877. _, err := execSQL(exec, "SELECT * FROM bench_users WHERE status = 'active'")
  878. if err != nil {
  879. b.Fatalf("query failed: %v", err)
  880. }
  881. }
  882. })
  883. // Cleanup
  884. execSQL(exec, "DROP INDEX IF EXISTS idx_bench_status")
  885. execSQL(exec, "DROP TABLE IF EXISTS bench_users")
  886. }
  887. // BenchmarkIndexVsNoIndexLargeTable tests with more rows
  888. func BenchmarkIndexVsNoIndexLargeTable(b *testing.B) {
  889. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  890. if err != nil {
  891. b.Skip("PizzaKV not available, skipping index benchmark")
  892. }
  893. defer pool.Close()
  894. schema := storage.NewSchemaManager(pool, "bench_db")
  895. table := storage.NewTableManager(pool, schema, "bench_db")
  896. exec := New(schema, table)
  897. // Cleanup first to ensure fresh state
  898. execSQL(exec, "DROP INDEX IF EXISTS idx_bench_category")
  899. execSQL(exec, "DROP TABLE IF EXISTS bench_large")
  900. _, err = execSQL(exec, "CREATE TABLE bench_large (id INTEGER PRIMARY KEY, category INTEGER, value TEXT)")
  901. if err != nil {
  902. b.Fatalf("failed to create table: %v", err)
  903. }
  904. // Insert 5000 rows with 100 distinct categories
  905. for i := 1; i <= 5000; i++ {
  906. category := i % 100
  907. _, err := execSQL(exec, fmt.Sprintf("INSERT INTO bench_large (id, category, value) VALUES (%d, %d, 'value_%d')", i, category, i))
  908. if err != nil {
  909. b.Fatalf("failed to insert row %d: %v", i, err)
  910. }
  911. }
  912. // Benchmark WITHOUT index (should scan all 5000 rows)
  913. b.Run("NoIndex_5000rows", func(b *testing.B) {
  914. for i := 0; i < b.N; i++ {
  915. _, err := execSQL(exec, "SELECT * FROM bench_large WHERE category = 42")
  916. if err != nil {
  917. b.Fatalf("query failed: %v", err)
  918. }
  919. }
  920. })
  921. // Create index
  922. _, err = execSQL(exec, "CREATE INDEX idx_bench_category ON bench_large (category)")
  923. if err != nil {
  924. b.Fatalf("failed to create index: %v", err)
  925. }
  926. // Benchmark WITH index (should only retrieve ~50 rows)
  927. b.Run("WithIndex_5000rows", func(b *testing.B) {
  928. for i := 0; i < b.N; i++ {
  929. _, err := execSQL(exec, "SELECT * FROM bench_large WHERE category = 42")
  930. if err != nil {
  931. b.Fatalf("query failed: %v", err)
  932. }
  933. }
  934. })
  935. // Cleanup
  936. execSQL(exec, "DROP INDEX IF EXISTS idx_bench_category")
  937. execSQL(exec, "DROP TABLE IF EXISTS bench_large")
  938. }
  939. // Test transaction statements
  940. func TestTransactions(t *testing.T) {
  941. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  942. if err != nil {
  943. t.Skip("PizzaKV not available, skipping transaction tests")
  944. }
  945. defer pool.Close()
  946. schema := storage.NewSchemaManager(pool, "test_tx_db")
  947. table := storage.NewTableManager(pool, schema, "test_tx_db")
  948. exec := New(schema, table)
  949. // Setup test table
  950. execSQL(exec, "DROP TABLE IF EXISTS tx_test")
  951. _, err = execSQL(exec, "CREATE TABLE tx_test (id INTEGER PRIMARY KEY, value TEXT)")
  952. if err != nil {
  953. t.Fatalf("failed to create table: %v", err)
  954. }
  955. t.Run("begin_transaction", func(t *testing.T) {
  956. result, err := execSQL(exec, "BEGIN")
  957. if err != nil {
  958. t.Fatalf("BEGIN failed: %v", err)
  959. }
  960. if result.CommandTag != "BEGIN" {
  961. t.Errorf("expected StatementType 'BEGIN', got '%s'", result.CommandTag)
  962. }
  963. if !exec.inTransaction {
  964. t.Error("expected inTransaction to be true")
  965. }
  966. // Rollback to reset state
  967. execSQL(exec, "ROLLBACK")
  968. })
  969. t.Run("begin_transaction_keyword", func(t *testing.T) {
  970. result, err := execSQL(exec, "BEGIN TRANSACTION")
  971. if err != nil {
  972. t.Fatalf("BEGIN TRANSACTION failed: %v", err)
  973. }
  974. if result.CommandTag != "BEGIN" {
  975. t.Errorf("expected StatementType 'BEGIN', got '%s'", result.CommandTag)
  976. }
  977. execSQL(exec, "ROLLBACK")
  978. })
  979. t.Run("commit_transaction", func(t *testing.T) {
  980. // Clean up any previous data
  981. execSQL(exec, "DELETE FROM tx_test WHERE id = 1")
  982. execSQL(exec, "BEGIN")
  983. _, err := execSQL(exec, "INSERT INTO tx_test (id, value) VALUES (1, 'test1')")
  984. if err != nil {
  985. t.Fatalf("INSERT failed: %v", err)
  986. }
  987. result, err := execSQL(exec, "COMMIT")
  988. if err != nil {
  989. t.Fatalf("COMMIT failed: %v", err)
  990. }
  991. if result.CommandTag != "COMMIT" {
  992. t.Errorf("expected StatementType 'COMMIT', got '%s'", result.CommandTag)
  993. }
  994. if exec.inTransaction {
  995. t.Error("expected inTransaction to be false after COMMIT")
  996. }
  997. // Verify data was committed
  998. checkResult, _ := execSQL(exec, "SELECT * FROM tx_test WHERE id = 1")
  999. if checkResult.RowCount != 1 {
  1000. t.Errorf("expected 1 row after commit, got %d", checkResult.RowCount)
  1001. }
  1002. })
  1003. t.Run("rollback_transaction", func(t *testing.T) {
  1004. // Clean up any previous data
  1005. execSQL(exec, "DELETE FROM tx_test WHERE id = 2")
  1006. execSQL(exec, "BEGIN")
  1007. _, err := execSQL(exec, "INSERT INTO tx_test (id, value) VALUES (2, 'test2')")
  1008. if err != nil {
  1009. t.Fatalf("INSERT failed: %v", err)
  1010. }
  1011. result, err := execSQL(exec, "ROLLBACK")
  1012. if err != nil {
  1013. t.Fatalf("ROLLBACK failed: %v", err)
  1014. }
  1015. if result.CommandTag != "ROLLBACK" {
  1016. t.Errorf("expected StatementType 'ROLLBACK', got '%s'", result.CommandTag)
  1017. }
  1018. if exec.inTransaction {
  1019. t.Error("expected inTransaction to be false after ROLLBACK")
  1020. }
  1021. // Verify data was not committed.
  1022. checkResult, _ := execSQL(exec, "SELECT * FROM tx_test WHERE id = 2")
  1023. if checkResult.RowCount != 0 {
  1024. t.Errorf("expected no rows after rollback, got %d", checkResult.RowCount)
  1025. }
  1026. })
  1027. t.Run("savepoint_create", func(t *testing.T) {
  1028. execSQL(exec, "BEGIN")
  1029. result, err := execSQL(exec, "SAVEPOINT sp1")
  1030. if err != nil {
  1031. t.Fatalf("SAVEPOINT failed: %v", err)
  1032. }
  1033. if result.CommandTag != "SAVEPOINT" {
  1034. t.Errorf("expected StatementType 'SAVEPOINT', got '%s'", result.CommandTag)
  1035. }
  1036. if len(exec.savepoints) != 1 || exec.savepoints[0] != "sp1" {
  1037. t.Errorf("expected savepoint 'sp1', got %v", exec.savepoints)
  1038. }
  1039. execSQL(exec, "ROLLBACK")
  1040. })
  1041. t.Run("nested_savepoints", func(t *testing.T) {
  1042. execSQL(exec, "BEGIN")
  1043. execSQL(exec, "SAVEPOINT sp1")
  1044. execSQL(exec, "SAVEPOINT sp2")
  1045. execSQL(exec, "SAVEPOINT sp3")
  1046. if len(exec.savepoints) != 3 {
  1047. t.Errorf("expected 3 savepoints, got %d", len(exec.savepoints))
  1048. }
  1049. if exec.savepoints[2] != "sp3" {
  1050. t.Errorf("expected last savepoint to be 'sp3', got '%s'", exec.savepoints[2])
  1051. }
  1052. execSQL(exec, "ROLLBACK")
  1053. })
  1054. t.Run("rollback_to_savepoint", func(t *testing.T) {
  1055. execSQL(exec, "BEGIN")
  1056. execSQL(exec, "INSERT INTO tx_test (id, value) VALUES (10, 'before_sp')")
  1057. execSQL(exec, "SAVEPOINT sp1")
  1058. execSQL(exec, "INSERT INTO tx_test (id, value) VALUES (11, 'after_sp')")
  1059. result, err := execSQL(exec, "ROLLBACK TO sp1")
  1060. if err != nil {
  1061. t.Fatalf("ROLLBACK TO failed: %v", err)
  1062. }
  1063. if result.CommandTag != "ROLLBACK" {
  1064. t.Errorf("expected StatementType 'ROLLBACK', got '%s'", result.CommandTag)
  1065. }
  1066. // Should still be in transaction
  1067. if !exec.inTransaction {
  1068. t.Error("expected to still be in transaction after ROLLBACK TO")
  1069. }
  1070. before, _ := execSQL(exec, "SELECT * FROM tx_test WHERE id = 10")
  1071. after, _ := execSQL(exec, "SELECT * FROM tx_test WHERE id = 11")
  1072. if before.RowCount != 1 || after.RowCount != 0 {
  1073. t.Errorf("unexpected savepoint rollback rows: before=%d after=%d", before.RowCount, after.RowCount)
  1074. }
  1075. execSQL(exec, "ROLLBACK")
  1076. })
  1077. t.Run("release_savepoint", func(t *testing.T) {
  1078. execSQL(exec, "BEGIN")
  1079. execSQL(exec, "SAVEPOINT sp1")
  1080. execSQL(exec, "SAVEPOINT sp2")
  1081. result, err := execSQL(exec, "RELEASE sp1")
  1082. if err != nil {
  1083. t.Fatalf("RELEASE failed: %v", err)
  1084. }
  1085. if result.CommandTag != "RELEASE" {
  1086. t.Errorf("expected StatementType 'RELEASE', got '%s'", result.CommandTag)
  1087. }
  1088. // Releasing sp1 should also remove sp2 (all nested savepoints)
  1089. if len(exec.savepoints) != 0 {
  1090. t.Errorf("expected no savepoints after RELEASE, got %d", len(exec.savepoints))
  1091. }
  1092. execSQL(exec, "ROLLBACK")
  1093. })
  1094. t.Run("release_savepoint_explicit", func(t *testing.T) {
  1095. execSQL(exec, "BEGIN")
  1096. execSQL(exec, "SAVEPOINT sp1")
  1097. result, err := execSQL(exec, "RELEASE SAVEPOINT sp1")
  1098. if err != nil {
  1099. t.Fatalf("RELEASE SAVEPOINT failed: %v", err)
  1100. }
  1101. if result.CommandTag != "RELEASE" {
  1102. t.Errorf("expected StatementType 'RELEASE', got '%s'", result.CommandTag)
  1103. }
  1104. execSQL(exec, "ROLLBACK")
  1105. })
  1106. // Cleanup
  1107. execSQL(exec, "DROP TABLE IF EXISTS tx_test")
  1108. }
  1109. // Test subqueries in FROM clause
  1110. func TestSubqueryInFrom(t *testing.T) {
  1111. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  1112. if err != nil {
  1113. t.Skip("PizzaKV not available, skipping subquery in FROM tests")
  1114. }
  1115. defer pool.Close()
  1116. schema := storage.NewSchemaManager(pool, "test_subquery_from_db")
  1117. table := storage.NewTableManager(pool, schema, "test_subquery_from_db")
  1118. exec := New(schema, table)
  1119. // Setup test table
  1120. execSQL(exec, "DROP TABLE IF EXISTS employees")
  1121. _, err = execSQL(exec, "CREATE TABLE employees (id INTEGER PRIMARY KEY, name TEXT, department TEXT, salary INTEGER)")
  1122. if err != nil {
  1123. t.Fatalf("failed to create table: %v", err)
  1124. }
  1125. // Insert test data
  1126. execSQL(exec, "INSERT INTO employees (id, name, department, salary) VALUES (1, 'Alice', 'Engineering', 100000)")
  1127. execSQL(exec, "INSERT INTO employees (id, name, department, salary) VALUES (2, 'Bob', 'Engineering', 90000)")
  1128. execSQL(exec, "INSERT INTO employees (id, name, department, salary) VALUES (3, 'Charlie', 'Sales', 80000)")
  1129. execSQL(exec, "INSERT INTO employees (id, name, department, salary) VALUES (4, 'Diana', 'Sales', 75000)")
  1130. t.Run("simple_subquery_from", func(t *testing.T) {
  1131. result, err := execSQL(exec, "SELECT * FROM (SELECT name, department FROM employees) AS emp")
  1132. if err != nil {
  1133. t.Fatalf("query failed: %v", err)
  1134. }
  1135. if result.RowCount != 4 {
  1136. t.Errorf("expected 4 rows, got %d", result.RowCount)
  1137. }
  1138. if len(result.Columns) != 2 {
  1139. t.Errorf("expected 2 columns, got %d", len(result.Columns))
  1140. }
  1141. })
  1142. t.Run("subquery_with_where", func(t *testing.T) {
  1143. result, err := execSQL(exec, "SELECT name FROM (SELECT id, name, salary FROM employees WHERE salary > 80000) AS high_earners")
  1144. if err != nil {
  1145. t.Fatalf("query failed: %v", err)
  1146. }
  1147. if result.RowCount != 2 {
  1148. t.Errorf("expected 2 rows, got %d", result.RowCount)
  1149. }
  1150. })
  1151. t.Run("subquery_with_outer_where", func(t *testing.T) {
  1152. result, err := execSQL(exec, "SELECT * FROM (SELECT name, department FROM employees) AS emp WHERE department = 'Engineering'")
  1153. if err != nil {
  1154. t.Fatalf("query failed: %v", err)
  1155. }
  1156. if result.RowCount != 2 {
  1157. t.Errorf("expected 2 rows, got %d", result.RowCount)
  1158. }
  1159. })
  1160. t.Run("subquery_select_specific_columns", func(t *testing.T) {
  1161. result, err := execSQL(exec, "SELECT name FROM (SELECT id, name, department FROM employees WHERE department = 'Sales') AS sales_emp")
  1162. if err != nil {
  1163. t.Fatalf("query failed: %v", err)
  1164. }
  1165. if result.RowCount != 2 {
  1166. t.Errorf("expected 2 rows, got %d", result.RowCount)
  1167. }
  1168. if len(result.Columns) != 1 || result.Columns[0] != "name" {
  1169. t.Errorf("expected column 'name', got %v", result.Columns)
  1170. }
  1171. })
  1172. t.Run("nested_subquery", func(t *testing.T) {
  1173. result, err := execSQL(exec, "SELECT * FROM (SELECT * FROM (SELECT name FROM employees) AS inner_q) AS outer_q")
  1174. if err != nil {
  1175. t.Fatalf("query failed: %v", err)
  1176. }
  1177. if result.RowCount != 4 {
  1178. t.Errorf("expected 4 rows, got %d", result.RowCount)
  1179. }
  1180. })
  1181. // Cleanup
  1182. execSQL(exec, "DROP TABLE IF EXISTS employees")
  1183. }
  1184. // Test ALTER TABLE statements
  1185. func TestAlterTable(t *testing.T) {
  1186. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  1187. if err != nil {
  1188. t.Skip("PizzaKV not available, skipping ALTER TABLE tests")
  1189. }
  1190. defer pool.Close()
  1191. schema := storage.NewSchemaManager(pool, "test_alter_db")
  1192. table := storage.NewTableManager(pool, schema, "test_alter_db")
  1193. exec := New(schema, table)
  1194. // Setup test table
  1195. execSQL(exec, "DROP TABLE IF EXISTS test_alter")
  1196. _, err = execSQL(exec, "CREATE TABLE test_alter (id INTEGER PRIMARY KEY, name TEXT)")
  1197. if err != nil {
  1198. t.Fatalf("failed to create table: %v", err)
  1199. }
  1200. t.Run("add_column", func(t *testing.T) {
  1201. _, err := execSQL(exec, "ALTER TABLE test_alter ADD COLUMN age INTEGER")
  1202. if err != nil {
  1203. t.Fatalf("ALTER TABLE ADD COLUMN failed: %v", err)
  1204. }
  1205. // Verify column was added
  1206. tSchema, err := schema.GetSchema("test_alter")
  1207. if err != nil {
  1208. t.Fatalf("failed to get schema: %v", err)
  1209. }
  1210. found := false
  1211. for _, col := range tSchema.Columns {
  1212. if col.Name == "age" {
  1213. found = true
  1214. if col.Type != "INTEGER" {
  1215. t.Errorf("expected type INTEGER, got %s", col.Type)
  1216. }
  1217. break
  1218. }
  1219. }
  1220. if !found {
  1221. t.Error("column 'age' not found after ADD COLUMN")
  1222. }
  1223. })
  1224. t.Run("add_column_optional_keyword", func(t *testing.T) {
  1225. _, err := execSQL(exec, "ALTER TABLE test_alter ADD email TEXT")
  1226. if err != nil {
  1227. t.Fatalf("ALTER TABLE ADD failed: %v", err)
  1228. }
  1229. // Verify column was added
  1230. tSchema, _ := schema.GetSchema("test_alter")
  1231. found := false
  1232. for _, col := range tSchema.Columns {
  1233. if col.Name == "email" {
  1234. found = true
  1235. break
  1236. }
  1237. }
  1238. if !found {
  1239. t.Error("column 'email' not found after ADD")
  1240. }
  1241. })
  1242. t.Run("rename_column", func(t *testing.T) {
  1243. _, err := execSQL(exec, "ALTER TABLE test_alter RENAME COLUMN name TO full_name")
  1244. if err != nil {
  1245. t.Fatalf("ALTER TABLE RENAME COLUMN failed: %v", err)
  1246. }
  1247. // Verify column was renamed
  1248. tSchema, _ := schema.GetSchema("test_alter")
  1249. hasOld := false
  1250. hasNew := false
  1251. for _, col := range tSchema.Columns {
  1252. if col.Name == "name" {
  1253. hasOld = true
  1254. }
  1255. if col.Name == "full_name" {
  1256. hasNew = true
  1257. }
  1258. }
  1259. if hasOld {
  1260. t.Error("old column 'name' still exists after RENAME COLUMN")
  1261. }
  1262. if !hasNew {
  1263. t.Error("new column 'full_name' not found after RENAME COLUMN")
  1264. }
  1265. })
  1266. t.Run("drop_column", func(t *testing.T) {
  1267. _, err := execSQL(exec, "ALTER TABLE test_alter DROP COLUMN email")
  1268. if err != nil {
  1269. t.Fatalf("ALTER TABLE DROP COLUMN failed: %v", err)
  1270. }
  1271. // Verify column was dropped
  1272. tSchema, _ := schema.GetSchema("test_alter")
  1273. for _, col := range tSchema.Columns {
  1274. if col.Name == "email" {
  1275. t.Error("column 'email' still exists after DROP COLUMN")
  1276. }
  1277. }
  1278. })
  1279. t.Run("rename_table", func(t *testing.T) {
  1280. _, err := execSQL(exec, "ALTER TABLE test_alter RENAME TO test_renamed")
  1281. if err != nil {
  1282. t.Fatalf("ALTER TABLE RENAME TO failed: %v", err)
  1283. }
  1284. // Verify old table doesn't exist
  1285. _, err = schema.GetSchema("test_alter")
  1286. if err == nil {
  1287. t.Error("old table 'test_alter' still exists after RENAME TO")
  1288. }
  1289. // Verify new table exists
  1290. _, err = schema.GetSchema("test_renamed")
  1291. if err != nil {
  1292. t.Errorf("new table 'test_renamed' not found after RENAME TO: %v", err)
  1293. }
  1294. // Cleanup with new name
  1295. execSQL(exec, "DROP TABLE IF EXISTS test_renamed")
  1296. })
  1297. // Final cleanup
  1298. execSQL(exec, "DROP TABLE IF EXISTS test_alter")
  1299. execSQL(exec, "DROP TABLE IF EXISTS test_renamed")
  1300. }
  1301. func TestExecutorResyncsCatalogAfterExternalCreateTable(t *testing.T) {
  1302. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  1303. if err != nil {
  1304. t.Skip("PizzaKV not available, skipping catalog resync tests")
  1305. }
  1306. defer pool.Close()
  1307. dbName := fmt.Sprintf("test_catalog_create_%d", time.Now().UnixNano())
  1308. schema := storage.NewSchemaManager(pool, dbName)
  1309. table := storage.NewTableManager(pool, schema, dbName)
  1310. staleExec := New(schema, table)
  1311. if err := staleExec.SyncCatalog(); err != nil {
  1312. t.Fatalf("initial sync: %v", err)
  1313. }
  1314. schemaWriter := New(schema, table)
  1315. if _, err := execSQL(schemaWriter, "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)"); err != nil {
  1316. t.Fatalf("create table through second executor: %v", err)
  1317. }
  1318. if _, err := execSQL(schemaWriter, "INSERT INTO users (id, name) VALUES (1, 'Alice')"); err != nil {
  1319. t.Fatalf("insert through second executor: %v", err)
  1320. }
  1321. result, err := execSQL(staleExec, "SELECT name FROM users WHERE id = 1")
  1322. if err != nil {
  1323. t.Fatalf("stale executor should resync and query new table: %v", err)
  1324. }
  1325. if len(result.Rows) != 1 || len(result.Rows[0]) != 1 || result.Rows[0][0] != "Alice" {
  1326. t.Fatalf("unexpected rows after catalog resync: %#v", result.Rows)
  1327. }
  1328. }
  1329. func TestExecutorResyncsCatalogAfterExternalAlterTable(t *testing.T) {
  1330. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  1331. if err != nil {
  1332. t.Skip("PizzaKV not available, skipping catalog resync tests")
  1333. }
  1334. defer pool.Close()
  1335. dbName := fmt.Sprintf("test_catalog_alter_%d", time.Now().UnixNano())
  1336. schema := storage.NewSchemaManager(pool, dbName)
  1337. table := storage.NewTableManager(pool, schema, dbName)
  1338. staleExec := New(schema, table)
  1339. if _, err := execSQL(staleExec, "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)"); err != nil {
  1340. t.Fatalf("create table: %v", err)
  1341. }
  1342. if _, err := execSQL(staleExec, "INSERT INTO users (id, name) VALUES (1, 'Alice')"); err != nil {
  1343. t.Fatalf("insert: %v", err)
  1344. }
  1345. if err := staleExec.SyncCatalog(); err != nil {
  1346. t.Fatalf("sync after create: %v", err)
  1347. }
  1348. schemaWriter := New(schema, table)
  1349. if _, err := execSQL(schemaWriter, "ALTER TABLE users ADD COLUMN status TEXT DEFAULT 'active'"); err != nil {
  1350. t.Fatalf("alter table through second executor: %v", err)
  1351. }
  1352. result, err := execSQL(staleExec, "SELECT status FROM users WHERE id = 1")
  1353. if err != nil {
  1354. t.Fatalf("stale executor should resync and query new column: %v", err)
  1355. }
  1356. if len(result.Rows) != 1 {
  1357. t.Fatalf("expected one row after catalog resync, got %#v", result.Rows)
  1358. }
  1359. }
  1360. // Test ATTACH/DETACH DATABASE statements
  1361. func TestAttachDetach(t *testing.T) {
  1362. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  1363. if err != nil {
  1364. t.Skip("PizzaKV not available, skipping ATTACH/DETACH tests")
  1365. }
  1366. defer pool.Close()
  1367. schema := storage.NewSchemaManager(pool, "test_main_db")
  1368. table := storage.NewTableManager(pool, schema, "test_main_db")
  1369. exec := New(schema, table)
  1370. // Create a table in main database
  1371. execSQL(exec, "DROP TABLE IF EXISTS main_table")
  1372. _, err = execSQL(exec, "CREATE TABLE main_table (id INTEGER PRIMARY KEY, data TEXT)")
  1373. if err != nil {
  1374. t.Fatalf("failed to create main table: %v", err)
  1375. }
  1376. execSQL(exec, "INSERT INTO main_table (id, data) VALUES (1, 'main data')")
  1377. t.Run("attach_database", func(t *testing.T) {
  1378. result, err := execSQL(exec, "ATTACH DATABASE 'test_other_db' AS other")
  1379. if err != nil {
  1380. t.Fatalf("ATTACH DATABASE failed: %v", err)
  1381. }
  1382. if result.CommandTag != "ATTACH" {
  1383. t.Errorf("expected command tag 'ATTACH', got '%s'", result.CommandTag)
  1384. }
  1385. // Verify database is attached
  1386. if _, exists := exec.attachedDatabases["other"]; !exists {
  1387. t.Error("database 'other' not found in attached databases")
  1388. }
  1389. })
  1390. t.Run("attach_duplicate_alias", func(t *testing.T) {
  1391. _, err := execSQL(exec, "ATTACH DATABASE 'test_dup_db' AS other")
  1392. if err == nil {
  1393. t.Error("expected error when attaching with duplicate alias")
  1394. }
  1395. })
  1396. t.Run("attach_reserved_alias", func(t *testing.T) {
  1397. _, err := execSQL(exec, "ATTACH DATABASE 'test_temp_db' AS temp")
  1398. if err == nil {
  1399. t.Error("expected error when using reserved alias 'temp'")
  1400. }
  1401. })
  1402. t.Run("detach_database", func(t *testing.T) {
  1403. result, err := execSQL(exec, "DETACH DATABASE other")
  1404. if err != nil {
  1405. t.Fatalf("DETACH DATABASE failed: %v", err)
  1406. }
  1407. if result.CommandTag != "DETACH" {
  1408. t.Errorf("expected command tag 'DETACH', got '%s'", result.CommandTag)
  1409. }
  1410. // Verify database is detached
  1411. if _, exists := exec.attachedDatabases["other"]; exists {
  1412. t.Error("database 'other' still attached after DETACH")
  1413. }
  1414. })
  1415. t.Run("detach_nonexistent", func(t *testing.T) {
  1416. _, err := execSQL(exec, "DETACH DATABASE nonexistent")
  1417. if err == nil {
  1418. t.Error("expected error when detaching nonexistent database")
  1419. }
  1420. })
  1421. t.Run("detach_main_database", func(t *testing.T) {
  1422. _, err := execSQL(exec, "DETACH DATABASE main")
  1423. if err == nil {
  1424. t.Error("expected error when detaching main database")
  1425. }
  1426. })
  1427. t.Run("attach_without_database_keyword", func(t *testing.T) {
  1428. result, err := execSQL(exec, "ATTACH 'test_short_db' AS short")
  1429. if err != nil {
  1430. t.Fatalf("ATTACH (without DATABASE) failed: %v", err)
  1431. }
  1432. if result.CommandTag != "ATTACH" {
  1433. t.Errorf("expected command tag 'ATTACH', got '%s'", result.CommandTag)
  1434. }
  1435. // Cleanup
  1436. execSQL(exec, "DETACH short")
  1437. })
  1438. t.Run("detach_without_database_keyword", func(t *testing.T) {
  1439. execSQL(exec, "ATTACH 'test_det_db' AS det")
  1440. result, err := execSQL(exec, "DETACH det")
  1441. if err != nil {
  1442. t.Fatalf("DETACH (without DATABASE) failed: %v", err)
  1443. }
  1444. if result.CommandTag != "DETACH" {
  1445. t.Errorf("expected command tag 'DETACH', got '%s'", result.CommandTag)
  1446. }
  1447. })
  1448. // Cleanup
  1449. execSQL(exec, "DROP TABLE IF EXISTS main_table")
  1450. }
  1451. func TestDistinct(t *testing.T) {
  1452. // Simple test without requiring KV connection
  1453. exec := &Executor{}
  1454. // Test applyDistinct function directly
  1455. t.Run("ApplyDistinct", func(t *testing.T) {
  1456. rows := [][]interface{}{
  1457. {"a", 1},
  1458. {"b", 2},
  1459. {"a", 1}, // duplicate
  1460. {"c", 3},
  1461. {"b", 2}, // duplicate
  1462. }
  1463. result := exec.applyDistinct(rows)
  1464. if len(result) != 3 {
  1465. t.Errorf("expected 3 unique rows, got %d", len(result))
  1466. }
  1467. // Check that we have the expected unique rows
  1468. expected := map[string]bool{
  1469. "a\x001": true,
  1470. "b\x002": true,
  1471. "c\x003": true,
  1472. }
  1473. for _, row := range result {
  1474. key := fmt.Sprintf("%v\x00%v", row[0], row[1])
  1475. if !expected[key] {
  1476. t.Errorf("unexpected row in result: %v", row)
  1477. }
  1478. }
  1479. })
  1480. }
  1481. // TestGroupByWithConstantFalseWhere tests the distinction between:
  1482. // 1. Aggregate without GROUP BY + WHERE false -> returns [NULL] (one row with aggregate result on empty set)
  1483. // 2. Aggregate with GROUP BY + WHERE false -> returns [] (no groups match, so no rows)
  1484. func TestGroupByWithConstantFalseWhere(t *testing.T) {
  1485. pool, err := storage.NewKVPool("localhost:8085", 5, 5*time.Second)
  1486. if err != nil {
  1487. t.Skip("PizzaKV not available, skipping test")
  1488. }
  1489. defer pool.Close()
  1490. schema := storage.NewSchemaManager(pool, "test_groupby_db")
  1491. table := storage.NewTableManager(pool, schema, "test_groupby_db")
  1492. exec := New(schema, table)
  1493. // Setup test tables
  1494. execSQL(exec, "DROP TABLE IF EXISTS tab0")
  1495. execSQL(exec, "DROP TABLE IF EXISTS tab1")
  1496. _, err = execSQL(exec, "CREATE TABLE tab0 (col0 INTEGER, col1 INTEGER, col2 INTEGER)")
  1497. if err != nil {
  1498. t.Fatalf("failed to create tab0: %v", err)
  1499. }
  1500. _, err = execSQL(exec, "CREATE TABLE tab1 (col0 INTEGER, col1 INTEGER, col2 INTEGER)")
  1501. if err != nil {
  1502. t.Fatalf("failed to create tab1: %v", err)
  1503. }
  1504. // Insert some test data
  1505. execSQL(exec, "INSERT INTO tab0 VALUES (1, 10, 100)")
  1506. execSQL(exec, "INSERT INTO tab0 VALUES (2, 20, 200)")
  1507. execSQL(exec, "INSERT INTO tab0 VALUES (3, 30, 300)")
  1508. execSQL(exec, "INSERT INTO tab1 VALUES (1, 10, 100)")
  1509. execSQL(exec, "INSERT INTO tab1 VALUES (2, 20, 200)")
  1510. execSQL(exec, "INSERT INTO tab1 VALUES (3, 30, 300)")
  1511. // Test 1: Aggregate with GROUP BY and constant FALSE WHERE -> should return empty result []
  1512. t.Run("aggregate_with_groupby_where_false", func(t *testing.T) {
  1513. result, err := execSQL(exec, "SELECT AVG(col1) FROM tab1 WHERE NULL IS NOT NULL GROUP BY col1")
  1514. if err != nil {
  1515. t.Fatalf("query failed: %v", err)
  1516. }
  1517. if result.RowCount != 0 {
  1518. t.Errorf("expected 0 rows (no groups), got %d rows with values: %v", result.RowCount, result.Rows)
  1519. }
  1520. })
  1521. // Test 2: Aggregate without GROUP BY and constant FALSE WHERE -> should return [NULL]
  1522. t.Run("aggregate_without_groupby_where_false", func(t *testing.T) {
  1523. result, err := execSQL(exec, "SELECT AVG(col1) FROM tab1 WHERE NULL IS NOT NULL")
  1524. if err != nil {
  1525. t.Fatalf("query failed: %v", err)
  1526. }
  1527. if result.RowCount != 1 {
  1528. t.Errorf("expected 1 row, got %d", result.RowCount)
  1529. }
  1530. if result.RowCount == 1 && result.Rows[0][0] != nil {
  1531. t.Errorf("expected NULL for aggregate on empty set, got %v", result.Rows[0][0])
  1532. }
  1533. })
  1534. // Test 3: More complex case from test failures
  1535. t.Run("complex_groupby_where_false", func(t *testing.T) {
  1536. result, err := execSQL(exec, "SELECT ALL AVG(+ col1) FROM tab1 WHERE NULL IS NULL AND NOT NULL IS NULL GROUP BY col1")
  1537. if err != nil {
  1538. t.Fatalf("query failed: %v", err)
  1539. }
  1540. if result.RowCount != 0 {
  1541. t.Errorf("expected 0 rows (no groups), got %d rows with values: %v", result.RowCount, result.Rows)
  1542. }
  1543. })
  1544. // Test 4: DISTINCT aggregate with GROUP BY and constant FALSE WHERE
  1545. t.Run("distinct_aggregate_with_groupby_where_false", func(t *testing.T) {
  1546. result, err := execSQL(exec, "SELECT DISTINCT AVG(DISTINCT - col2) FROM tab0 WHERE NOT NULL IS NULL GROUP BY col2")
  1547. if err != nil {
  1548. t.Fatalf("query failed: %v", err)
  1549. }
  1550. if result.RowCount != 0 {
  1551. t.Errorf("expected 0 rows (no groups), got %d rows with values: %v", result.RowCount, result.Rows)
  1552. }
  1553. })
  1554. // Test 5: Verify normal GROUP BY still works (WHERE true)
  1555. t.Run("normal_groupby_sanity_check", func(t *testing.T) {
  1556. result, err := execSQL(exec, "SELECT AVG(col1) FROM tab1 WHERE NULL IS NULL GROUP BY col1")
  1557. if err != nil {
  1558. t.Fatalf("query failed: %v", err)
  1559. }
  1560. if result.RowCount != 3 {
  1561. t.Errorf("expected 3 groups, got %d", result.RowCount)
  1562. }
  1563. })
  1564. // Cleanup
  1565. execSQL(exec, "DROP TABLE IF EXISTS tab0")
  1566. execSQL(exec, "DROP TABLE IF EXISTS tab1")
  1567. }