diff --git a/embedded/sql/engine_test.go b/embedded/sql/engine_test.go index 5244f5e4aa..4706150262 100644 --- a/embedded/sql/engine_test.go +++ b/embedded/sql/engine_test.go @@ -2973,13 +2973,13 @@ func TestQuery(t *testing.T) { `SELECT department, job_title, - CASE - WHEN department = 'sales' THEN + CASE department + WHEN 'sales' THEN CASE WHEN job_title = 'manager' THEN '20% Bonus' ELSE '10% Bonus' END - WHEN department = 'engineering' THEN + WHEN 'engineering' THEN CASE WHEN job_title = 'senior engineer' THEN '15% Bonus' ELSE '5% Bonus' diff --git a/embedded/sql/parser_test.go b/embedded/sql/parser_test.go index ef8dceb6a8..953b0c0e2c 100644 --- a/embedded/sql/parser_test.go +++ b/embedded/sql/parser_test.go @@ -1674,6 +1674,57 @@ func TestParseExp(t *testing.T) { }}, expectedError: nil, }, + { + input: "SELECT CASE 1 + 1 WHEN 2 THEN 1 ELSE 0 END FROM my_table", + expectedOutput: []SQLStmt{ + &SelectStmt{ + ds: &tableRef{table: "my_table"}, + targets: []TargetEntry{ + { + Exp: &CaseWhenExp{ + exp: &NumExp{ + op: ADDOP, + left: &Integer{1}, + right: &Integer{1}, + }, + whenThen: []whenThenClause{ + { + when: &Integer{2}, + then: &Integer{1}, + }, + }, + elseExp: &Integer{0}, + }, + }, + }, + }, + }, + }, + { + input: "SELECT CASE WHEN is_deleted OR is_expired THEN 1 END AS is_deleted_or_expired FROM my_table", + expectedOutput: []SQLStmt{ + &SelectStmt{ + ds: &tableRef{table: "my_table"}, + targets: []TargetEntry{ + { + Exp: &CaseWhenExp{ + whenThen: []whenThenClause{ + { + when: &BinBoolExp{ + op: OR, + left: &ColSelector{col: "is_deleted"}, + right: &ColSelector{col: "is_expired"}, + }, + then: &Integer{1}, + }, + }, + }, + As: "is_deleted_or_expired", + }, + }, + }, + }, + }, { input: "SELECT CASE WHEN is_deleted OR is_expired THEN 1 END AS is_deleted_or_expired FROM my_table", expectedOutput: []SQLStmt{ diff --git a/embedded/sql/sql_grammar.y b/embedded/sql/sql_grammar.y index 4fe736f332..115e350ff8 100644 --- a/embedded/sql/sql_grammar.y +++ b/embedded/sql/sql_grammar.y @@ -136,7 +136,7 @@ func setResult(l yyLexer, stmts []SQLStmt) { %type join %type opt_join_type %type opt_checks -%type exp opt_where opt_having boundexp opt_else when_then_else +%type exp opt_exp opt_where opt_having boundexp opt_else %type binExp %type opt_groupby %type opt_limit opt_offset case_when_exp @@ -1057,6 +1057,17 @@ opt_checks: $$ = append([]CheckConstraint{{name: $2, exp: $4}}, $6...) } +opt_exp: + { + $$ = nil + } +| + exp + { + $$ = $1 + } +; + exp: boundexp { @@ -1104,18 +1115,12 @@ exp: } case_when_exp: - CASE when_then_else END - { - $$ = $2 - } -; - -when_then_else: - when_then_clauses opt_else + CASE opt_exp when_then_clauses opt_else END { $$ = &CaseWhenExp{ - whenThen: $1, - elseExp: $2, + exp: $2, + whenThen: $3, + elseExp: $4, } } ; diff --git a/embedded/sql/sql_parser.go b/embedded/sql/sql_parser.go index 266135dabe..33b1b4bd62 100644 --- a/embedded/sql/sql_parser.go +++ b/embedded/sql/sql_parser.go @@ -134,38 +134,37 @@ const WHEN = 57415 const THEN = 57416 const ELSE = 57417 const END = 57418 -const BETWEEN = 57419 -const NOT = 57420 -const LIKE = 57421 -const IF = 57422 -const EXISTS = 57423 -const IN = 57424 -const IS = 57425 -const AUTO_INCREMENT = 57426 -const NULL = 57427 -const CAST = 57428 -const SCAST = 57429 -const SHOW = 57430 -const DATABASES = 57431 -const TABLES = 57432 -const USERS = 57433 -const NPARAM = 57434 -const PPARAM = 57435 -const JOINTYPE = 57436 -const LOP = 57437 -const CMPOP = 57438 -const IDENTIFIER = 57439 -const TYPE = 57440 -const INTEGER = 57441 -const FLOAT = 57442 -const VARCHAR = 57443 -const BOOLEAN = 57444 -const BLOB = 57445 -const AGGREGATE_FUNC = 57446 -const ERROR = 57447 -const DOT = 57448 -const ARROW = 57449 -const STMT_SEPARATOR = 57450 +const NOT = 57419 +const LIKE = 57420 +const IF = 57421 +const EXISTS = 57422 +const IN = 57423 +const IS = 57424 +const AUTO_INCREMENT = 57425 +const NULL = 57426 +const CAST = 57427 +const SCAST = 57428 +const SHOW = 57429 +const DATABASES = 57430 +const TABLES = 57431 +const USERS = 57432 +const NPARAM = 57433 +const PPARAM = 57434 +const JOINTYPE = 57435 +const LOP = 57436 +const CMPOP = 57437 +const IDENTIFIER = 57438 +const TYPE = 57439 +const INTEGER = 57440 +const FLOAT = 57441 +const VARCHAR = 57442 +const BOOLEAN = 57443 +const BLOB = 57444 +const AGGREGATE_FUNC = 57445 +const ERROR = 57446 +const DOT = 57447 +const ARROW = 57448 +const STMT_SEPARATOR = 57449 var yyToknames = [...]string{ "$end", @@ -244,7 +243,6 @@ var yyToknames = [...]string{ "THEN", "ELSE", "END", - "BETWEEN", "NOT", "LIKE", "IF", @@ -300,138 +298,138 @@ var yyExca = [...]int16{ 1, -1, -2, 0, -1, 97, - 79, 191, - 82, 191, - -2, 172, - -1, 272, + 78, 192, + 81, 192, + -2, 174, + -1, 268, 59, 145, -2, 140, - -1, 320, + -1, 317, 59, 145, -2, 142, } const yyPrivate = 57344 -const yyLast = 582 +const yyLast = 583 var yyAct = [...]int16{ - 131, 427, 103, 107, 313, 202, 266, 336, 351, 208, - 153, 354, 115, 244, 249, 319, 245, 308, 199, 299, - 71, 394, 144, 22, 6, 147, 342, 264, 341, 415, - 355, 264, 294, 264, 264, 264, 399, 129, 130, 106, - 379, 368, 343, 303, 265, 99, 161, 398, 101, 356, - 24, 395, 118, 114, 387, 21, 370, 367, 365, 116, - 117, 329, 96, 327, 119, 161, 109, 110, 111, 112, - 113, 108, 154, 155, 157, 156, 158, 100, 160, 326, - 426, 324, 293, 105, 242, 291, 290, 285, 263, 352, - 106, 154, 155, 157, 156, 158, 99, 179, 240, 101, - 167, 168, 298, 118, 114, 284, 170, 178, 161, 178, - 116, 117, 132, 161, 149, 119, 279, 109, 110, 111, - 112, 113, 108, 278, 277, 159, 160, 276, 100, 251, - 188, 187, 181, 177, 105, 176, 157, 156, 158, 154, - 155, 157, 156, 158, 169, 143, 204, 232, 142, 163, - 213, 419, 381, 217, 145, 218, 219, 220, 221, 222, - 223, 224, 201, 161, 215, 185, 186, 295, 294, 205, - 161, 264, 152, 83, 237, 159, 160, 162, 243, 246, - 241, 238, 159, 160, 175, 179, 289, 134, 378, 154, - 155, 157, 156, 158, 231, 416, 154, 155, 157, 156, - 158, 206, 242, 260, 253, 255, 377, 254, 271, 108, - 239, 269, 339, 32, 272, 338, 211, 212, 214, 163, - 33, 334, 296, 230, 216, 106, 280, 76, 281, 283, - 273, 99, 270, 242, 101, 274, 286, 287, 118, 114, - 200, 373, 362, 210, 347, 116, 117, 162, 346, 345, - 119, 328, 109, 110, 111, 112, 113, 108, 311, 148, - 259, 258, 257, 100, 94, 256, 250, 252, 315, 105, - 297, 247, 227, 197, 196, 189, 317, 250, 182, 150, - 305, 133, 122, 312, 323, 246, 120, 91, 310, 333, - 310, 54, 80, 79, 78, 335, 75, 70, 77, 161, - 69, 331, 322, 31, 292, 207, 376, 166, 393, 330, - 337, 159, 160, 375, 226, 353, 165, 344, 161, 58, - 275, 225, 357, 22, 389, 154, 155, 157, 156, 158, - 159, 160, 282, 369, 60, 361, 359, 363, 364, 372, - 366, 358, 392, 39, 154, 155, 157, 156, 158, 161, - 180, 106, 65, 246, 309, 21, 121, 99, 233, 49, - 101, 22, 22, 173, 118, 114, 382, 235, 90, 236, - 386, 116, 117, 215, 228, 383, 119, 229, 109, 110, - 111, 112, 113, 108, 55, 56, 57, 59, 410, 100, - 397, 407, 403, 21, 21, 105, 314, 406, 404, 418, - 405, 267, 411, 402, 332, 145, 413, 161, 385, 288, - 428, 429, 401, 161, 360, 420, 417, 151, 161, 159, - 160, 424, 422, 425, 421, 159, 160, 140, 52, 430, - 159, 160, 431, 154, 155, 157, 156, 158, 64, 154, - 155, 157, 156, 158, 154, 155, 157, 156, 158, 10, - 12, 11, 43, 47, 62, 408, 396, 209, 380, 88, - 51, 50, 25, 82, 92, 339, 66, 67, 338, 390, - 388, 371, 13, 193, 194, 48, 137, 53, 190, 191, - 192, 14, 15, 304, 262, 261, 7, 414, 8, 9, - 16, 17, 349, 44, 18, 19, 36, 46, 45, 135, - 136, 22, 316, 183, 42, 26, 30, 124, 85, 86, - 87, 34, 123, 35, 2, 84, 81, 268, 68, 40, - 38, 27, 29, 28, 325, 128, 127, 73, 74, 300, - 301, 302, 195, 21, 184, 37, 138, 125, 307, 63, - 306, 141, 139, 203, 23, 172, 41, 348, 146, 164, - 374, 391, 409, 423, 340, 95, 93, 102, 384, 98, - 171, 234, 97, 400, 321, 320, 318, 126, 72, 89, - 61, 174, 104, 350, 412, 198, 248, 20, 5, 4, - 3, 1, + 131, 428, 103, 107, 310, 153, 262, 335, 201, 353, + 115, 207, 350, 240, 245, 241, 316, 305, 71, 144, + 198, 296, 395, 147, 22, 260, 341, 6, 340, 260, + 291, 416, 130, 260, 400, 260, 399, 396, 379, 367, + 106, 129, 342, 387, 300, 99, 161, 260, 101, 370, + 366, 364, 118, 114, 326, 21, 261, 324, 323, 116, + 117, 354, 96, 321, 119, 290, 109, 110, 111, 112, + 113, 108, 154, 155, 157, 156, 158, 100, 288, 287, + 355, 178, 281, 105, 106, 259, 351, 295, 280, 99, + 161, 177, 101, 177, 275, 274, 118, 114, 273, 272, + 167, 168, 247, 116, 117, 187, 170, 172, 119, 163, + 109, 110, 111, 112, 113, 108, 132, 149, 157, 156, + 158, 100, 161, 238, 180, 176, 175, 105, 169, 143, + 142, 186, 24, 427, 159, 160, 162, 236, 145, 420, + 381, 292, 291, 260, 212, 152, 203, 234, 154, 155, + 157, 156, 158, 216, 83, 217, 218, 219, 220, 221, + 222, 223, 214, 106, 200, 174, 204, 178, 99, 184, + 185, 101, 134, 286, 238, 118, 114, 239, 242, 237, + 256, 108, 116, 117, 205, 249, 235, 119, 378, 109, + 110, 111, 112, 113, 108, 377, 163, 230, 333, 338, + 100, 94, 337, 293, 251, 32, 105, 267, 250, 210, + 211, 213, 33, 265, 229, 238, 268, 215, 161, 199, + 276, 76, 277, 162, 373, 361, 346, 269, 279, 266, + 106, 160, 319, 345, 285, 99, 209, 270, 101, 344, + 325, 308, 118, 114, 154, 155, 157, 156, 158, 116, + 117, 148, 255, 254, 119, 253, 109, 110, 111, 112, + 113, 108, 252, 246, 312, 246, 248, 100, 294, 243, + 226, 196, 314, 105, 195, 320, 188, 181, 302, 309, + 150, 242, 133, 122, 330, 331, 120, 307, 91, 307, + 54, 77, 334, 80, 31, 79, 328, 78, 75, 70, + 69, 206, 166, 376, 394, 271, 306, 336, 327, 161, + 375, 165, 352, 161, 22, 225, 343, 22, 278, 356, + 39, 227, 224, 393, 228, 159, 160, 360, 179, 362, + 363, 65, 365, 369, 358, 357, 49, 121, 372, 154, + 155, 157, 156, 158, 58, 21, 22, 231, 21, 329, + 233, 55, 242, 283, 161, 284, 90, 411, 311, 60, + 161, 429, 430, 263, 419, 382, 159, 160, 403, 388, + 214, 386, 159, 160, 385, 145, 383, 21, 402, 417, + 154, 155, 157, 156, 158, 390, 154, 155, 157, 156, + 158, 151, 408, 405, 398, 404, 359, 52, 407, 406, + 368, 62, 409, 412, 140, 397, 332, 414, 161, 56, + 57, 59, 380, 88, 161, 51, 421, 418, 50, 25, + 159, 160, 425, 423, 426, 422, 159, 160, 82, 92, + 431, 391, 289, 432, 154, 155, 157, 156, 158, 161, + 154, 155, 157, 156, 158, 161, 389, 10, 12, 11, + 338, 159, 160, 337, 64, 43, 47, 159, 160, 371, + 189, 208, 192, 193, 301, 154, 155, 157, 156, 158, + 13, 154, 155, 157, 156, 158, 190, 191, 48, 14, + 15, 53, 66, 67, 7, 137, 8, 9, 16, 17, + 258, 257, 18, 19, 415, 348, 44, 313, 182, 22, + 46, 45, 26, 30, 123, 84, 264, 42, 135, 136, + 36, 81, 85, 86, 87, 68, 2, 38, 27, 29, + 28, 322, 40, 124, 194, 34, 183, 35, 128, 127, + 21, 138, 37, 73, 74, 297, 298, 299, 125, 304, + 303, 63, 141, 139, 202, 23, 232, 41, 347, 146, + 164, 374, 392, 410, 424, 339, 95, 93, 102, 384, + 98, 282, 97, 401, 171, 318, 317, 315, 126, 72, + 89, 61, 173, 104, 349, 413, 197, 244, 20, 5, + 4, 3, 1, } var yyPact = [...]int16{ - 445, -1000, -1000, -65, -1000, -1000, -1000, 420, -1000, -1000, - 498, 206, 488, 512, 448, 448, 414, 413, 370, 194, - 314, 296, 397, -1000, 445, -1000, 272, 272, 272, 493, - 203, -1000, 200, 511, 199, 201, 197, 196, 195, 490, - 423, 65, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 489, - 194, 194, 194, 408, -1000, 297, -1000, -1000, 190, -1000, - 425, 153, -1000, -1000, 189, 278, 185, 486, 272, 528, - -1000, -1000, 507, 18, 18, -1000, 184, 81, -1000, 471, - 527, 535, -1000, 448, 534, 32, 29, 344, 162, 267, - -1000, -1000, 182, 359, -1000, 64, 80, 229, -1000, 279, - 279, 28, -1000, -1000, -1000, 279, 290, 77, 19, -1000, - -1000, -1000, -1000, -1000, 17, -1000, -1000, -1000, -1000, -9, - -1000, 269, 16, 181, 477, 524, -1000, 18, 18, -1000, - 279, 324, -1000, 14, 178, 447, 449, 442, 522, 177, - -1000, 176, 143, 143, 537, 279, 93, -1000, 209, -1000, - -1000, 127, 279, -1000, 279, 279, 279, 279, 279, 279, - 279, 236, -1000, 175, 295, 125, -1000, -18, 25, 267, - 30, 282, 294, 279, 74, 109, -13, 279, 279, 174, - -1000, 169, 13, 170, 103, -1000, -1000, 324, 143, -1000, - 169, 168, 165, 164, 163, 102, 455, 454, -29, 63, - -1000, -73, 337, 492, 324, 537, 162, 279, 537, 511, - 305, 11, 8, 7, 0, 150, -7, 80, 25, 25, - 266, 266, 266, -18, -37, -1000, 247, -1000, 279, -11, - -1000, -30, -1000, -1000, -1000, 279, 279, 335, 85, -1000, - -31, -32, 79, 235, -35, 60, 324, -1000, 59, -1000, - 124, 143, -14, 518, -74, -1000, -1000, 453, -1000, -1000, - 518, 532, 530, 306, 161, 306, 331, 279, 476, 337, - -1000, 324, 208, 150, -36, 503, -38, -54, 154, -56, - -1000, -1000, -1000, -18, -33, -1000, 330, 324, 279, -1000, - -1000, -1000, 123, -1000, 279, 180, -90, -75, 143, -1000, - -1000, -1000, -1000, -1000, 152, -1000, 151, 147, 466, -27, - -1000, -1000, -1000, -1000, 279, 324, -67, 331, 344, -1000, - 208, 355, -1000, -1000, 150, 145, 150, 150, -59, 150, - -60, -76, 279, 324, -61, 324, 438, -1000, 279, 144, - 228, 107, 89, -1000, -77, -1000, -1000, -1000, -1000, 406, - 44, -1000, 279, 324, -1000, -1000, 143, -1000, 346, -1000, - 127, -1000, -63, -1000, -1000, -1000, -1000, -1000, -1000, 324, - -1000, 436, 216, 434, 258, -1000, 223, -98, -66, -1000, - 403, -27, -70, -81, 352, 340, 537, 150, -67, 433, - 279, -1000, -1000, -1000, -1000, -1000, 401, -1000, -1000, -1000, - 322, 279, 136, 461, -1000, -88, -1000, 87, -1000, 337, - 336, 324, 43, -1000, 279, -1000, 433, 331, 105, 136, - 324, -1000, -1000, -28, 343, -1000, 105, -1000, -1000, -1000, - 343, -1000, + 443, -1000, -1000, 18, -1000, -1000, -1000, 377, -1000, -1000, + 495, 198, 502, 509, 451, 451, 371, 368, 339, 194, + 281, 321, 344, -1000, 443, -1000, 252, 252, 252, 490, + 204, -1000, 203, 517, 202, 195, 201, 199, 197, 485, + 388, 47, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 479, + 194, 194, 194, 362, -1000, 285, -1000, -1000, 192, -1000, + 390, 91, -1000, -1000, 190, 260, 187, 478, 252, 529, + -1000, -1000, 510, 12, 12, -1000, 186, 67, -1000, 480, + 522, 536, -1000, 451, 535, 15, 14, 314, 155, 261, + -1000, -1000, 184, 333, -1000, 38, 40, 225, -1000, 158, + 158, 13, -1000, -1000, -1000, 158, 158, 59, 11, -1000, + -1000, -1000, -1000, -1000, 10, -1000, -1000, -1000, -1000, -24, + -1000, 248, 9, 181, 472, 516, -1000, 12, 12, -1000, + 158, 357, -1000, -10, 180, 429, 446, 431, 514, 178, + -1000, 175, 123, 123, 538, 158, 77, -1000, 206, -1000, + -1000, 121, 158, -1000, 158, 158, 158, 158, 158, 158, + 158, 238, -1000, 174, 243, 117, -1000, 136, 8, 261, + 231, 277, 357, 41, 86, 27, 158, 158, 173, -1000, + 169, -13, 170, 85, -1000, -1000, 357, 123, -1000, 169, + 166, 159, 157, 156, 80, 461, 460, -31, 36, -1000, + -60, 299, 481, 357, 538, 155, 158, 538, 517, 290, + -16, -17, -20, -21, 127, -22, 40, 8, 8, 227, + 227, 227, 136, -36, -1000, 234, -1000, 158, -27, -1000, + -34, -1000, 280, 158, 73, -1000, -37, -38, 62, 363, + -51, 35, 357, -1000, 34, -1000, 106, 123, -28, 524, + -72, -1000, -1000, 434, -1000, -1000, 524, 532, 531, 258, + 145, 258, 293, 158, 471, 299, -1000, 357, 139, 127, + -53, 500, -58, -59, 144, -62, -1000, -1000, -1000, 136, + -32, -1000, 273, 158, 158, 332, -1000, -1000, -1000, 101, + -1000, 158, 167, -89, -74, 123, -1000, -1000, -1000, -1000, + -1000, 143, -1000, 137, 130, 469, -29, -1000, -1000, -1000, + -1000, 158, 357, -35, 293, 314, -1000, 139, 337, -1000, + -1000, 127, 129, 127, 127, -65, 127, -66, -77, -1000, + 326, 357, 158, -67, 357, 426, -1000, 158, 128, 226, + 97, 90, -1000, -78, -1000, -1000, -1000, -1000, 360, 33, + -1000, 158, 357, -1000, -1000, 123, -1000, 312, -1000, 121, + -1000, -73, -1000, -1000, -1000, -1000, -1000, -1000, 158, 357, + -1000, 412, 278, 396, 240, -1000, 220, -96, -79, -1000, + 352, -29, -80, -82, 318, 305, 538, 127, 357, -35, + 418, 158, -1000, -1000, -1000, -1000, -1000, 348, -1000, -1000, + -1000, 291, 158, 119, 468, -1000, -85, -1000, 272, -1000, + 299, 301, 357, 32, -1000, 158, -1000, 418, 293, 78, + 119, 357, -1000, -1000, 26, 294, -1000, 78, -1000, -1000, + -1000, 294, -1000, } var yyPgo = [...]int16{ - 0, 581, 514, 580, 579, 578, 24, 577, 576, 14, - 18, 11, 575, 574, 573, 8, 16, 13, 572, 12, - 2, 571, 3, 570, 569, 9, 17, 457, 20, 568, - 567, 37, 566, 15, 565, 564, 7, 0, 22, 563, - 562, 561, 560, 559, 558, 6, 4, 557, 556, 555, - 554, 10, 553, 552, 1, 5, 438, 551, 550, 549, - 25, 548, 547, 19, 546, 343, 545, 544, + 0, 582, 516, 581, 580, 579, 27, 578, 577, 14, + 20, 9, 576, 575, 574, 12, 15, 13, 573, 10, + 2, 572, 3, 571, 570, 11, 17, 461, 18, 569, + 568, 41, 567, 16, 566, 565, 7, 0, 564, 19, + 563, 562, 561, 560, 559, 6, 4, 558, 557, 556, + 555, 5, 554, 553, 1, 8, 454, 552, 551, 550, + 23, 549, 548, 21, 547, 320, 546, 545, } var yyR1 = [...]int8{ @@ -449,13 +447,13 @@ var yyR1 = [...]int8{ 48, 48, 49, 49, 20, 20, 20, 20, 21, 21, 22, 22, 25, 25, 25, 25, 25, 25, 25, 25, 27, 28, 29, 29, 29, 30, 30, 30, 31, 31, - 32, 32, 33, 33, 34, 35, 35, 38, 38, 44, - 44, 39, 39, 45, 45, 46, 46, 53, 53, 55, + 32, 32, 33, 33, 34, 35, 35, 39, 39, 44, + 44, 40, 40, 45, 45, 46, 46, 53, 53, 55, 55, 52, 52, 54, 54, 54, 51, 51, 51, 36, - 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 47, 42, 66, 66, 41, 41, 40, 40, 40, - 40, 59, 59, 43, 43, 43, 43, 43, 43, 43, - 43, 43, + 36, 36, 38, 38, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 47, 66, 66, 42, 42, 41, 41, + 41, 41, 59, 59, 43, 43, 43, 43, 43, 43, + 43, 43, 43, } var yyR2 = [...]int8{ @@ -476,57 +474,57 @@ var yyR2 = [...]int8{ 0, 1, 1, 2, 6, 0, 1, 0, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 3, 0, 4, 2, 4, 0, 1, 1, 0, 1, 2, 0, - 4, 6, 1, 1, 2, 2, 4, 4, 6, 6, - 1, 3, 2, 4, 5, 0, 2, 1, 1, 3, - 3, 0, 1, 3, 3, 3, 3, 3, 3, 3, - 3, 4, + 4, 6, 0, 1, 1, 1, 2, 2, 4, 4, + 6, 6, 1, 5, 4, 5, 0, 2, 1, 1, + 3, 3, 0, 1, 3, 3, 3, 3, 3, 3, + 3, 3, 4, } var yyChk = [...]int16{ -1000, -1, -2, -3, -4, -5, -6, 41, 43, 44, 4, 6, 5, 27, 36, 37, 45, 46, 49, 50, - -7, 88, 56, -67, 115, 42, 7, 23, 25, 24, - 8, 97, 7, 14, 23, 25, 8, 23, 8, -65, + -7, 87, 56, -67, 114, 42, 7, 23, 25, 24, + 8, 96, 7, 14, 23, 25, 8, 23, 8, -65, 71, -64, 56, 4, 45, 50, 49, 5, 27, -65, - 47, 47, 58, -27, 97, 70, 89, 90, 23, 91, - 38, -23, 57, -2, -56, 80, -56, -56, 25, 97, - 97, -28, -29, 16, 17, 97, 26, 97, 97, 97, - 97, 26, 40, 108, 26, -27, -27, -27, 51, -24, - 71, 97, 39, -48, 111, -49, -37, -40, -43, 78, - 110, 81, -47, -20, -18, 116, 72, -22, 104, 99, - 100, 101, 102, 103, 86, -19, 92, 93, 85, 97, - 97, 78, 97, 26, -56, 9, -30, 19, 18, -31, - 20, -37, -31, 97, 106, 28, 29, 5, 9, 7, - -65, 7, 116, 116, -38, 61, -61, -60, 97, -6, - 97, 58, 108, -51, 109, 110, 112, 111, 113, 95, - 96, 83, 97, 69, -59, 87, 78, -37, -37, 116, - -37, -42, -66, 73, -21, 107, 116, 116, 116, 106, - 81, 116, 97, 26, 10, -31, -31, -37, 116, 97, - 31, 30, 31, 31, 32, 10, 97, 97, -12, -10, - 97, -10, -55, 6, -37, -38, 108, 96, -25, -27, - 116, 89, 90, 23, 91, -19, 97, -37, -37, -37, - -37, -37, -37, -37, -37, 85, 78, 97, 79, 82, - 98, -6, 117, 76, -41, 73, 75, -37, 107, 101, - 111, -22, 97, -37, -17, -16, -37, 97, -8, -9, - 97, 116, 97, 101, -10, -9, 97, 97, 97, 97, - 101, 30, 30, 117, 108, 117, -45, 64, 25, -55, - -60, -37, -55, -28, -6, 15, 116, 116, 116, 116, - -51, -51, 85, -37, 116, 117, -37, -37, 74, 101, - 117, 117, 69, 117, 108, 108, 98, -10, 116, -63, - 11, 12, 13, 117, 30, -63, 8, 8, -26, 48, - -6, 97, -26, -46, 65, -37, 26, -45, -32, -33, - -34, -35, 94, -51, 117, 21, 117, 117, 97, 117, - -6, -16, 74, -37, 98, -37, -36, -9, 35, 32, - -50, 118, 116, 117, -10, 97, 97, 97, -62, 26, - -14, -15, 116, -37, -11, 97, 116, -46, -38, -33, - 59, -51, 97, -51, -51, 117, -51, 117, 117, -37, - 117, 33, -37, 97, -58, 85, 78, 99, 99, 117, - 52, 108, -17, -10, -44, 62, -25, 117, 34, 108, - 35, -57, 84, 85, 119, 117, 53, -15, 117, 117, - -39, 60, 63, -55, -51, -11, -36, -37, 54, -53, - 66, -37, -13, -22, 26, 117, 108, -45, 63, 108, - -37, -36, -46, -52, -20, -22, 108, -54, 67, 68, - -20, -54, + 47, 47, 58, -27, 96, 70, 88, 89, 23, 90, + 38, -23, 57, -2, -56, 79, -56, -56, 25, 96, + 96, -28, -29, 16, 17, 96, 26, 96, 96, 96, + 96, 26, 40, 107, 26, -27, -27, -27, 51, -24, + 71, 96, 39, -48, 110, -49, -37, -41, -43, 77, + 109, 80, -47, -20, -18, 115, 72, -22, 103, 98, + 99, 100, 101, 102, 85, -19, 91, 92, 84, 96, + 96, 77, 96, 26, -56, 9, -30, 19, 18, -31, + 20, -37, -31, 96, 105, 28, 29, 5, 9, 7, + -65, 7, 115, 115, -39, 61, -61, -60, 96, -6, + 96, 58, 107, -51, 108, 109, 111, 110, 112, 94, + 95, 82, 96, 69, -59, 86, 77, -37, -37, 115, + -37, -38, -37, -21, 106, 115, 115, 115, 105, 80, + 115, 96, 26, 10, -31, -31, -37, 115, 96, 31, + 30, 31, 31, 32, 10, 96, 96, -12, -10, 96, + -10, -55, 6, -37, -39, 107, 95, -25, -27, 115, + 88, 89, 23, 90, -19, 96, -37, -37, -37, -37, + -37, -37, -37, -37, 84, 77, 96, 78, 81, 97, + -6, 116, -66, 73, 106, 100, 110, -22, 96, -37, + -17, -16, -37, 96, -8, -9, 96, 115, 96, 100, + -10, -9, 96, 96, 96, 96, 100, 30, 30, 116, + 107, 116, -45, 64, 25, -55, -60, -37, -55, -28, + -6, 15, 115, 115, 115, 115, -51, -51, 84, -37, + 115, 116, -42, 73, 75, -37, 100, 116, 116, 69, + 116, 107, 107, 97, -10, 115, -63, 11, 12, 13, + 116, 30, -63, 8, 8, -26, 48, -6, 96, -26, + -46, 65, -37, 26, -45, -32, -33, -34, -35, 93, + -51, 116, 21, 116, 116, 96, 116, -6, -16, 76, + -37, -37, 74, 97, -37, -36, -9, 35, 32, -50, + 117, 115, 116, -10, 96, 96, 96, -62, 26, -14, + -15, 115, -37, -11, 96, 115, -46, -39, -33, 59, + -51, 96, -51, -51, 116, -51, 116, 116, 74, -37, + 116, 33, -37, 96, -58, 84, 77, 98, 98, 116, + 52, 107, -17, -10, -44, 62, -25, 116, -37, 34, + 107, 35, -57, 83, 84, 118, 116, 53, -15, 116, + 116, -40, 60, 63, -55, -51, -11, -36, -37, 54, + -53, 66, -37, -13, -22, 26, 116, 107, -45, 63, + 107, -37, -36, -46, -52, -20, -22, 107, -54, 67, + 68, -20, -54, } var yyDef = [...]int16{ @@ -539,54 +537,54 @@ var yyDef = [...]int16{ 103, 0, 109, 3, 0, 0, 0, 0, 47, 0, 15, 16, 135, 0, 0, 18, 0, 0, 30, 0, 0, 0, 33, 0, 0, 0, 0, 147, 0, 0, - 107, 101, 0, 0, 110, 111, 166, -2, 173, 0, - 0, 0, 180, 187, 188, 0, 0, 114, 0, 75, + 107, 101, 0, 0, 110, 111, 166, -2, 175, 0, + 0, 0, 182, 188, 189, 0, 172, 114, 0, 75, 76, 77, 78, 79, 0, 81, 82, 83, 84, 120, 13, 0, 0, 0, 0, 0, 131, 0, 0, 133, 0, 139, 134, 0, 0, 0, 0, 0, 0, 0, 35, 0, 62, 0, 159, 0, 147, 59, 0, 98, 104, 0, 0, 112, 0, 0, 0, 0, 0, 0, - 0, 0, 167, 0, 0, 0, 192, 174, 175, 0, - 0, 0, 185, 0, 115, 0, 0, 0, 71, 0, - 48, 0, 0, 0, 0, 136, 137, 138, 0, 22, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, - 67, 0, 153, 0, 148, 159, 0, 0, 159, 132, - 0, 0, 0, 0, 0, 166, 130, 166, 193, 194, - 195, 196, 197, 198, 199, 200, 0, 168, 0, 0, - 190, 0, 189, 181, 182, 0, 0, 0, 0, 118, - 0, 0, 120, 0, 0, 72, 73, 121, 0, 86, - 0, 0, 0, 43, 0, 23, 24, 0, 26, 27, - 43, 0, 0, 0, 0, 0, 155, 0, 0, 153, - 60, 61, -2, 166, 0, 0, 0, 0, 0, 0, - 128, 113, 201, 176, 0, 177, 0, 186, 0, 119, - 116, 117, 0, 85, 0, 169, 89, 0, 0, 28, - 44, 45, 46, 21, 0, 29, 0, 0, 57, 0, - 56, 68, 52, 53, 0, 154, 0, 155, 147, 141, - -2, 0, 146, 122, 166, 0, 166, 166, 0, 166, - 0, 0, 0, 183, 0, 74, 0, 87, 0, 0, - 94, 0, 0, 19, 0, 25, 31, 32, 51, 0, - 55, 64, 71, 156, 160, 49, 0, 54, 149, 143, - 0, 123, 0, 124, 125, 126, 127, 178, 179, 184, + 0, 0, 167, 0, 0, 0, 193, 176, 177, 0, + 0, 0, 173, 115, 0, 0, 0, 71, 0, 48, + 0, 0, 0, 0, 136, 137, 138, 0, 22, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 63, 67, + 0, 153, 0, 148, 159, 0, 0, 159, 132, 0, + 0, 0, 0, 0, 166, 130, 166, 194, 195, 196, + 197, 198, 199, 200, 201, 0, 168, 0, 0, 191, + 0, 190, 186, 0, 0, 118, 0, 0, 120, 0, + 0, 72, 73, 121, 0, 86, 0, 0, 0, 43, + 0, 23, 24, 0, 26, 27, 43, 0, 0, 0, + 0, 0, 155, 0, 0, 153, 60, 61, -2, 166, + 0, 0, 0, 0, 0, 0, 128, 113, 202, 178, + 0, 179, 0, 0, 0, 0, 119, 116, 117, 0, + 85, 0, 169, 89, 0, 0, 28, 44, 45, 46, + 21, 0, 29, 0, 0, 57, 0, 56, 68, 52, + 53, 0, 154, 0, 155, 147, 141, -2, 0, 146, + 122, 166, 0, 166, 166, 0, 166, 0, 0, 183, + 0, 187, 0, 0, 74, 0, 87, 0, 0, 94, + 0, 0, 19, 0, 25, 31, 32, 51, 0, 55, + 64, 71, 156, 160, 49, 0, 54, 149, 143, 0, + 123, 0, 124, 125, 126, 127, 180, 181, 0, 184, 80, 0, 0, 0, 92, 95, 0, 0, 0, 20, - 0, 0, 0, 0, 151, 0, 159, 166, 0, 169, - 0, 88, 93, 96, 90, 91, 0, 65, 66, 50, - 157, 0, 0, 0, 129, 0, 170, 0, 58, 153, - 0, 152, 150, 69, 0, 17, 169, 155, 0, 0, - 144, 171, 105, 158, 163, 70, 0, 161, 164, 165, - 163, 162, + 0, 0, 0, 0, 151, 0, 159, 166, 185, 0, + 169, 0, 88, 93, 96, 90, 91, 0, 65, 66, + 50, 157, 0, 0, 0, 129, 0, 170, 0, 58, + 153, 0, 152, 150, 69, 0, 17, 169, 155, 0, + 0, 144, 171, 105, 158, 163, 70, 0, 161, 164, + 165, 163, 162, } var yyTok1 = [...]int8{ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 113, 3, 3, - 116, 117, 111, 109, 108, 110, 114, 112, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 112, 3, 3, + 115, 116, 110, 108, 107, 109, 113, 111, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 118, 3, 119, + 3, 117, 3, 118, } var yyTok2 = [...]int8{ @@ -600,7 +598,7 @@ var yyTok2 = [...]int8{ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 115, + 102, 103, 104, 105, 106, 114, } var yyTok3 = [...]int8{ @@ -1809,154 +1807,160 @@ yydefault: yyVAL.checks = append([]CheckConstraint{{name: yyDollar[2].id, exp: yyDollar[4].exp}}, yyDollar[6].checks...) } case 172: + yyDollar = yyS[yypt-0 : yypt+1] + { + yyVAL.exp = nil + } + case 173: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].exp } - case 173: + case 174: + yyDollar = yyS[yypt-1 : yypt+1] + { + yyVAL.exp = yyDollar[1].exp + } + case 175: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].binExp } - case 174: + case 176: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = &NotBoolExp{exp: yyDollar[2].exp} } - case 175: + case 177: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = &NumExp{left: &Integer{val: 0}, op: SUBSOP, right: yyDollar[2].exp} } - case 176: + case 178: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.exp = &LikeBoolExp{val: yyDollar[1].exp, notLike: yyDollar[2].boolean, pattern: yyDollar[4].exp} } - case 177: + case 179: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.exp = &ExistsBoolExp{q: (yyDollar[3].stmt).(DataSource)} } - case 178: + case 180: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.exp = &InSubQueryExp{val: yyDollar[1].exp, notIn: yyDollar[2].boolean, q: yyDollar[5].stmt.(*SelectStmt)} } - case 179: + case 181: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.exp = &InListExp{val: yyDollar[1].exp, notIn: yyDollar[2].boolean, values: yyDollar[5].values} } - case 180: + case 182: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].exp } - case 181: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.exp = yyDollar[2].exp - } - case 182: - yyDollar = yyS[yypt-2 : yypt+1] + case 183: + yyDollar = yyS[yypt-5 : yypt+1] { yyVAL.exp = &CaseWhenExp{ - whenThen: yyDollar[1].whenThenClauses, - elseExp: yyDollar[2].exp, + exp: yyDollar[2].exp, + whenThen: yyDollar[3].whenThenClauses, + elseExp: yyDollar[4].exp, } } - case 183: + case 184: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.whenThenClauses = []whenThenClause{{when: yyDollar[2].exp, then: yyDollar[4].exp}} } - case 184: + case 185: yyDollar = yyS[yypt-5 : yypt+1] { yyVAL.whenThenClauses = append(yyDollar[1].whenThenClauses, whenThenClause{when: yyDollar[3].exp, then: yyDollar[5].exp}) } - case 185: + case 186: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.exp = nil } - case 186: + case 187: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 187: + case 188: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].sel } - case 188: + case 189: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].value } - case 189: + case 190: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 190: + case 191: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.exp = &Cast{val: yyDollar[1].exp, t: yyDollar[3].sqlType} } - case 191: + case 192: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.boolean = false } - case 192: + case 193: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.boolean = true } - case 193: + case 194: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: ADDOP, right: yyDollar[3].exp} } - case 194: + case 195: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: SUBSOP, right: yyDollar[3].exp} } - case 195: + case 196: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: DIVOP, right: yyDollar[3].exp} } - case 196: + case 197: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: MULTOP, right: yyDollar[3].exp} } - case 197: + case 198: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: MODOP, right: yyDollar[3].exp} } - case 198: + case 199: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &BinBoolExp{left: yyDollar[1].exp, op: yyDollar[2].logicOp, right: yyDollar[3].exp} } - case 199: + case 200: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &CmpBoolExp{left: yyDollar[1].exp, op: yyDollar[2].cmpOp, right: yyDollar[3].exp} } - case 200: + case 201: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &CmpBoolExp{left: yyDollar[1].exp, op: EQ, right: &NullValue{t: AnyType}} } - case 201: + case 202: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.binExp = &CmpBoolExp{left: yyDollar[1].exp, op: NE, right: &NullValue{t: AnyType}} diff --git a/embedded/sql/stmt.go b/embedded/sql/stmt.go index 2a54b5b972..b8025637d3 100644 --- a/embedded/sql/stmt.go +++ b/embedded/sql/stmt.go @@ -2945,6 +2945,7 @@ type whenThenClause struct { } type CaseWhenExp struct { + exp ValueExp whenThen []whenThenClause elseExp ValueExp } @@ -2970,24 +2971,33 @@ func (ce *CaseWhenExp) inferType(cols map[string]ColDescriptor, params map[strin return t, nil } - inferredType := AnyType + searchType := BooleanType + inferredResType := AnyType + if ce.exp != nil { + t, err := ce.exp.inferType(cols, params, implicitTable) + if err != nil { + return "", err + } + searchType = t + } + for _, e := range ce.whenThen { whenType, err := e.when.inferType(cols, params, implicitTable) if err != nil { return "", err } - if whenType != BooleanType { - return "", fmt.Errorf("%w: argument of CASE/WHEN must be type %s, not type %s", ErrInvalidTypes, BooleanType, whenType) + if whenType != searchType { + return "", fmt.Errorf("%w: argument of CASE/WHEN must be of type %s, not type %s", ErrInvalidTypes, searchType, whenType) } - t, err := checkType(e.then, inferredType) + t, err := checkType(e.then, inferredResType) if err != nil { return "", err } - inferredType = t + inferredResType = t } - return checkType(ce.elseExp, inferredType) + return checkType(ce.elseExp, inferredResType) } func (ce *CaseWhenExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error { @@ -3003,6 +3013,15 @@ func (ce *CaseWhenExp) requiresType(t SQLValueType, cols map[string]ColDescripto } func (ce *CaseWhenExp) substitute(params map[string]interface{}) (ValueExp, error) { + var exp ValueExp + if ce.exp != nil { + e, err := ce.exp.substitute(params) + if err != nil { + return nil, err + } + exp = e + } + whenThen := make([]whenThenClause, len(ce.whenThen)) for i, wt := range ce.whenThen { whenValue, err := wt.when.substitute(params) @@ -3020,6 +3039,7 @@ func (ce *CaseWhenExp) substitute(params map[string]interface{}) (ValueExp, erro if ce.elseExp == nil { return &CaseWhenExp{ + exp: exp, whenThen: whenThen, }, nil } @@ -3029,6 +3049,7 @@ func (ce *CaseWhenExp) substitute(params map[string]interface{}) (ValueExp, erro return nil, err } return &CaseWhenExp{ + exp: exp, whenThen: whenThen, elseExp: elseValue, }, nil @@ -3036,6 +3057,9 @@ func (ce *CaseWhenExp) substitute(params map[string]interface{}) (ValueExp, erro func (ce *CaseWhenExp) selectors() []Selector { selectors := make([]Selector, 0) + if ce.exp != nil { + selectors = append(selectors, ce.exp.selectors()...) + } for _, wh := range ce.whenThen { selectors = append(selectors, wh.when.selectors()...) @@ -3049,17 +3073,32 @@ func (ce *CaseWhenExp) selectors() []Selector { } func (ce *CaseWhenExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) { + var searchValue TypedValue + if ce.exp != nil { + v, err := ce.exp.reduce(tx, row, implicitTable) + if err != nil { + return nil, err + } + searchValue = v + } else { + searchValue = &Bool{val: true} + } + for _, wt := range ce.whenThen { v, err := wt.when.reduce(tx, row, implicitTable) if err != nil { return nil, err } - if v.Type() != BooleanType { - return nil, fmt.Errorf("%w: argument of CASE/WHEN must be type %s, not type %s", ErrInvalidTypes, BooleanType, v.Type()) + if v.Type() != searchValue.Type() { + return nil, fmt.Errorf("%w: argument of CASE/WHEN must be type %s, not type %s", ErrInvalidTypes, v.Type(), searchValue.Type()) } - if v.RawValue() == true { + res, err := v.Compare(searchValue) + if err != nil { + return nil, err + } + if res == 0 { return wt.then.reduce(tx, row, implicitTable) } } diff --git a/embedded/sql/stmt_test.go b/embedded/sql/stmt_test.go index 5ec6f3d4f6..5f344ad63e 100644 --- a/embedded/sql/stmt_test.go +++ b/embedded/sql/stmt_test.go @@ -841,91 +841,151 @@ func TestYetUnsupportedInSubQueryExp(t *testing.T) { } func TestCaseWhenExp(t *testing.T) { - e, err := ParseExpFromString( - "CASE WHEN salary > 100000 THEN @p0 ELSE @p1 END", - ) - require.NoError(t, err) + t.Run("simple case", func(t *testing.T) { + e, err := ParseExpFromString( + "CASE job_title WHEN 1 THEN true ELSE false END", + ) + require.NoError(t, err) - e, err = e.substitute(map[string]interface{}{"p0": int64(0), "p1": int64(1)}) - require.NoError(t, err) + err = e.requiresType(BooleanType, map[string]ColDescriptor{ + EncodeSelector("", "", "job_title"): {Type: VarcharType}, + }, nil, "") + require.ErrorIs(t, err, ErrInvalidTypes) + require.ErrorContains(t, err, "argument of CASE/WHEN must be of type VARCHAR, not type INTEGER") - err = e.requiresType(IntegerType, map[string]ColDescriptor{ - EncodeSelector("", "", "salary"): {Type: IntegerType}, - }, nil, "") - require.NoError(t, err) + e, err = ParseExpFromString( + "CASE concat(@prefix, job_title) WHEN 'job_engineer' THEN true ELSE false END", + ) + require.NoError(t, err) - require.False(t, e.isConstant()) - require.Nil(t, e.selectorRanges(nil, "", nil, nil)) + e, err = e.substitute(map[string]interface{}{"prefix": "job_"}) + require.NoError(t, err) - row := &Row{ValuesBySelector: map[string]TypedValue{EncodeSelector("", "", "salary"): &Integer{50000}}} - require.Equal(t, - &CaseWhenExp{ - whenThen: []whenThenClause{ - { - when: NewCmpBoolExp(GT, &Integer{50000}, &Integer{100000}), then: &Integer{0}, - }, + v, err := e.reduce(nil, &Row{ + ValuesBySelector: map[string]TypedValue{ + EncodeSelector("", "", "job_title"): &Varchar{"engineer"}, }, - elseExp: &Integer{1}, - }, e.reduceSelectors(row, "")) + }, "") + require.NoError(t, err) + require.Equal(t, v, &Bool{true}) + }) - v, err := e.reduce(nil, row, "") - require.NoError(t, err) - require.Equal(t, int64(1), v.RawValue()) + t.Run("searched case", func(t *testing.T) { + e, err := ParseExpFromString( + "CASE WHEN salary > 100000 THEN @p0 ELSE @p1 END", + ) + require.NoError(t, err) + + e, err = e.substitute(map[string]interface{}{"p0": int64(0), "p1": int64(1)}) + require.NoError(t, err) + + err = e.requiresType(IntegerType, map[string]ColDescriptor{ + EncodeSelector("", "", "salary"): {Type: IntegerType}, + }, nil, "") + require.NoError(t, err) + + require.False(t, e.isConstant()) + require.Nil(t, e.selectorRanges(nil, "", nil, nil)) + + row := &Row{ValuesBySelector: map[string]TypedValue{EncodeSelector("", "", "salary"): &Integer{50000}}} + require.Equal(t, + &CaseWhenExp{ + whenThen: []whenThenClause{ + { + when: NewCmpBoolExp(GT, &Integer{50000}, &Integer{100000}), then: &Integer{0}, + }, + }, + elseExp: &Integer{1}, + }, e.reduceSelectors(row, "")) + + v, err := e.reduce(nil, row, "") + require.NoError(t, err) + require.Equal(t, int64(1), v.RawValue()) + }) } func TestInferTypeCaseWhenExp(t *testing.T) { - e, err := ParseExpFromString( - "CASE WHEN salary THEN 10 ELSE '0' END", - ) - require.NoError(t, err) + t.Run("simple case", func(t *testing.T) { + e, err := ParseExpFromString( + "CASE department WHEN 'engineering' THEN 0 ELSE 1 END", + ) + require.NoError(t, err) - _, err = e.inferType( - map[string]ColDescriptor{ - EncodeSelector("", "", "salary"): {Type: IntegerType}, - }, - nil, - "", - ) - require.ErrorIs(t, err, ErrInvalidTypes) + _, err = e.inferType( + map[string]ColDescriptor{ + EncodeSelector("", "", "department"): {Type: IntegerType}, + }, + nil, + "", + ) + require.ErrorIs(t, err, ErrInvalidTypes) + require.ErrorContains(t, err, "argument of CASE/WHEN must be of type INTEGER, not type VARCHAR") - e, err = ParseExpFromString( - "CASE WHEN salary > 0 THEN 10 ELSE '0' END", - ) - require.NoError(t, err) + it, err := e.inferType( + map[string]ColDescriptor{ + EncodeSelector("", "", "department"): {Type: VarcharType}, + }, + nil, + "", + ) + require.NoError(t, err) + require.Equal(t, IntegerType, it) + }) - _, err = e.inferType( - map[string]ColDescriptor{ - EncodeSelector("", "", "salary"): {Type: IntegerType}, - }, - nil, - "", - ) - require.ErrorIs(t, err, ErrInferredMultipleTypes) + t.Run("searched case", func(t *testing.T) { + e, err := ParseExpFromString( + "CASE WHEN salary THEN 10 ELSE '0' END", + ) + require.NoError(t, err) - e, err = ParseExpFromString( - "CASE WHEN salary > 0 THEN 10 ELSE 0 END", - ) - require.NoError(t, err) + _, err = e.inferType( + map[string]ColDescriptor{ + EncodeSelector("", "", "salary"): {Type: IntegerType}, + }, + nil, + "", + ) + require.ErrorIs(t, err, ErrInvalidTypes) - it, err := e.inferType( - map[string]ColDescriptor{ - EncodeSelector("", "", "salary"): {Type: IntegerType}, - }, - nil, - "", - ) - require.NoError(t, err) - require.Equal(t, IntegerType, it) + e, err = ParseExpFromString( + "CASE WHEN salary > 0 THEN 10 ELSE '0' END", + ) + require.NoError(t, err) - it, err = e.inferType( - map[string]ColDescriptor{ - EncodeSelector("", "", "salary"): {Type: Float64Type}, - }, - nil, - "", - ) - require.NoError(t, err) - require.Equal(t, IntegerType, it) + _, err = e.inferType( + map[string]ColDescriptor{ + EncodeSelector("", "", "salary"): {Type: IntegerType}, + }, + nil, + "", + ) + require.ErrorIs(t, err, ErrInferredMultipleTypes) + + e, err = ParseExpFromString( + "CASE WHEN salary > 0 THEN 10 ELSE 0 END", + ) + require.NoError(t, err) + + it, err := e.inferType( + map[string]ColDescriptor{ + EncodeSelector("", "", "salary"): {Type: IntegerType}, + }, + nil, + "", + ) + require.NoError(t, err) + require.Equal(t, IntegerType, it) + + it, err = e.inferType( + map[string]ColDescriptor{ + EncodeSelector("", "", "salary"): {Type: Float64Type}, + }, + nil, + "", + ) + require.NoError(t, err) + require.Equal(t, IntegerType, it) + }) } func TestLikeBoolExpEdgeCases(t *testing.T) {