TL;DR: You'd have to restrict all literals, not just the ones in WHERE
clauses. For reasons why they don't, it allows the database to remain decoupled from other systems.
Firstly, your premise is flawed. You want to restrict only WHERE
clauses, but that's not the only place user input can go. For example,
SELECT
COUNT(CASE WHEN item_type = 'blender' THEN 1 END) as type1_count,
COUNT(CASE WHEN item_type = 'television' THEN 1 END) AS type2_count)
FROM item
This is equally vulnerable to SQL injection:
SELECT
COUNT(CASE WHEN item_type = 'blender' THEN 1 END) FROM item; DROP TABLE user_info; SELECT CASE(WHEN item_type = 'blender' THEN 1 END) as type1_count,
COUNT(CASE WHEN item_type = 'television' THEN 1 END) AS type2_count)
FROM item
So you can't just restrict literals in the WHERE
clause. You have to restrict all literals.
Now we're left with the question, "Why allow literals at all?" Keep this in mind: while relational databases are used underneath an application written in another language a large percentage of the time, there is no requirement that you must use application code to use the database. And here we have an answer: you need literals to write code. The only other alternative would be to require all code to be written in some language independent of the database. So having them gives you the ability to write "code" (SQL) directly in the database. This is a valuable decoupling, and it would be impossible without literals. (Try writing in your favorite language sometime without literals. I'm sure you can imagine how difficult this would be.)
As a common example, literals are often used in the population of list-of-value/look-up tables:
CREATE TABLE user_roles (role_id INTEGER, role_name VARCHAR(50));
INSERT INTO user_roles (1, 'normal');
INSERT INTO user_roles (2, 'admin');
INSERT INTO user_roles (3, 'banned');
Without them, you would need to write code in another programming language just to populate this table. The ability to do so directly in SQL is valuable.
We're then left with one more question: why don't programming language client libraries do it then? And here we have a very simple answer: they would have re-implement the entire database parser for each supported version of the database. Why? Because there's no other way to guarantee you've found every literal. Regular expressions aren't enough. For example: this contains 4 separate literals in PostgreSQL:
SELECT $lit1$I'm a literal$lit1$||$lit2$I'm another literal $$ with nested string delimiters$$ $lit2$||'I''m ANOTHER literal'||$$I'm the last literal$$;
Trying to do that would be a maintenance nightmare, especially since valid syntax often changes between major releases of databases.
bad_ideas_sql = 'SELECT title FROM idea WHERE idea.status == "bad" AND idea.user == :mwheeler'
would have both hard-coded and parameterized values in a single query – try to catch that! I think there are valid use cases for such mixed queries.SELECT * FROM jokes WHERE date > DATE_SUB(NOW(), INTERVAL 1 DAY) ORDER BY score DESC;
"bad"
is truly literal or resulted from string concatenation. The two solutions I see are either getting rid of SQL and other string-embedded DSLs (yes please), or promoting languages where string concatenation is more annoying than using parameterized queries (umm, no).