NAME
Mojo::SQL - Safely generate and compose SQL statements
SYNOPSIS
use Mojo::SQL qw(sql);
# {text => 'SELECT * FROM users WHERE name = $1', values => ['sebastian']}
my $query = sql('SELECT * FROM users WHERE name = ?', 'sebastian')->to_query;
DESCRIPTION
Mojo::SQL safely generates and composes SQL statements. To prevent SQL injection attacks, every ? in the input becomes a placeholder in the generated query, with the corresponding value bound to it. Partial statements can be composed recursively to build more complex queries.
use Mojo::SQL qw(sql);
my $role = 'admin';
my $partial = sql('AND role = ?', $role);
my $name = 'root';
# {text => 'SELECT * FROM users WHERE name = $1 AND role = $2', values => ['root', 'admin']}
my $query = sql('SELECT * FROM users WHERE name = ? ?', $name, $partial)->to_query;
Make partial statements optional to dynamically generate WHERE clauses.
my $optional = $foo ? sql('AND foo IS NOT NULL') : sql('');
my $query = sql('SELECT * FROM users WHERE name = ? ?', 'sebastian', $optional)->to_query;
If you need a little more control over the generated SQL query, you can also bypass safety features with "sql_unsafe". But make sure to handle unsafe values yourself with appropriate escaping functions for your database. For PostgreSQL there are "escape_literal" and "escape_identifier" functions included with this module.
use Mojo::SQL qw(sql sql_unsafe escape_literal);
my $role = 'role = ' . escape_literal('power user');
my $partial = sql_unsafe 'AND ?', $role;
my $name = 'root';
# {text => "SELECT * FROM users WHERE name = \$1 AND role = 'power user'", values => ['root']}
my $query = sql('SELECT * FROM users WHERE name = ? ?', $name, $partial)->to_query;
For databases that do not support numbered placeholders like $1 and $2, you can set a custom character with the placeholder option.
# {text => 'SELECT * FROM users WHERE name = ?', values => ['root']}
my $query = sql('SELECT * FROM users WHERE name = ?', 'root')->to_query({placeholder => '?'});
FUNCTIONS
Mojo::SQL implements the following functions, which can be imported individually.
escape_identifier
my $escaped = escape_identifier('some_table');
Escape an identifier (only the PostgreSQL format is currently supported).
escape_literal
my $escaped = escape_literal('some value');
Escape a literal (only the PostgreSQL format is currently supported).
sql
my $stmt = sql('SELECT * FROM users WHERE name = ?', 'sebastian');
Create a new Mojo::SQL::Statement from an SQL string. Each ? in the string becomes a placeholder, and the corresponding value is bound to it. Mojo::SQL::Statement values are spliced in recursively, so partial statements can be composed to build more complex queries.
sql_unsafe
my $stmt = sql_unsafe 'SELECT * FROM users WHERE name = ?', 'sebastian';
Create a new Mojo::SQL::Statement without safe placeholders. Each ? in the string is replaced literally by the corresponding value. Use with care.
COPYRIGHT AND LICENSE
Copyright (C) 2026, Sebastian Riedel.
This program is free software, you can redistribute it and/or modify it under the terms of the MIT license.