Force identifier case sensitivity in oracle - sql

In oracle, when one uses non-quoted identifiers, they are silently capitalized. In other words these two statements are equivalent:
SELECT name FROM my_table
SELECT "NAME" FROM "MY_TABLE"
Is there any way to stop the silent capitalization, so that the following statements become equivalent?
SELECT name FROM my_table
SELECT "name" FROM "my_table"

No, unfortunately you can't customize how Oracle interprets your identifiers:
Note that Oracle interprets the following names the same, so they cannot be used for different objects in the same namespace:
employees
EMPLOYEES
"EMPLOYEES"
It is a convenience (backward compatibility?) that non-quoted identifiers are converted to upper-case (internally all object names are case-sensitive).

Related

Regex validation of table schema and name

I have an API that performs some query on a table that the caller specifies. The table name is placed in the query via string replace, and so is a risk for SQL injection.
Example:
tableName = req.body.tableName;
sql = "SELECT * FROM <<TABLE_NAME>>;";
sql = sql.replace("<<TABLE_NAME>>", tableName);
I'm required to keep this query dynamic, as we don't want to redeploy this code every time we add a new table. In other words, I can't just maintain a list of valid table names.
So for the purposes of keeping this safe from sql injection, is it sufficient to do a regex validation on the table name? We can be certain the table name will always be of the format schema.table_name where table_name will be only a-z, 0-9, -, _
Is there any sql injection that could slip past this table name regex?
^myschema\.[a-zA-Z0-9-_]+$
Since minus is not a valid character in a tablename, you could change your regex to just:
^myschema\.\w+$
\w is equivalent to [a-zA-Z0-9_]
There is no risk of injection.
Most databases allow special characters, even spaces and minuses, in table names if special syntax is used, eg
MySQL: `my stupid table-name!`
Postgres: "my stupid table-name!"
SQL Server: [my stupid table-name!]
It is poor practice to allow non-standard characters in names in the first place, and it would be fine to deny such names in your situation.
The minus sign cannot be used as an identifier in SQL. In the case of table names, I don't think it will lead to SQL injection attacks, but if you allow minus signs in column names, subtraction can be injected.
In the case of MySQL, the following SQL statement will return all users, not just 'tom'. This is because of the implicit type conversion that occurs when subtracting from a string.
SELECT * FROM users WHERE myschema.user-0 = 'tom'
The workaround is to exclude the minus sign or quote the identifier. The following will not result in a SQL injection attack.
SELECT * FROM users WHERE `myschema`.`user-0` = 'tom'.
The above is the way to write for MySQL, and the way to write for standard SQL is as follows
SELECT * FROM users WHERE "myschema"."user-0" = 'tom'

Why do you only need double quotation marks in SQL for particular cases?

I have a column in my database table named UID. For some reason queries fail unless I surround the column name with double quotation marks (" "). None of the other columns require these quotation marks.
For example, this doesn't work:
SELECT user_name FROM user_table WHERE UID = '...'
But this does:
SELECT user_name FROM user_table WHERE "UID" = '...'
Is UID some kind of keyword? Why is it only happening to that column? How do I know if I need to use double quotes for other columns?
By the way, I'm running JDK 1.8_221 and using an oracle JDBC driver if that makes a difference.
Yes, it is about keywords. You can double quote everything (tables, columns) to avoid this but I can understand you don't want to do this.
To have a list of standard keywords: SQL Keywords
But you can see UID is not in this list as I assume it is a reserved keyword by your database implementation. I had the same problem with a table called "order" as it contains orders. ORDER is a keyword so I had to quote it each time.
So best is to test your statements using a SQL client tool.
Since you mention Oracle: Oracle keywords: "You can obtain a list of keywords by querying the V$RESERVED_WORDS data dictionary view."
If your create table command for user_table looks something like this:
create table user_table ("UID" varchar2(10))
then you will have to use quotes around UID in your query. This query:
select * from user_table where UID = 'somestring'
means to use the Oracle predefined UID pseudo column and your table's UID column will not be accessed.
If your table doesn't have a user-defined UID column, then using "UID" should fail.
My guess is your table does indeed have a UID column and when you say it "doesn't work" without using the quotes you probably mean it motivates an ORA-1722.
The type of failure, when using UID without quotes, depends on the content of the string 'somestring'. If the content of that string can be cast as a number then you probably won't get the rows you expect. If it cannot be cast as a number then you'll get an ORA-1722.
As an aside, if you try to execute this, then you'll get an ORA-904:
create table user_table (UID number)
Yes, it is keywords and return
UID returns an integer that uniquely identifies the session user (the
user who logged on).
By default, Oracle identifiers (table names, column names, etc.) are case-insensitive. You can make them case-sensitive by using quotes around them when creating them (eg: SELECT * FROM "My_Table" WHERE "my_field" = 1). SQL keywords (SELECT, WHERE, JOIN, etc.) are always case-insensitive.
You can use it for more information here.

Asp Classic & Firbird Sql without quotation marks

