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.

Literal question marks can be escaped with ??.

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. Literal question marks can be escaped with ??.

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. Literal question marks can be escaped with ??. 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.

SEE ALSO

Mojo::SQL::Statement, Mojolicious, https://mojolicious.org.