mirror of
https://github.com/grafana/grafana.git
synced 2025-07-30 20:52:34 +08:00
SQL Expressions: Add more functions to the allowlist (#103546)
* SQL Expressions: Allow many more functions and nodes * Also allow the `REGEXP_SUBSTR` function * Add window functions * add more JSON support, remove now and current time (for now) --------- Co-authored-by: Kyle Brandt <kyle@grafana.com>
This commit is contained in:
@ -28,8 +28,13 @@ func TestAllowQuery(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "all allowed functions",
|
||||
q: example_all_allowed_functions,
|
||||
name: "many allowed functions",
|
||||
q: example_many_allowed_functions,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "many more allowed functions",
|
||||
q: example_many_more_allowed_functions,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
@ -77,6 +82,16 @@ func TestAllowQuery(t *testing.T) {
|
||||
q: `SELECT '2024-04-01 15:30:00' BETWEEN '2024-04-01 15:29:00' AND '2024-04-01 15:31:00'`,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "window functions",
|
||||
q: example_window_functions,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "json table",
|
||||
q: "SELECT * FROM mockGitHubIssuesDSResponse, JSON_TABLE(labels, '$[*]' COLUMNS(val VARCHAR(255) PATH '$')) AS jt WHERE CAST(jt.val AS CHAR) LIKE 'type%'",
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@ -174,15 +189,15 @@ var example_case_statement = `SELECT
|
||||
END AS category
|
||||
FROM metrics`
|
||||
|
||||
var example_all_allowed_functions = `WITH sample_data AS (
|
||||
var example_many_allowed_functions = `WITH sample_data AS (
|
||||
SELECT
|
||||
100 AS value,
|
||||
'example' AS name,
|
||||
NOW() AS created_at
|
||||
'2025-01-01 00:00:00' AS created_at
|
||||
UNION ALL SELECT
|
||||
50 AS value,
|
||||
'test' AS name,
|
||||
DATE_SUB(NOW(), INTERVAL 1 DAY) AS created_at
|
||||
DATE_SUB('2025-01-01 00:00:00', INTERVAL 1 DAY) AS created_at
|
||||
)
|
||||
SELECT
|
||||
-- Conditional functions
|
||||
@ -229,17 +244,15 @@ SELECT
|
||||
|
||||
-- Date functions
|
||||
STR_TO_DATE('2023-01-01', '%Y-%m-%d') AS date_str_to_date,
|
||||
DATE_FORMAT(NOW(), '%Y-%m-%d') AS date_format,
|
||||
NOW() AS date_now,
|
||||
CURDATE() AS date_curdate,
|
||||
CURTIME() AS date_curtime,
|
||||
DATE_FORMAT('2025-01-01 00:00:00', '%Y-%m-%d') AS date_format,
|
||||
'2025-01-01 00:00:00' AS date_now,
|
||||
DATE_ADD(created_at, INTERVAL 1 DAY) AS date_add,
|
||||
DATE_SUB(created_at, INTERVAL 1 DAY) AS date_sub,
|
||||
YEAR(created_at) AS date_year,
|
||||
MONTH(created_at) AS date_month,
|
||||
DAY(created_at) AS date_day,
|
||||
WEEKDAY(created_at) AS date_weekday,
|
||||
DATEDIFF(NOW(), created_at) AS date_datediff,
|
||||
DATEDIFF('2025-01-01 00:00:00', created_at) AS date_datediff,
|
||||
UNIX_TIMESTAMP(created_at) AS date_unix_timestamp,
|
||||
FROM_UNIXTIME(1634567890) AS date_from_unixtime,
|
||||
|
||||
@ -261,3 +274,84 @@ var example_json_functions = `SELECT
|
||||
JSON_LENGTH('{"a": 1, "b": {"c": 3}}') AS json_len,
|
||||
JSON_SEARCH('{"a": "xyz", "b": "abc"}', 'one', 'abc') AS json_search,
|
||||
JSON_TYPE('{"a": 1}') AS json_type`
|
||||
|
||||
var example_many_more_allowed_functions = `
|
||||
SELECT
|
||||
-- Math functions
|
||||
LN(10) as ln_val,
|
||||
TRUNCATE(12.345, 2) as truncate_val,
|
||||
SIN(0.5) as sin_val,
|
||||
COS(0.5) as cos_val,
|
||||
TAN(0.5) as tan_val,
|
||||
ASIN(0.5) as asin_val,
|
||||
ACOS(0.5) as acos_val,
|
||||
ATAN(0.5) as atan_val,
|
||||
ATAN2(1, 2) as atan2_val,
|
||||
RAND() as rand_val,
|
||||
PI() as pi_val,
|
||||
|
||||
-- String functions
|
||||
LEFT('hello', 2) as left_val,
|
||||
RIGHT('hello', 2) as right_val,
|
||||
LTRIM(' hello') as ltrim_val,
|
||||
RTRIM('hello ') as rtrim_val,
|
||||
REPLACE('hello', 'l', 'x') as replace_val,
|
||||
REVERSE('hello') as reverse_val,
|
||||
LCASE('HELLO') as lcase_val,
|
||||
UCASE('hello') as ucase_val,
|
||||
MID('hello', 2, 2) as mid_val,
|
||||
REPEAT('a', 3) as repeat_val,
|
||||
POSITION('l' IN 'hello') as position_val,
|
||||
INSTR('hello', 'l') as instr_val,
|
||||
LOCATE('l', 'hello') as locate_val,
|
||||
ASCII('A') as ascii_val,
|
||||
ORD('A') as ord_val,
|
||||
CHAR(65) as char_val,
|
||||
REGEXP_SUBSTR('hello world', 'world') as regexp_substr_val,
|
||||
|
||||
-- Date functions
|
||||
EXTRACT(YEAR FROM '2023-01-01') as extract_val,
|
||||
HOUR('12:34:56') as hour_val,
|
||||
MINUTE('12:34:56') as minute_val,
|
||||
SECOND('12:34:56') as second_val,
|
||||
DAYNAME('2023-01-01') as dayname_val,
|
||||
MONTHNAME('2023-01-01') as monthname_val,
|
||||
DAYOFWEEK('2023-01-01') as dayofweek_val,
|
||||
DAYOFMONTH('2023-01-01') as dayofmonth_val,
|
||||
DAYOFYEAR('2023-01-01') as dayofyear_val,
|
||||
WEEK('2023-01-01') as week_val,
|
||||
QUARTER('2023-01-01') as quarter_val,
|
||||
TIME_TO_SEC('12:34:56') as time_to_sec_val,
|
||||
SEC_TO_TIME(45296) as sec_to_time_val,
|
||||
TIMESTAMPDIFF(HOUR, '2023-01-01', '2023-01-02') as timestampdiff_val,
|
||||
TIMESTAMPADD(HOUR, 1, '2023-01-01') as timestampadd_val,
|
||||
|
||||
-- Type conversion
|
||||
CONVERT(12.34, CHAR) as convert_val,
|
||||
|
||||
-- JSON functions
|
||||
JSON_MERGE_PATCH('{"a": 1}', '{"b": 2}') as json_merge_patch_val,
|
||||
JSON_VALID('{"a": 1}') as json_valid_val,
|
||||
JSON_KEYS('{"a": 1, "b": 2}') as json_keys_val,
|
||||
JSON_QUOTE('hello') as json_quote_val,
|
||||
JSON_INSERT('{"a": 1}', '$.b', 2) as json_insert_val,
|
||||
JSON_REPLACE('{"a": 1, "b": 2}', '$.b', 3) as json_replace_val
|
||||
FROM dual;`
|
||||
|
||||
var example_window_functions = `
|
||||
WITH dummy_data AS (
|
||||
SELECT 1 as val, 'apple' as txt
|
||||
UNION ALL SELECT 2, 'banana'
|
||||
UNION ALL SELECT 3, 'cherry'
|
||||
)
|
||||
SELECT
|
||||
val,
|
||||
txt,
|
||||
ROW_NUMBER() OVER (ORDER BY val) as row_num,
|
||||
RANK() OVER (ORDER BY val) as rank_val,
|
||||
DENSE_RANK() OVER (ORDER BY val) as dense_rank_val,
|
||||
LEAD(val) OVER (ORDER BY val) as lead_val,
|
||||
LAG(val) OVER (ORDER BY val) as lag_val,
|
||||
FIRST_VALUE(val) OVER (ORDER BY val) as first_val,
|
||||
LAST_VALUE(val) OVER (ORDER BY val ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as last_val
|
||||
FROM dummy_data;`
|
||||
|
Reference in New Issue
Block a user