diff --git a/backend/parsers/windmill-parser-sql/src/lib.rs b/backend/parsers/windmill-parser-sql/src/lib.rs index 9e24c33c0b..2e3af43421 100644 --- a/backend/parsers/windmill-parser-sql/src/lib.rs +++ b/backend/parsers/windmill-parser-sql/src/lib.rs @@ -61,24 +61,27 @@ lazy_static::lazy_static! { static ref RE_CODE_PGSQL: Regex = Regex::new(r#"(?m)\$(\d+)(?:::(\w+(?:\[\])?))?"#).unwrap(); // -- $1 name (type) = default - static ref RE_ARG_MYSQL: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap(); + static ref RE_ARG_MYSQL: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); + pub static ref RE_ARG_MYSQL_NAMED: Regex = Regex::new(r#"(?m)^-- :([a-z_][a-z0-9_]*) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); - static ref RE_ARG_PGSQL: Regex = Regex::new(r#"(?m)^-- \$(\d+) (\w+)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap(); + static ref RE_ARG_PGSQL: Regex = Regex::new(r#"(?m)^-- \$(\d+) (\w+)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); // -- @name (type) = default - static ref RE_ARG_BIGQUERY: Regex = Regex::new(r#"(?m)^-- @(\w+) \((\w+(?:\[\])?)\)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap(); + static ref RE_ARG_BIGQUERY: Regex = Regex::new(r#"(?m)^-- @(\w+) \((\w+(?:\[\])?)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); - static ref RE_ARG_SNOWFLAKE: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap(); + static ref RE_ARG_SNOWFLAKE: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); - static ref RE_ARG_MSSQL: Regex = Regex::new(r#"(?m)^-- @(?:P|p)\d+ (\w+) \((\w+)\)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap(); + static ref RE_ARG_MSSQL: Regex = Regex::new(r#"(?m)^-- @(?:P|p)\d+ (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); } fn parse_mysql_file(code: &str) -> anyhow::Result>> { let mut args: Vec = vec![]; - for cap in RE_ARG_MYSQL.captures_iter(code) { + let mut using_named_args = false; + for cap in RE_ARG_MYSQL_NAMED.captures_iter(code) { + using_named_args = true; let name = cap.get(1).map(|x| x.as_str().to_string()).unwrap(); let typ = cap .get(2) @@ -102,6 +105,33 @@ fn parse_mysql_file(code: &str) -> anyhow::Result>> { }); } + if !using_named_args { + // backwards compatibility + for cap in RE_ARG_MYSQL.captures_iter(code) { + let name = cap.get(1).map(|x| x.as_str().to_string()).unwrap(); + let typ = cap + .get(2) + .map(|x| x.as_str().to_string().to_lowercase()) + .unwrap(); + let default = cap.get(3).map(|x| x.as_str().to_string()); + let has_default = default.is_some(); + let parsed_typ = parse_mysql_typ(typ.as_str()); + + let parsed_default = default.and_then(|x| match parsed_typ { + Typ::Int => x.parse::().ok().map(|x| json!(x)), + Typ::Float => x.parse::().ok().map(|x| json!(x)), + _ => Some(json!(x)), + }); + args.push(Arg { + name, + typ: parsed_typ, + default: parsed_default, + otyp: Some(typ), + has_default, + }); + } + } + Ok(Some(args)) } diff --git a/backend/parsers/windmill-parser-wasm/pkg/package.json b/backend/parsers/windmill-parser-wasm/pkg/package.json index 1bb3322f21..4ee2b3e48b 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/package.json +++ b/backend/parsers/windmill-parser-wasm/pkg/package.json @@ -3,7 +3,7 @@ "collaborators": [ "Ruben Fiszel " ], - "version": "1.219.1", + "version": "1.221.0", "files": [ "windmill_parser_wasm_bg.wasm", "windmill_parser_wasm.js", diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js index 98c1e3acb8..4104776d85 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js +++ b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js @@ -97,15 +97,6 @@ function getInt32Memory0() { return cachedInt32Memory0; } -function addHeapObject(obj) { - if (heap_next === heap.length) heap.push(heap.length + 1); - const idx = heap_next; - heap_next = heap[idx]; - - heap[idx] = obj; - return idx; -} - const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; @@ -115,6 +106,15 @@ function getStringFromWasm0(ptr, len) { return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); } +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + let cachedFloat64Memory0 = null; function getFloat64Memory0() { @@ -515,6 +515,10 @@ async function __wbg_load(module, imports) { function __wbg_get_imports() { const imports = {}; imports.wbg = {}; + imports.wbg.__wbg_eval_815c246ab40cdfe4 = function(arg0, arg1) { + const ret = eval(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }; imports.wbg.__wbindgen_object_drop_ref = function(arg0) { takeObject(arg0); }; @@ -526,8 +530,8 @@ function __wbg_get_imports() { getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_eval_a7fb8f2e206bad71 = function(arg0, arg1) { - const ret = eval(getStringFromWasm0(arg0, arg1)); + imports.wbg.__wbindgen_error_new = function(arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }; imports.wbg.__wbindgen_boolean_get = function(arg0) { @@ -551,10 +555,6 @@ function __wbg_get_imports() { const ret = BigInt.asUintN(64, arg0); return addHeapObject(ret); }; - imports.wbg.__wbindgen_error_new = function(arg0, arg1) { - const ret = new Error(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }; imports.wbg.__wbindgen_number_get = function(arg0, arg1) { const obj = getObject(arg1); const ret = typeof(obj) === 'number' ? obj : undefined; diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm index bf25ad23c6..8389e64dc9 100644 Binary files a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm and b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm differ diff --git a/backend/windmill-worker/src/mysql_executor.rs b/backend/windmill-worker/src/mysql_executor.rs index 59e5875a5d..ab8b60c22d 100644 --- a/backend/windmill-worker/src/mysql_executor.rs +++ b/backend/windmill-worker/src/mysql_executor.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use base64::Engine; use mysql_async::{ consts::ColumnType, prelude::*, FromValueError, OptsBuilder, Params, Row, SslOpts, @@ -9,7 +11,7 @@ use windmill_common::{ error::{to_anyhow, Error}, jobs::QueuedJob, }; -use windmill_parser_sql::parse_mysql_sig; +use windmill_parser_sql::{parse_mysql_sig, RE_ARG_MYSQL_NAMED}; use crate::{common::build_args_map, AuthedClientBackgroundTask}; @@ -63,14 +65,19 @@ pub async fn do_mysql( let pool = mysql_async::Pool::new(opts); let mut conn = pool.get_conn().await.map_err(to_anyhow)?; - let mut statement_values: Vec = vec![]; - let sig = parse_mysql_sig(&query) .map_err(|x| Error::ExecutionErr(x.to_string()))? .args; + let using_named_params = RE_ARG_MYSQL_NAMED.captures_iter(&query).count() > 0; + + let mut statement_values: Params = match using_named_params { + true => Params::Named(HashMap::new()), + false => Params::Positional(vec![]), + }; for arg in &sig { let arg_t = arg.otyp.clone().unwrap_or_else(|| "text".to_string()); + let arg_n = arg.clone().name; let mysql_v = match job .args .as_ref() @@ -103,10 +110,23 @@ pub async fn do_mysql( ))) } }; - statement_values.push(mysql_v); + match &mut statement_values { + Params::Positional(v) => v.push(mysql_v), + Params::Named(m) => { + m.insert(arg_n.into_bytes(), mysql_v); + } + _ => {} + } } let rows: Vec = conn - .exec(query, Params::Positional(statement_values)) + .exec( + query, + match statement_values { + Params::Positional(v) => Params::Positional(v), + Params::Named(m) => Params::Named(m), + _ => Params::Empty, + }, + ) .await .map_err(to_anyhow)?; let rows = rows diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 972e76b817..a36d84eb0f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -48,7 +48,7 @@ "vscode-languageclient": "~9.0.1", "vscode-uri": "~3.0.8", "vscode-ws-jsonrpc": "~3.1.0", - "windmill-parser-wasm": "^1.219.1", + "windmill-parser-wasm": "^1.221.0", "y-monaco": "^0.1.4", "y-websocket": "^1.5.0", "yaml": "^2.3.4", @@ -9585,9 +9585,9 @@ } }, "node_modules/windmill-parser-wasm": { - "version": "1.219.1", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.219.1.tgz", - "integrity": "sha512-nmiS1F5Lfjb3SIescYIH3Zd333wZzekeZxjMgH3barj6LJn/sqpEFcJn9J1kptrIycth9ec5urQj5J1lMJfuvg==" + "version": "1.221.0", + "resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.221.0.tgz", + "integrity": "sha512-HxrwI+ihtw6XhWqGH8p3nsMIHswNsVoy1wp+ZlViYDxXJVApHQjKTINZo1w4x169zjtm62M1GmJivz5AYpAnrg==" }, "node_modules/wordwrap": { "version": "1.0.0", diff --git a/frontend/package.json b/frontend/package.json index e31c9db146..0951bd293a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -131,7 +131,7 @@ "vscode-languageclient": "~9.0.1", "vscode-uri": "~3.0.8", "vscode-ws-jsonrpc": "~3.1.0", - "windmill-parser-wasm": "^1.219.1", + "windmill-parser-wasm": "^1.221.0", "y-monaco": "^0.1.4", "y-websocket": "^1.5.0", "yaml": "^2.3.4", diff --git a/frontend/src/lib/script_helpers.ts b/frontend/src/lib/script_helpers.ts index cb88afe03b..3f98eedaf5 100644 --- a/frontend/src/lib/script_helpers.ts +++ b/frontend/src/lib/script_helpers.ts @@ -143,9 +143,9 @@ export const POSTGRES_INIT_CODE = `-- $1 name1 = default arg INSERT INTO demo VALUES (\$1::TEXT, \$2::INT, \$3::TEXT[]) RETURNING * ` -export const MYSQL_INIT_CODE = `-- ? name1 (text) = default arg --- ? name2 (int) -INSERT INTO demo VALUES (?, ?) +export const MYSQL_INIT_CODE = `-- :name1 (text) = default arg +-- :name2 (int) +INSERT INTO demo VALUES (:name1, :name2) ` export const BIGQUERY_INIT_CODE = `-- @name1 (string) = default arg