mirror of
https://github.com/PostHog/posthog.git
synced 2024-11-21 13:39:22 +01:00
feat: add "INTERSECT" and "EXCEPT" to HogQL (#25737)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
e6877d3436
commit
447a18930f
File diff suppressed because it is too large
Load Diff
@ -16,32 +16,33 @@ public:
|
||||
ASOF = 8, BETWEEN = 9, BOTH = 10, BY = 11, CASE = 12, CAST = 13, CATCH = 14,
|
||||
COHORT = 15, COLLATE = 16, CROSS = 17, CUBE = 18, CURRENT = 19, DATE = 20,
|
||||
DAY = 21, DESC = 22, DESCENDING = 23, DISTINCT = 24, ELSE = 25, END = 26,
|
||||
EXTRACT = 27, FINAL = 28, FINALLY = 29, FIRST = 30, FN = 31, FOLLOWING = 32,
|
||||
FOR = 33, FROM = 34, FULL = 35, FUN = 36, GROUP = 37, HAVING = 38, HOUR = 39,
|
||||
ID = 40, IF = 41, ILIKE = 42, IN = 43, INF = 44, INNER = 45, INTERVAL = 46,
|
||||
IS = 47, JOIN = 48, KEY = 49, LAST = 50, LEADING = 51, LEFT = 52, LET = 53,
|
||||
LIKE = 54, LIMIT = 55, MINUTE = 56, MONTH = 57, NAN_SQL = 58, NOT = 59,
|
||||
NULL_SQL = 60, NULLS = 61, OFFSET = 62, ON = 63, OR = 64, ORDER = 65,
|
||||
OUTER = 66, OVER = 67, PARTITION = 68, PRECEDING = 69, PREWHERE = 70,
|
||||
QUARTER = 71, RANGE = 72, RETURN = 73, RIGHT = 74, ROLLUP = 75, ROW = 76,
|
||||
ROWS = 77, SAMPLE = 78, SECOND = 79, SELECT = 80, SEMI = 81, SETTINGS = 82,
|
||||
SUBSTRING = 83, THEN = 84, THROW = 85, TIES = 86, TIMESTAMP = 87, TO = 88,
|
||||
TOP = 89, TOTALS = 90, TRAILING = 91, TRIM = 92, TRUNCATE = 93, TRY = 94,
|
||||
UNBOUNDED = 95, UNION = 96, USING = 97, WEEK = 98, WHEN = 99, WHERE = 100,
|
||||
WHILE = 101, WINDOW = 102, WITH = 103, YEAR = 104, ESCAPE_CHAR_COMMON = 105,
|
||||
IDENTIFIER = 106, FLOATING_LITERAL = 107, OCTAL_LITERAL = 108, DECIMAL_LITERAL = 109,
|
||||
HEXADECIMAL_LITERAL = 110, STRING_LITERAL = 111, ARROW = 112, ASTERISK = 113,
|
||||
BACKQUOTE = 114, BACKSLASH = 115, COLON = 116, COMMA = 117, CONCAT = 118,
|
||||
DASH = 119, DOLLAR = 120, DOT = 121, EQ_DOUBLE = 122, EQ_SINGLE = 123,
|
||||
GT_EQ = 124, GT = 125, HASH = 126, IREGEX_SINGLE = 127, IREGEX_DOUBLE = 128,
|
||||
LBRACE = 129, LBRACKET = 130, LPAREN = 131, LT_EQ = 132, LT = 133, NOT_EQ = 134,
|
||||
NOT_IREGEX = 135, NOT_REGEX = 136, NULL_PROPERTY = 137, NULLISH = 138,
|
||||
PERCENT = 139, PLUS = 140, QUERY = 141, QUOTE_DOUBLE = 142, QUOTE_SINGLE_TEMPLATE = 143,
|
||||
QUOTE_SINGLE_TEMPLATE_FULL = 144, QUOTE_SINGLE = 145, REGEX_SINGLE = 146,
|
||||
REGEX_DOUBLE = 147, RBRACE = 148, RBRACKET = 149, RPAREN = 150, SEMICOLON = 151,
|
||||
SLASH = 152, UNDERSCORE = 153, MULTI_LINE_COMMENT = 154, SINGLE_LINE_COMMENT = 155,
|
||||
WHITESPACE = 156, STRING_TEXT = 157, STRING_ESCAPE_TRIGGER = 158, FULL_STRING_TEXT = 159,
|
||||
FULL_STRING_ESCAPE_TRIGGER = 160
|
||||
EXCEPT = 27, EXTRACT = 28, FINAL = 29, FINALLY = 30, FIRST = 31, FN = 32,
|
||||
FOLLOWING = 33, FOR = 34, FROM = 35, FULL = 36, FUN = 37, GROUP = 38,
|
||||
HAVING = 39, HOUR = 40, ID = 41, IF = 42, ILIKE = 43, IN = 44, INF = 45,
|
||||
INNER = 46, INTERSECT = 47, INTERVAL = 48, IS = 49, JOIN = 50, KEY = 51,
|
||||
LAST = 52, LEADING = 53, LEFT = 54, LET = 55, LIKE = 56, LIMIT = 57,
|
||||
MINUTE = 58, MONTH = 59, NAN_SQL = 60, NOT = 61, NULL_SQL = 62, NULLS = 63,
|
||||
OFFSET = 64, ON = 65, OR = 66, ORDER = 67, OUTER = 68, OVER = 69, PARTITION = 70,
|
||||
PRECEDING = 71, PREWHERE = 72, QUARTER = 73, RANGE = 74, RETURN = 75,
|
||||
RIGHT = 76, ROLLUP = 77, ROW = 78, ROWS = 79, SAMPLE = 80, SECOND = 81,
|
||||
SELECT = 82, SEMI = 83, SETTINGS = 84, SUBSTRING = 85, THEN = 86, THROW = 87,
|
||||
TIES = 88, TIMESTAMP = 89, TO = 90, TOP = 91, TOTALS = 92, TRAILING = 93,
|
||||
TRIM = 94, TRUNCATE = 95, TRY = 96, UNBOUNDED = 97, UNION = 98, USING = 99,
|
||||
WEEK = 100, WHEN = 101, WHERE = 102, WHILE = 103, WINDOW = 104, WITH = 105,
|
||||
YEAR = 106, ESCAPE_CHAR_COMMON = 107, IDENTIFIER = 108, FLOATING_LITERAL = 109,
|
||||
OCTAL_LITERAL = 110, DECIMAL_LITERAL = 111, HEXADECIMAL_LITERAL = 112,
|
||||
STRING_LITERAL = 113, ARROW = 114, ASTERISK = 115, BACKQUOTE = 116,
|
||||
BACKSLASH = 117, COLON = 118, COMMA = 119, CONCAT = 120, DASH = 121,
|
||||
DOLLAR = 122, DOT = 123, EQ_DOUBLE = 124, EQ_SINGLE = 125, GT_EQ = 126,
|
||||
GT = 127, HASH = 128, IREGEX_SINGLE = 129, IREGEX_DOUBLE = 130, LBRACE = 131,
|
||||
LBRACKET = 132, LPAREN = 133, LT_EQ = 134, LT = 135, NOT_EQ = 136, NOT_IREGEX = 137,
|
||||
NOT_REGEX = 138, NULL_PROPERTY = 139, NULLISH = 140, PERCENT = 141,
|
||||
PLUS = 142, QUERY = 143, QUOTE_DOUBLE = 144, QUOTE_SINGLE_TEMPLATE = 145,
|
||||
QUOTE_SINGLE_TEMPLATE_FULL = 146, QUOTE_SINGLE = 147, REGEX_SINGLE = 148,
|
||||
REGEX_DOUBLE = 149, RBRACE = 150, RBRACKET = 151, RPAREN = 152, SEMICOLON = 153,
|
||||
SLASH = 154, UNDERSCORE = 155, MULTI_LINE_COMMENT = 156, SINGLE_LINE_COMMENT = 157,
|
||||
WHITESPACE = 158, STRING_TEXT = 159, STRING_ESCAPE_TRIGGER = 160, FULL_STRING_TEXT = 161,
|
||||
FULL_STRING_ESCAPE_TRIGGER = 162
|
||||
};
|
||||
|
||||
enum {
|
||||
|
File diff suppressed because one or more lines are too long
@ -24,178 +24,180 @@ DESCENDING=23
|
||||
DISTINCT=24
|
||||
ELSE=25
|
||||
END=26
|
||||
EXTRACT=27
|
||||
FINAL=28
|
||||
FINALLY=29
|
||||
FIRST=30
|
||||
FN=31
|
||||
FOLLOWING=32
|
||||
FOR=33
|
||||
FROM=34
|
||||
FULL=35
|
||||
FUN=36
|
||||
GROUP=37
|
||||
HAVING=38
|
||||
HOUR=39
|
||||
ID=40
|
||||
IF=41
|
||||
ILIKE=42
|
||||
IN=43
|
||||
INF=44
|
||||
INNER=45
|
||||
INTERVAL=46
|
||||
IS=47
|
||||
JOIN=48
|
||||
KEY=49
|
||||
LAST=50
|
||||
LEADING=51
|
||||
LEFT=52
|
||||
LET=53
|
||||
LIKE=54
|
||||
LIMIT=55
|
||||
MINUTE=56
|
||||
MONTH=57
|
||||
NAN_SQL=58
|
||||
NOT=59
|
||||
NULL_SQL=60
|
||||
NULLS=61
|
||||
OFFSET=62
|
||||
ON=63
|
||||
OR=64
|
||||
ORDER=65
|
||||
OUTER=66
|
||||
OVER=67
|
||||
PARTITION=68
|
||||
PRECEDING=69
|
||||
PREWHERE=70
|
||||
QUARTER=71
|
||||
RANGE=72
|
||||
RETURN=73
|
||||
RIGHT=74
|
||||
ROLLUP=75
|
||||
ROW=76
|
||||
ROWS=77
|
||||
SAMPLE=78
|
||||
SECOND=79
|
||||
SELECT=80
|
||||
SEMI=81
|
||||
SETTINGS=82
|
||||
SUBSTRING=83
|
||||
THEN=84
|
||||
THROW=85
|
||||
TIES=86
|
||||
TIMESTAMP=87
|
||||
TO=88
|
||||
TOP=89
|
||||
TOTALS=90
|
||||
TRAILING=91
|
||||
TRIM=92
|
||||
TRUNCATE=93
|
||||
TRY=94
|
||||
UNBOUNDED=95
|
||||
UNION=96
|
||||
USING=97
|
||||
WEEK=98
|
||||
WHEN=99
|
||||
WHERE=100
|
||||
WHILE=101
|
||||
WINDOW=102
|
||||
WITH=103
|
||||
YEAR=104
|
||||
ESCAPE_CHAR_COMMON=105
|
||||
IDENTIFIER=106
|
||||
FLOATING_LITERAL=107
|
||||
OCTAL_LITERAL=108
|
||||
DECIMAL_LITERAL=109
|
||||
HEXADECIMAL_LITERAL=110
|
||||
STRING_LITERAL=111
|
||||
ARROW=112
|
||||
ASTERISK=113
|
||||
BACKQUOTE=114
|
||||
BACKSLASH=115
|
||||
COLON=116
|
||||
COMMA=117
|
||||
CONCAT=118
|
||||
DASH=119
|
||||
DOLLAR=120
|
||||
DOT=121
|
||||
EQ_DOUBLE=122
|
||||
EQ_SINGLE=123
|
||||
GT_EQ=124
|
||||
GT=125
|
||||
HASH=126
|
||||
IREGEX_SINGLE=127
|
||||
IREGEX_DOUBLE=128
|
||||
LBRACE=129
|
||||
LBRACKET=130
|
||||
LPAREN=131
|
||||
LT_EQ=132
|
||||
LT=133
|
||||
NOT_EQ=134
|
||||
NOT_IREGEX=135
|
||||
NOT_REGEX=136
|
||||
NULL_PROPERTY=137
|
||||
NULLISH=138
|
||||
PERCENT=139
|
||||
PLUS=140
|
||||
QUERY=141
|
||||
QUOTE_DOUBLE=142
|
||||
QUOTE_SINGLE_TEMPLATE=143
|
||||
QUOTE_SINGLE_TEMPLATE_FULL=144
|
||||
QUOTE_SINGLE=145
|
||||
REGEX_SINGLE=146
|
||||
REGEX_DOUBLE=147
|
||||
RBRACE=148
|
||||
RBRACKET=149
|
||||
RPAREN=150
|
||||
SEMICOLON=151
|
||||
SLASH=152
|
||||
UNDERSCORE=153
|
||||
MULTI_LINE_COMMENT=154
|
||||
SINGLE_LINE_COMMENT=155
|
||||
WHITESPACE=156
|
||||
STRING_TEXT=157
|
||||
STRING_ESCAPE_TRIGGER=158
|
||||
FULL_STRING_TEXT=159
|
||||
FULL_STRING_ESCAPE_TRIGGER=160
|
||||
'->'=112
|
||||
'*'=113
|
||||
'`'=114
|
||||
'\\'=115
|
||||
':'=116
|
||||
','=117
|
||||
'||'=118
|
||||
'-'=119
|
||||
'$'=120
|
||||
'.'=121
|
||||
'=='=122
|
||||
'='=123
|
||||
'>='=124
|
||||
'>'=125
|
||||
'#'=126
|
||||
'~*'=127
|
||||
'=~*'=128
|
||||
'{'=129
|
||||
'['=130
|
||||
'('=131
|
||||
'<='=132
|
||||
'<'=133
|
||||
'!~*'=135
|
||||
'!~'=136
|
||||
'?.'=137
|
||||
'??'=138
|
||||
'%'=139
|
||||
'+'=140
|
||||
'?'=141
|
||||
'"'=142
|
||||
'f\''=143
|
||||
'F\''=144
|
||||
'\''=145
|
||||
'~'=146
|
||||
'=~'=147
|
||||
'}'=148
|
||||
']'=149
|
||||
')'=150
|
||||
';'=151
|
||||
'/'=152
|
||||
'_'=153
|
||||
EXCEPT=27
|
||||
EXTRACT=28
|
||||
FINAL=29
|
||||
FINALLY=30
|
||||
FIRST=31
|
||||
FN=32
|
||||
FOLLOWING=33
|
||||
FOR=34
|
||||
FROM=35
|
||||
FULL=36
|
||||
FUN=37
|
||||
GROUP=38
|
||||
HAVING=39
|
||||
HOUR=40
|
||||
ID=41
|
||||
IF=42
|
||||
ILIKE=43
|
||||
IN=44
|
||||
INF=45
|
||||
INNER=46
|
||||
INTERSECT=47
|
||||
INTERVAL=48
|
||||
IS=49
|
||||
JOIN=50
|
||||
KEY=51
|
||||
LAST=52
|
||||
LEADING=53
|
||||
LEFT=54
|
||||
LET=55
|
||||
LIKE=56
|
||||
LIMIT=57
|
||||
MINUTE=58
|
||||
MONTH=59
|
||||
NAN_SQL=60
|
||||
NOT=61
|
||||
NULL_SQL=62
|
||||
NULLS=63
|
||||
OFFSET=64
|
||||
ON=65
|
||||
OR=66
|
||||
ORDER=67
|
||||
OUTER=68
|
||||
OVER=69
|
||||
PARTITION=70
|
||||
PRECEDING=71
|
||||
PREWHERE=72
|
||||
QUARTER=73
|
||||
RANGE=74
|
||||
RETURN=75
|
||||
RIGHT=76
|
||||
ROLLUP=77
|
||||
ROW=78
|
||||
ROWS=79
|
||||
SAMPLE=80
|
||||
SECOND=81
|
||||
SELECT=82
|
||||
SEMI=83
|
||||
SETTINGS=84
|
||||
SUBSTRING=85
|
||||
THEN=86
|
||||
THROW=87
|
||||
TIES=88
|
||||
TIMESTAMP=89
|
||||
TO=90
|
||||
TOP=91
|
||||
TOTALS=92
|
||||
TRAILING=93
|
||||
TRIM=94
|
||||
TRUNCATE=95
|
||||
TRY=96
|
||||
UNBOUNDED=97
|
||||
UNION=98
|
||||
USING=99
|
||||
WEEK=100
|
||||
WHEN=101
|
||||
WHERE=102
|
||||
WHILE=103
|
||||
WINDOW=104
|
||||
WITH=105
|
||||
YEAR=106
|
||||
ESCAPE_CHAR_COMMON=107
|
||||
IDENTIFIER=108
|
||||
FLOATING_LITERAL=109
|
||||
OCTAL_LITERAL=110
|
||||
DECIMAL_LITERAL=111
|
||||
HEXADECIMAL_LITERAL=112
|
||||
STRING_LITERAL=113
|
||||
ARROW=114
|
||||
ASTERISK=115
|
||||
BACKQUOTE=116
|
||||
BACKSLASH=117
|
||||
COLON=118
|
||||
COMMA=119
|
||||
CONCAT=120
|
||||
DASH=121
|
||||
DOLLAR=122
|
||||
DOT=123
|
||||
EQ_DOUBLE=124
|
||||
EQ_SINGLE=125
|
||||
GT_EQ=126
|
||||
GT=127
|
||||
HASH=128
|
||||
IREGEX_SINGLE=129
|
||||
IREGEX_DOUBLE=130
|
||||
LBRACE=131
|
||||
LBRACKET=132
|
||||
LPAREN=133
|
||||
LT_EQ=134
|
||||
LT=135
|
||||
NOT_EQ=136
|
||||
NOT_IREGEX=137
|
||||
NOT_REGEX=138
|
||||
NULL_PROPERTY=139
|
||||
NULLISH=140
|
||||
PERCENT=141
|
||||
PLUS=142
|
||||
QUERY=143
|
||||
QUOTE_DOUBLE=144
|
||||
QUOTE_SINGLE_TEMPLATE=145
|
||||
QUOTE_SINGLE_TEMPLATE_FULL=146
|
||||
QUOTE_SINGLE=147
|
||||
REGEX_SINGLE=148
|
||||
REGEX_DOUBLE=149
|
||||
RBRACE=150
|
||||
RBRACKET=151
|
||||
RPAREN=152
|
||||
SEMICOLON=153
|
||||
SLASH=154
|
||||
UNDERSCORE=155
|
||||
MULTI_LINE_COMMENT=156
|
||||
SINGLE_LINE_COMMENT=157
|
||||
WHITESPACE=158
|
||||
STRING_TEXT=159
|
||||
STRING_ESCAPE_TRIGGER=160
|
||||
FULL_STRING_TEXT=161
|
||||
FULL_STRING_ESCAPE_TRIGGER=162
|
||||
'->'=114
|
||||
'*'=115
|
||||
'`'=116
|
||||
'\\'=117
|
||||
':'=118
|
||||
','=119
|
||||
'||'=120
|
||||
'-'=121
|
||||
'$'=122
|
||||
'.'=123
|
||||
'=='=124
|
||||
'='=125
|
||||
'>='=126
|
||||
'>'=127
|
||||
'#'=128
|
||||
'~*'=129
|
||||
'=~*'=130
|
||||
'{'=131
|
||||
'['=132
|
||||
'('=133
|
||||
'<='=134
|
||||
'<'=135
|
||||
'!~*'=137
|
||||
'!~'=138
|
||||
'?.'=139
|
||||
'??'=140
|
||||
'%'=141
|
||||
'+'=142
|
||||
'?'=143
|
||||
'"'=144
|
||||
'f\''=145
|
||||
'F\''=146
|
||||
'\''=147
|
||||
'~'=148
|
||||
'=~'=149
|
||||
'}'=150
|
||||
']'=151
|
||||
')'=152
|
||||
';'=153
|
||||
'/'=154
|
||||
'_'=155
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,32 +16,33 @@ public:
|
||||
ASOF = 8, BETWEEN = 9, BOTH = 10, BY = 11, CASE = 12, CAST = 13, CATCH = 14,
|
||||
COHORT = 15, COLLATE = 16, CROSS = 17, CUBE = 18, CURRENT = 19, DATE = 20,
|
||||
DAY = 21, DESC = 22, DESCENDING = 23, DISTINCT = 24, ELSE = 25, END = 26,
|
||||
EXTRACT = 27, FINAL = 28, FINALLY = 29, FIRST = 30, FN = 31, FOLLOWING = 32,
|
||||
FOR = 33, FROM = 34, FULL = 35, FUN = 36, GROUP = 37, HAVING = 38, HOUR = 39,
|
||||
ID = 40, IF = 41, ILIKE = 42, IN = 43, INF = 44, INNER = 45, INTERVAL = 46,
|
||||
IS = 47, JOIN = 48, KEY = 49, LAST = 50, LEADING = 51, LEFT = 52, LET = 53,
|
||||
LIKE = 54, LIMIT = 55, MINUTE = 56, MONTH = 57, NAN_SQL = 58, NOT = 59,
|
||||
NULL_SQL = 60, NULLS = 61, OFFSET = 62, ON = 63, OR = 64, ORDER = 65,
|
||||
OUTER = 66, OVER = 67, PARTITION = 68, PRECEDING = 69, PREWHERE = 70,
|
||||
QUARTER = 71, RANGE = 72, RETURN = 73, RIGHT = 74, ROLLUP = 75, ROW = 76,
|
||||
ROWS = 77, SAMPLE = 78, SECOND = 79, SELECT = 80, SEMI = 81, SETTINGS = 82,
|
||||
SUBSTRING = 83, THEN = 84, THROW = 85, TIES = 86, TIMESTAMP = 87, TO = 88,
|
||||
TOP = 89, TOTALS = 90, TRAILING = 91, TRIM = 92, TRUNCATE = 93, TRY = 94,
|
||||
UNBOUNDED = 95, UNION = 96, USING = 97, WEEK = 98, WHEN = 99, WHERE = 100,
|
||||
WHILE = 101, WINDOW = 102, WITH = 103, YEAR = 104, ESCAPE_CHAR_COMMON = 105,
|
||||
IDENTIFIER = 106, FLOATING_LITERAL = 107, OCTAL_LITERAL = 108, DECIMAL_LITERAL = 109,
|
||||
HEXADECIMAL_LITERAL = 110, STRING_LITERAL = 111, ARROW = 112, ASTERISK = 113,
|
||||
BACKQUOTE = 114, BACKSLASH = 115, COLON = 116, COMMA = 117, CONCAT = 118,
|
||||
DASH = 119, DOLLAR = 120, DOT = 121, EQ_DOUBLE = 122, EQ_SINGLE = 123,
|
||||
GT_EQ = 124, GT = 125, HASH = 126, IREGEX_SINGLE = 127, IREGEX_DOUBLE = 128,
|
||||
LBRACE = 129, LBRACKET = 130, LPAREN = 131, LT_EQ = 132, LT = 133, NOT_EQ = 134,
|
||||
NOT_IREGEX = 135, NOT_REGEX = 136, NULL_PROPERTY = 137, NULLISH = 138,
|
||||
PERCENT = 139, PLUS = 140, QUERY = 141, QUOTE_DOUBLE = 142, QUOTE_SINGLE_TEMPLATE = 143,
|
||||
QUOTE_SINGLE_TEMPLATE_FULL = 144, QUOTE_SINGLE = 145, REGEX_SINGLE = 146,
|
||||
REGEX_DOUBLE = 147, RBRACE = 148, RBRACKET = 149, RPAREN = 150, SEMICOLON = 151,
|
||||
SLASH = 152, UNDERSCORE = 153, MULTI_LINE_COMMENT = 154, SINGLE_LINE_COMMENT = 155,
|
||||
WHITESPACE = 156, STRING_TEXT = 157, STRING_ESCAPE_TRIGGER = 158, FULL_STRING_TEXT = 159,
|
||||
FULL_STRING_ESCAPE_TRIGGER = 160
|
||||
EXCEPT = 27, EXTRACT = 28, FINAL = 29, FINALLY = 30, FIRST = 31, FN = 32,
|
||||
FOLLOWING = 33, FOR = 34, FROM = 35, FULL = 36, FUN = 37, GROUP = 38,
|
||||
HAVING = 39, HOUR = 40, ID = 41, IF = 42, ILIKE = 43, IN = 44, INF = 45,
|
||||
INNER = 46, INTERSECT = 47, INTERVAL = 48, IS = 49, JOIN = 50, KEY = 51,
|
||||
LAST = 52, LEADING = 53, LEFT = 54, LET = 55, LIKE = 56, LIMIT = 57,
|
||||
MINUTE = 58, MONTH = 59, NAN_SQL = 60, NOT = 61, NULL_SQL = 62, NULLS = 63,
|
||||
OFFSET = 64, ON = 65, OR = 66, ORDER = 67, OUTER = 68, OVER = 69, PARTITION = 70,
|
||||
PRECEDING = 71, PREWHERE = 72, QUARTER = 73, RANGE = 74, RETURN = 75,
|
||||
RIGHT = 76, ROLLUP = 77, ROW = 78, ROWS = 79, SAMPLE = 80, SECOND = 81,
|
||||
SELECT = 82, SEMI = 83, SETTINGS = 84, SUBSTRING = 85, THEN = 86, THROW = 87,
|
||||
TIES = 88, TIMESTAMP = 89, TO = 90, TOP = 91, TOTALS = 92, TRAILING = 93,
|
||||
TRIM = 94, TRUNCATE = 95, TRY = 96, UNBOUNDED = 97, UNION = 98, USING = 99,
|
||||
WEEK = 100, WHEN = 101, WHERE = 102, WHILE = 103, WINDOW = 104, WITH = 105,
|
||||
YEAR = 106, ESCAPE_CHAR_COMMON = 107, IDENTIFIER = 108, FLOATING_LITERAL = 109,
|
||||
OCTAL_LITERAL = 110, DECIMAL_LITERAL = 111, HEXADECIMAL_LITERAL = 112,
|
||||
STRING_LITERAL = 113, ARROW = 114, ASTERISK = 115, BACKQUOTE = 116,
|
||||
BACKSLASH = 117, COLON = 118, COMMA = 119, CONCAT = 120, DASH = 121,
|
||||
DOLLAR = 122, DOT = 123, EQ_DOUBLE = 124, EQ_SINGLE = 125, GT_EQ = 126,
|
||||
GT = 127, HASH = 128, IREGEX_SINGLE = 129, IREGEX_DOUBLE = 130, LBRACE = 131,
|
||||
LBRACKET = 132, LPAREN = 133, LT_EQ = 134, LT = 135, NOT_EQ = 136, NOT_IREGEX = 137,
|
||||
NOT_REGEX = 138, NULL_PROPERTY = 139, NULLISH = 140, PERCENT = 141,
|
||||
PLUS = 142, QUERY = 143, QUOTE_DOUBLE = 144, QUOTE_SINGLE_TEMPLATE = 145,
|
||||
QUOTE_SINGLE_TEMPLATE_FULL = 146, QUOTE_SINGLE = 147, REGEX_SINGLE = 148,
|
||||
REGEX_DOUBLE = 149, RBRACE = 150, RBRACKET = 151, RPAREN = 152, SEMICOLON = 153,
|
||||
SLASH = 154, UNDERSCORE = 155, MULTI_LINE_COMMENT = 156, SINGLE_LINE_COMMENT = 157,
|
||||
WHITESPACE = 158, STRING_TEXT = 159, STRING_ESCAPE_TRIGGER = 160, FULL_STRING_TEXT = 161,
|
||||
FULL_STRING_ESCAPE_TRIGGER = 162
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -50,26 +51,27 @@ public:
|
||||
RuleCatchBlock = 8, RuleTryCatchStmt = 9, RuleIfStmt = 10, RuleWhileStmt = 11,
|
||||
RuleForStmt = 12, RuleForInStmt = 13, RuleFuncStmt = 14, RuleVarAssignment = 15,
|
||||
RuleExprStmt = 16, RuleEmptyStmt = 17, RuleBlock = 18, RuleKvPair = 19,
|
||||
RuleKvPairList = 20, RuleSelect = 21, RuleSelectUnionStmt = 22, RuleSelectStmtWithParens = 23,
|
||||
RuleSelectStmt = 24, RuleWithClause = 25, RuleTopClause = 26, RuleFromClause = 27,
|
||||
RuleArrayJoinClause = 28, RuleWindowClause = 29, RulePrewhereClause = 30,
|
||||
RuleWhereClause = 31, RuleGroupByClause = 32, RuleHavingClause = 33,
|
||||
RuleOrderByClause = 34, RuleProjectionOrderByClause = 35, RuleLimitAndOffsetClause = 36,
|
||||
RuleOffsetOnlyClause = 37, RuleSettingsClause = 38, RuleJoinExpr = 39,
|
||||
RuleJoinOp = 40, RuleJoinOpCross = 41, RuleJoinConstraintClause = 42,
|
||||
RuleSampleClause = 43, RuleOrderExprList = 44, RuleOrderExpr = 45, RuleRatioExpr = 46,
|
||||
RuleSettingExprList = 47, RuleSettingExpr = 48, RuleWindowExpr = 49,
|
||||
RuleWinPartitionByClause = 50, RuleWinOrderByClause = 51, RuleWinFrameClause = 52,
|
||||
RuleWinFrameExtend = 53, RuleWinFrameBound = 54, RuleExpr = 55, RuleColumnTypeExpr = 56,
|
||||
RuleColumnExprList = 57, RuleColumnExpr = 58, RuleColumnLambdaExpr = 59,
|
||||
RuleHogqlxTagElement = 60, RuleHogqlxTagAttribute = 61, RuleWithExprList = 62,
|
||||
RuleWithExpr = 63, RuleColumnIdentifier = 64, RuleNestedIdentifier = 65,
|
||||
RuleTableExpr = 66, RuleTableFunctionExpr = 67, RuleTableIdentifier = 68,
|
||||
RuleTableArgList = 69, RuleDatabaseIdentifier = 70, RuleFloatingLiteral = 71,
|
||||
RuleNumberLiteral = 72, RuleLiteral = 73, RuleInterval = 74, RuleKeyword = 75,
|
||||
RuleKeywordForAlias = 76, RuleAlias = 77, RuleIdentifier = 78, RuleEnumValue = 79,
|
||||
RulePlaceholder = 80, RuleString = 81, RuleTemplateString = 82, RuleStringContents = 83,
|
||||
RuleFullTemplateString = 84, RuleStringContentsFull = 85
|
||||
RuleKvPairList = 20, RuleSelect = 21, RuleSelectStmtWithParens = 22,
|
||||
RuleSubsequentSelectSetClause = 23, RuleSelectSetStmt = 24, RuleSelectStmt = 25,
|
||||
RuleWithClause = 26, RuleTopClause = 27, RuleFromClause = 28, RuleArrayJoinClause = 29,
|
||||
RuleWindowClause = 30, RulePrewhereClause = 31, RuleWhereClause = 32,
|
||||
RuleGroupByClause = 33, RuleHavingClause = 34, RuleOrderByClause = 35,
|
||||
RuleProjectionOrderByClause = 36, RuleLimitAndOffsetClause = 37, RuleOffsetOnlyClause = 38,
|
||||
RuleSettingsClause = 39, RuleJoinExpr = 40, RuleJoinOp = 41, RuleJoinOpCross = 42,
|
||||
RuleJoinConstraintClause = 43, RuleSampleClause = 44, RuleOrderExprList = 45,
|
||||
RuleOrderExpr = 46, RuleRatioExpr = 47, RuleSettingExprList = 48, RuleSettingExpr = 49,
|
||||
RuleWindowExpr = 50, RuleWinPartitionByClause = 51, RuleWinOrderByClause = 52,
|
||||
RuleWinFrameClause = 53, RuleWinFrameExtend = 54, RuleWinFrameBound = 55,
|
||||
RuleExpr = 56, RuleColumnTypeExpr = 57, RuleColumnExprList = 58, RuleColumnExpr = 59,
|
||||
RuleColumnLambdaExpr = 60, RuleHogqlxTagElement = 61, RuleHogqlxTagAttribute = 62,
|
||||
RuleWithExprList = 63, RuleWithExpr = 64, RuleColumnIdentifier = 65,
|
||||
RuleNestedIdentifier = 66, RuleTableExpr = 67, RuleTableFunctionExpr = 68,
|
||||
RuleTableIdentifier = 69, RuleTableArgList = 70, RuleDatabaseIdentifier = 71,
|
||||
RuleFloatingLiteral = 72, RuleNumberLiteral = 73, RuleLiteral = 74,
|
||||
RuleInterval = 75, RuleKeyword = 76, RuleKeywordForAlias = 77, RuleAlias = 78,
|
||||
RuleIdentifier = 79, RuleEnumValue = 80, RulePlaceholder = 81, RuleString = 82,
|
||||
RuleTemplateString = 83, RuleStringContents = 84, RuleFullTemplateString = 85,
|
||||
RuleStringContentsFull = 86
|
||||
};
|
||||
|
||||
explicit HogQLParser(antlr4::TokenStream *input);
|
||||
@ -111,8 +113,9 @@ public:
|
||||
class KvPairContext;
|
||||
class KvPairListContext;
|
||||
class SelectContext;
|
||||
class SelectUnionStmtContext;
|
||||
class SelectStmtWithParensContext;
|
||||
class SubsequentSelectSetClauseContext;
|
||||
class SelectSetStmtContext;
|
||||
class SelectStmtContext;
|
||||
class WithClauseContext;
|
||||
class TopClauseContext;
|
||||
@ -552,7 +555,7 @@ public:
|
||||
SelectContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
antlr4::tree::TerminalNode *EOF();
|
||||
SelectUnionStmtContext *selectUnionStmt();
|
||||
SelectSetStmtContext *selectSetStmt();
|
||||
SelectStmtContext *selectStmt();
|
||||
HogqlxTagElementContext *hogqlxTagElement();
|
||||
|
||||
@ -563,31 +566,13 @@ public:
|
||||
|
||||
SelectContext* select();
|
||||
|
||||
class SelectUnionStmtContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
SelectUnionStmtContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
std::vector<SelectStmtWithParensContext *> selectStmtWithParens();
|
||||
SelectStmtWithParensContext* selectStmtWithParens(size_t i);
|
||||
std::vector<antlr4::tree::TerminalNode *> UNION();
|
||||
antlr4::tree::TerminalNode* UNION(size_t i);
|
||||
std::vector<antlr4::tree::TerminalNode *> ALL();
|
||||
antlr4::tree::TerminalNode* ALL(size_t i);
|
||||
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
SelectUnionStmtContext* selectUnionStmt();
|
||||
|
||||
class SelectStmtWithParensContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
SelectStmtWithParensContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
SelectStmtContext *selectStmt();
|
||||
antlr4::tree::TerminalNode *LPAREN();
|
||||
SelectUnionStmtContext *selectUnionStmt();
|
||||
SelectSetStmtContext *selectSetStmt();
|
||||
antlr4::tree::TerminalNode *RPAREN();
|
||||
PlaceholderContext *placeholder();
|
||||
|
||||
@ -598,6 +583,38 @@ public:
|
||||
|
||||
SelectStmtWithParensContext* selectStmtWithParens();
|
||||
|
||||
class SubsequentSelectSetClauseContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
SubsequentSelectSetClauseContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
SelectStmtWithParensContext *selectStmtWithParens();
|
||||
antlr4::tree::TerminalNode *EXCEPT();
|
||||
antlr4::tree::TerminalNode *UNION();
|
||||
antlr4::tree::TerminalNode *ALL();
|
||||
antlr4::tree::TerminalNode *INTERSECT();
|
||||
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
SubsequentSelectSetClauseContext* subsequentSelectSetClause();
|
||||
|
||||
class SelectSetStmtContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
SelectSetStmtContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
SelectStmtWithParensContext *selectStmtWithParens();
|
||||
std::vector<SubsequentSelectSetClauseContext *> subsequentSelectSetClause();
|
||||
SubsequentSelectSetClauseContext* subsequentSelectSetClause(size_t i);
|
||||
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
SelectSetStmtContext* selectSetStmt();
|
||||
|
||||
class SelectStmtContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
HogQLParser::WithClauseContext *with = nullptr;
|
||||
@ -1398,7 +1415,7 @@ public:
|
||||
ColumnExprSubqueryContext(ColumnExprContext *ctx);
|
||||
|
||||
antlr4::tree::TerminalNode *LPAREN();
|
||||
SelectUnionStmtContext *selectUnionStmt();
|
||||
SelectSetStmtContext *selectSetStmt();
|
||||
antlr4::tree::TerminalNode *RPAREN();
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
@ -1999,7 +2016,7 @@ public:
|
||||
IdentifierContext *identifier();
|
||||
antlr4::tree::TerminalNode *AS();
|
||||
antlr4::tree::TerminalNode *LPAREN();
|
||||
SelectUnionStmtContext *selectUnionStmt();
|
||||
SelectSetStmtContext *selectSetStmt();
|
||||
antlr4::tree::TerminalNode *RPAREN();
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
@ -2084,7 +2101,7 @@ public:
|
||||
TableExprSubqueryContext(TableExprContext *ctx);
|
||||
|
||||
antlr4::tree::TerminalNode *LPAREN();
|
||||
SelectUnionStmtContext *selectUnionStmt();
|
||||
SelectSetStmtContext *selectSetStmt();
|
||||
antlr4::tree::TerminalNode *RPAREN();
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
File diff suppressed because one or more lines are too long
@ -24,178 +24,180 @@ DESCENDING=23
|
||||
DISTINCT=24
|
||||
ELSE=25
|
||||
END=26
|
||||
EXTRACT=27
|
||||
FINAL=28
|
||||
FINALLY=29
|
||||
FIRST=30
|
||||
FN=31
|
||||
FOLLOWING=32
|
||||
FOR=33
|
||||
FROM=34
|
||||
FULL=35
|
||||
FUN=36
|
||||
GROUP=37
|
||||
HAVING=38
|
||||
HOUR=39
|
||||
ID=40
|
||||
IF=41
|
||||
ILIKE=42
|
||||
IN=43
|
||||
INF=44
|
||||
INNER=45
|
||||
INTERVAL=46
|
||||
IS=47
|
||||
JOIN=48
|
||||
KEY=49
|
||||
LAST=50
|
||||
LEADING=51
|
||||
LEFT=52
|
||||
LET=53
|
||||
LIKE=54
|
||||
LIMIT=55
|
||||
MINUTE=56
|
||||
MONTH=57
|
||||
NAN_SQL=58
|
||||
NOT=59
|
||||
NULL_SQL=60
|
||||
NULLS=61
|
||||
OFFSET=62
|
||||
ON=63
|
||||
OR=64
|
||||
ORDER=65
|
||||
OUTER=66
|
||||
OVER=67
|
||||
PARTITION=68
|
||||
PRECEDING=69
|
||||
PREWHERE=70
|
||||
QUARTER=71
|
||||
RANGE=72
|
||||
RETURN=73
|
||||
RIGHT=74
|
||||
ROLLUP=75
|
||||
ROW=76
|
||||
ROWS=77
|
||||
SAMPLE=78
|
||||
SECOND=79
|
||||
SELECT=80
|
||||
SEMI=81
|
||||
SETTINGS=82
|
||||
SUBSTRING=83
|
||||
THEN=84
|
||||
THROW=85
|
||||
TIES=86
|
||||
TIMESTAMP=87
|
||||
TO=88
|
||||
TOP=89
|
||||
TOTALS=90
|
||||
TRAILING=91
|
||||
TRIM=92
|
||||
TRUNCATE=93
|
||||
TRY=94
|
||||
UNBOUNDED=95
|
||||
UNION=96
|
||||
USING=97
|
||||
WEEK=98
|
||||
WHEN=99
|
||||
WHERE=100
|
||||
WHILE=101
|
||||
WINDOW=102
|
||||
WITH=103
|
||||
YEAR=104
|
||||
ESCAPE_CHAR_COMMON=105
|
||||
IDENTIFIER=106
|
||||
FLOATING_LITERAL=107
|
||||
OCTAL_LITERAL=108
|
||||
DECIMAL_LITERAL=109
|
||||
HEXADECIMAL_LITERAL=110
|
||||
STRING_LITERAL=111
|
||||
ARROW=112
|
||||
ASTERISK=113
|
||||
BACKQUOTE=114
|
||||
BACKSLASH=115
|
||||
COLON=116
|
||||
COMMA=117
|
||||
CONCAT=118
|
||||
DASH=119
|
||||
DOLLAR=120
|
||||
DOT=121
|
||||
EQ_DOUBLE=122
|
||||
EQ_SINGLE=123
|
||||
GT_EQ=124
|
||||
GT=125
|
||||
HASH=126
|
||||
IREGEX_SINGLE=127
|
||||
IREGEX_DOUBLE=128
|
||||
LBRACE=129
|
||||
LBRACKET=130
|
||||
LPAREN=131
|
||||
LT_EQ=132
|
||||
LT=133
|
||||
NOT_EQ=134
|
||||
NOT_IREGEX=135
|
||||
NOT_REGEX=136
|
||||
NULL_PROPERTY=137
|
||||
NULLISH=138
|
||||
PERCENT=139
|
||||
PLUS=140
|
||||
QUERY=141
|
||||
QUOTE_DOUBLE=142
|
||||
QUOTE_SINGLE_TEMPLATE=143
|
||||
QUOTE_SINGLE_TEMPLATE_FULL=144
|
||||
QUOTE_SINGLE=145
|
||||
REGEX_SINGLE=146
|
||||
REGEX_DOUBLE=147
|
||||
RBRACE=148
|
||||
RBRACKET=149
|
||||
RPAREN=150
|
||||
SEMICOLON=151
|
||||
SLASH=152
|
||||
UNDERSCORE=153
|
||||
MULTI_LINE_COMMENT=154
|
||||
SINGLE_LINE_COMMENT=155
|
||||
WHITESPACE=156
|
||||
STRING_TEXT=157
|
||||
STRING_ESCAPE_TRIGGER=158
|
||||
FULL_STRING_TEXT=159
|
||||
FULL_STRING_ESCAPE_TRIGGER=160
|
||||
'->'=112
|
||||
'*'=113
|
||||
'`'=114
|
||||
'\\'=115
|
||||
':'=116
|
||||
','=117
|
||||
'||'=118
|
||||
'-'=119
|
||||
'$'=120
|
||||
'.'=121
|
||||
'=='=122
|
||||
'='=123
|
||||
'>='=124
|
||||
'>'=125
|
||||
'#'=126
|
||||
'~*'=127
|
||||
'=~*'=128
|
||||
'{'=129
|
||||
'['=130
|
||||
'('=131
|
||||
'<='=132
|
||||
'<'=133
|
||||
'!~*'=135
|
||||
'!~'=136
|
||||
'?.'=137
|
||||
'??'=138
|
||||
'%'=139
|
||||
'+'=140
|
||||
'?'=141
|
||||
'"'=142
|
||||
'f\''=143
|
||||
'F\''=144
|
||||
'\''=145
|
||||
'~'=146
|
||||
'=~'=147
|
||||
'}'=148
|
||||
']'=149
|
||||
')'=150
|
||||
';'=151
|
||||
'/'=152
|
||||
'_'=153
|
||||
EXCEPT=27
|
||||
EXTRACT=28
|
||||
FINAL=29
|
||||
FINALLY=30
|
||||
FIRST=31
|
||||
FN=32
|
||||
FOLLOWING=33
|
||||
FOR=34
|
||||
FROM=35
|
||||
FULL=36
|
||||
FUN=37
|
||||
GROUP=38
|
||||
HAVING=39
|
||||
HOUR=40
|
||||
ID=41
|
||||
IF=42
|
||||
ILIKE=43
|
||||
IN=44
|
||||
INF=45
|
||||
INNER=46
|
||||
INTERSECT=47
|
||||
INTERVAL=48
|
||||
IS=49
|
||||
JOIN=50
|
||||
KEY=51
|
||||
LAST=52
|
||||
LEADING=53
|
||||
LEFT=54
|
||||
LET=55
|
||||
LIKE=56
|
||||
LIMIT=57
|
||||
MINUTE=58
|
||||
MONTH=59
|
||||
NAN_SQL=60
|
||||
NOT=61
|
||||
NULL_SQL=62
|
||||
NULLS=63
|
||||
OFFSET=64
|
||||
ON=65
|
||||
OR=66
|
||||
ORDER=67
|
||||
OUTER=68
|
||||
OVER=69
|
||||
PARTITION=70
|
||||
PRECEDING=71
|
||||
PREWHERE=72
|
||||
QUARTER=73
|
||||
RANGE=74
|
||||
RETURN=75
|
||||
RIGHT=76
|
||||
ROLLUP=77
|
||||
ROW=78
|
||||
ROWS=79
|
||||
SAMPLE=80
|
||||
SECOND=81
|
||||
SELECT=82
|
||||
SEMI=83
|
||||
SETTINGS=84
|
||||
SUBSTRING=85
|
||||
THEN=86
|
||||
THROW=87
|
||||
TIES=88
|
||||
TIMESTAMP=89
|
||||
TO=90
|
||||
TOP=91
|
||||
TOTALS=92
|
||||
TRAILING=93
|
||||
TRIM=94
|
||||
TRUNCATE=95
|
||||
TRY=96
|
||||
UNBOUNDED=97
|
||||
UNION=98
|
||||
USING=99
|
||||
WEEK=100
|
||||
WHEN=101
|
||||
WHERE=102
|
||||
WHILE=103
|
||||
WINDOW=104
|
||||
WITH=105
|
||||
YEAR=106
|
||||
ESCAPE_CHAR_COMMON=107
|
||||
IDENTIFIER=108
|
||||
FLOATING_LITERAL=109
|
||||
OCTAL_LITERAL=110
|
||||
DECIMAL_LITERAL=111
|
||||
HEXADECIMAL_LITERAL=112
|
||||
STRING_LITERAL=113
|
||||
ARROW=114
|
||||
ASTERISK=115
|
||||
BACKQUOTE=116
|
||||
BACKSLASH=117
|
||||
COLON=118
|
||||
COMMA=119
|
||||
CONCAT=120
|
||||
DASH=121
|
||||
DOLLAR=122
|
||||
DOT=123
|
||||
EQ_DOUBLE=124
|
||||
EQ_SINGLE=125
|
||||
GT_EQ=126
|
||||
GT=127
|
||||
HASH=128
|
||||
IREGEX_SINGLE=129
|
||||
IREGEX_DOUBLE=130
|
||||
LBRACE=131
|
||||
LBRACKET=132
|
||||
LPAREN=133
|
||||
LT_EQ=134
|
||||
LT=135
|
||||
NOT_EQ=136
|
||||
NOT_IREGEX=137
|
||||
NOT_REGEX=138
|
||||
NULL_PROPERTY=139
|
||||
NULLISH=140
|
||||
PERCENT=141
|
||||
PLUS=142
|
||||
QUERY=143
|
||||
QUOTE_DOUBLE=144
|
||||
QUOTE_SINGLE_TEMPLATE=145
|
||||
QUOTE_SINGLE_TEMPLATE_FULL=146
|
||||
QUOTE_SINGLE=147
|
||||
REGEX_SINGLE=148
|
||||
REGEX_DOUBLE=149
|
||||
RBRACE=150
|
||||
RBRACKET=151
|
||||
RPAREN=152
|
||||
SEMICOLON=153
|
||||
SLASH=154
|
||||
UNDERSCORE=155
|
||||
MULTI_LINE_COMMENT=156
|
||||
SINGLE_LINE_COMMENT=157
|
||||
WHITESPACE=158
|
||||
STRING_TEXT=159
|
||||
STRING_ESCAPE_TRIGGER=160
|
||||
FULL_STRING_TEXT=161
|
||||
FULL_STRING_ESCAPE_TRIGGER=162
|
||||
'->'=114
|
||||
'*'=115
|
||||
'`'=116
|
||||
'\\'=117
|
||||
':'=118
|
||||
','=119
|
||||
'||'=120
|
||||
'-'=121
|
||||
'$'=122
|
||||
'.'=123
|
||||
'=='=124
|
||||
'='=125
|
||||
'>='=126
|
||||
'>'=127
|
||||
'#'=128
|
||||
'~*'=129
|
||||
'=~*'=130
|
||||
'{'=131
|
||||
'['=132
|
||||
'('=133
|
||||
'<='=134
|
||||
'<'=135
|
||||
'!~*'=137
|
||||
'!~'=138
|
||||
'?.'=139
|
||||
'??'=140
|
||||
'%'=141
|
||||
'+'=142
|
||||
'?'=143
|
||||
'"'=144
|
||||
'f\''=145
|
||||
'F\''=146
|
||||
'\''=147
|
||||
'~'=148
|
||||
'=~'=149
|
||||
'}'=150
|
||||
']'=151
|
||||
')'=152
|
||||
';'=153
|
||||
'/'=154
|
||||
'_'=155
|
||||
|
@ -103,11 +103,15 @@ public:
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitSelectUnionStmt(HogQLParser::SelectUnionStmtContext *ctx) override {
|
||||
virtual std::any visitSelectStmtWithParens(HogQLParser::SelectStmtWithParensContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitSelectStmtWithParens(HogQLParser::SelectStmtWithParensContext *ctx) override {
|
||||
virtual std::any visitSubsequentSelectSetClause(HogQLParser::SubsequentSelectSetClauseContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitSelectSetStmt(HogQLParser::SelectSetStmtContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
|
@ -63,10 +63,12 @@ public:
|
||||
|
||||
virtual std::any visitSelect(HogQLParser::SelectContext *context) = 0;
|
||||
|
||||
virtual std::any visitSelectUnionStmt(HogQLParser::SelectUnionStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitSelectStmtWithParens(HogQLParser::SelectStmtWithParensContext *context) = 0;
|
||||
|
||||
virtual std::any visitSubsequentSelectSetClause(HogQLParser::SubsequentSelectSetClauseContext *context) = 0;
|
||||
|
||||
virtual std::any visitSelectSetStmt(HogQLParser::SelectSetStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitSelectStmt(HogQLParser::SelectStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitWithClause(HogQLParser::WithClauseContext *context) = 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
from posthog.hogql.ast import SelectQuery, SelectUnionQuery, Program
|
||||
from posthog.hogql.ast import SelectQuery, SelectSetQuery, Program
|
||||
from posthog.hogql.base import AST
|
||||
|
||||
def parse_expr(expr: str, /, *, is_internal: bool = False) -> AST:
|
||||
@ -15,7 +15,7 @@ def parse_order_expr(expr: str, /, *, is_internal: bool = False) -> AST:
|
||||
"""
|
||||
...
|
||||
|
||||
def parse_select(expr: str, /, *, is_internal: bool = False) -> SelectQuery | SelectUnionQuery:
|
||||
def parse_select(expr: str, /, *, is_internal: bool = False) -> SelectQuery | SelectSetQuery:
|
||||
"""Parse the HogQL SELECT statement string into an AST.
|
||||
|
||||
If the expr `is_internal`, spans and notices won't be included in the AST.
|
||||
|
@ -827,9 +827,9 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
||||
// HogQL rules
|
||||
|
||||
VISIT(Select) {
|
||||
auto select_union_stmt_ctx = ctx->selectUnionStmt();
|
||||
if (select_union_stmt_ctx) {
|
||||
return visit(select_union_stmt_ctx);
|
||||
auto select_set_stmt_ctx = ctx->selectSetStmt();
|
||||
if (select_set_stmt_ctx) {
|
||||
return visit(select_set_stmt_ctx);
|
||||
}
|
||||
|
||||
auto select_stmt_ctx = ctx->selectStmt();
|
||||
@ -851,68 +851,48 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
||||
return visitAsPyObject(placeholder_ctx);
|
||||
}
|
||||
|
||||
return visit(ctx->selectUnionStmt());
|
||||
return visit(ctx->selectSetStmt());
|
||||
}
|
||||
|
||||
VISIT(SelectUnionStmt) {
|
||||
// Using a vector of PyObjects atypically here, because this is a precursor of flattened_queries
|
||||
vector<PyObject*> select_queries;
|
||||
auto select_stmt_with_parens_ctxs = ctx->selectStmtWithParens();
|
||||
select_queries.reserve(select_stmt_with_parens_ctxs.size());
|
||||
for (auto select_stmt_with_parens_ctx : select_stmt_with_parens_ctxs) {
|
||||
try {
|
||||
select_queries.push_back(visitAsPyObject(select_stmt_with_parens_ctx));
|
||||
} catch (...) {
|
||||
X_Py_DECREF_ALL(select_queries);
|
||||
VISIT(SelectSetStmt) {
|
||||
PyObject* initial_query = visitAsPyObject(ctx->selectStmtWithParens());
|
||||
PyObject* select_query = NULL;
|
||||
PyObject* select_queries = PyList_New(0);
|
||||
if (!select_queries) {
|
||||
throw PyInternalError();
|
||||
}
|
||||
|
||||
try {
|
||||
for (auto subsequent : ctx->subsequentSelectSetClause()) {
|
||||
char* set_operator;
|
||||
if (subsequent->UNION() && subsequent->ALL()) {
|
||||
set_operator = "UNION ALL";
|
||||
} else if (subsequent->INTERSECT()) {
|
||||
set_operator = "INTERSECT";
|
||||
} else if (subsequent->EXCEPT()) {
|
||||
set_operator = "EXCEPT";
|
||||
} else {
|
||||
throw SyntaxError("Set operator must be one of UNION ALL, INTERSECT, and EXCEPT");
|
||||
}
|
||||
select_query = visitAsPyObject(subsequent->selectStmtWithParens());
|
||||
PyObject* query = build_ast_node("SelectSetNode", "{s:N,s:N}", "select_query", select_query, "set_operator", PyUnicode_FromString(set_operator));
|
||||
if (!query) {
|
||||
throw PyInternalError();
|
||||
}
|
||||
PyList_Append(select_queries, query);
|
||||
}
|
||||
} catch (...) {
|
||||
Py_DECREF(select_queries);
|
||||
Py_DECREF(initial_query);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
PyObject* flattened_queries = PyList_New(0);
|
||||
if (!flattened_queries) {
|
||||
X_Py_DECREF_ALL(select_queries);
|
||||
throw PyInternalError();
|
||||
|
||||
if (PyList_Size(select_queries) == 0) {
|
||||
Py_DECREF(select_queries);
|
||||
return initial_query;
|
||||
}
|
||||
for (auto query : select_queries) {
|
||||
int is_select_query = is_ast_node_instance(query, "SelectQuery");
|
||||
if (is_select_query == -1) goto select_queries_loop_py_error;
|
||||
if (is_ast_node_instance(query, "SelectQuery")) {
|
||||
int append_code = PyList_Append(flattened_queries, query);
|
||||
if (append_code == -1) goto select_queries_loop_py_error;
|
||||
} else if (is_ast_node_instance(query, "SelectUnionQuery")) {
|
||||
// Extend flattened_queries with sub_select_queries
|
||||
PyObject* sub_select_queries = PyObject_GetAttrString(query, "select_queries");
|
||||
if (!sub_select_queries) goto select_queries_loop_py_error;
|
||||
int extend_code = X_PyList_Extend(flattened_queries, sub_select_queries);
|
||||
if (extend_code == -1) goto select_queries_loop_py_error;
|
||||
Py_DECREF(sub_select_queries);
|
||||
} else if (is_ast_node_instance(query, "Placeholder")) {
|
||||
int append_code = PyList_Append(flattened_queries, query);
|
||||
if (append_code == -1) goto select_queries_loop_py_error;
|
||||
} else {
|
||||
Py_DECREF(flattened_queries);
|
||||
X_Py_DECREF_ALL(select_queries);
|
||||
throw ParsingError("Unexpected query node type: " + string(Py_TYPE(query)->tp_name));
|
||||
}
|
||||
}
|
||||
goto select_queries_loop_success;
|
||||
select_queries_loop_py_error:
|
||||
X_Py_DECREF_ALL(select_queries);
|
||||
Py_DECREF(flattened_queries);
|
||||
throw PyInternalError();
|
||||
select_queries_loop_success:
|
||||
X_Py_DECREF_ALL(select_queries);
|
||||
Py_ssize_t flattened_queries_size = PyList_Size(flattened_queries);
|
||||
if (flattened_queries_size == -1) {
|
||||
Py_DECREF(flattened_queries);
|
||||
throw PyInternalError();
|
||||
}
|
||||
if (flattened_queries_size == 1) {
|
||||
PyObject* query = PyList_GET_ITEM(flattened_queries, 0);
|
||||
Py_INCREF(query);
|
||||
Py_DECREF(flattened_queries);
|
||||
return query;
|
||||
}
|
||||
RETURN_NEW_AST_NODE("SelectUnionQuery", "{s:N}", "select_queries", flattened_queries);
|
||||
|
||||
RETURN_NEW_AST_NODE("SelectSetQuery", "{s:N, s:N}", "initial_select_query", initial_query, "subsequent_select_queries", select_queries);
|
||||
}
|
||||
|
||||
VISIT(SelectStmt) {
|
||||
@ -1632,7 +1612,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
||||
RETURN_NEW_AST_NODE("ArithmeticOperation", "{s:N,s:N,s:N}", "left", left, "right", right, "op", op);
|
||||
}
|
||||
|
||||
VISIT(ColumnExprSubquery) { return visit(ctx->selectUnionStmt()); }
|
||||
VISIT(ColumnExprSubquery) { return visit(ctx->selectSetStmt()); }
|
||||
|
||||
VISIT(ColumnExprArray) {
|
||||
RETURN_NEW_AST_NODE("Array", "{s:N}", "exprs", visitAsPyObjectOrEmptyList(ctx->columnExprList()));
|
||||
@ -2286,7 +2266,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
||||
VISIT(WithExprSubquery) {
|
||||
string name = visitAsString(ctx->identifier());
|
||||
RETURN_NEW_AST_NODE(
|
||||
"CTE", "{s:s#,s:N,s:s}", "name", name.data(), name.size(), "expr", visitAsPyObject(ctx->selectUnionStmt()),
|
||||
"CTE", "{s:s#,s:N,s:s}", "name", name.data(), name.size(), "expr", visitAsPyObject(ctx->selectSetStmt()),
|
||||
"cte_type", "subquery"
|
||||
);
|
||||
}
|
||||
@ -2332,7 +2312,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
||||
RETURN_NEW_AST_NODE("Field", "{s:N}", "chain", X_PyList_FromStrings(chain));
|
||||
}
|
||||
|
||||
VISIT(TableExprSubquery) { return visit(ctx->selectUnionStmt()); }
|
||||
VISIT(TableExprSubquery) { return visit(ctx->selectSetStmt()); }
|
||||
|
||||
VISIT(TableExprPlaceholder) { return visitAsPyObject(ctx->placeholder()); }
|
||||
|
||||
|
@ -32,7 +32,7 @@ module = Extension(
|
||||
|
||||
setup(
|
||||
name="hogql_parser",
|
||||
version="1.0.45",
|
||||
version="1.0.46",
|
||||
url="https://github.com/PostHog/posthog/tree/master/hogql_parser",
|
||||
author="PostHog Inc.",
|
||||
author_email="hey@posthog.com",
|
||||
|
@ -88,10 +88,10 @@ posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "OrderExpr", variable has type "CTE") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "CTE") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "WindowExpr", variable has type "CTE") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "FieldAliasType", variable has type "BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "Type", variable has type "BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "FieldAliasType", variable has type "BaseTableType | SelectSetQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "Type", variable has type "BaseTableType | SelectSetQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType") [assignment]
|
||||
posthog/models/filters/mixins/simplify.py:0: error: Incompatible type for lookup 'pk': (got "str | int | list[str]", expected "str | int") [misc]
|
||||
posthog/hogql/resolver_utils.py:0: error: Argument 1 to "lookup_field_by_name" has incompatible type "SelectQueryType | SelectUnionQueryType"; expected "SelectQueryType" [arg-type]
|
||||
posthog/hogql/resolver_utils.py:0: error: Argument 1 to "lookup_field_by_name" has incompatible type "SelectQueryType | SelectSetQueryType"; expected "SelectQueryType" [arg-type]
|
||||
posthog/helpers/dashboard_templates.py:0: error: Incompatible types in assignment (expression has type "str | None", variable has type "str | Combinable") [assignment]
|
||||
posthog/hogql/parser.py:0: error: Item "None" of "list[Expr] | None" has no attribute "__iter__" (not iterable) [union-attr]
|
||||
posthog/hogql/parser.py:0: error: "None" has no attribute "text" [attr-defined]
|
||||
@ -161,23 +161,22 @@ posthog/hogql_queries/utils/query_date_range.py:0: error: Incompatible default f
|
||||
posthog/hogql_queries/utils/query_date_range.py:0: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
|
||||
posthog/hogql_queries/utils/query_date_range.py:0: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
|
||||
posthog/hogql_queries/utils/query_date_range.py:0: error: Item "None" of "IntervalType | None" has no attribute "name" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: List comprehension has incompatible type List[SelectQueryType | None]; expected List[SelectQueryType] [misc]
|
||||
posthog/hogql/resolver.py:0: error: Need type annotation for "columns_with_visible_alias" (hint: "columns_with_visible_alias: dict[<type>, <type>] = ...") [var-annotated]
|
||||
posthog/hogql/resolver.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "SelectQuery | SelectUnionQuery | Field | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "SelectQuery | SelectSetQuery | Field | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "Database | None" has no attribute "get_table" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "TableType", variable has type "LazyTableType") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument "table_type" to "TableAliasType" has incompatible type "LazyTableType"; expected "TableType" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "LazyTableType", variable has type "TableAliasType") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "clone_expr" has incompatible type "SelectQuery | SelectUnionQuery | Field | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "clone_expr" has incompatible type "SelectQuery | SelectSetQuery | Field | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "JoinExpr | None" has no attribute "join_type" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: Argument "select_query_type" to "SelectViewType" has incompatible type "SelectQueryType | None"; expected "SelectQueryType | SelectUnionQueryType" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "SelectQuery | SelectUnionQuery | Field | None" has no attribute "type" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: Argument "select_query_type" to "SelectQueryAliasType" has incompatible type "Type | Any | None"; expected "SelectQueryType | SelectUnionQueryType" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "SelectQuery | SelectUnionQuery | Field | None" has no attribute "type" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Type | Any | None", variable has type "BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "append" of "list" has incompatible type "BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType | None"; expected "SelectQueryType | SelectUnionQueryType" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Argument "select_query_type" to "SelectViewType" has incompatible type "SelectQueryType | None"; expected "SelectQueryType | SelectSetQueryType" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "SelectQuery | SelectSetQuery | Field | None" has no attribute "type" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: Argument "select_query_type" to "SelectQueryAliasType" has incompatible type "Type | Any | None"; expected "SelectQueryType | SelectSetQueryType" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "SelectQuery | SelectSetQuery | Field | None" has no attribute "type" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Type | Any | None", variable has type "BaseTableType | SelectSetQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "append" of "list" has incompatible type "BaseTableType | SelectSetQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType | None"; expected "SelectQueryType | SelectSetQueryType" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql/resolver.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "Type | None" has no attribute "resolve_constant_type" [union-attr]
|
||||
@ -193,12 +192,12 @@ posthog/hogql_queries/insights/trends/aggregation_operations.py:0: note: "List"
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: note: Consider using "Sequence" instead, which is covariant
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: List item 1 has incompatible type "str | None"; expected "str" [list-item]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Argument "chain" to "Field" has incompatible type "list[str | int] | list[str]"; expected "list[str | int]" [arg-type]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "select" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "select" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "group_by" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectSetQuery" of "SelectQuery | SelectSetQuery" has no attribute "select" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectSetQuery" of "SelectQuery | SelectSetQuery" has no attribute "select" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectSetQuery" of "SelectQuery | SelectSetQuery" has no attribute "group_by" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "None" of "list[Expr] | None" has no attribute "append" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "select" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "group_by" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectSetQuery" of "SelectQuery | SelectSetQuery" has no attribute "select" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectSetQuery" of "SelectQuery | SelectSetQuery" has no attribute "group_by" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "None" of "list[Expr] | Any | None" has no attribute "append" [union-attr]
|
||||
posthog/hogql/transforms/lazy_tables.py:0: error: Incompatible types in assignment (expression has type "dict[Never, Never]", variable has type "list[ConstraintOverride]") [assignment]
|
||||
posthog/hogql/transforms/lazy_tables.py:0: error: Non-overlapping equality check (left operand type: "TableType", right operand type: "LazyTableType") [comparison-overlap]
|
||||
@ -206,7 +205,7 @@ posthog/hogql/transforms/lazy_tables.py:0: error: Non-overlapping equality check
|
||||
posthog/hogql/transforms/lazy_tables.py:0: error: Name "chain" already defined on line 0 [no-redef]
|
||||
posthog/hogql/transforms/lazy_tables.py:0: error: Subclass of "TableType" and "LazyTableType" cannot exist: would have incompatible method signatures [unreachable]
|
||||
posthog/hogql/transforms/lazy_tables.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql/transforms/lazy_tables.py:0: error: Incompatible types in assignment (expression has type "BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType", variable has type "SelectQueryAliasType | None") [assignment]
|
||||
posthog/hogql/transforms/lazy_tables.py:0: error: Incompatible types in assignment (expression has type "BaseTableType | SelectSetQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType", variable has type "SelectQueryAliasType | None") [assignment]
|
||||
posthog/hogql/transforms/in_cohort.py:0: error: Incompatible default for argument "context" (default has type "None", argument has type "HogQLContext") [assignment]
|
||||
posthog/hogql/transforms/in_cohort.py:0: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
|
||||
posthog/hogql/transforms/in_cohort.py:0: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
|
||||
@ -217,7 +216,7 @@ posthog/hogql/transforms/in_cohort.py:0: note: PEP 484 prohibits implicit Option
|
||||
posthog/hogql/transforms/in_cohort.py:0: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
|
||||
posthog/hogql/transforms/in_cohort.py:0: error: Incompatible type for lookup 'team_id': (got "int | None", expected "str | int") [misc]
|
||||
posthog/hogql/transforms/in_cohort.py:0: error: Incompatible type for lookup 'team_id': (got "int | None", expected "str | int") [misc]
|
||||
posthog/hogql/transforms/in_cohort.py:0: error: Argument "table" to "JoinExpr" has incompatible type "Expr"; expected "SelectQuery | SelectUnionQuery | Field | None" [arg-type]
|
||||
posthog/hogql/transforms/in_cohort.py:0: error: Argument "table" to "JoinExpr" has incompatible type "Expr"; expected "SelectQuery | SelectSetQuery | Field | None" [arg-type]
|
||||
posthog/hogql/transforms/in_cohort.py:0: error: List item 0 has incompatible type "SelectQueryType | None"; expected "SelectQueryType" [list-item]
|
||||
posthog/hogql/transforms/in_cohort.py:0: error: Item "None" of "JoinConstraint | None" has no attribute "expr" [union-attr]
|
||||
posthog/hogql/transforms/in_cohort.py:0: error: Item "Expr" of "Expr | Any" has no attribute "left" [union-attr]
|
||||
@ -332,17 +331,16 @@ posthog/hogql/filters.py:0: error: Incompatible default for argument "team" (def
|
||||
posthog/hogql/filters.py:0: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
|
||||
posthog/hogql/filters.py:0: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
|
||||
posthog/api/organization.py:0: error: Incompatible return value type (got "int | None", expected "Level | None") [return-value]
|
||||
posthog/hogql/query.py:0: error: Incompatible types in assignment (expression has type "None", variable has type "str | SelectQuery | SelectUnionQuery") [assignment]
|
||||
posthog/hogql/query.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "SelectQuery | SelectUnionQuery") [assignment]
|
||||
posthog/hogql/query.py:0: error: Incompatible types in assignment (expression has type "None", variable has type "str | SelectQuery | SelectSetQuery") [assignment]
|
||||
posthog/hogql/query.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "SelectQuery | SelectSetQuery") [assignment]
|
||||
posthog/hogql/query.py:0: error: Argument 1 to "get_default_limit_for_context" has incompatible type "LimitContext | None"; expected "LimitContext" [arg-type]
|
||||
posthog/hogql/query.py:0: error: "SelectQuery" has no attribute "select_queries" [attr-defined]
|
||||
posthog/hogql/query.py:0: error: Subclass of "SelectQuery" and "SelectUnionQuery" cannot exist: would have incompatible method signatures [unreachable]
|
||||
posthog/hogql/query.py:0: error: Subclass of "SelectQuery" and "SelectSetQuery" cannot exist: would have incompatible method signatures [unreachable]
|
||||
posthog/queries/person_query.py:0: error: Incompatible type for lookup 'pk': (got "str | int | list[str]", expected "str | int") [misc]
|
||||
posthog/api/action.py:0: error: Argument 1 to <tuple> has incompatible type "*tuple[str, ...]"; expected "type[BaseRenderer]" [arg-type]
|
||||
posthog/queries/event_query/event_query.py:0: error: Incompatible type for lookup 'pk': (got "str | int | list[str]", expected "str | int") [misc]
|
||||
posthog/hogql_queries/sessions_timeline_query_runner.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql_queries/hogql_query_runner.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql_queries/hogql_query_runner.py:0: error: Incompatible return value type (got "SelectQuery | SelectUnionQuery", expected "SelectQuery") [return-value]
|
||||
posthog/hogql_queries/hogql_query_runner.py:0: error: Incompatible return value type (got "SelectQuery | SelectSetQuery", expected "SelectQuery") [return-value]
|
||||
posthog/hogql_queries/events_query_runner.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/queries/breakdown_props.py:0: error: Argument 1 to "translate_hogql" has incompatible type "str | int"; expected "str" [arg-type]
|
||||
posthog/queries/breakdown_props.py:0: error: Incompatible type for lookup 'pk': (got "str | None", expected "str | int") [misc]
|
||||
@ -386,15 +384,15 @@ posthog/hogql_queries/insights/stickiness_query_runner.py:0: error: Module "djan
|
||||
posthog/hogql_queries/insights/retention_query_runner.py:0: error: Item "None" of "JoinExpr | None" has no attribute "sample" [union-attr]
|
||||
posthog/hogql_queries/insights/retention_query_runner.py:0: error: Unsupported operand types for - ("int" and "None") [operator]
|
||||
posthog/hogql_queries/insights/retention_query_runner.py:0: note: Right operand is of type "int | None"
|
||||
posthog/hogql_queries/insights/retention_query_runner.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "select" [union-attr]
|
||||
posthog/hogql_queries/insights/retention_query_runner.py:0: error: Incompatible return value type (got "SelectQuery | SelectUnionQuery", expected "SelectQuery") [return-value]
|
||||
posthog/hogql_queries/insights/retention_query_runner.py:0: error: Item "SelectSetQuery" of "SelectQuery | SelectSetQuery" has no attribute "select" [union-attr]
|
||||
posthog/hogql_queries/insights/retention_query_runner.py:0: error: Incompatible return value type (got "SelectQuery | SelectSetQuery", expected "SelectQuery") [return-value]
|
||||
posthog/hogql_queries/insights/lifecycle_query_runner.py:0: error: Module "django.utils.timezone" does not explicitly export attribute "datetime" [attr-defined]
|
||||
posthog/hogql_queries/insights/lifecycle_query_runner.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "Constant") [assignment]
|
||||
posthog/hogql_queries/insights/lifecycle_query_runner.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "Constant") [assignment]
|
||||
posthog/hogql_queries/insights/lifecycle_query_runner.py:0: error: Argument "exprs" to "And" has incompatible type "list[CompareOperation]"; expected "list[Expr]" [arg-type]
|
||||
posthog/hogql_queries/insights/lifecycle_query_runner.py:0: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
|
||||
posthog/hogql_queries/insights/lifecycle_query_runner.py:0: note: Consider using "Sequence" instead, which is covariant
|
||||
posthog/hogql_queries/insights/lifecycle_query_runner.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "select_from" [union-attr]
|
||||
posthog/hogql_queries/insights/lifecycle_query_runner.py:0: error: Item "SelectSetQuery" of "SelectQuery | SelectSetQuery" has no attribute "select_from" [union-attr]
|
||||
posthog/hogql_queries/insights/lifecycle_query_runner.py:0: error: Item "None" of "JoinExpr | Any | None" has no attribute "sample" [union-attr]
|
||||
posthog/hogql_queries/insights/funnels/funnels_query_runner.py:0: error: Module "django.utils.timezone" does not explicitly export attribute "datetime" [attr-defined]
|
||||
posthog/api/survey.py:0: error: Incompatible types in assignment (expression has type "Any | Sequence[Any] | None", variable has type "Survey | None") [assignment]
|
||||
@ -503,19 +501,19 @@ posthog/hogql/test/test_resolver.py:0: error: Item "None" of "JoinConstraint | A
|
||||
posthog/hogql/test/test_resolver.py:0: error: Item "None" of "JoinExpr | None" has no attribute "next_join" [union-attr]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Item "None" of "JoinExpr | Any | None" has no attribute "constraint" [union-attr]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Item "None" of "JoinConstraint | Any | None" has no attribute "constraint_type" [union-attr]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Item "SelectUnionQueryType" of "SelectQueryType | SelectUnionQueryType | None" has no attribute "columns" [union-attr]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Item "None" of "SelectQueryType | SelectUnionQueryType | None" has no attribute "columns" [union-attr]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Item "SelectSetQueryType" of "SelectQueryType | SelectSetQueryType | None" has no attribute "columns" [union-attr]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Item "None" of "SelectQueryType | SelectSetQueryType | None" has no attribute "columns" [union-attr]
|
||||
posthog/hogql/test/test_resolver.py:0: error: "FieldOrTable" has no attribute "fields" [attr-defined]
|
||||
posthog/hogql/test/test_resolver.py:0: error: "FieldOrTable" has no attribute "fields" [attr-defined]
|
||||
posthog/hogql/test/test_resolver.py:0: error: "FieldOrTable" has no attribute "fields" [attr-defined]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Item "None" of "JoinExpr | None" has no attribute "table" [union-attr]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Argument 1 to "clone_expr" has incompatible type "SelectQuery | SelectUnionQuery | Field | Any | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Argument 1 to "clone_expr" has incompatible type "SelectQuery | SelectSetQuery | Field | Any | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/test/test_resolver.py:0: error: Item "None" of "JoinExpr | None" has no attribute "alias" [union-attr]
|
||||
posthog/hogql/test/test_property.py:0: error: Argument 1 to "_property_to_expr" of "TestProperty" has incompatible type "HogQLPropertyFilter"; expected "PropertyGroup | Property | dict[Any, Any] | list[Any]" [arg-type]
|
||||
posthog/hogql/test/test_printer.py:0: error: Argument 2 to "Database" has incompatible type "int"; expected "WeekStartDay | None" [arg-type]
|
||||
posthog/hogql/test/test_printer.py:0: error: Argument 2 to "Database" has incompatible type "int"; expected "WeekStartDay | None" [arg-type]
|
||||
posthog/hogql/test/test_printer.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "settings" [union-attr]
|
||||
posthog/hogql/test/test_printer.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "settings" [union-attr]
|
||||
posthog/hogql/test/test_printer.py:0: error: Item "SelectSetQuery" of "SelectQuery | SelectSetQuery" has no attribute "settings" [union-attr]
|
||||
posthog/hogql/test/test_printer.py:0: error: Item "SelectSetQuery" of "SelectQuery | SelectSetQuery" has no attribute "settings" [union-attr]
|
||||
posthog/hogql/test/test_printer.py:0: error: "TestPrinter" has no attribute "snapshot" [attr-defined]
|
||||
posthog/hogql/test/test_modifiers.py:0: error: Unsupported right operand type for in ("str | None") [operator]
|
||||
posthog/hogql/test/test_modifiers.py:0: error: Unsupported right operand type for in ("str | None") [operator]
|
||||
@ -531,7 +529,7 @@ posthog/hogql/test/test_modifiers.py:0: error: Unsupported right operand type fo
|
||||
posthog/hogql/test/test_modifiers.py:0: error: Unsupported right operand type for in ("str | None") [operator]
|
||||
posthog/hogql/test/test_modifiers.py:0: error: Unsupported right operand type for in ("str | None") [operator]
|
||||
posthog/hogql/test/_test_parser.py:0: error: Invalid base class [misc]
|
||||
posthog/hogql/test/_test_parser.py:0: error: Argument "table" to "JoinExpr" has incompatible type "Placeholder"; expected "SelectQuery | SelectUnionQuery | Field | None" [arg-type]
|
||||
posthog/hogql/test/_test_parser.py:0: error: Argument "table" to "JoinExpr" has incompatible type "Placeholder"; expected "SelectQuery | SelectSetQuery | Field | None" [arg-type]
|
||||
posthog/hogql/test/_test_parser.py:0: error: Item "None" of "JoinExpr | None" has no attribute "table" [union-attr]
|
||||
posthog/hogql/test/_test_parser.py:0: error: Item "None" of "JoinExpr | None" has no attribute "table" [union-attr]
|
||||
posthog/hogql/test/_test_parser.py:0: error: Item "None" of "JoinExpr | None" has no attribute "table" [union-attr]
|
||||
|
@ -371,35 +371,36 @@ class TestPluginAPI(APIBaseTest, QueryMatchingTest):
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(mock_sync_from_plugin_archive.call_count, 2) # Not extracted on auth failure
|
||||
|
||||
@freeze_time("2021-08-25T22:09:14.252Z")
|
||||
def test_delete_plugin_auth(self, mock_get, mock_reload):
|
||||
repo_url = "https://github.com/PostHog/helloworldplugin"
|
||||
response = self.client.post("/api/organizations/@current/plugins/", {"url": repo_url})
|
||||
self.assertEqual(response.status_code, 201)
|
||||
with freeze_time("2021-08-25T22:09:14.252Z"):
|
||||
repo_url = "https://github.com/PostHog/helloworldplugin"
|
||||
response = self.client.post("/api/organizations/@current/plugins/", {"url": repo_url})
|
||||
self.assertEqual(response.status_code, 201)
|
||||
|
||||
plugin_id = response.json()["id"]
|
||||
with freeze_time("2021-08-25T22:09:14.253Z"):
|
||||
plugin_id = response.json()["id"]
|
||||
|
||||
api_url = "/api/organizations/@current/plugins/{}".format(response.json()["id"])
|
||||
api_url = "/api/organizations/@current/plugins/{}".format(response.json()["id"])
|
||||
|
||||
for level in (
|
||||
Organization.PluginsAccessLevel.NONE,
|
||||
Organization.PluginsAccessLevel.CONFIG,
|
||||
):
|
||||
self.organization.plugins_access_level = level
|
||||
for level in (
|
||||
Organization.PluginsAccessLevel.NONE,
|
||||
Organization.PluginsAccessLevel.CONFIG,
|
||||
):
|
||||
self.organization.plugins_access_level = level
|
||||
self.organization.save()
|
||||
response = self.client.delete(api_url)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
self.organization.plugins_access_level = Organization.PluginsAccessLevel.INSTALL
|
||||
self.organization.save()
|
||||
response = self.client.delete(api_url)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
self.organization.plugins_access_level = Organization.PluginsAccessLevel.INSTALL
|
||||
self.organization.save()
|
||||
response = self.client.delete(api_url)
|
||||
self.assertEqual(response.status_code, 204)
|
||||
self.assert_plugin_activity(
|
||||
[
|
||||
{
|
||||
"user": {"first_name": "", "email": "user1@posthog.com"},
|
||||
"activity": "installed",
|
||||
"created_at": "2021-08-25T22:09:14.252000Z",
|
||||
"activity": "uninstalled",
|
||||
"created_at": "2021-08-25T22:09:14.253000Z",
|
||||
"scope": "Plugin",
|
||||
"item_id": str(plugin_id),
|
||||
"detail": {
|
||||
@ -412,7 +413,7 @@ class TestPluginAPI(APIBaseTest, QueryMatchingTest):
|
||||
},
|
||||
{
|
||||
"user": {"first_name": "", "email": "user1@posthog.com"},
|
||||
"activity": "uninstalled",
|
||||
"activity": "installed",
|
||||
"created_at": "2021-08-25T22:09:14.252000Z",
|
||||
"scope": "Plugin",
|
||||
"item_id": str(plugin_id),
|
||||
|
@ -183,7 +183,7 @@ class BatchExportDestinationSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
class HogQLSelectQueryField(serializers.Field):
|
||||
def to_internal_value(self, data: str) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_internal_value(self, data: str) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
"""Parse a HogQL SelectQuery from a string query."""
|
||||
try:
|
||||
parsed_query = parse_select(data)
|
||||
@ -329,7 +329,7 @@ class BatchExportSerializer(serializers.ModelSerializer):
|
||||
|
||||
return batch_export_schema
|
||||
|
||||
def validate_hogql_query(self, hogql_query: ast.SelectQuery | ast.SelectUnionQuery) -> ast.SelectQuery:
|
||||
def validate_hogql_query(self, hogql_query: ast.SelectQuery | ast.SelectSetQuery) -> ast.SelectQuery:
|
||||
"""Validate a HogQLQuery being used for batch exports.
|
||||
|
||||
This method essentially checks that a query is supported by batch exports:
|
||||
@ -338,7 +338,7 @@ class BatchExportSerializer(serializers.ModelSerializer):
|
||||
3. Query must SELECT FROM events, and only from events.
|
||||
"""
|
||||
|
||||
if isinstance(hogql_query, ast.SelectUnionQuery):
|
||||
if isinstance(hogql_query, ast.SelectSetQuery):
|
||||
raise serializers.ValidationError("UNIONs are not supported")
|
||||
|
||||
parsed = cast(ast.SelectQuery, hogql_query)
|
||||
|
@ -1,5 +1,6 @@
|
||||
from enum import StrEnum
|
||||
from typing import Any, Literal, Optional, Union
|
||||
from typing import Any, Literal, Optional, Union, get_args
|
||||
from collections.abc import Sequence
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from posthog.hogql.base import Type, Expr, CTE, ConstantType, UnknownType, AST
|
||||
@ -173,7 +174,7 @@ class BaseTableType(Type):
|
||||
|
||||
|
||||
TableOrSelectType = Union[
|
||||
BaseTableType, "SelectUnionQueryType", "SelectQueryType", "SelectQueryAliasType", "SelectViewType"
|
||||
BaseTableType, "SelectSetQueryType", "SelectQueryType", "SelectQueryAliasType", "SelectViewType"
|
||||
]
|
||||
|
||||
|
||||
@ -243,9 +244,9 @@ class SelectQueryType(Type):
|
||||
tables: dict[str, TableOrSelectType] = field(default_factory=dict)
|
||||
ctes: dict[str, CTE] = field(default_factory=dict)
|
||||
# all from and join subqueries without aliases
|
||||
anonymous_tables: list[Union["SelectQueryType", "SelectUnionQueryType"]] = field(default_factory=list)
|
||||
anonymous_tables: list[Union["SelectQueryType", "SelectSetQueryType"]] = field(default_factory=list)
|
||||
# the parent select query, if this is a lambda
|
||||
parent: Optional[Union["SelectQueryType", "SelectUnionQueryType"]] = None
|
||||
parent: Optional[Union["SelectQueryType", "SelectSetQueryType"]] = None
|
||||
|
||||
def get_alias_for_table_type(self, table_type: TableOrSelectType) -> Optional[str]:
|
||||
for key, value in self.tables.items():
|
||||
@ -276,8 +277,8 @@ class SelectQueryType(Type):
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class SelectUnionQueryType(Type):
|
||||
types: list[SelectQueryType]
|
||||
class SelectSetQueryType(Type):
|
||||
types: list[Union[SelectQueryType, "SelectSetQueryType"]]
|
||||
|
||||
def get_alias_for_table_type(self, table_type: TableOrSelectType) -> Optional[str]:
|
||||
return self.types[0].get_alias_for_table_type(table_type)
|
||||
@ -296,7 +297,7 @@ class SelectUnionQueryType(Type):
|
||||
class SelectViewType(Type):
|
||||
view_name: str
|
||||
alias: str
|
||||
select_query_type: SelectQueryType | SelectUnionQueryType
|
||||
select_query_type: SelectQueryType | SelectSetQueryType
|
||||
|
||||
def get_child(self, name: str, context: HogQLContext) -> Type:
|
||||
if name == "*":
|
||||
@ -343,7 +344,7 @@ class SelectViewType(Type):
|
||||
@dataclass(kw_only=True)
|
||||
class SelectQueryAliasType(Type):
|
||||
alias: str
|
||||
select_query_type: SelectQueryType | SelectUnionQueryType
|
||||
select_query_type: SelectQueryType | SelectSetQueryType
|
||||
|
||||
def get_child(self, name: str, context: HogQLContext) -> Type:
|
||||
if name == "*":
|
||||
@ -763,7 +764,7 @@ class JoinExpr(Expr):
|
||||
type: Optional[TableOrSelectType] = None
|
||||
|
||||
join_type: Optional[str] = None
|
||||
table: Optional[Union["SelectQuery", "SelectUnionQuery", Field]] = None
|
||||
table: Optional[Union["SelectQuery", "SelectSetQuery", Field]] = None
|
||||
table_args: Optional[list[Expr]] = None
|
||||
alias: Optional[str] = None
|
||||
table_final: Optional[bool] = None
|
||||
@ -820,10 +821,35 @@ class SelectQuery(Expr):
|
||||
view_name: Optional[str] = None
|
||||
|
||||
|
||||
SetOperator = Literal["UNION ALL", "INTERSECT", "EXCEPT"]
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class SelectUnionQuery(Expr):
|
||||
type: Optional[SelectUnionQueryType] = None
|
||||
select_queries: list[SelectQuery]
|
||||
class SelectSetNode:
|
||||
select_query: Union[SelectQuery, "SelectSetQuery"]
|
||||
set_operator: SetOperator
|
||||
|
||||
def __post_init__(self):
|
||||
if self.set_operator not in get_args(SetOperator):
|
||||
raise ValueError("Invalid Set Operator")
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class SelectSetQuery(Expr):
|
||||
type: Optional[SelectSetQueryType] = None
|
||||
initial_select_query: Union[SelectQuery, "SelectSetQuery"]
|
||||
subsequent_select_queries: list[SelectSetNode]
|
||||
|
||||
@classmethod
|
||||
def create_from_queries(
|
||||
cls, queries: Sequence[Union[SelectQuery, "SelectSetQuery"]], set_operator: SetOperator
|
||||
) -> "SelectSetQuery":
|
||||
return SelectSetQuery(
|
||||
initial_select_query=queries[0],
|
||||
subsequent_select_queries=[
|
||||
SelectSetNode(select_query=query, set_operator=set_operator) for query in queries[1:]
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
|
@ -28,6 +28,7 @@ from posthog.hogql.resolver import resolve_types
|
||||
from posthog.hogql.timings import HogQLTimings
|
||||
from posthog.hogql.visitor import TraversingVisitor, clone_expr
|
||||
from posthog.hogql_queries.query_runner import get_query_runner
|
||||
from posthog.hogql.resolver_utils import extract_select_queries
|
||||
from posthog.models.insight_variable import InsightVariable
|
||||
from posthog.models.property_definition import PropertyDefinition
|
||||
from posthog.models.team.team import Team
|
||||
@ -475,8 +476,8 @@ def get_hogql_autocomplete(
|
||||
|
||||
if isinstance(select_ast, ast.SelectQuery):
|
||||
ctes = select_ast.ctes
|
||||
elif isinstance(select_ast, ast.SelectUnionQuery):
|
||||
ctes = select_ast.select_queries[0].ctes
|
||||
elif isinstance(select_ast, ast.SelectSetQuery):
|
||||
ctes = next(extract_select_queries(select_ast)).ctes
|
||||
nearest_select = find_node.nearest_select_query or select_ast
|
||||
|
||||
table_has_alias = (
|
||||
|
@ -24,7 +24,7 @@ def _expr(s: Union[str, ast.Expr, None], placeholders: Optional[dict[str, ast.Ex
|
||||
def _select(
|
||||
s: str,
|
||||
placeholders: Optional[dict[str, ast.Expr]] = None,
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
parsed = parse_select(s, placeholders=placeholders)
|
||||
return parsed
|
||||
|
||||
|
@ -26,7 +26,7 @@ def f(s: Union[str, ast.Expr, None], placeholders: Optional[dict[str, ast.Expr]]
|
||||
def parse(
|
||||
s: str,
|
||||
placeholders: Optional[dict[str, ast.Expr]] = None,
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
parsed = parse_select(s, placeholders=placeholders)
|
||||
return parsed
|
||||
|
||||
@ -363,7 +363,8 @@ class TestSessionsV2QueriesHogQLToClickhouse(ClickhouseTestMixin, APIBaseTest):
|
||||
|
||||
def test_select_with_timestamp(self):
|
||||
actual = self.print_query("SELECT session_id FROM sessions WHERE $start_timestamp > '2021-01-01'")
|
||||
assert self.generalize_sql(actual) == snapshot("""\
|
||||
assert self.generalize_sql(actual) == snapshot(
|
||||
"""\
|
||||
SELECT
|
||||
sessions.session_id AS session_id
|
||||
FROM
|
||||
@ -381,7 +382,8 @@ FROM
|
||||
WHERE
|
||||
ifNull(greater(sessions.`$start_timestamp`, %(hogql_val_2)s), 0)
|
||||
LIMIT 50000\
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
def test_join_with_events(self):
|
||||
actual = self.print_query(
|
||||
@ -396,7 +398,8 @@ WHERE events.timestamp > '2021-01-01'
|
||||
GROUP BY sessions.session_id
|
||||
"""
|
||||
)
|
||||
assert self.generalize_sql(actual) == snapshot("""\
|
||||
assert self.generalize_sql(actual) == snapshot(
|
||||
"""\
|
||||
SELECT
|
||||
sessions.session_id AS session_id,
|
||||
uniq(events.uuid)
|
||||
@ -417,7 +420,8 @@ WHERE
|
||||
GROUP BY
|
||||
sessions.session_id
|
||||
LIMIT 50000\
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
def test_union(self):
|
||||
actual = self.print_query(
|
||||
@ -429,7 +433,8 @@ FROM events
|
||||
WHERE events.timestamp < today()
|
||||
"""
|
||||
)
|
||||
assert self.generalize_sql(actual) == snapshot("""\
|
||||
assert self.generalize_sql(actual) == snapshot(
|
||||
"""\
|
||||
SELECT
|
||||
0 AS duration
|
||||
LIMIT 50000
|
||||
@ -451,7 +456,8 @@ FROM
|
||||
WHERE
|
||||
and(equals(events.team_id, <TEAM_ID>), less(toTimeZone(events.timestamp, %(hogql_val_4)s), today()))
|
||||
LIMIT 50000\
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
def test_session_breakdown(self):
|
||||
actual = self.print_query(
|
||||
@ -495,7 +501,8 @@ WHERE and(greaterOrEquals(timestamp, toStartOfDay(assumeNotNull(toDateTime('2024
|
||||
GROUP BY day_start,
|
||||
breakdown_value"""
|
||||
)
|
||||
assert self.generalize_sql(actual) == snapshot("""\
|
||||
assert self.generalize_sql(actual) == snapshot(
|
||||
"""\
|
||||
SELECT
|
||||
count(DISTINCT e.`$session_id`) AS total,
|
||||
toStartOfDay(toTimeZone(e.timestamp, %(hogql_val_8)s)) AS day_start,
|
||||
@ -535,7 +542,8 @@ GROUP BY
|
||||
day_start,
|
||||
breakdown_value
|
||||
LIMIT 50000\
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
def test_session_replay_query(self):
|
||||
actual = self.print_query(
|
||||
@ -548,7 +556,8 @@ WHERE s.session.$entry_pathname = '/home' AND min_first_timestamp >= '2021-01-01
|
||||
GROUP BY session_id
|
||||
"""
|
||||
)
|
||||
assert self.generalize_sql(actual) == snapshot("""\
|
||||
assert self.generalize_sql(actual) == snapshot(
|
||||
"""\
|
||||
SELECT
|
||||
s.session_id AS session_id,
|
||||
min(toTimeZone(s.min_first_timestamp, %(hogql_val_5)s)) AS start_time
|
||||
@ -569,7 +578,8 @@ WHERE
|
||||
GROUP BY
|
||||
s.session_id
|
||||
LIMIT 50000\
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
def test_urls_in_sessions_in_timestamp_query(self):
|
||||
actual = self.print_query(
|
||||
@ -582,7 +592,8 @@ from sessions
|
||||
where `$start_timestamp` >= now() - toIntervalDay(7)
|
||||
"""
|
||||
)
|
||||
assert self.generalize_sql(actual) == snapshot("""\
|
||||
assert self.generalize_sql(actual) == snapshot(
|
||||
"""\
|
||||
SELECT
|
||||
sessions.session_id AS session_id,
|
||||
sessions.`$urls` AS `$urls`,
|
||||
@ -603,4 +614,5 @@ FROM
|
||||
WHERE
|
||||
ifNull(greaterOrEquals(sessions.`$start_timestamp`, minus(now64(6, %(hogql_val_2)s), toIntervalDay(7))), 0)
|
||||
LIMIT 50000\
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
@ -26,7 +26,7 @@ def f(s: Union[str, ast.Expr, None], placeholders: Optional[dict[str, ast.Expr]]
|
||||
def parse(
|
||||
s: str,
|
||||
placeholders: Optional[dict[str, ast.Expr]] = None,
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
parsed = parse_select(s, placeholders=placeholders)
|
||||
return parsed
|
||||
|
||||
|
@ -30,6 +30,7 @@ DESCENDING: D E S C E N D I N G;
|
||||
DISTINCT: D I S T I N C T;
|
||||
ELSE: E L S E;
|
||||
END: E N D;
|
||||
EXCEPT: E X C E P T;
|
||||
EXTRACT: E X T R A C T;
|
||||
FINAL: F I N A L;
|
||||
FINALLY: F I N A L L Y;
|
||||
@ -49,6 +50,7 @@ ILIKE: I L I K E;
|
||||
IN: I N;
|
||||
INF: I N F | I N F I N I T Y;
|
||||
INNER: I N N E R;
|
||||
INTERSECT: I N T E R S E C T;
|
||||
INTERVAL: I N T E R V A L;
|
||||
IS: I S;
|
||||
JOIN: J O I N;
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -24,178 +24,180 @@ DESCENDING=23
|
||||
DISTINCT=24
|
||||
ELSE=25
|
||||
END=26
|
||||
EXTRACT=27
|
||||
FINAL=28
|
||||
FINALLY=29
|
||||
FIRST=30
|
||||
FN=31
|
||||
FOLLOWING=32
|
||||
FOR=33
|
||||
FROM=34
|
||||
FULL=35
|
||||
FUN=36
|
||||
GROUP=37
|
||||
HAVING=38
|
||||
HOUR=39
|
||||
ID=40
|
||||
IF=41
|
||||
ILIKE=42
|
||||
IN=43
|
||||
INF=44
|
||||
INNER=45
|
||||
INTERVAL=46
|
||||
IS=47
|
||||
JOIN=48
|
||||
KEY=49
|
||||
LAST=50
|
||||
LEADING=51
|
||||
LEFT=52
|
||||
LET=53
|
||||
LIKE=54
|
||||
LIMIT=55
|
||||
MINUTE=56
|
||||
MONTH=57
|
||||
NAN_SQL=58
|
||||
NOT=59
|
||||
NULL_SQL=60
|
||||
NULLS=61
|
||||
OFFSET=62
|
||||
ON=63
|
||||
OR=64
|
||||
ORDER=65
|
||||
OUTER=66
|
||||
OVER=67
|
||||
PARTITION=68
|
||||
PRECEDING=69
|
||||
PREWHERE=70
|
||||
QUARTER=71
|
||||
RANGE=72
|
||||
RETURN=73
|
||||
RIGHT=74
|
||||
ROLLUP=75
|
||||
ROW=76
|
||||
ROWS=77
|
||||
SAMPLE=78
|
||||
SECOND=79
|
||||
SELECT=80
|
||||
SEMI=81
|
||||
SETTINGS=82
|
||||
SUBSTRING=83
|
||||
THEN=84
|
||||
THROW=85
|
||||
TIES=86
|
||||
TIMESTAMP=87
|
||||
TO=88
|
||||
TOP=89
|
||||
TOTALS=90
|
||||
TRAILING=91
|
||||
TRIM=92
|
||||
TRUNCATE=93
|
||||
TRY=94
|
||||
UNBOUNDED=95
|
||||
UNION=96
|
||||
USING=97
|
||||
WEEK=98
|
||||
WHEN=99
|
||||
WHERE=100
|
||||
WHILE=101
|
||||
WINDOW=102
|
||||
WITH=103
|
||||
YEAR=104
|
||||
ESCAPE_CHAR_COMMON=105
|
||||
IDENTIFIER=106
|
||||
FLOATING_LITERAL=107
|
||||
OCTAL_LITERAL=108
|
||||
DECIMAL_LITERAL=109
|
||||
HEXADECIMAL_LITERAL=110
|
||||
STRING_LITERAL=111
|
||||
ARROW=112
|
||||
ASTERISK=113
|
||||
BACKQUOTE=114
|
||||
BACKSLASH=115
|
||||
COLON=116
|
||||
COMMA=117
|
||||
CONCAT=118
|
||||
DASH=119
|
||||
DOLLAR=120
|
||||
DOT=121
|
||||
EQ_DOUBLE=122
|
||||
EQ_SINGLE=123
|
||||
GT_EQ=124
|
||||
GT=125
|
||||
HASH=126
|
||||
IREGEX_SINGLE=127
|
||||
IREGEX_DOUBLE=128
|
||||
LBRACE=129
|
||||
LBRACKET=130
|
||||
LPAREN=131
|
||||
LT_EQ=132
|
||||
LT=133
|
||||
NOT_EQ=134
|
||||
NOT_IREGEX=135
|
||||
NOT_REGEX=136
|
||||
NULL_PROPERTY=137
|
||||
NULLISH=138
|
||||
PERCENT=139
|
||||
PLUS=140
|
||||
QUERY=141
|
||||
QUOTE_DOUBLE=142
|
||||
QUOTE_SINGLE_TEMPLATE=143
|
||||
QUOTE_SINGLE_TEMPLATE_FULL=144
|
||||
QUOTE_SINGLE=145
|
||||
REGEX_SINGLE=146
|
||||
REGEX_DOUBLE=147
|
||||
RBRACE=148
|
||||
RBRACKET=149
|
||||
RPAREN=150
|
||||
SEMICOLON=151
|
||||
SLASH=152
|
||||
UNDERSCORE=153
|
||||
MULTI_LINE_COMMENT=154
|
||||
SINGLE_LINE_COMMENT=155
|
||||
WHITESPACE=156
|
||||
STRING_TEXT=157
|
||||
STRING_ESCAPE_TRIGGER=158
|
||||
FULL_STRING_TEXT=159
|
||||
FULL_STRING_ESCAPE_TRIGGER=160
|
||||
'->'=112
|
||||
'*'=113
|
||||
'`'=114
|
||||
'\\'=115
|
||||
':'=116
|
||||
','=117
|
||||
'||'=118
|
||||
'-'=119
|
||||
'$'=120
|
||||
'.'=121
|
||||
'=='=122
|
||||
'='=123
|
||||
'>='=124
|
||||
'>'=125
|
||||
'#'=126
|
||||
'~*'=127
|
||||
'=~*'=128
|
||||
'{'=129
|
||||
'['=130
|
||||
'('=131
|
||||
'<='=132
|
||||
'<'=133
|
||||
'!~*'=135
|
||||
'!~'=136
|
||||
'?.'=137
|
||||
'??'=138
|
||||
'%'=139
|
||||
'+'=140
|
||||
'?'=141
|
||||
'"'=142
|
||||
'f\''=143
|
||||
'F\''=144
|
||||
'\''=145
|
||||
'~'=146
|
||||
'=~'=147
|
||||
'}'=148
|
||||
']'=149
|
||||
')'=150
|
||||
';'=151
|
||||
'/'=152
|
||||
'_'=153
|
||||
EXCEPT=27
|
||||
EXTRACT=28
|
||||
FINAL=29
|
||||
FINALLY=30
|
||||
FIRST=31
|
||||
FN=32
|
||||
FOLLOWING=33
|
||||
FOR=34
|
||||
FROM=35
|
||||
FULL=36
|
||||
FUN=37
|
||||
GROUP=38
|
||||
HAVING=39
|
||||
HOUR=40
|
||||
ID=41
|
||||
IF=42
|
||||
ILIKE=43
|
||||
IN=44
|
||||
INF=45
|
||||
INNER=46
|
||||
INTERSECT=47
|
||||
INTERVAL=48
|
||||
IS=49
|
||||
JOIN=50
|
||||
KEY=51
|
||||
LAST=52
|
||||
LEADING=53
|
||||
LEFT=54
|
||||
LET=55
|
||||
LIKE=56
|
||||
LIMIT=57
|
||||
MINUTE=58
|
||||
MONTH=59
|
||||
NAN_SQL=60
|
||||
NOT=61
|
||||
NULL_SQL=62
|
||||
NULLS=63
|
||||
OFFSET=64
|
||||
ON=65
|
||||
OR=66
|
||||
ORDER=67
|
||||
OUTER=68
|
||||
OVER=69
|
||||
PARTITION=70
|
||||
PRECEDING=71
|
||||
PREWHERE=72
|
||||
QUARTER=73
|
||||
RANGE=74
|
||||
RETURN=75
|
||||
RIGHT=76
|
||||
ROLLUP=77
|
||||
ROW=78
|
||||
ROWS=79
|
||||
SAMPLE=80
|
||||
SECOND=81
|
||||
SELECT=82
|
||||
SEMI=83
|
||||
SETTINGS=84
|
||||
SUBSTRING=85
|
||||
THEN=86
|
||||
THROW=87
|
||||
TIES=88
|
||||
TIMESTAMP=89
|
||||
TO=90
|
||||
TOP=91
|
||||
TOTALS=92
|
||||
TRAILING=93
|
||||
TRIM=94
|
||||
TRUNCATE=95
|
||||
TRY=96
|
||||
UNBOUNDED=97
|
||||
UNION=98
|
||||
USING=99
|
||||
WEEK=100
|
||||
WHEN=101
|
||||
WHERE=102
|
||||
WHILE=103
|
||||
WINDOW=104
|
||||
WITH=105
|
||||
YEAR=106
|
||||
ESCAPE_CHAR_COMMON=107
|
||||
IDENTIFIER=108
|
||||
FLOATING_LITERAL=109
|
||||
OCTAL_LITERAL=110
|
||||
DECIMAL_LITERAL=111
|
||||
HEXADECIMAL_LITERAL=112
|
||||
STRING_LITERAL=113
|
||||
ARROW=114
|
||||
ASTERISK=115
|
||||
BACKQUOTE=116
|
||||
BACKSLASH=117
|
||||
COLON=118
|
||||
COMMA=119
|
||||
CONCAT=120
|
||||
DASH=121
|
||||
DOLLAR=122
|
||||
DOT=123
|
||||
EQ_DOUBLE=124
|
||||
EQ_SINGLE=125
|
||||
GT_EQ=126
|
||||
GT=127
|
||||
HASH=128
|
||||
IREGEX_SINGLE=129
|
||||
IREGEX_DOUBLE=130
|
||||
LBRACE=131
|
||||
LBRACKET=132
|
||||
LPAREN=133
|
||||
LT_EQ=134
|
||||
LT=135
|
||||
NOT_EQ=136
|
||||
NOT_IREGEX=137
|
||||
NOT_REGEX=138
|
||||
NULL_PROPERTY=139
|
||||
NULLISH=140
|
||||
PERCENT=141
|
||||
PLUS=142
|
||||
QUERY=143
|
||||
QUOTE_DOUBLE=144
|
||||
QUOTE_SINGLE_TEMPLATE=145
|
||||
QUOTE_SINGLE_TEMPLATE_FULL=146
|
||||
QUOTE_SINGLE=147
|
||||
REGEX_SINGLE=148
|
||||
REGEX_DOUBLE=149
|
||||
RBRACE=150
|
||||
RBRACKET=151
|
||||
RPAREN=152
|
||||
SEMICOLON=153
|
||||
SLASH=154
|
||||
UNDERSCORE=155
|
||||
MULTI_LINE_COMMENT=156
|
||||
SINGLE_LINE_COMMENT=157
|
||||
WHITESPACE=158
|
||||
STRING_TEXT=159
|
||||
STRING_ESCAPE_TRIGGER=160
|
||||
FULL_STRING_TEXT=161
|
||||
FULL_STRING_ESCAPE_TRIGGER=162
|
||||
'->'=114
|
||||
'*'=115
|
||||
'`'=116
|
||||
'\\'=117
|
||||
':'=118
|
||||
','=119
|
||||
'||'=120
|
||||
'-'=121
|
||||
'$'=122
|
||||
'.'=123
|
||||
'=='=124
|
||||
'='=125
|
||||
'>='=126
|
||||
'>'=127
|
||||
'#'=128
|
||||
'~*'=129
|
||||
'=~*'=130
|
||||
'{'=131
|
||||
'['=132
|
||||
'('=133
|
||||
'<='=134
|
||||
'<'=135
|
||||
'!~*'=137
|
||||
'!~'=138
|
||||
'?.'=139
|
||||
'??'=140
|
||||
'%'=141
|
||||
'+'=142
|
||||
'?'=143
|
||||
'"'=144
|
||||
'f\''=145
|
||||
'F\''=146
|
||||
'\''=147
|
||||
'~'=148
|
||||
'=~'=149
|
||||
'}'=150
|
||||
']'=151
|
||||
')'=152
|
||||
';'=153
|
||||
'/'=154
|
||||
'_'=155
|
||||
|
@ -51,10 +51,12 @@ kvPairList: kvPair (COMMA kvPair)* COMMA?;
|
||||
|
||||
|
||||
// SELECT statement
|
||||
select: (selectUnionStmt | selectStmt | hogqlxTagElement) EOF;
|
||||
select: (selectSetStmt | selectStmt | hogqlxTagElement) EOF;
|
||||
|
||||
selectUnionStmt: selectStmtWithParens (UNION ALL selectStmtWithParens)*;
|
||||
selectStmtWithParens: selectStmt | LPAREN selectUnionStmt RPAREN | placeholder;
|
||||
selectStmtWithParens: selectStmt | LPAREN selectSetStmt RPAREN | placeholder;
|
||||
|
||||
subsequentSelectSetClause: (EXCEPT | UNION ALL | INTERSECT) selectStmtWithParens;
|
||||
selectSetStmt: selectStmtWithParens (subsequentSelectSetClause)*;
|
||||
|
||||
selectStmt:
|
||||
with=withClause?
|
||||
@ -201,7 +203,7 @@ columnExpr
|
||||
| <assoc=right> columnExpr QUERY columnExpr COLON columnExpr # ColumnExprTernaryOp
|
||||
| columnExpr (AS identifier | AS STRING_LITERAL) # ColumnExprAlias
|
||||
| (tableIdentifier DOT)? ASTERISK # ColumnExprAsterisk // single-column only
|
||||
| LPAREN selectUnionStmt RPAREN # ColumnExprSubquery // single-column only
|
||||
| LPAREN selectSetStmt RPAREN # ColumnExprSubquery // single-column only
|
||||
| LPAREN columnExpr RPAREN # ColumnExprParens // single-column only
|
||||
| LPAREN columnExprList RPAREN # ColumnExprTuple
|
||||
| LBRACKET columnExprList? RBRACKET # ColumnExprArray
|
||||
@ -231,7 +233,7 @@ hogqlxTagAttribute
|
||||
|
||||
withExprList: withExpr (COMMA withExpr)* COMMA?;
|
||||
withExpr
|
||||
: identifier AS LPAREN selectUnionStmt RPAREN # WithExprSubquery
|
||||
: identifier AS LPAREN selectSetStmt RPAREN # WithExprSubquery
|
||||
// NOTE: asterisk and subquery goes before |columnExpr| so that we can mark them as multi-column expressions.
|
||||
| columnExpr AS identifier # WithExprColumn
|
||||
;
|
||||
@ -246,7 +248,7 @@ nestedIdentifier: identifier (DOT identifier)*;
|
||||
tableExpr
|
||||
: tableIdentifier # TableExprIdentifier
|
||||
| tableFunctionExpr # TableExprFunction
|
||||
| LPAREN selectUnionStmt RPAREN # TableExprSubquery
|
||||
| LPAREN selectSetStmt RPAREN # TableExprSubquery
|
||||
| tableExpr (alias | AS identifier) # TableExprAlias
|
||||
| hogqlxTagElement # TableExprTag
|
||||
| placeholder # TableExprPlaceholder
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -24,178 +24,180 @@ DESCENDING=23
|
||||
DISTINCT=24
|
||||
ELSE=25
|
||||
END=26
|
||||
EXTRACT=27
|
||||
FINAL=28
|
||||
FINALLY=29
|
||||
FIRST=30
|
||||
FN=31
|
||||
FOLLOWING=32
|
||||
FOR=33
|
||||
FROM=34
|
||||
FULL=35
|
||||
FUN=36
|
||||
GROUP=37
|
||||
HAVING=38
|
||||
HOUR=39
|
||||
ID=40
|
||||
IF=41
|
||||
ILIKE=42
|
||||
IN=43
|
||||
INF=44
|
||||
INNER=45
|
||||
INTERVAL=46
|
||||
IS=47
|
||||
JOIN=48
|
||||
KEY=49
|
||||
LAST=50
|
||||
LEADING=51
|
||||
LEFT=52
|
||||
LET=53
|
||||
LIKE=54
|
||||
LIMIT=55
|
||||
MINUTE=56
|
||||
MONTH=57
|
||||
NAN_SQL=58
|
||||
NOT=59
|
||||
NULL_SQL=60
|
||||
NULLS=61
|
||||
OFFSET=62
|
||||
ON=63
|
||||
OR=64
|
||||
ORDER=65
|
||||
OUTER=66
|
||||
OVER=67
|
||||
PARTITION=68
|
||||
PRECEDING=69
|
||||
PREWHERE=70
|
||||
QUARTER=71
|
||||
RANGE=72
|
||||
RETURN=73
|
||||
RIGHT=74
|
||||
ROLLUP=75
|
||||
ROW=76
|
||||
ROWS=77
|
||||
SAMPLE=78
|
||||
SECOND=79
|
||||
SELECT=80
|
||||
SEMI=81
|
||||
SETTINGS=82
|
||||
SUBSTRING=83
|
||||
THEN=84
|
||||
THROW=85
|
||||
TIES=86
|
||||
TIMESTAMP=87
|
||||
TO=88
|
||||
TOP=89
|
||||
TOTALS=90
|
||||
TRAILING=91
|
||||
TRIM=92
|
||||
TRUNCATE=93
|
||||
TRY=94
|
||||
UNBOUNDED=95
|
||||
UNION=96
|
||||
USING=97
|
||||
WEEK=98
|
||||
WHEN=99
|
||||
WHERE=100
|
||||
WHILE=101
|
||||
WINDOW=102
|
||||
WITH=103
|
||||
YEAR=104
|
||||
ESCAPE_CHAR_COMMON=105
|
||||
IDENTIFIER=106
|
||||
FLOATING_LITERAL=107
|
||||
OCTAL_LITERAL=108
|
||||
DECIMAL_LITERAL=109
|
||||
HEXADECIMAL_LITERAL=110
|
||||
STRING_LITERAL=111
|
||||
ARROW=112
|
||||
ASTERISK=113
|
||||
BACKQUOTE=114
|
||||
BACKSLASH=115
|
||||
COLON=116
|
||||
COMMA=117
|
||||
CONCAT=118
|
||||
DASH=119
|
||||
DOLLAR=120
|
||||
DOT=121
|
||||
EQ_DOUBLE=122
|
||||
EQ_SINGLE=123
|
||||
GT_EQ=124
|
||||
GT=125
|
||||
HASH=126
|
||||
IREGEX_SINGLE=127
|
||||
IREGEX_DOUBLE=128
|
||||
LBRACE=129
|
||||
LBRACKET=130
|
||||
LPAREN=131
|
||||
LT_EQ=132
|
||||
LT=133
|
||||
NOT_EQ=134
|
||||
NOT_IREGEX=135
|
||||
NOT_REGEX=136
|
||||
NULL_PROPERTY=137
|
||||
NULLISH=138
|
||||
PERCENT=139
|
||||
PLUS=140
|
||||
QUERY=141
|
||||
QUOTE_DOUBLE=142
|
||||
QUOTE_SINGLE_TEMPLATE=143
|
||||
QUOTE_SINGLE_TEMPLATE_FULL=144
|
||||
QUOTE_SINGLE=145
|
||||
REGEX_SINGLE=146
|
||||
REGEX_DOUBLE=147
|
||||
RBRACE=148
|
||||
RBRACKET=149
|
||||
RPAREN=150
|
||||
SEMICOLON=151
|
||||
SLASH=152
|
||||
UNDERSCORE=153
|
||||
MULTI_LINE_COMMENT=154
|
||||
SINGLE_LINE_COMMENT=155
|
||||
WHITESPACE=156
|
||||
STRING_TEXT=157
|
||||
STRING_ESCAPE_TRIGGER=158
|
||||
FULL_STRING_TEXT=159
|
||||
FULL_STRING_ESCAPE_TRIGGER=160
|
||||
'->'=112
|
||||
'*'=113
|
||||
'`'=114
|
||||
'\\'=115
|
||||
':'=116
|
||||
','=117
|
||||
'||'=118
|
||||
'-'=119
|
||||
'$'=120
|
||||
'.'=121
|
||||
'=='=122
|
||||
'='=123
|
||||
'>='=124
|
||||
'>'=125
|
||||
'#'=126
|
||||
'~*'=127
|
||||
'=~*'=128
|
||||
'{'=129
|
||||
'['=130
|
||||
'('=131
|
||||
'<='=132
|
||||
'<'=133
|
||||
'!~*'=135
|
||||
'!~'=136
|
||||
'?.'=137
|
||||
'??'=138
|
||||
'%'=139
|
||||
'+'=140
|
||||
'?'=141
|
||||
'"'=142
|
||||
'f\''=143
|
||||
'F\''=144
|
||||
'\''=145
|
||||
'~'=146
|
||||
'=~'=147
|
||||
'}'=148
|
||||
']'=149
|
||||
')'=150
|
||||
';'=151
|
||||
'/'=152
|
||||
'_'=153
|
||||
EXCEPT=27
|
||||
EXTRACT=28
|
||||
FINAL=29
|
||||
FINALLY=30
|
||||
FIRST=31
|
||||
FN=32
|
||||
FOLLOWING=33
|
||||
FOR=34
|
||||
FROM=35
|
||||
FULL=36
|
||||
FUN=37
|
||||
GROUP=38
|
||||
HAVING=39
|
||||
HOUR=40
|
||||
ID=41
|
||||
IF=42
|
||||
ILIKE=43
|
||||
IN=44
|
||||
INF=45
|
||||
INNER=46
|
||||
INTERSECT=47
|
||||
INTERVAL=48
|
||||
IS=49
|
||||
JOIN=50
|
||||
KEY=51
|
||||
LAST=52
|
||||
LEADING=53
|
||||
LEFT=54
|
||||
LET=55
|
||||
LIKE=56
|
||||
LIMIT=57
|
||||
MINUTE=58
|
||||
MONTH=59
|
||||
NAN_SQL=60
|
||||
NOT=61
|
||||
NULL_SQL=62
|
||||
NULLS=63
|
||||
OFFSET=64
|
||||
ON=65
|
||||
OR=66
|
||||
ORDER=67
|
||||
OUTER=68
|
||||
OVER=69
|
||||
PARTITION=70
|
||||
PRECEDING=71
|
||||
PREWHERE=72
|
||||
QUARTER=73
|
||||
RANGE=74
|
||||
RETURN=75
|
||||
RIGHT=76
|
||||
ROLLUP=77
|
||||
ROW=78
|
||||
ROWS=79
|
||||
SAMPLE=80
|
||||
SECOND=81
|
||||
SELECT=82
|
||||
SEMI=83
|
||||
SETTINGS=84
|
||||
SUBSTRING=85
|
||||
THEN=86
|
||||
THROW=87
|
||||
TIES=88
|
||||
TIMESTAMP=89
|
||||
TO=90
|
||||
TOP=91
|
||||
TOTALS=92
|
||||
TRAILING=93
|
||||
TRIM=94
|
||||
TRUNCATE=95
|
||||
TRY=96
|
||||
UNBOUNDED=97
|
||||
UNION=98
|
||||
USING=99
|
||||
WEEK=100
|
||||
WHEN=101
|
||||
WHERE=102
|
||||
WHILE=103
|
||||
WINDOW=104
|
||||
WITH=105
|
||||
YEAR=106
|
||||
ESCAPE_CHAR_COMMON=107
|
||||
IDENTIFIER=108
|
||||
FLOATING_LITERAL=109
|
||||
OCTAL_LITERAL=110
|
||||
DECIMAL_LITERAL=111
|
||||
HEXADECIMAL_LITERAL=112
|
||||
STRING_LITERAL=113
|
||||
ARROW=114
|
||||
ASTERISK=115
|
||||
BACKQUOTE=116
|
||||
BACKSLASH=117
|
||||
COLON=118
|
||||
COMMA=119
|
||||
CONCAT=120
|
||||
DASH=121
|
||||
DOLLAR=122
|
||||
DOT=123
|
||||
EQ_DOUBLE=124
|
||||
EQ_SINGLE=125
|
||||
GT_EQ=126
|
||||
GT=127
|
||||
HASH=128
|
||||
IREGEX_SINGLE=129
|
||||
IREGEX_DOUBLE=130
|
||||
LBRACE=131
|
||||
LBRACKET=132
|
||||
LPAREN=133
|
||||
LT_EQ=134
|
||||
LT=135
|
||||
NOT_EQ=136
|
||||
NOT_IREGEX=137
|
||||
NOT_REGEX=138
|
||||
NULL_PROPERTY=139
|
||||
NULLISH=140
|
||||
PERCENT=141
|
||||
PLUS=142
|
||||
QUERY=143
|
||||
QUOTE_DOUBLE=144
|
||||
QUOTE_SINGLE_TEMPLATE=145
|
||||
QUOTE_SINGLE_TEMPLATE_FULL=146
|
||||
QUOTE_SINGLE=147
|
||||
REGEX_SINGLE=148
|
||||
REGEX_DOUBLE=149
|
||||
RBRACE=150
|
||||
RBRACKET=151
|
||||
RPAREN=152
|
||||
SEMICOLON=153
|
||||
SLASH=154
|
||||
UNDERSCORE=155
|
||||
MULTI_LINE_COMMENT=156
|
||||
SINGLE_LINE_COMMENT=157
|
||||
WHITESPACE=158
|
||||
STRING_TEXT=159
|
||||
STRING_ESCAPE_TRIGGER=160
|
||||
FULL_STRING_TEXT=161
|
||||
FULL_STRING_ESCAPE_TRIGGER=162
|
||||
'->'=114
|
||||
'*'=115
|
||||
'`'=116
|
||||
'\\'=117
|
||||
':'=118
|
||||
','=119
|
||||
'||'=120
|
||||
'-'=121
|
||||
'$'=122
|
||||
'.'=123
|
||||
'=='=124
|
||||
'='=125
|
||||
'>='=126
|
||||
'>'=127
|
||||
'#'=128
|
||||
'~*'=129
|
||||
'=~*'=130
|
||||
'{'=131
|
||||
'['=132
|
||||
'('=133
|
||||
'<='=134
|
||||
'<'=135
|
||||
'!~*'=137
|
||||
'!~'=138
|
||||
'?.'=139
|
||||
'??'=140
|
||||
'%'=141
|
||||
'+'=142
|
||||
'?'=143
|
||||
'"'=144
|
||||
'f\''=145
|
||||
'F\''=146
|
||||
'\''=147
|
||||
'~'=148
|
||||
'=~'=149
|
||||
'}'=150
|
||||
']'=151
|
||||
')'=152
|
||||
';'=153
|
||||
'/'=154
|
||||
'_'=155
|
||||
|
@ -119,13 +119,18 @@ class HogQLParserVisitor(ParseTreeVisitor):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
# Visit a parse tree produced by HogQLParser#selectUnionStmt.
|
||||
def visitSelectUnionStmt(self, ctx:HogQLParser.SelectUnionStmtContext):
|
||||
# Visit a parse tree produced by HogQLParser#selectStmtWithParens.
|
||||
def visitSelectStmtWithParens(self, ctx:HogQLParser.SelectStmtWithParensContext):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
# Visit a parse tree produced by HogQLParser#selectStmtWithParens.
|
||||
def visitSelectStmtWithParens(self, ctx:HogQLParser.SelectStmtWithParensContext):
|
||||
# Visit a parse tree produced by HogQLParser#subsequentSelectSetClause.
|
||||
def visitSubsequentSelectSetClause(self, ctx:HogQLParser.SubsequentSelectSetClauseContext):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
# Visit a parse tree produced by HogQLParser#selectSetStmt.
|
||||
def visitSelectSetStmt(self, ctx:HogQLParser.SelectSetStmtContext):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
|
@ -13,6 +13,7 @@ from posthog.hogql.variables import replace_variables
|
||||
from posthog.hogql.visitor import clone_expr
|
||||
from posthog.hogql_queries.query_runner import get_query_runner
|
||||
from posthog.models import Team
|
||||
from posthog.hogql.resolver_utils import extract_select_queries
|
||||
from posthog.schema import HogQLMetadataResponse, HogQLMetadata, HogQLNotice, HogLanguage
|
||||
from posthog.hogql import ast
|
||||
|
||||
@ -99,7 +100,7 @@ def get_hogql_metadata(
|
||||
def process_expr_on_table(
|
||||
node: ast.Expr,
|
||||
context: HogQLContext,
|
||||
source_query: Optional[ast.SelectQuery | ast.SelectUnionQuery] = None,
|
||||
source_query: Optional[ast.SelectQuery | ast.SelectSetQuery] = None,
|
||||
):
|
||||
try:
|
||||
if source_query is not None:
|
||||
@ -114,15 +115,9 @@ def process_expr_on_table(
|
||||
raise
|
||||
|
||||
|
||||
def is_valid_view(select_query: ast.SelectQuery | ast.SelectUnionQuery) -> bool:
|
||||
if isinstance(select_query, ast.SelectQuery):
|
||||
for field in select_query.select:
|
||||
def is_valid_view(select_query: ast.SelectQuery | ast.SelectSetQuery) -> bool:
|
||||
for query in extract_select_queries(select_query):
|
||||
for field in query.select:
|
||||
if not isinstance(field, ast.Alias):
|
||||
return False
|
||||
elif isinstance(select_query, ast.SelectUnionQuery):
|
||||
for select in select_query.select_queries:
|
||||
for field in select.select:
|
||||
if not isinstance(field, ast.Alias):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -6,6 +6,7 @@ from antlr4.error.ErrorListener import ErrorListener
|
||||
from prometheus_client import Histogram
|
||||
|
||||
from posthog.hogql import ast
|
||||
from posthog.hogql.ast import SelectSetNode
|
||||
from posthog.hogql.base import AST
|
||||
from posthog.hogql.constants import RESERVED_KEYWORDS
|
||||
from posthog.hogql.errors import BaseHogQLError, NotImplementedError, SyntaxError
|
||||
@ -132,7 +133,7 @@ def parse_select(
|
||||
timings: Optional[HogQLTimings] = None,
|
||||
*,
|
||||
backend: Literal["python", "cpp"] = "cpp",
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
if timings is None:
|
||||
timings = HogQLTimings()
|
||||
with timings.measure(f"parse_select_{backend}"):
|
||||
@ -327,28 +328,33 @@ class HogQLParseTreeConverter(ParseTreeVisitor):
|
||||
##### HogQL rules
|
||||
|
||||
def visitSelect(self, ctx: HogQLParser.SelectContext):
|
||||
return self.visit(ctx.selectUnionStmt() or ctx.selectStmt() or ctx.hogqlxTagElement())
|
||||
return self.visit(ctx.selectSetStmt() or ctx.selectStmt() or ctx.hogqlxTagElement())
|
||||
|
||||
def visitSelectUnionStmt(self, ctx: HogQLParser.SelectUnionStmtContext):
|
||||
select_queries: list[ast.SelectQuery | ast.SelectUnionQuery | ast.Placeholder] = [
|
||||
self.visit(select) for select in ctx.selectStmtWithParens()
|
||||
]
|
||||
flattened_queries: list[ast.SelectQuery] = []
|
||||
for query in select_queries:
|
||||
if isinstance(query, ast.SelectQuery):
|
||||
flattened_queries.append(query)
|
||||
elif isinstance(query, ast.SelectUnionQuery):
|
||||
flattened_queries.extend(query.select_queries)
|
||||
elif isinstance(query, ast.Placeholder):
|
||||
flattened_queries.append(query) # type: ignore
|
||||
def visitSelectSetStmt(self, ctx: HogQLParser.SelectSetStmtContext):
|
||||
select_queries: list[SelectSetNode] = []
|
||||
|
||||
initial_query = self.visit(ctx.selectStmtWithParens())
|
||||
|
||||
for subsequent in ctx.subsequentSelectSetClause():
|
||||
if subsequent.UNION() and subsequent.ALL():
|
||||
union_type = "UNION ALL"
|
||||
elif subsequent.INTERSECT():
|
||||
union_type = "INTERSECT"
|
||||
elif subsequent.EXCEPT():
|
||||
union_type = "EXCEPT"
|
||||
else:
|
||||
raise Exception(f"Unexpected query node type {type(query).__name__}")
|
||||
if len(flattened_queries) == 1:
|
||||
return flattened_queries[0]
|
||||
return ast.SelectUnionQuery(select_queries=flattened_queries)
|
||||
raise SyntaxError("Set operator must be one of UNION ALL, INTERSECT, and EXCEPT")
|
||||
select_query = self.visit(subsequent.selectStmtWithParens())
|
||||
select_queries.append(
|
||||
SelectSetNode(select_query=select_query, set_operator=cast(ast.SetOperator, union_type))
|
||||
)
|
||||
|
||||
if len(select_queries) == 0:
|
||||
return initial_query
|
||||
return ast.SelectSetQuery(initial_select_query=initial_query, subsequent_select_queries=select_queries)
|
||||
|
||||
def visitSelectStmtWithParens(self, ctx: HogQLParser.SelectStmtWithParensContext):
|
||||
return self.visit(ctx.selectStmt() or ctx.selectUnionStmt() or ctx.placeholder())
|
||||
return self.visit(ctx.selectStmt() or ctx.selectSetStmt() or ctx.placeholder())
|
||||
|
||||
def visitSelectStmt(self, ctx: HogQLParser.SelectStmtContext):
|
||||
select_query = ast.SelectQuery(
|
||||
@ -673,7 +679,7 @@ class HogQLParseTreeConverter(ParseTreeVisitor):
|
||||
return ast.Dict(items=self.visit(ctx.kvPairList()) if ctx.kvPairList() else [])
|
||||
|
||||
def visitColumnExprSubquery(self, ctx: HogQLParser.ColumnExprSubqueryContext):
|
||||
return self.visit(ctx.selectUnionStmt())
|
||||
return self.visit(ctx.selectSetStmt())
|
||||
|
||||
def visitColumnExprLiteral(self, ctx: HogQLParser.ColumnExprLiteralContext):
|
||||
return self.visitChildren(ctx)
|
||||
@ -958,7 +964,7 @@ class HogQLParseTreeConverter(ParseTreeVisitor):
|
||||
return ctes
|
||||
|
||||
def visitWithExprSubquery(self, ctx: HogQLParser.WithExprSubqueryContext):
|
||||
subquery = self.visit(ctx.selectUnionStmt())
|
||||
subquery = self.visit(ctx.selectSetStmt())
|
||||
name = self.visit(ctx.identifier())
|
||||
return ast.CTE(name=name, expr=subquery, cte_type="subquery")
|
||||
|
||||
@ -992,7 +998,7 @@ class HogQLParseTreeConverter(ParseTreeVisitor):
|
||||
return ast.Field(chain=chain)
|
||||
|
||||
def visitTableExprSubquery(self, ctx: HogQLParser.TableExprSubqueryContext):
|
||||
return self.visit(ctx.selectUnionStmt())
|
||||
return self.visit(ctx.selectSetStmt())
|
||||
|
||||
def visitTableExprPlaceholder(self, ctx: HogQLParser.TableExprPlaceholderContext):
|
||||
return self.visit(ctx.placeholder())
|
||||
|
@ -266,7 +266,7 @@ class _Printer(Visitor):
|
||||
self.stack.pop()
|
||||
|
||||
if len(self.stack) == 0 and self.dialect == "clickhouse" and self.settings:
|
||||
if not isinstance(node, ast.SelectQuery) and not isinstance(node, ast.SelectUnionQuery):
|
||||
if not isinstance(node, ast.SelectQuery) and not isinstance(node, ast.SelectSetQuery):
|
||||
raise QueryError("Settings can only be applied to SELECT queries")
|
||||
settings = self._print_settings(self.settings)
|
||||
if settings is not None:
|
||||
@ -274,17 +274,25 @@ class _Printer(Visitor):
|
||||
|
||||
return response
|
||||
|
||||
def visit_select_union_query(self, node: ast.SelectUnionQuery):
|
||||
def visit_select_set_query(self, node: ast.SelectSetQuery):
|
||||
self._indent -= 1
|
||||
queries = [self.visit(expr) for expr in node.select_queries]
|
||||
ret = self.visit(node.initial_select_query)
|
||||
if self.pretty:
|
||||
query = f"\n{self.indent(1)}UNION ALL\n{self.indent(1)}".join([query.strip() for query in queries])
|
||||
else:
|
||||
query = " UNION ALL ".join(queries)
|
||||
ret = ret.strip()
|
||||
for expr in node.subsequent_select_queries:
|
||||
query = self.visit(expr.select_query)
|
||||
if self.pretty:
|
||||
query = query.strip()
|
||||
if expr.set_operator is not None:
|
||||
if self.pretty:
|
||||
ret += f"\n{self.indent(1)}{expr.set_operator}\n{self.indent(1)}"
|
||||
else:
|
||||
ret += f" {expr.set_operator} "
|
||||
ret += query
|
||||
self._indent += 1
|
||||
if len(self.stack) > 1:
|
||||
return f"({query.strip()})"
|
||||
return query
|
||||
return f"({ret.strip()})"
|
||||
return ret
|
||||
|
||||
def visit_select_query(self, node: ast.SelectQuery):
|
||||
if self.dialect == "clickhouse":
|
||||
@ -293,8 +301,8 @@ class _Printer(Visitor):
|
||||
if not self.context.team_id:
|
||||
raise InternalHogQLError("Full SELECT queries are disabled if context.team_id is not set")
|
||||
|
||||
# if we are the first parsed node in the tree, or a child of a SelectUnionQuery, mark us as a top level query
|
||||
part_of_select_union = len(self.stack) >= 2 and isinstance(self.stack[-2], ast.SelectUnionQuery)
|
||||
# if we are the first parsed node in the tree, or a child of a SelectSetQuery, mark us as a top level query
|
||||
part_of_select_union = len(self.stack) >= 2 and isinstance(self.stack[-2], ast.SelectSetQuery)
|
||||
is_top_level_query = len(self.stack) <= 1 or (len(self.stack) == 2 and part_of_select_union)
|
||||
|
||||
# We will add extra clauses onto this from the joined tables
|
||||
@ -507,7 +515,7 @@ class _Printer(Visitor):
|
||||
elif isinstance(node.type, ast.SelectQueryType):
|
||||
join_strings.append(self.visit(node.table))
|
||||
|
||||
elif isinstance(node.type, ast.SelectUnionQueryType):
|
||||
elif isinstance(node.type, ast.SelectSetQueryType):
|
||||
join_strings.append(self.visit(node.table))
|
||||
|
||||
elif isinstance(node.type, ast.SelectViewType) and node.alias is not None:
|
||||
@ -1251,7 +1259,7 @@ class _Printer(Visitor):
|
||||
isinstance(type.table_type, ast.SelectQueryType)
|
||||
or isinstance(type.table_type, ast.SelectQueryAliasType)
|
||||
or isinstance(type.table_type, ast.SelectViewType)
|
||||
or isinstance(type.table_type, ast.SelectUnionQueryType)
|
||||
or isinstance(type.table_type, ast.SelectSetQueryType)
|
||||
):
|
||||
field_sql = self._print_identifier(type.name)
|
||||
if isinstance(type.table_type, ast.SelectQueryAliasType) or isinstance(type.table_type, ast.SelectViewType):
|
||||
|
@ -19,6 +19,7 @@ from posthog.hogql.filters import replace_filters
|
||||
from posthog.hogql.timings import HogQLTimings
|
||||
from posthog.hogql.variables import replace_variables
|
||||
from posthog.hogql.visitor import clone_expr
|
||||
from posthog.hogql.resolver_utils import extract_select_queries
|
||||
from posthog.models.team import Team
|
||||
from posthog.clickhouse.query_tagging import tag_queries
|
||||
from posthog.client import sync_execute
|
||||
@ -35,7 +36,7 @@ from posthog.settings import HOGQL_INCREASED_MAX_EXECUTION_TIME
|
||||
|
||||
|
||||
def execute_hogql_query(
|
||||
query: Union[str, ast.SelectQuery, ast.SelectUnionQuery],
|
||||
query: Union[str, ast.SelectQuery, ast.SelectSetQuery],
|
||||
team: Team,
|
||||
*,
|
||||
query_type: str = "hogql_query",
|
||||
@ -65,7 +66,7 @@ def execute_hogql_query(
|
||||
metadata: Optional[HogQLMetadataResponse] = None
|
||||
|
||||
with timings.measure("query"):
|
||||
if isinstance(query, ast.SelectQuery) or isinstance(query, ast.SelectUnionQuery):
|
||||
if isinstance(query, ast.SelectQuery) or isinstance(query, ast.SelectSetQuery):
|
||||
select_query = query
|
||||
query = None
|
||||
else:
|
||||
@ -105,10 +106,7 @@ def execute_hogql_query(
|
||||
select_query = replace_placeholders(select_query, placeholders)
|
||||
|
||||
with timings.measure("max_limit"):
|
||||
select_queries = (
|
||||
select_query.select_queries if isinstance(select_query, ast.SelectUnionQuery) else [select_query]
|
||||
)
|
||||
for one_query in select_queries:
|
||||
for one_query in extract_select_queries(select_query):
|
||||
if one_query.limit is None:
|
||||
one_query.limit = ast.Constant(value=get_default_limit_for_context(limit_context))
|
||||
|
||||
@ -138,8 +136,8 @@ def execute_hogql_query(
|
||||
)
|
||||
print_columns = []
|
||||
columns_query = (
|
||||
select_query_hogql.select_queries[0]
|
||||
if isinstance(select_query_hogql, ast.SelectUnionQuery)
|
||||
next(extract_select_queries(select_query_hogql))
|
||||
if isinstance(select_query_hogql, ast.SelectSetQuery)
|
||||
else select_query_hogql
|
||||
)
|
||||
for node in columns_query.select:
|
||||
|
@ -24,7 +24,12 @@ from posthog.hogql.functions.recording_button import recording_button
|
||||
from posthog.hogql.functions.sparkline import sparkline
|
||||
from posthog.hogql.hogqlx import HOGQLX_COMPONENTS, convert_to_hx
|
||||
from posthog.hogql.parser import parse_select
|
||||
from posthog.hogql.resolver_utils import expand_hogqlx_query, lookup_cte_by_name, lookup_field_by_name
|
||||
from posthog.hogql.resolver_utils import (
|
||||
expand_hogqlx_query,
|
||||
lookup_cte_by_name,
|
||||
lookup_field_by_name,
|
||||
extract_select_queries,
|
||||
)
|
||||
from posthog.hogql.visitor import CloningVisitor, TraversingVisitor, clone_expr
|
||||
from posthog.models.utils import UUIDT
|
||||
|
||||
@ -123,15 +128,17 @@ class Resolver(CloningVisitor):
|
||||
raise QueryError("Too many CTE expansions (50+). Probably a CTE loop.")
|
||||
return super().visit(node)
|
||||
|
||||
def visit_select_union_query(self, node: ast.SelectUnionQuery):
|
||||
def visit_select_set_query(self, node: ast.SelectSetQuery):
|
||||
# all expressions combined by UNION ALL can use CTEs from the first expression
|
||||
# so we put these CTEs to the scope
|
||||
default_ctes = node.select_queries[0].ctes if node.select_queries else None
|
||||
default_ctes = next(extract_select_queries(node)).ctes
|
||||
if default_ctes:
|
||||
self.scopes.append(ast.SelectQueryType(ctes=default_ctes))
|
||||
|
||||
node = super().visit_select_union_query(node)
|
||||
node.type = ast.SelectUnionQueryType(types=[expr.type for expr in node.select_queries])
|
||||
node = super().visit_select_set_query(node)
|
||||
node.type = ast.SelectSetQueryType(
|
||||
types=[node.initial_select_query.type, *(x.select_query.type for x in node.subsequent_select_queries)] # type: ignore
|
||||
)
|
||||
|
||||
if default_ctes:
|
||||
self.scopes.pop()
|
||||
@ -254,7 +261,7 @@ class Resolver(CloningVisitor):
|
||||
database_fields = table.get_asterisk()
|
||||
return [ast.Field(chain=[key]) for key in database_fields.keys()]
|
||||
elif (
|
||||
isinstance(asterisk.table_type, ast.SelectUnionQueryType)
|
||||
isinstance(asterisk.table_type, ast.SelectSetQueryType)
|
||||
or isinstance(asterisk.table_type, ast.SelectQueryType)
|
||||
or isinstance(asterisk.table_type, ast.SelectQueryAliasType)
|
||||
or isinstance(asterisk.table_type, ast.SelectViewType)
|
||||
@ -262,7 +269,7 @@ class Resolver(CloningVisitor):
|
||||
select = asterisk.table_type
|
||||
while isinstance(select, ast.SelectQueryAliasType) or isinstance(select, ast.SelectViewType):
|
||||
select = select.select_query_type
|
||||
if isinstance(select, ast.SelectUnionQueryType):
|
||||
if isinstance(select, ast.SelectSetQueryType):
|
||||
select = select.types[0]
|
||||
if isinstance(select, ast.SelectQueryType):
|
||||
return [ast.Field(chain=[key]) for key in select.columns.keys()]
|
||||
@ -369,7 +376,7 @@ class Resolver(CloningVisitor):
|
||||
|
||||
return node
|
||||
|
||||
elif isinstance(node.table, ast.SelectQuery) or isinstance(node.table, ast.SelectUnionQuery):
|
||||
elif isinstance(node.table, ast.SelectQuery) or isinstance(node.table, ast.SelectSetQuery):
|
||||
node = cast(ast.JoinExpr, clone_expr(node))
|
||||
if node.constraint and node.constraint.constraint_type == "USING":
|
||||
# visit USING constraint before adding the table to avoid ambiguous names
|
||||
|
@ -1,4 +1,5 @@
|
||||
from typing import Optional
|
||||
from collections.abc import Generator
|
||||
|
||||
from posthog import schema
|
||||
from posthog.hogql import ast
|
||||
@ -86,3 +87,12 @@ def expand_hogqlx_query(node: ast.HogQLXTag, team_id: Optional[int]):
|
||||
return query
|
||||
except Exception as e:
|
||||
raise ResolutionError(f"Error parsing query tag: {e}", start=node.start, end=node.end)
|
||||
|
||||
|
||||
def extract_select_queries(select: ast.SelectSetQuery | ast.SelectQuery) -> Generator[ast.SelectQuery, None, None]:
|
||||
if isinstance(select, ast.SelectQuery):
|
||||
yield select
|
||||
else:
|
||||
yield from extract_select_queries(select.initial_select_query)
|
||||
for select_query in select.subsequent_select_queries:
|
||||
yield from extract_select_queries(select_query.select_query)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,8 @@ from posthog.hogql.ast import (
|
||||
Array,
|
||||
Dict,
|
||||
VariableDeclaration,
|
||||
SelectSetNode,
|
||||
SelectSetQuery,
|
||||
)
|
||||
|
||||
from posthog.hogql.parser import parse_program
|
||||
@ -50,9 +52,9 @@ def parser_test_factory(backend: Literal["python", "cpp"]):
|
||||
|
||||
def _select(
|
||||
self, query: str, placeholders: Optional[dict[str, ast.Expr]] = None
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery | ast.HogQLXTag:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery | ast.HogQLXTag:
|
||||
return cast(
|
||||
ast.SelectQuery | ast.SelectUnionQuery | ast.HogQLXTag,
|
||||
ast.SelectQuery | ast.SelectSetQuery | ast.HogQLXTag,
|
||||
clear_locations(parse_select(query, placeholders=placeholders, backend=backend)),
|
||||
)
|
||||
|
||||
@ -1381,12 +1383,48 @@ def parser_test_factory(backend: Literal["python", "cpp"]):
|
||||
def test_select_union_all(self):
|
||||
self.assertEqual(
|
||||
self._select("select 1 union all select 2 union all select 3"),
|
||||
ast.SelectUnionQuery(
|
||||
select_queries=[
|
||||
ast.SelectQuery(select=[ast.Constant(value=1)]),
|
||||
ast.SelectQuery(select=[ast.Constant(value=2)]),
|
||||
ast.SelectQuery(select=[ast.Constant(value=3)]),
|
||||
]
|
||||
ast.SelectSetQuery(
|
||||
initial_select_query=ast.SelectQuery(select=[ast.Constant(value=1)]),
|
||||
subsequent_select_queries=[
|
||||
SelectSetNode(set_operator="UNION ALL", select_query=query)
|
||||
for query in (
|
||||
ast.SelectQuery(select=[ast.Constant(value=2)]),
|
||||
ast.SelectQuery(select=[ast.Constant(value=3)]),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
def test_nested_selects(self):
|
||||
self.assertEqual(
|
||||
self._select("(select 1 intersect select 2) union all (select 3 except select 4)"),
|
||||
SelectSetQuery(
|
||||
initial_select_query=SelectSetQuery(
|
||||
initial_select_query=SelectQuery(select=[Constant(value=1)]),
|
||||
subsequent_select_queries=[
|
||||
SelectSetNode(
|
||||
select_query=SelectQuery(
|
||||
select=[Constant(value=2)],
|
||||
),
|
||||
set_operator="INTERSECT",
|
||||
)
|
||||
],
|
||||
),
|
||||
subsequent_select_queries=[
|
||||
SelectSetNode(
|
||||
select_query=SelectSetQuery(
|
||||
initial_select_query=SelectQuery(
|
||||
select=[Constant(value=3)],
|
||||
),
|
||||
subsequent_select_queries=[
|
||||
SelectSetNode(
|
||||
select_query=SelectQuery(select=[Constant(value=4)]), set_operator="EXCEPT"
|
||||
)
|
||||
],
|
||||
),
|
||||
set_operator="UNION ALL",
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -114,6 +114,136 @@ class TestPrinter(BaseTest):
|
||||
repsponse, f"SELECT\n plus(1, 2),\n 3\nFROM\n events\nLIMIT {MAX_SELECT_RETURNED_ROWS}"
|
||||
)
|
||||
|
||||
def test_intersect(self):
|
||||
expr = parse_select("""select 1 as id intersect select 2 as id""")
|
||||
response = to_printed_hogql(expr, self.team)
|
||||
self.assertEqual(
|
||||
response,
|
||||
f"SELECT\n 1 AS id\nLIMIT 50000\nINTERSECT\nSELECT\n 2 AS id\nLIMIT {MAX_SELECT_RETURNED_ROWS}",
|
||||
)
|
||||
|
||||
def test_except(self):
|
||||
expr = parse_select("""select 1 as id except select 2 as id""")
|
||||
response = to_printed_hogql(expr, self.team)
|
||||
self.assertEqual(
|
||||
response,
|
||||
f"SELECT\n 1 AS id\nLIMIT 50000\nEXCEPT\nSELECT\n 2 AS id\nLIMIT {MAX_SELECT_RETURNED_ROWS}",
|
||||
)
|
||||
|
||||
# these share the same priority, should stay in order
|
||||
def test_except_and_union(self):
|
||||
expr = parse_select("""select 1 as id except select 2 as id union all select 3 as id""")
|
||||
response = to_printed_hogql(expr, self.team)
|
||||
self.assertEqual(
|
||||
response,
|
||||
(
|
||||
"SELECT\n"
|
||||
" 1 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"EXCEPT\n"
|
||||
"SELECT\n"
|
||||
" 2 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"UNION ALL\n"
|
||||
"SELECT\n"
|
||||
" 3 AS id\n"
|
||||
"LIMIT 50000"
|
||||
),
|
||||
)
|
||||
|
||||
def test_union_and_except(self):
|
||||
expr = parse_select("""select 1 as id union all select 2 as id except select 3 as id""")
|
||||
response = to_printed_hogql(expr, self.team)
|
||||
self.assertEqual(
|
||||
response,
|
||||
(
|
||||
"SELECT\n"
|
||||
" 1 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"UNION ALL\n"
|
||||
"SELECT\n"
|
||||
" 2 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"EXCEPT\n"
|
||||
"SELECT\n"
|
||||
" 3 AS id\n"
|
||||
"LIMIT 50000"
|
||||
),
|
||||
)
|
||||
|
||||
def test_intersect3(self):
|
||||
expr = parse_select("""select 1 as id intersect select 2 as id intersect select 3 as id""")
|
||||
response = to_printed_hogql(expr, self.team)
|
||||
self.assertEqual(
|
||||
response,
|
||||
"SELECT\n"
|
||||
" 1 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"INTERSECT\n"
|
||||
"SELECT\n"
|
||||
" 2 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"INTERSECT\n"
|
||||
"SELECT\n"
|
||||
" 3 AS id\n"
|
||||
"LIMIT 50000",
|
||||
)
|
||||
|
||||
def test_union3(self):
|
||||
expr = parse_select("""select 1 as id union all select 2 as id union all select 3 as id""")
|
||||
response = to_printed_hogql(expr, self.team)
|
||||
self.assertEqual(
|
||||
response,
|
||||
"SELECT\n"
|
||||
" 1 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"UNION ALL\n"
|
||||
"SELECT\n"
|
||||
" 2 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"UNION ALL\n"
|
||||
"SELECT\n"
|
||||
" 3 AS id\n"
|
||||
"LIMIT 50000",
|
||||
)
|
||||
|
||||
def test_intersect_and_union_parens(self):
|
||||
expr = parse_select("""select 1 as id intersect (select 2 as id union all select 3 as id)""")
|
||||
response = to_printed_hogql(expr, self.team)
|
||||
self.assertEqual(
|
||||
response,
|
||||
"SELECT\n"
|
||||
" 1 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"INTERSECT\n"
|
||||
"(SELECT\n"
|
||||
" 2 AS id\n"
|
||||
"UNION ALL\n"
|
||||
"SELECT\n"
|
||||
" 3 AS id)",
|
||||
)
|
||||
|
||||
# INTERSECT has higher priority than union
|
||||
def test_intersect_and_union(self):
|
||||
expr = parse_select("""select 1 as id union all select 2 as id intersect select 3 as id""")
|
||||
response = to_printed_hogql(expr, self.team)
|
||||
self.assertEqual(
|
||||
response,
|
||||
(
|
||||
"SELECT\n"
|
||||
" 1 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"UNION ALL\n"
|
||||
"SELECT\n"
|
||||
" 2 AS id\n"
|
||||
"LIMIT 50000\n"
|
||||
"INTERSECT\n"
|
||||
"SELECT\n"
|
||||
" 3 AS id\n"
|
||||
"LIMIT 50000"
|
||||
),
|
||||
)
|
||||
|
||||
def test_print_to_string(self):
|
||||
assert str(parse_select("select 1 + 2, 3 from events")) == "sql(SELECT plus(1, 2), 3 FROM events)"
|
||||
assert str(parse_expr("1 + 2")) == "sql(plus(1, 2))"
|
||||
@ -1076,7 +1206,7 @@ class TestPrinter(BaseTest):
|
||||
)
|
||||
self.assertEqual(
|
||||
self._select("SELECT 1 UNION ALL (SELECT 1 UNION ALL SELECT 1) UNION ALL SELECT 1"),
|
||||
f"SELECT 1 LIMIT {MAX_SELECT_RETURNED_ROWS} UNION ALL SELECT 1 LIMIT {MAX_SELECT_RETURNED_ROWS} UNION ALL SELECT 1 LIMIT {MAX_SELECT_RETURNED_ROWS} UNION ALL SELECT 1 LIMIT {MAX_SELECT_RETURNED_ROWS}",
|
||||
f"SELECT 1 LIMIT {MAX_SELECT_RETURNED_ROWS} UNION ALL (SELECT 1 UNION ALL SELECT 1) UNION ALL SELECT 1 LIMIT {MAX_SELECT_RETURNED_ROWS}",
|
||||
)
|
||||
self.assertEqual(
|
||||
self._select("SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1"),
|
||||
|
@ -2,6 +2,7 @@ from copy import deepcopy
|
||||
from typing import Optional, TypeVar, Generic, Any
|
||||
|
||||
from posthog.hogql import ast
|
||||
from posthog.hogql.ast import SelectSetNode
|
||||
from posthog.hogql.base import AST, Expr
|
||||
from posthog.hogql.errors import BaseHogQLError
|
||||
|
||||
@ -151,9 +152,10 @@ class TraversingVisitor(Visitor[None]):
|
||||
for expr in (node.window_exprs or {}).values():
|
||||
self.visit(expr)
|
||||
|
||||
def visit_select_union_query(self, node: ast.SelectUnionQuery):
|
||||
for expr in node.select_queries:
|
||||
self.visit(expr)
|
||||
def visit_select_set_query(self, node: ast.SelectSetQuery):
|
||||
self.visit(node.initial_select_query)
|
||||
for expr in node.subsequent_select_queries:
|
||||
self.visit(expr.select_query)
|
||||
|
||||
def visit_lambda_argument_type(self, node: ast.LambdaArgumentType):
|
||||
pass
|
||||
@ -174,7 +176,7 @@ class TraversingVisitor(Visitor[None]):
|
||||
for expr in node.columns.values():
|
||||
self.visit(expr)
|
||||
|
||||
def visit_select_union_query_type(self, node: ast.SelectUnionQueryType):
|
||||
def visit_select_set_query_type(self, node: ast.SelectSetQueryType):
|
||||
for type in node.types:
|
||||
self.visit(type)
|
||||
|
||||
@ -600,12 +602,16 @@ class CloningVisitor(Visitor[Any]):
|
||||
view_name=node.view_name,
|
||||
)
|
||||
|
||||
def visit_select_union_query(self, node: ast.SelectUnionQuery):
|
||||
return ast.SelectUnionQuery(
|
||||
def visit_select_set_query(self, node: ast.SelectSetQuery):
|
||||
return ast.SelectSetQuery(
|
||||
start=None if self.clear_locations else node.start,
|
||||
end=None if self.clear_locations else node.end,
|
||||
type=None if self.clear_types else node.type,
|
||||
select_queries=[self.visit(expr) for expr in node.select_queries],
|
||||
initial_select_query=self.visit(node.initial_select_query),
|
||||
subsequent_select_queries=[
|
||||
SelectSetNode(set_operator=expr.set_operator, select_query=self.visit(expr.select_query))
|
||||
for expr in node.subsequent_select_queries
|
||||
],
|
||||
)
|
||||
|
||||
def visit_window_expr(self, node: ast.WindowExpr):
|
||||
|
@ -6,6 +6,7 @@ from posthog.hogql import ast
|
||||
from posthog.hogql.constants import HogQLGlobalSettings
|
||||
from posthog.hogql.parser import parse_expr, parse_order_expr
|
||||
from posthog.hogql.property import has_aggregation
|
||||
from posthog.hogql.resolver_utils import extract_select_queries
|
||||
from posthog.hogql_queries.actor_strategies import ActorStrategy, PersonStrategy, GroupStrategy
|
||||
from posthog.hogql_queries.insights.funnels.funnels_query_runner import FunnelsQueryRunner
|
||||
from posthog.hogql_queries.insights.insight_actors_query_runner import InsightActorsQueryRunner
|
||||
@ -142,12 +143,12 @@ class ActorsQueryRunner(QueryRunner):
|
||||
return self.strategy.input_columns()
|
||||
|
||||
# TODO: Figure out a more sure way of getting the actor id than using the alias or chain name
|
||||
def source_id_column(self, source_query: ast.SelectQuery | ast.SelectUnionQuery) -> list[str]:
|
||||
def source_id_column(self, source_query: ast.SelectQuery | ast.SelectSetQuery) -> list[str]:
|
||||
# Figure out the id column of the source query, first column that has id in the name
|
||||
if isinstance(source_query, ast.SelectQuery):
|
||||
select = source_query.select
|
||||
else:
|
||||
select = source_query.select_queries[0].select
|
||||
select = next(extract_select_queries(source_query)).select
|
||||
|
||||
for column in select:
|
||||
if isinstance(column, ast.Alias) and (column.alias in ("group_key", "actor_id", "person_id")):
|
||||
|
@ -49,7 +49,7 @@ class ActorsPropertyTaxonomyQueryRunner(TaxonomyCacheMixin, QueryRunner):
|
||||
modifiers=self.modifiers,
|
||||
)
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
query = ast.SelectQuery(
|
||||
select=[
|
||||
ast.Call(name="groupArray", args=[ast.Field(chain=["prop"])], params=[ast.Constant(value=5)]),
|
||||
|
@ -49,7 +49,7 @@ class EventTaxonomyQueryRunner(TaxonomyCacheMixin, QueryRunner):
|
||||
modifiers=self.modifiers,
|
||||
)
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
query = parse_select(
|
||||
"""
|
||||
SELECT
|
||||
|
@ -43,7 +43,7 @@ class TeamTaxonomyQueryRunner(TaxonomyCacheMixin, QueryRunner):
|
||||
results=results, timings=response.timings, hogql=hogql, modifiers=self.modifiers
|
||||
)
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
query = parse_select(
|
||||
"""
|
||||
SELECT
|
||||
|
@ -532,7 +532,7 @@ class FunnelBase(ABC):
|
||||
|
||||
return ast.JoinExpr(
|
||||
join_type="INNER JOIN",
|
||||
table=ast.SelectUnionQuery(select_queries=cohort_queries),
|
||||
table=ast.SelectSetQuery.create_from_queries(cohort_queries, "UNION ALL"),
|
||||
alias="cohort_join",
|
||||
constraint=ast.JoinConstraint(
|
||||
expr=ast.CompareOperation(
|
||||
|
@ -332,7 +332,7 @@ class FunnelCorrelationQueryRunner(QueryRunner):
|
||||
|
||||
return EventDefinition(event=event, properties={}, elements=[])
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
"""
|
||||
Returns a query string and params, which are used to generate the contingency table.
|
||||
The query returns success and failure count for event / property values, along with total success and failure counts.
|
||||
@ -345,7 +345,7 @@ class FunnelCorrelationQueryRunner(QueryRunner):
|
||||
|
||||
return self.get_event_query()
|
||||
|
||||
def to_actors_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_actors_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
assert self.correlation_actors_query is not None
|
||||
|
||||
if self.query.funnelCorrelationType == FunnelCorrelationResultsType.PROPERTIES:
|
||||
@ -362,7 +362,7 @@ class FunnelCorrelationQueryRunner(QueryRunner):
|
||||
else:
|
||||
return self.events_actor_query()
|
||||
|
||||
def events_actor_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def events_actor_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
assert self.correlation_actors_query is not None
|
||||
|
||||
if not self.correlation_actors_query.funnelCorrelationPersonEntity:
|
||||
@ -431,7 +431,7 @@ class FunnelCorrelationQueryRunner(QueryRunner):
|
||||
|
||||
def properties_actor_query(
|
||||
self,
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
assert self.correlation_actors_query is not None
|
||||
|
||||
if not self.correlation_actors_query.funnelCorrelationPropertyValues:
|
||||
@ -470,7 +470,7 @@ class FunnelCorrelationQueryRunner(QueryRunner):
|
||||
|
||||
return query
|
||||
|
||||
def get_event_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def get_event_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
funnel_persons_query = self.get_funnel_actors_cte()
|
||||
event_join_query = self._get_events_join_query()
|
||||
target_step = self.context.max_steps
|
||||
@ -548,7 +548,7 @@ class FunnelCorrelationQueryRunner(QueryRunner):
|
||||
|
||||
return event_correlation_query
|
||||
|
||||
def get_event_property_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def get_event_property_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
if not self.query.funnelCorrelationEventNames:
|
||||
raise ValidationError("Event Property Correlation expects atleast one event name to run correlation on")
|
||||
|
||||
@ -646,7 +646,7 @@ class FunnelCorrelationQueryRunner(QueryRunner):
|
||||
|
||||
return query
|
||||
|
||||
def get_properties_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def get_properties_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
if not self.query.funnelCorrelationNames:
|
||||
raise ValidationError("Property Correlation expects atleast one Property to run correlation on")
|
||||
|
||||
|
@ -115,7 +115,7 @@ class FunnelUnordered(FunnelBase):
|
||||
entities_to_use.append(entities_to_use.pop(0))
|
||||
union_queries.append(formatted_query)
|
||||
|
||||
return ast.SelectUnionQuery(select_queries=union_queries)
|
||||
return ast.SelectSetQuery.create_from_queries(union_queries, "UNION ALL")
|
||||
|
||||
def _get_step_times(self, max_steps: int) -> list[ast.Expr]:
|
||||
windowInterval = self.context.funnelWindowInterval
|
||||
|
@ -76,7 +76,7 @@ class FunnelsQueryRunner(QueryRunner):
|
||||
def to_query(self) -> ast.SelectQuery:
|
||||
return self.funnel_class.get_query()
|
||||
|
||||
def to_actors_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_actors_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
return self.funnel_actor_class.actor_query()
|
||||
|
||||
def calculate(self):
|
||||
|
@ -21,7 +21,7 @@ class InsightActorsQueryOptionsRunner(QueryRunner):
|
||||
def source_runner(self) -> QueryRunner:
|
||||
return get_query_runner(self.query.source.source, self.team, self.timings, self.limit_context)
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
raise ValueError(f"Cannot convert source query of type {self.query.source.kind} to query")
|
||||
|
||||
def calculate(self) -> InsightActorsQueryOptionsResponse:
|
||||
|
@ -33,7 +33,7 @@ class InsightActorsQueryRunner(QueryRunner):
|
||||
def source_runner(self) -> QueryRunner:
|
||||
return get_query_runner(self.query.source, self.team, self.timings, self.limit_context, self.modifiers)
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
if isinstance(self.source_runner, TrendsQueryRunner):
|
||||
trends_runner = cast(TrendsQueryRunner, self.source_runner)
|
||||
query = cast(InsightActorsQuery, self.query)
|
||||
@ -73,7 +73,7 @@ class InsightActorsQueryRunner(QueryRunner):
|
||||
|
||||
raise ValueError(f"Cannot convert source query of type {self.query.source.kind} to persons query")
|
||||
|
||||
def to_actors_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_actors_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
return self.to_query()
|
||||
|
||||
@property
|
||||
|
@ -33,7 +33,7 @@ class LifecycleQueryRunner(QueryRunner):
|
||||
response: LifecycleQueryResponse
|
||||
cached_response: CachedLifecycleQueryResponse
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
if self.query.samplingFactor == 0:
|
||||
counts_with_sampling = ast.Constant(value=0)
|
||||
elif self.query.samplingFactor is not None and self.query.samplingFactor != 1:
|
||||
@ -95,7 +95,7 @@ class LifecycleQueryRunner(QueryRunner):
|
||||
|
||||
def to_actors_query(
|
||||
self, day: Optional[str] = None, status: Optional[str] = None
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
with self.timings.measure("actors_query"):
|
||||
exprs = []
|
||||
if day is not None:
|
||||
|
@ -750,7 +750,7 @@ class PathsQueryRunner(QueryRunner):
|
||||
)
|
||||
return conditions
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
placeholders: dict[str, ast.Expr] = {
|
||||
"paths_per_person_query": self.paths_per_person_query(),
|
||||
}
|
||||
@ -876,7 +876,7 @@ class PathsQueryRunner(QueryRunner):
|
||||
def extra_event_fields_and_properties(self) -> list[str]:
|
||||
return self.extra_event_fields + self.extra_event_properties
|
||||
|
||||
def to_actors_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_actors_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
# To include matching_events, we need to add extra fields and properties
|
||||
# TODO: Make sure going via self is the best way to do this
|
||||
self.extra_event_fields = ["uuid", "timestamp"]
|
||||
|
@ -316,7 +316,7 @@ class RetentionQueryRunner(QueryRunner):
|
||||
|
||||
return inner_query
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
with self.timings.measure("retention_query"):
|
||||
if self.query.retentionFilter.cumulative:
|
||||
actor_query = parse_select(
|
||||
|
@ -128,8 +128,8 @@ class StickinessQueryRunner(QueryRunner):
|
||||
|
||||
return cast(ast.SelectQuery, select_query)
|
||||
|
||||
def to_query(self) -> ast.SelectUnionQuery:
|
||||
return ast.SelectUnionQuery(select_queries=self.to_queries())
|
||||
def to_query(self) -> ast.SelectSetQuery:
|
||||
return ast.SelectSetQuery.create_from_queries(self.to_queries(), "UNION ALL")
|
||||
|
||||
def to_queries(self) -> list[ast.SelectQuery]:
|
||||
queries = []
|
||||
@ -170,7 +170,7 @@ class StickinessQueryRunner(QueryRunner):
|
||||
|
||||
return queries
|
||||
|
||||
def to_actors_query(self, interval_num: Optional[int] = None) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_actors_query(self, interval_num: Optional[int] = None) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
queries: list[ast.SelectQuery] = []
|
||||
|
||||
for series in self.series:
|
||||
@ -194,7 +194,7 @@ class StickinessQueryRunner(QueryRunner):
|
||||
|
||||
queries.append(events_query)
|
||||
|
||||
return ast.SelectUnionQuery(select_queries=queries)
|
||||
return ast.SelectSetQuery.create_from_queries(queries, "UNION ALL")
|
||||
|
||||
def calculate(self):
|
||||
queries = self.to_queries()
|
||||
|
@ -187,8 +187,8 @@ class AggregationOperations(DataWarehouseInsightQueryMixin):
|
||||
return f"toStartOf{self.query_date_range.interval_name.title()}"
|
||||
|
||||
def _actors_parent_select_query(
|
||||
self, inner_query: ast.SelectQuery | ast.SelectUnionQuery
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
self, inner_query: ast.SelectQuery | ast.SelectSetQuery
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
if self.is_count_per_actor_variant():
|
||||
query = parse_select(
|
||||
"SELECT total FROM {inner_query}",
|
||||
@ -232,8 +232,8 @@ class AggregationOperations(DataWarehouseInsightQueryMixin):
|
||||
return query
|
||||
|
||||
def _actors_inner_select_query(
|
||||
self, cross_join_select_query: ast.SelectQuery | ast.SelectUnionQuery
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
self, cross_join_select_query: ast.SelectQuery | ast.SelectSetQuery
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
if self.is_count_per_actor_variant():
|
||||
if self.series.math == "avg_count_per_actor":
|
||||
math_func = self._math_func("avg", ["total"])
|
||||
@ -308,7 +308,7 @@ class AggregationOperations(DataWarehouseInsightQueryMixin):
|
||||
|
||||
def _actors_events_query(
|
||||
self, events_where_clause: ast.Expr, sample_value: ast.RatioExpr
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
date_from_with_lookback = "{date_from} - {inclusive_lookback}"
|
||||
if self.chart_display_type in NON_TIME_SERIES_DISPLAY_TYPES and self.series.math in (
|
||||
BaseMathType.WEEKLY_ACTIVE,
|
||||
|
@ -31,7 +31,7 @@ class TrendsDisplay:
|
||||
def should_wrap_inner_query(self) -> bool:
|
||||
return self.display_type == ChartDisplayType.ACTIONS_LINE_GRAPH_CUMULATIVE
|
||||
|
||||
def _build_aggregate_dates(self, dates_queries: ast.SelectUnionQuery) -> ast.Expr:
|
||||
def _build_aggregate_dates(self, dates_queries: ast.SelectSetQuery) -> ast.Expr:
|
||||
return parse_select(
|
||||
"""
|
||||
SELECT day_start
|
||||
@ -49,7 +49,7 @@ class TrendsDisplay:
|
||||
)
|
||||
|
||||
def modify_outer_query(
|
||||
self, outer_query: ast.SelectQuery, inner_query: ast.SelectQuery, dates_queries: ast.SelectUnionQuery
|
||||
self, outer_query: ast.SelectQuery, inner_query: ast.SelectQuery, dates_queries: ast.SelectSetQuery
|
||||
) -> ast.SelectQuery:
|
||||
if not self.is_total_value():
|
||||
return outer_query
|
||||
|
@ -167,7 +167,7 @@ class TrendsActorsQueryBuilder:
|
||||
def is_total_value(self) -> bool:
|
||||
return self.trends_display.is_total_value()
|
||||
|
||||
def build_actors_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def build_actors_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
return ast.SelectQuery(
|
||||
select=[
|
||||
ast.Field(chain=["actor_id"]),
|
||||
|
@ -60,7 +60,7 @@ class TrendsQueryBuilder(DataWarehouseInsightQueryMixin):
|
||||
self.modifiers = modifiers
|
||||
self.limit_context = limit_context
|
||||
|
||||
def build_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def build_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
breakdown = self.breakdown
|
||||
events_query = self._get_events_subquery(False, is_actors_query=False, breakdown=breakdown)
|
||||
|
||||
@ -73,7 +73,7 @@ class TrendsQueryBuilder(DataWarehouseInsightQueryMixin):
|
||||
|
||||
def _get_wrapper_query(
|
||||
self, events_query: ast.SelectQuery, breakdown: Breakdown
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
if not breakdown.enabled:
|
||||
return events_query
|
||||
|
||||
@ -312,7 +312,7 @@ class TrendsQueryBuilder(DataWarehouseInsightQueryMixin):
|
||||
|
||||
def _outer_select_query(
|
||||
self, breakdown: Breakdown, inner_query: ast.SelectQuery
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
total_array = parse_expr(
|
||||
"""
|
||||
arrayMap(
|
||||
@ -453,7 +453,7 @@ class TrendsQueryBuilder(DataWarehouseInsightQueryMixin):
|
||||
) or get_breakdown_limit_for_context(self.limit_context)
|
||||
|
||||
def _inner_select_query(
|
||||
self, breakdown: Breakdown, inner_query: ast.SelectQuery | ast.SelectUnionQuery
|
||||
self, breakdown: Breakdown, inner_query: ast.SelectQuery | ast.SelectSetQuery
|
||||
) -> ast.SelectQuery:
|
||||
query = cast(
|
||||
ast.SelectQuery,
|
||||
|
@ -110,16 +110,10 @@ class TrendsQueryRunner(QueryRunner):
|
||||
|
||||
return BASE_MINIMUM_INSIGHT_REFRESH_INTERVAL
|
||||
|
||||
def to_query(self) -> ast.SelectUnionQuery:
|
||||
queries = []
|
||||
for query in self.to_queries():
|
||||
if isinstance(query, ast.SelectQuery):
|
||||
queries.append(query)
|
||||
else:
|
||||
queries.extend(query.select_queries)
|
||||
return ast.SelectUnionQuery(select_queries=queries)
|
||||
def to_query(self) -> ast.SelectSetQuery:
|
||||
return ast.SelectSetQuery.create_from_queries(self.to_queries(), "UNION ALL")
|
||||
|
||||
def to_queries(self) -> list[ast.SelectQuery | ast.SelectUnionQuery]:
|
||||
def to_queries(self) -> list[ast.SelectQuery | ast.SelectSetQuery]:
|
||||
queries = []
|
||||
with self.timings.measure("trends_to_query"):
|
||||
for series in self.series:
|
||||
@ -154,7 +148,7 @@ class TrendsQueryRunner(QueryRunner):
|
||||
breakdown_value: Optional[str | int | list[str]] = None,
|
||||
compare_value: Optional[Compare] = None,
|
||||
include_recordings: Optional[bool] = None,
|
||||
) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
with self.timings.measure("trends_to_actors_query"):
|
||||
if self.query.breakdownFilter and self.query.breakdownFilter.breakdown_type == BreakdownType.COHORT:
|
||||
if self.query.breakdownFilter.breakdown in ("all", ["all"]) or breakdown_value == "all":
|
||||
@ -300,18 +294,16 @@ class TrendsQueryRunner(QueryRunner):
|
||||
def calculate(self):
|
||||
queries = self.to_queries()
|
||||
|
||||
if len(queries) == 1:
|
||||
response_hogql_query = queries[0]
|
||||
if len(queries) == 0:
|
||||
response_hogql = ""
|
||||
else:
|
||||
response_hogql_query = ast.SelectUnionQuery(select_queries=[])
|
||||
for query in queries:
|
||||
if isinstance(query, ast.SelectQuery):
|
||||
response_hogql_query.select_queries.append(query)
|
||||
else:
|
||||
response_hogql_query.select_queries.extend(query.select_queries)
|
||||
if len(queries) == 1:
|
||||
response_hogql_query = queries[0]
|
||||
else:
|
||||
response_hogql_query = ast.SelectSetQuery.create_from_queries(queries, "UNION ALL")
|
||||
|
||||
with self.timings.measure("printing_hogql_for_response"):
|
||||
response_hogql = to_printed_hogql(response_hogql_query, self.team, self.modifiers)
|
||||
with self.timings.measure("printing_hogql_for_response"):
|
||||
response_hogql = to_printed_hogql(response_hogql_query, self.team, self.modifiers)
|
||||
|
||||
res_matrix: list[list[Any] | Any | None] = [None] * len(queries)
|
||||
timings_matrix: list[list[QueryTiming] | None] = [None] * (2 + len(queries))
|
||||
@ -320,7 +312,7 @@ class TrendsQueryRunner(QueryRunner):
|
||||
|
||||
def run(
|
||||
index: int,
|
||||
query: ast.SelectQuery | ast.SelectUnionQuery,
|
||||
query: ast.SelectQuery | ast.SelectSetQuery,
|
||||
timings: HogQLTimings,
|
||||
is_parallel: bool,
|
||||
query_tags: Optional[dict] = None,
|
||||
|
@ -11,7 +11,7 @@ class QueryAlternator:
|
||||
_group_bys: list[ast.Expr]
|
||||
_select_from: ast.JoinExpr | None
|
||||
|
||||
def __init__(self, query: ast.SelectQuery | ast.SelectUnionQuery):
|
||||
def __init__(self, query: ast.SelectQuery | ast.SelectSetQuery):
|
||||
assert isinstance(query, ast.SelectQuery)
|
||||
|
||||
self._query = query
|
||||
@ -19,7 +19,7 @@ class QueryAlternator:
|
||||
self._group_bys = []
|
||||
self._select_from = None
|
||||
|
||||
def build(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def build(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
if len(self._selects) > 0:
|
||||
self._query.select.extend(self._selects)
|
||||
|
||||
|
@ -708,10 +708,10 @@ class QueryRunner(ABC, Generic[Q, R, CR]):
|
||||
return fresh_response
|
||||
|
||||
@abstractmethod
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
raise NotImplementedError()
|
||||
|
||||
def to_actors_query(self, *args, **kwargs) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_actors_query(self, *args, **kwargs) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
# TODO: add support for selecting and filtering by breakdowns
|
||||
raise NotImplementedError()
|
||||
|
||||
|
@ -16,7 +16,7 @@ class WebTopClicksQueryRunner(WebAnalyticsQueryRunner):
|
||||
response: WebTopClicksQueryResponse
|
||||
cached_response: CachedWebTopClicksQueryResponse
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
with self.timings.measure("top_clicks_query"):
|
||||
top_sources_query = parse_select(
|
||||
"""
|
||||
|
@ -24,7 +24,7 @@ class WebGoalsQueryRunner(WebAnalyticsQueryRunner):
|
||||
response: WebGoalsQueryResponse
|
||||
cached_response: CachedWebGoalsQueryResponse
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
with self.timings.measure("date_expr"):
|
||||
start = self.query_date_range.date_from_as_hogql()
|
||||
end = self.query_date_range.date_to_as_hogql()
|
||||
|
@ -28,7 +28,7 @@ class WebOverviewQueryRunner(WebAnalyticsQueryRunner):
|
||||
response: WebOverviewQueryResponse
|
||||
cached_response: CachedWebOverviewQueryResponse
|
||||
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def to_query(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
return self.outer_select
|
||||
|
||||
def calculate(self):
|
||||
|
@ -7,6 +7,8 @@ from dateutil import parser
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from posthog.hogql.resolver_utils import extract_select_queries
|
||||
from posthog.queries.util import PersonPropertiesMode
|
||||
from posthog.clickhouse.client.connection import Workload
|
||||
from posthog.clickhouse.query_tagging import tag_queries
|
||||
@ -83,8 +85,7 @@ def print_cohort_hogql_query(cohort: Cohort, hogql_context: HogQLContext) -> str
|
||||
cast(dict, cohort.query), team=cast(Team, cohort.team), limit_context=LimitContext.COHORT_CALCULATION
|
||||
).to_query()
|
||||
|
||||
select_queries: list[ast.SelectQuery] = [query] if isinstance(query, ast.SelectQuery) else query.select_queries
|
||||
for select_query in select_queries:
|
||||
for select_query in extract_select_queries(query):
|
||||
columns: dict[str, ast.Expr] = {}
|
||||
for expr in select_query.select:
|
||||
if isinstance(expr, ast.Alias):
|
||||
|
@ -328,7 +328,7 @@ class PersonsPropertiesSubQuery:
|
||||
self._filter = filter
|
||||
self._ttl_days = ttl_days
|
||||
|
||||
def get_query(self) -> ast.SelectQuery | ast.SelectUnionQuery | None:
|
||||
def get_query(self) -> ast.SelectQuery | ast.SelectSetQuery | None:
|
||||
if self.person_properties and not poe_is_active(self._team):
|
||||
return parse_select(
|
||||
"""
|
||||
@ -383,7 +383,7 @@ HAVING argMax(is_deleted, version) = 0 AND {cohort_predicate}
|
||||
self._filter = filter
|
||||
self._ttl_days = ttl_days
|
||||
|
||||
def get_query(self) -> ast.SelectQuery | ast.SelectUnionQuery | None:
|
||||
def get_query(self) -> ast.SelectQuery | ast.SelectSetQuery | None:
|
||||
if self.cohort_properties:
|
||||
return parse_select(
|
||||
self.raw_cohort_to_distinct_id,
|
||||
@ -433,7 +433,7 @@ class PersonsIdCompareOperation:
|
||||
right=q,
|
||||
)
|
||||
|
||||
def get_query(self) -> ast.SelectQuery | ast.SelectUnionQuery | None:
|
||||
def get_query(self) -> ast.SelectQuery | ast.SelectSetQuery | None:
|
||||
if not self._filter.person_uuid:
|
||||
return None
|
||||
|
||||
@ -529,14 +529,14 @@ class ReplayFiltersEventsSubQuery:
|
||||
group_by=[ast.Field(chain=["$session_id"])],
|
||||
)
|
||||
|
||||
def get_query_for_session_id_matching(self) -> ast.SelectQuery | ast.SelectUnionQuery | None:
|
||||
def get_query_for_session_id_matching(self) -> ast.SelectQuery | ast.SelectSetQuery | None:
|
||||
use_poe = poe_is_active(self._team) and self.person_properties
|
||||
if self._filter.entities or self.event_properties or self.group_properties or use_poe:
|
||||
return self._select_from_events(ast.Alias(alias="session_id", expr=ast.Field(chain=["$session_id"])))
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_query_for_event_id_matching(self) -> ast.SelectQuery | ast.SelectUnionQuery:
|
||||
def get_query_for_event_id_matching(self) -> ast.SelectQuery | ast.SelectSetQuery:
|
||||
return self._select_from_events(ast.Call(name="groupUniqArray", args=[ast.Field(chain=["uuid"])]))
|
||||
|
||||
def get_event_ids_for_session(self) -> SessionRecordingQueryResult:
|
||||
|
@ -10,6 +10,7 @@ from django.db import connection, models, transaction
|
||||
from posthog.hogql import ast
|
||||
from posthog.hogql.database.database import Database, create_hogql_database
|
||||
from posthog.hogql.parser import parse_select
|
||||
from posthog.hogql.resolver_utils import extract_select_queries
|
||||
from posthog.models.team import Team
|
||||
from posthog.models.user import User
|
||||
from posthog.models.utils import (
|
||||
@ -99,8 +100,8 @@ def get_parents_from_model_query(model_query: str) -> set[str]:
|
||||
|
||||
hogql_query = parse_select(model_query)
|
||||
|
||||
if isinstance(hogql_query, ast.SelectUnionQuery):
|
||||
queries = hogql_query.select_queries
|
||||
if isinstance(hogql_query, ast.SelectSetQuery):
|
||||
queries = list(extract_select_queries(hogql_query))
|
||||
else:
|
||||
queries = [hogql_query]
|
||||
|
||||
@ -114,8 +115,8 @@ def get_parents_from_model_query(model_query: str) -> set[str]:
|
||||
for name, cte in query.ctes.items():
|
||||
ctes.add(name)
|
||||
|
||||
if isinstance(cte.expr, ast.SelectUnionQuery):
|
||||
queries.extend(cte.expr.select_queries)
|
||||
if isinstance(cte.expr, ast.SelectSetQuery):
|
||||
queries.extend(list(extract_select_queries(cte.expr)))
|
||||
elif isinstance(cte.expr, ast.SelectQuery):
|
||||
queries.append(cte.expr)
|
||||
|
||||
@ -130,8 +131,8 @@ def get_parents_from_model_query(model_query: str) -> set[str]:
|
||||
continue
|
||||
|
||||
queries.append(join.table)
|
||||
elif isinstance(join.table, ast.SelectUnionQuery):
|
||||
queries.extend(join.table.select_queries)
|
||||
elif isinstance(join.table, ast.SelectSetQuery):
|
||||
queries.extend(list(extract_select_queries(join.table)))
|
||||
|
||||
while join is not None:
|
||||
parent_name = join.table.chain[0] # type: ignore
|
||||
|
@ -105,7 +105,7 @@ phonenumberslite==8.13.6
|
||||
openai==1.51.2
|
||||
tiktoken==0.8.0
|
||||
nh3==0.2.14
|
||||
hogql-parser==1.0.45
|
||||
hogql-parser==1.0.46
|
||||
zxcvbn==4.4.28
|
||||
zstd==1.5.5.1
|
||||
xmlsec==1.3.13 # Do not change this version - it will break SAML
|
||||
|
@ -282,7 +282,7 @@ h11==0.13.0
|
||||
# wsproto
|
||||
hexbytes==1.0.0
|
||||
# via dlt
|
||||
hogql-parser==1.0.45
|
||||
hogql-parser==1.0.46
|
||||
# via -r requirements.in
|
||||
httpcore==1.0.2
|
||||
# via httpx
|
||||
|
Loading…
Reference in New Issue
Block a user