ORA-01006 with bindings within quotes - sql

I got some trouble with my bindings using dbms_sql. The user creates the statement and give it to may function as well as the bindings and their values. That means I know about nothing of the statement. An input could be
select salary from employee where name like '%:name%'
This raises an ORA-01006. This post leads me to the reason: the binding is within single quotes so they are treated as a literal, not a binding.
I wrote some code to adjust the statement. But it works only for the given example ('%<binding>%'). Is there any way (maybe using regex) to solve it for all bindings within quotes?
So if input is like '<any pre content><binding><any post content>' it should be modified to '<any precontent>''||<binding>||''<any post content>' (hope that clears my wishes).
I'm not good in using regex so my solution for the example is very unflexible:
l_sql := replace(l_sql, '%:'||p_name||'%', '%''||:'||p_name||'||''%');
BTW: I'm using Oracle 11g.

Related

How to dynamically format BigQuery `dataset.schema.table name` with backticks

I need to work through how to take stored procedure functions from
region-us.INFORMATION_SCHEMA.ROUTINES
and modify the backticks that default to coming through around the project and place them around the dataset.schema.table()
The reason is more for uniform results across our system than a technical error need.
currently when I run this query
SELECT
replace(ddl, 'CREATE PROC', 'CREATE OR REPLACE PROC'),
FROM region-us.INFORMATION_SCHEMA.ROUTINES
where lower(routine_type) = 'procedure'
It will return the below:
`project-data-sandbox`.schema.MySP()
`project-data-sandbox`.schema.YourSP(MySP)
`project-data-sandbox`.inv.partnumber(orderid)
`project-data-sandbox`.inv_part.part_number(part_id)
I have tried the below query
SELECT
REGEXP_REPLACE(ddl, r"project-data-sandbox`.", "project-data-sandbox.") AS replaced_word
, REGEXP_REPLACE(ddl, r'`([a-zA-Z]+(-[a-zA-Z]+)+)`\.[a-zA-Z]+\.[a-zA-Z]+\(\)','Apples') tester
FROM region-us.INFORMATION_SCHEMA.ROUTINES
where lower(routine_type) = 'procedure'
I get part of what I want. However, the problem is our stored procedures can be named any sort of names and they could require objects to be passed to them.
I added the tester column to see if I could replace the project string with another word (or regex) but it isn't even replacing it with apples yet.
which I would want turned into this:
`project-data-sandbox.schema.MySP`()
`project-data-sandbox.schema.YourSP`(MySP)
`project-data-sandbox.inv.partnumber`(orderid)
`project-data-sandbox.inv_part.part_number`(part_id)
I'm working through Regexp_replace but I'm having difficulty figuring out how to get the backtick between the parenthesis and the last letter.
Thanks for any help!

undefined method `and' for #<Arel::Attributes::Attribute

I'm having an issue getting a query to work.
I'm essentially trying to write something like the following SQL, with the literal 5 replaced with a variable:
SELECT *
FROM "my_table"
WHERE 5 BETWEEN "my_table"."minimum" AND "my_table"."maximum"
This is what I have at the moment:
MyModel.where(
Arel::Nodes::Between.new(
my_variable, (MyModel.arel_table[:minimum]).and(MyModel.arel_table[:maximum])
)
)
Please ignore the way I am using arel_table, the actual query has multiple joins and is more complex, but this is the most minimum reproducible example I have to demonstrate the problem.
The error, as in the subject of the question is as follows:
undefined method `and' for #<Arel::Attributes::Attribute:0x00007f55e15514f8>
and method is for Arel::Nodes::Node i.e. MyModel.arel_attribute[:name].eq(Arel::Nodes::Quoted.new('engineersmnky')) This is an Arel::Nodes::Equality and you can chain with and.
That being said you can construct an Arel::Nodes::And for yourself via
Arel::Nodes::And.new([left,right])
Then we can pass this to the Between class like so
Arel::Nodes::Between.new(
Arel::Nodes::Quoted.new(my_variable),
Arel::Nodes::And.new([
MyModel.arel_table[:minimum],
MyModel.arel_table[:maximum]])
)
The Arel::Nodes::Quoted (also: Arel::Nodes.build_quoted(arg)) is not needed in your case since your my_variable is an Integer which can be visited and will be treated as an Arel::Nodes::SqlLiteral but I find it best to let arel decide how to handle the quoting in case your my_variable ends up being some other un-visitable Object
There are other ways to create a Between and other ways to create an And depending on what objects you are dealing with.
between is a Arel::Predication and these predications are available to Arel::Nodes::Attribute objects e.g.
MyModel.arel_table[:minimum].between([1,6])
and as mentioned is available to Arel::Nodes::Node and instances of this class provides a convenience method (create_and) for creating an And so we could do the following:
Arel::Nodes::Node.new.create_and([
MyModel.arel_table[:minimum],
MyModel.arel_table[:maximum]])
There are a number of other ways to hack this functionality together by using other Arel classes but this should get you headed in the right direction.

parameters FDquery delphi does not work

