Understanding parameter types, extraction, and usage in SQLPage
SQLPage allows you to access HTTP request data directly in your SQL queries through SQL parameters. This page explains how parameters work and the different types available.
-- URL: /users.sql?id=42&role=adminSELECT 'card' as component;SELECT name as title, email as descriptionFROM usersWHERE id = $id -- Gets '42' AND role = $role; -- Gets 'admin'
-- Display formSELECT 'form' as component, 'Create User' as title, 'create_user.sql' as action;SELECT 'text' as type, 'username' as name;SELECT 'email' as type, 'email' as name;-- Process form submissionINSERT INTO users (username, email, created_at)SELECT :username, :email, CURRENT_TIMESTAMPWHERE :username IS NOT NULL;-- Redirect after insertSELECT 'redirect' as component, '/users.sql' as linkWHERE :username IS NOT NULL;
SELECT 'table' as component;SELECT product_name, price, categoryFROM productsWHERE ($category IS NULL OR category = $category) AND ($min_price IS NULL OR price >= CAST($min_price AS DECIMAL)) AND ($max_price IS NULL OR price <= CAST($max_price AS DECIMAL)) AND ($search IS NULL OR product_name LIKE '%' || $search || '%');
Use $param IS NULL to make filters optional. When the parameter isn’t provided, the condition is ignored.
-- Store a valueSET user_name = SELECT name FROM users WHERE id = $id;-- Use the variableSELECT 'text' as component, 'Welcome, ' || $user_name as contents;
-- Compute a valueSET total_sales = SELECT SUM(amount) FROM orders;SET avg_sale = SELECT AVG(amount) FROM orders;-- Use in multiple placesSELECT 'card' as component;SELECT 'Total Sales' as title, $total_sales as value;SELECT 'Average Sale' as title, $avg_sale as value;
-- Set based on conditionSET discount = CASE WHEN :customer_type = 'premium' THEN 0.20 WHEN :customer_type = 'regular' THEN 0.10 ELSE 0.05 END;-- Apply discountSELECT product_name, price, price * (1 - $discount) as discounted_priceFROM products;
SQLPage automatically protects against SQL injection:
Safe (Parameterized)
Unsafe (String Concatenation)
Dynamic Column Names
-- ✅ SAFE: Parameters are escapedSELECT * FROM users WHERE id = $id;-- Even if $id = "1 OR 1=1", query becomes:SELECT * FROM users WHERE id = '1 OR 1=1';-- (No injection possible)
SQLPage uses prepared statements, so parameters are always escaped.
-- ❌ UNSAFE: Don't do this!SET query = 'SELECT * FROM users WHERE id = ' || $id;-- If $id = "1 OR 1=1", this executes:SELECT * FROM users WHERE id = 1 OR 1=1;-- (Returns all users!)
Never concatenate user input into SQL strings. Always use parameterized queries.
-- ❌ Cannot parameterize column namesSELECT * FROM users ORDER BY $sort_column;-- This won't work as expected-- ✅ Use CASE for safe dynamic sortingSELECT * FROM usersORDER BY CASE $sort_column WHEN 'name' THEN name WHEN 'email' THEN email WHEN 'created_at' THEN created_at ELSE id END;
Parameters are strings by default. Cast them to the appropriate type:
-- Numeric comparisonsWHERE price > CAST($min_price AS DECIMAL) AND quantity >= CAST($min_qty AS INTEGER);-- Date comparisons WHERE created_at >= CAST($start_date AS DATE) AND created_at <= CAST($end_date AS DATE);-- Boolean (database-specific)WHERE active = CAST($is_active AS BOOLEAN); -- PostgreSQLWHERE active = CASE WHEN $is_active = 'true' THEN 1 ELSE 0 END; -- SQLite/MySQL
SQLPage casts parameters to TEXT/VARCHAR when binding to the database. Explicit casting ensures correct comparisons.
-- Different queries based on parameterSELECT 'table' as component;SELECT * FROM admin_usersWHERE $view = 'admin'UNION ALLSELECT * FROM regular_users WHERE $view != 'admin' OR $view IS NULL;
-- Check required parametersSELECT 'redirect' as component, '/error.sql?msg=Missing user ID' as linkWHERE $user_id IS NULL;-- Validate parameter formatSELECT 'redirect' as component, '/error.sql?msg=Invalid email' as linkWHERE :email NOT LIKE '%@%';
Use Appropriate Parameter Type
$param for URL/GET parameters
:param for form/POST data
?param when you specifically need GET-only
SET variables for computed values
Handle NULL Values
-- Provide defaultsSELECT COALESCE($page_size, 20) as page_size;-- Optional filtersWHERE ($category IS NULL OR category = $category);-- Required parametersWHERE $user_id IS NOT NULL;
Type Safety
-- Always cast when comparing numbersWHERE price > CAST($min AS DECIMAL);-- Validate numeric inputWHERE $id ~ '^[0-9]+$' -- PostgreSQL regex OR $id GLOB '[0-9]*' -- SQLite