I have a script in ASP Classic that uses a Firebird database. I would like to execute a query without "quotation marks"
Now I must write this:
SQL = "SELECT ""TArticoli"".""IDArticolo"",""TArticoli"".""Desc"" FROM ""TArticoli"";"
I would write this:
SQL = "SELECT TArticles.IDArticle, TArticles.Desc FROM TArticles;"
The first one is accepted the second not, how can I do this?
You can't. DESC is a reserved word in Firebird, so to be able to use it as a column name (or any other object name for that matter), you will need to enclose it in quotes.
A second problem is that you are currently using
SELECT "TArticoli"."IDArticolo","TArticoli"."Desc" FROM "TArticoli"
And this means both your table name and the column names are case sensitive, and in that case, quoting those object names is mandatory. Unquoted object names are case insensitive, but are mapped to object names in upper case. This means that select * from TArticoli will select from a table called TARTICOLI, while select * from "TArticoli", selects from a table called TArticoli.
So unless you are going to rename or recreate all your tables or columns, you will not be able to get rid of quotes. The only thing you can do to reduce the number of quotes, is by not prefixing the columns with the table names (in the query shown it isn't necessary), or otherwise use a case insensitive alias for the table, eg
SELECT "IDArticolo", "Desc" FROM "TArticoli"
or
SELECT a."IDArticolo", a."Desc" FROM "TArticoli" AS a

How can I use a column named _id from a dashDB table?

I have a database in Cloudant where the document ID is _id.
After replicating this data from Cloudant to dashDB I have 2 separate tables that I want to join using this _id column. In Run SQL I tried the below, but this would not run. What am I missing here? Do I need to replace the column name _id to something without an underscore?
select m.title, m.year, g.value
from MOVIES m
inner join MOVIES_GENRE g on m._ID = g._ID;
TL;DR: As #gmiley points out the issue is caused by the _ID column name, which is not an ordinary identifier (see definition below) and therefore needs to be enclosed in double quotes "_ID" or single quotes '_ID' in your SQL statements.
select m.title, m.year, g.value
from MOVIES m
inner join MOVIES_GENRE g on m."_ID" = g."_ID";
Unlike ordinary identifiers quoted identifiers are case sensitive ("_id" is not identical to "_ID" whereas title is identical to TITLE). If you were to specify "_id" in your statement an error would be raised indicating that the column wasn't found.
Since you've mentioned that you've used the Cloudant warehousing process to populate your DashDB tables it's probably worth mentioning that property names are upper-cased when the DDL is generated during the schema discovery.
Example: The content of JSON documents with this structure
{
"_id": "000018723bdb4f2b06f830f676cfafd6",
"_rev": "1-91f98642f125315b929be5b5436530e7",
"date_received": "2016-12-04T17:46:47.090Z",
...
}
will be mapped to three columns:
_ID of type VARCHAR(...)
_REV of type VARCHAR(...)
DATE_RECEIVED of type ...
...
Hope this helps!
From the DB2 SQL reference:
An ordinary identifier is an uppercase letter followed by zero or more characters, each of which is an uppercase letter, a digit, or the underscore character. Note that lowercase letters can be used when specifying an ordinary identifier, but they are converted to uppercase when processed. An ordinary identifier should not be a reserved word.
Examples: WKLYSAL WKLY_SAL
A delimited identifier is a sequence of one or more characters enclosed by
double quotation marks. Leading blanks in the sequence are significant.
Trailing blanks in the sequence are not significant, although they are stored
with the identifier. Two consecutive quotation marks are used to represent
one quotation mark within the delimited identifier. In this way an identifier
can include lowercase letters.
Examples:
"WKLY_SAL" "WKLY SAL" "UNION" "wkly_sal"

Are PostgreSQL column names case-sensitive?

I have a db table say, persons in Postgres handed down by another team that has a column name say, "first_Name". Now am trying to use PG commander to query this table on this column-name.
select * from persons where first_Name="xyz";
And it just returns
ERROR: column "first_Name" does not exist
Not sure if I am doing something silly or is there a workaround to this problem that I am missing?
Identifiers (including column names) that are not double-quoted are folded to lowercase in PostgreSQL. Column names that were created with double-quotes and thereby retained uppercase letters (and/or other syntax violations) have to be double-quoted for the rest of their life:
"first_Name"
Values (string literals / constants) are enclosed in single quotes:
'xyz'
So, yes, PostgreSQL column names are case-sensitive (when double-quoted):
SELECT * FROM persons WHERE "first_Name" = 'xyz';
Read the manual on identifiers here.
My standing advice is to use legal, lower-case names exclusively so double-quoting is never required.
To quote the documentation:
Key words and unquoted identifiers are case insensitive. Therefore:
UPDATE MY_TABLE SET A = 5;
can equivalently be written as:
uPDaTE my_TabLE SeT a = 5;
You could also write it using quoted identifiers:
UPDATE "my_table" SET "a" = 5;
Quoting an identifier makes it case-sensitive, whereas unquoted names are always folded to lower case (unlike the SQL standard where unquoted names are folded to upper case). For example, the identifiers FOO, foo, and "foo" are considered the same by PostgreSQL, but "Foo" and "FOO" are different from these three and each other.
If you want to write portable applications you are advised to always quote a particular name or never quote it.
The column names which are mixed case or uppercase have to be double quoted in PostgresQL. So best convention will be to follow all small case with underscore.
if use JPA I recommend change to lowercase schema, table and column names, you can use next intructions for help you:
select
psat.schemaname,
psat.relname,
pa.attname,
psat.relid
from
pg_catalog.pg_stat_all_tables psat,
pg_catalog.pg_attribute pa
where
psat.relid = pa.attrelid
change schema name:
ALTER SCHEMA "XXXXX" RENAME TO xxxxx;
change table names:
ALTER TABLE xxxxx."AAAAA" RENAME TO aaaaa;
change column names:
ALTER TABLE xxxxx.aaaaa RENAME COLUMN "CCCCC" TO ccccc;
You can try this example for table and column naming in capital letters. (postgresql)
//Sql;
create table "Test"
(
"ID" integer,
"NAME" varchar(255)
)
//C#
string sqlCommand = $#"create table ""TestTable"" (
""ID"" integer GENERATED BY DEFAULT AS IDENTITY primary key,
""ExampleProperty"" boolean,
""ColumnName"" varchar(255))";