i have the following delphi code:
FDQuery1.SQL.Clear;
FDQuery1.SQL.Add('SELECT * FROM :Tablename');
FDQuery1.ParamByName('Tablename').AsString := 'tasks';
ShowMessage(FDQuery1.sql.Text);
FDQuery1.Open;
(coppied from this link: http://www.delphigroups.info/2/da/237634.html)
it does not work because the parameter is not filled but stays the same.
does somebody know why it is not filled?
Because you cannot use parameters for table name substitution in SQL commands in general. You are lucky enough here though, FireDAC supports preprocessor macros to parametrize table names in SQL commands. So you can write for example this (note that if you want to see the command as you did in your code, it must be after macro preprocessing, that is e.g. after calling Prepare):
FDQuery1.SQL.Text := 'SELECT * FROM &TableName';
FDQuery1.MacroByName('TableName').AsIdentifier := 'tasks';
FDQuery1.Open;
For details about this kind of macros, see the substitution variables topic.

Protecting against SQL injection in python

I have some code in Python that sets a char(80) value in an sqlite DB.
The string is obtained directly from the user through a text input field and sent back to the server with a POST method in a JSON structure.
On the server side I currently pass the string to a method calling the SQL UPDATE operation.
It works, but I'm aware it is not safe at all.
I expect that the client side is unsafe anyway, so any protection is to be put on the server side. What can I do to secure the UPDATE operation agains SQL injection ?
A function that would "quote" the text so that it can't confuse the SQL parser is what I'm looking for. I expect such function exist but couldn't find it.
Edit:
Here is my current code setting the char field name label:
def setLabel( self, userId, refId, label ):
self._db.cursor().execute( """
UPDATE items SET label = ? WHERE userId IS ? AND refId IS ?""", ( label, userId, refId) )
self._db.commit()
From the documentation:
con.execute("insert into person(firstname) values (?)", ("Joe",))
This escapes "Joe", so what you want is
con.execute("insert into person(firstname) values (?)", (firstname_from_client,))
The DB-API's .execute() supports parameter substitution which will take care of escaping for you, its mentioned near the top of the docs; http://docs.python.org/library/sqlite3.html above Never do this -- insecure.
Noooo... USE BIND VARIABLES! That's what they're there for. See this
Another name for the technique is parameterized sql (I think "bind variables" may be the name used with Oracle specifically).

What characters are allowed in Oracle bind param placeholders?

Could anyone please point me to where the characters allowed for a bind variable name are listed? I've spent several hours digging through Oracle SQL docs to no avail.
I mean ":id" in the following:
SELECT * FROM mytable WHERE id = :id
E.g. can a dot be used there like ":some.id"? Will it function exactly like the version without the dot?
These pages both state bind variables must be "legal Oracle identifiers"
The documentation I found doesn't specifically say that a dot can
be part of a legal identifer. I was able to use a dot in both
a table name and as a bind variable name, but it looks like it is
not recommended.
PAGES THAT HAVE BIND VARIABLE NAMING CONVENTIONS
(These pages state a bind variable must be a legal identifier):
http://www.utoug.org/i/doc/concept_bind_var.htm
http://docs.oracle.com/cd/E23903_01/doc.41/e21674/concept_ses_val.htm#BEIEGCCC
PAGE THAT DESCRIBES LEGAL IDENTIFIERS:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements008.htm
I could not find anything on this page that says that a dot is a legal
part of an identifier (E.G. table or bind variable name) except in a DB link.
Even though $ and # are legal, they are not even recommended, so "."
may work but is obviously not recommended (not even mentioned as legal on
this page)
Bind variable names must correspond to an item name.
Bind variable names are not case-sensitive.
Bind variable names cannot be longer than 30 characters (that is, they must be a valid Oracle identifier).
I know that a valid ORACLE identifer (based on ORACLE's definition
of a legal identifier) cannot start with a number,
and can have SOME special characters like $ and . but if there are
special characters the identifier MUST be in double quotes.
I was able to get an identifier with a dot to work in a bind
variable, but I had to put double quotes around the bind
variable when the bind variable had a dot in it.
create or replace function F0416B
RETURN VARCHAR2
is
V_STMT VARCHAR2(1999);
V_RESULT VARCHAR2(1999);
BEGIN
V_STMT := 'INSERT INTO TEST0411(FIELD1, FIELD2) VALUES ( :"A.1" , :"A.2")';
EXECUTE IMMEDIATE V_STMT USING 'AS201', 'AS202';
RETURN 'INSERT-OK';
COMMIT;
EXCEPTION
WHEN OTHERS THEN RETURN SQLERRM;
END;
#This may work but according to the above documentation a period/dot
in a bind variable or other object name is not legal/recommended...
#This is the sentence on the ORACLE schema object naming page that is
telling me this:
Nonquoted identifiers can contain only alphanumeric characters from your database character set and the underscore (_), dollar sign ($), and pound sign (#). Database links can also contain periods (.) and "at" signs (#). Oracle strongly discourages you from using $ and # in nonquoted identifiers.
I also had trouble finding the official Oracle doc for this: http://docs.oracle.com/cd/E14072_01/appdev.112/e10646/oci04sql.htm#i420655
On top of that, it turns out that you can quote placeholders (:"_normallyinvalid") and then most of the rules listed in the preceding link stop being relevant. I couldn't find any Oracle doc offering this suggestion; just hints around the internet.