{"record":{"id":"c2213d37846fbe27","repo":"diesel-rs/diesel","slug":"expect-sql-function-blocks-to-be-safe","errorCode":null,"errorMessage":"expect `SQL` function blocks to be safe","messagePattern":"expect `SQL` function blocks to be safe","errorType":"exception","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"diesel_derives/src/sql_function.rs","lineNumber":1180,"sourceCode":"\n        let mut combine_error = |e: syn::Error| {\n            error = Some(\n                error\n                    .take()\n                    .map(|mut o| {\n                        o.combine(e.clone());\n                        o\n                    })\n                    .unwrap_or(e),\n            )\n        };\n\n        let block = syn::ItemForeignMod::parse(input)?;\n        if block.abi.name.as_ref().map(|n| n.value()) != Some(\"SQL\".into()) {\n            return Err(syn::Error::new(block.abi.span(), \"expect `SQL` as ABI\"));\n        }\n        if let Some(unsafety) = block.unsafety {\n            return Err(syn::Error::new(\n                unsafety.span(),\n                \"expect `SQL` function blocks to be safe\",\n            ));\n        }\n\n        let parsed_block_attrs = parse_attributes(&mut combine_error, block.attrs);\n\n        let item_count = block.items.len();\n        let function_decls_input = block\n            .items\n            .into_iter()\n            .map(|i| syn::parse2::<SqlFunctionDecl>(quote! { #i }));\n\n        let mut function_decls = Vec::with_capacity(item_count);\n        for decl in function_decls_input {\n            match decl {\n                Ok(mut decl) => {\n                    decl.attributes = merge_attributes(&parsed_block_attrs, decl.attributes);","sourceCodeStart":1162,"sourceCodeEnd":1198,"githubUrl":"https://github.com/diesel-rs/diesel/blob/6fa6ed01b24b24248ab2a611698d0a7c6a2e9120/diesel_derives/src/sql_function.rs#L1162-L1198","documentation":"Diesel's `sql_function!` foreign block must be safe; declaring it `unsafe extern \"SQL\"` is rejected in `parse`. SQL functions are not real FFI and never produce unsafe code, so the `unsafe` keyword is meaningless and disallowed.","triggerScenarios":"Writing `unsafe extern \"SQL\" { ... }` inside `sql_function!` or `#[sql_function]` macro input.","commonSituations":"Copy-pasting an `unsafe extern \"C\"` FFI block and only changing the ABI string to `SQL`; assuming SQL function declarations need `unsafe` like normal externs.","solutions":["Remove the `unsafe` keyword from the `extern \"SQL\"` block.","Keep the block plain: `extern \"SQL\" { ... }`."],"exampleFix":"// before\nsql_function! {\n    unsafe extern \"SQL\" {\n        fn md5(x: Text) -> Text;\n    }\n}\n\n// after\nsql_function! {\n    extern \"SQL\" {\n        fn md5(x: Text) -> Text;\n    }\n}","handlingStrategy":"validation","validationCode":"// Reject unsafe in sql_function blocks before compiling:\n// WRONG: unsafe extern \"SQL\" { ... }\n// RIGHT: extern \"SQL\" { ... }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never write `unsafe` in diesel sql_function foreign blocks.","When converting FFI extern blocks, remove both `unsafe` and the `C` ABI.","Search your codebase for `unsafe extern \"SQL\"` before upgrading diesel versions."],"tags":["rust","proc-macro","diesel","sql-function","unsafety"],"backgroundTag":"invalid-argument-value","analyzedSha":"6fa6ed01b24b24248ab2a611698d0a7c6a2e9120","analyzedAt":"2026-09-07T01:50:13.074Z","contentChangedAt":"2026-09-07T01:50:13.074Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}