Handling SQL reserved table and column names - mysql

Is there a way to handle reserved table & column names in your app which can work through all kinds of databases like Oracle, MySQL, SQL Server, PostGreSQL etc.
Currently, I have to do the following :
Oracle - use double quotes.
MySQL - Use backtick or double quotes (depends if ANSI_QUOTES mode is enabled)
SQL Server - Use brackets
PostGreSQL - use double quotes.
I am aware that ANSI standard states to use double quotes but unfortunately not all dbms seem to support them.

Use double quotes. That's what the standard says, and surprisingly, it actually works on most platforms.
Require that MySQL have ANSI_QUOTES enabled, or set it at the session level:
SET SESSION sql_mode = 'ANSI'
(I used ANSI not just ANSI_QUOTES here because it makes MySQL generally a bit saner).
PostgreSQL doesn't require any special settings for identifiers (though very old versions need standard_conforming_strings = on to handle literals sensibly).
Neither does Oracle.
Modern MS-SQL shouldn't require any special settings to support double quoted identifiers:
When SET QUOTED_IDENTIFIER is ON (default), all strings delimited by double quotation marks are interpreted as object identifiers
The docs suggest that was the case in MS-SQL 2008, and if you still care about 2005 in a new application you have bigger problems.
SQLFiddles:
MySQL
MS-SQL 2008
Oracle 11g R2
Interestingly, I found that the SQLFiddle for PostgreSQL failed with an odd error. I suspect an SQLFiddle bug, as it's fine on the PostgreSQL command line and via PgJDBC. It fails with there is no table that match the following pattern [with].
All that said, if you're seriously trying to write ANSI SQL, I hope you don't plan on using:
Date/time maths
String concatenation
Non-trivial aggregates
Window functions (MySQL still doesn't support them)
Common table expressions
SQL/XML
Arbitrary precision decimal data types
Any kind of user defined procedure or function
Any kind of user-defined type
... lots more
because different vendors use different names, have different support for features, etc.
(On a side note, if I ever meet the person who decided to call Microsoft SQL Server "SQL" in a dark alley...)

Related

SQL syntax for characters not in brackets

I'm accessing a Microsoft Access database using ODBC.
According to the w3schools SQL tutorial, the ANSI-92 wildcard for "any character not in brackets" should be ^. However, their own example uses the ANSI-89 wildcard !.
The MSDN documentation is also confusing. The ANSI-92 section shows ^ character, but the example next to it actually uses !. That looks like an error and I've filled out feedback to notify Microsoft.
What is the correct "any character not in brackets" syntax? And will this apply across multiple databases and access technologies (DAO, ODBC, OleDB, MySQL, etc)?
There is no way to do this across databases. SQL supports the LIKE syntax that has exactly two wildcards:
% matches zero or more characters.
_ matches exactly one character.
One could throw in the \ character to escape wildcards as well.
In addition, SQL Server supports character classes as explained in the tutorial (which seems to be accurate). The only other database that comes to mind that does this is Sybase (which has the same code base). MS Access just has a bastardized version with special characters. It never supported SQL standards in this respect.
Most other databases implement full regular expression support (YAY!), but their syntax varies by database. So, there is not a database-independent way to do what you want.

Are the escape functions in the Node.js mysql package sufficient enough to securely query a mysql database (without the use of prepared statements)?

According to Node.js' mysql package documentation:
In order to avoid SQL Injection attacks, you should always escape any user provided data before using it inside a SQL query. You can do so using the mysql.escape(), connection.escape() or pool.escape() methods.
I cannot find any documentation / reference to using prepared statements with mysql, except for in a reference to using '?' characters. It states the following:
Alternatively, you can use ? characters as placeholders for values you would like to have escaped...
This looks similar to prepared statements in MySQL, however it really
just uses the same connection.escape() method internally.
From my experience with talking to other developers, the general consensus in the developer community is that prepared statements are the ONLY safe way to perform mysql queries from Node.js however, as you can see with the mysql package, there is no obvious support for prepared statements. However, it is indicated that their method for avoiding SQL injection is via the usage of the escape functions.
My Question:
Are the escape functions in the mysql package sufficient enough to securely query a mysql database (without the use of prepared statements)?
Escaping is actually just as safe as using parameterized queries, if you do it consistently.
But it's recommended to use parameters because it makes your code simpler. Therefore developers are probably more likely to do it.
If the Node.js library makes it just as convenient as parameters, but implements it internally by modifying query strings, replacing the ? marks with the parameter values, then you're good.
For what it's worth, Python's MySQL driver does this too, and also PHP's PDO extension when the "emulate prepares" option is in effect. As long as those libraries are well-tested, it should be safe.
FWIW, both escaping and parameters is limited in SQL injection prevention, because in both cases, you can only protect values that you would combine with your SQL query. You cannot protect identifiers (like table names, or column names), or SQL keywords, or expressions, etc. In these cases, just be careful that you have vetted any dynamic content before combining it with your SQL query.
See also:
Preventing SQL injection in Node.js
Difference between real_escape_string and prepare()?

Using reserved words in queries that can run on different database servers

I have used backticks (`) in some SELECT queries to escape fields such as 'first-name'. This will work on MySQL. These queries are run through a DBO class in a php application and I would like the application to be able to use other database servers, such as MSSQL and Posgres.
What is the best approach for allowing problematic field names to be used across all of these database servers? I was thinking of taking the fields as an array and quoting them with the escaping character that is appropriate to each.
[EDIT]
To clarify: I am building a tool that will be used to map configurations stored within the php application to the fields of an external database. I wanted to escape these as a precaution because I have no idea what field names will actually be mapped to and used within the queries.
The solution is very simple: do not use reserved words as identifiers. It makes the code more difficult to read anyways.
If you really need to use such words (as in "there is some obscure reason beyond your control"), you can just prefix all your identifiers by an arbitrary character, such as _ for example.
The cross-DBMS mechanism (as defined in SQL-92 and other standards) is using double-quoted delimited identifiers. According to this reference it's widely supported.
It's worth nothing that MySQL allows to enable/disable this syntax so you still need to ensure that session settings are correct before issuing any query.
MySQL uses backticks (`) by default, but can be configured to support proper ANSI quoting.
IMO: If you're connecting to MySQL, set it to ANSI mode, and while you're at it enable every STRICT option it has. It becomes much easier to write code that's portable against it then.
Of course, the best option has to be not using reserved words, but the list of reserved words can change over time so rigorous quoting isn't such a bad idea.
The proper way of escaping is not to use field names that need escaping.
If you still have to use escaping - use ". It is the standard one (defined by ANSI SQL).
Postgres and Oracle understand " escaping. But i do not know about MSSQL an MySQL.

How to use reserved words without backquotes in MySQL

I would like to use reserved words such as "user" or "right" as table or column names in my databases. Until now I've been using back quotes, but I read somewhere that they are MySQL specific, and I would like to preserve database compatibility. I've also read about using ANSI mode with MySQL to avoid using back quotes, but I want everything in my apps to be UTF-8.
What can I do to use reserved words without using back quotes or losing cross database compatibility ?
MySQL supports the ANSI standard of using double quotes surrounding identifiers such as table and column names. You have to enable this option since by default MySQL recognizes both single and double quotes as enclosing string literals:
http://dev.mysql.com/doc/refman/5.1/en/server-sql-mode.html#sqlmode_ansi_quotes

Why does MySQL sort correctly but SQLite doesn't when field is marked with quotation marks?

In the following SQL statement, SQLite sorts correctly but MySQL does not:
However, if I don't include the quotation marks around the field names, it works correctly:
Can anyone explain the behavior that MySQL but not SQLite would not sort correctly if a field is defined with quotation marks?
"TotalOrders" (with double quotes) is a constant string - ordering by it doesn't do anything ... in essence you get the unsorted sequence of rows, which might seem to be correctly sorted.
You want
ORDER BY `TotalOrders`
with backticks. which is the column identifier.
In addition to Eugen's answer:
It might be worth noting that this behaviour depends on the configuration of MySQL.
The described behaviour only shows if MySQL is left in the default - non standard compliant configuration.
If it's configured to run in "ANSI mode" the double quotes are not used for string literals but for identifiers (as nearly all other DBMS).
Another solution to the problem would have been to make MySQL comply with the SQL standard by changing the SQL_MODE to "ANSI".
Then standard compliant single quotes are used for literals and the double quotes are used for identifiers.