I have been told that binding variables to a query in Teradata could improve its performances because the query would be always the same, so Teradata would not re-prepare nor re-parse the SQL statement and would rather reuse the execution plan stored in memory of the session.
Example, I have the following macro:
REPLACE MACRO DB.MACRO(USER_ACCOUNT_ID# VARCHAR(100))
AS (
SELECT USER_ACCOUNT_ID
,USER_ACCOUNT_TYPE_DESCRIPTION
,CAST(TD_DATE_KEY_TO_DATE(DATE_KEY) AS VARCHAR(10)) AS "DATE"
,CLUSTER_DESC AS CLUSTER_DESCRIPTION
FROM DB.VIEW
WHERE USER_ACCOUNT_ID = :USER_ACCOUNT_ID#;
);
Which I execute like this: EXECUTE DB.MACRO('123');
With query binding, the statement would like this EXECUTE DB.MACRO(?);
with the actual value of the USER_ACCOUNT_ID supplied in some way.
How can I do query binding on such a statement in order to avoid both query prepartion and parsing time?
Related
Trying to exploit SQL injection for my assignment. Is it possible to execute delete or drop query after order by in select query without using the semicolon in Postgresql?
This is my sample query:
Select *
from table
order by {sql injection payload}
Without using the semicolon in the payload, can we delete data or drop a table?
https://stackoverflow.com/a/6800585
Do we have similar to this Postgrsql?
I tried
Select * from (delete from table_name returning *) a
But getting sql error as 'syntax error at or near from'
Check this document it says we can bypass forbidden character by CHR()
https://book.hacktricks.xyz/pentesting-web/sql-injection/postgresql-injection
DELETE cannot be put inside a subquery. Nor can DELETE be part of a UNION.
So aside from running a second query (that is, separated by a semicolon), there's almost no way you can do what you describe.
You could invoke a stored procedure or function, if you knew of an existing function that performs a DELETE. Example:
Select *
from table
order by {sql injection payload}
After your payload modifies this query:
Select *
from table
order by SomeFunctionThatDeletes()
Another type which works because you can select from a procedure in PostgreSQL:
Select *
from table
order by id
UNION
Select *
from SomeProcedureThatDeletes()
You can't create the function or procedure with SQL injection, so that routine must exist already, and you would need to know its name and how to call it.
DELETE or DROP TABLE are not the only bad things that can happen from SQL injection. It could be a problem if the query returns data that the current user shouldn't have privilege to see. For example, records about a different user's purchases or medical history.
SQL injection can also be accidental instead of malicious. I would even say that most instances of SQL injection result in simple errors instead of data breaches. Those aren't really attacks, but they lead to an unsatisfactory experience for your users.
I am writing a PL/SQL procedure. In the body of this procedure, how can I use twice the same query without re-writing it ?
To simplify, let's say that I have this SQL query :
SELECT *
FROM mytable
WHERE age > 18
Is there a way to "store it", so I could do for example :
SELECT COUNT(*) INTO var1
FROM myQuery
I know the WITH ... AS keywords, but as I know it can be only used in the current statement, and I want to be able to call it from different statements.
Thanks !
There are various possibilities. Here are the ones I think of immediately, there are probably others:
Declare an explicit CURSOR using your query, and use that cursor multiple times in the body of your procedure.
Store the query in a string variable, and use EXECUTE IMMEDIATE to run it multiple times
Execute the query once, storing the results in a local collection (nested table, most likely), and process those stored results multiple times
Create a function that executes the query and returns its results as a nested-table type. Then SELECT FROM TABLE( my_function ) multiple times
I have a table A with columns 1.Column 1 contains a query select * from tableD;
I need to execute the query inside column1 using single query if possible..How to do this..
Database is netezza.If u provide ans for oracle Db also fine.
This seems Dynamic query problem for me ..
In Oracle you can create a procedure to call this query which is actually stored in a table.
In my knowledge you can not directly run query stored as text.
You need to create a procedure or function where you can call this query as dynamically with execute immediate command.
I Have a procedure executed in SQL Server 2008 R2, the script is:
DECLARE #LocalVar SMALLINT = GetLocalVarFunction();
SELECT
[TT].[ID],
[TT].[Title]
FROM [TargetTable] AS [TT]
LEFT JOIN [AcceccTable] AS [AT] ON [AT].[AccessID] = [TT].[ID]
WHERE
(
(#LocalVar = 1 AND ([AT].[Access] = 0 OR [AT].[Access] Is Null) AND
([TT].[Level] > 7)
);
GO
This Procedure executed in 16 seconds.
But When I change the Where Clause to:
WHERE
(
((1=1) AND [AT].[Access] = 0 OR [AT].[Access] Is Null) AND
([TT].[Level] > 7)
);
The Procedure Executed in less than 1 second.
As You see I just remove the local variable.
So where is the problem? Is there any thing I missing to use local variable in where clause? any suggestion to improve execute time when I using local variable in where clause?
Update:
I also think to add an if statement before script and split the procedure to 2 procedures, but I have 4 or 5 variables like above and use if statement is so complex.
Update2:
I change the set of #LocalVar:
DECLARE #LocalVar SMALLINT = 1;
There is no change in execute time.
When you use use local variables in WHERE filter then it causes FULL TABLE SCAN. The value of the local variable is not known to the SQL Server at compile time. hence SQL Server creates an execution plan for the largest scale that is avaliable for that column.
As you have seen that when you pass 1==1 then SQL server knows the value and hence the performance is not degraded. But the moment you pass a local variable the value is unknown.
One solution may be to use OPTION ( RECOMPILE ) at the end of your SQL query
You can check out the OPTIMIZE FOR UNKNOWN
When you use a local variable in WHERE optimizer doesn't know what to do with it.
You may check this link
What you could do in your case is run your query with displaying the actual plan in both cases and see how SQL is treating them.
It seems that you are using the #LocalVar as a branch condition, as follows:
If #LocalVar is 1 then apply a filter to the query
If #LocalVaris 0 then return an empty result set.
IMO you would be better off writing this condition explicitly, as then SQL will be in a position to optimize separate plans for the 2 branches, i.e.
DECLARE #LocalVar SMALLINT = GetLocalVarFunction();
IF (#LocalVar = 1)
SELECT
[TT].[ID],
[TT].[Title]
FROM [TargetTable] AS [TT]
LEFT JOIN [AcceccTable] AS [AT] ON [AT].[AccessID] = [TT].[ID]
WHERE
(
([AT].[Access] = 0 OR [AT].[Access] Is Null) AND
([TT].[Level] > 7)
)
ELSE
SELECT
[TT].[ID],
[TT].[Title]
FROM [TargetTable] AS [TT]
WHERE 1=2 -- Or any invalid filter, to retain the empty result
And then, because there are now 2 branches through your stored procedure, you should add WITH RECOMPILE to the stored proc, because the 2 branches have radically different query plans.
Edit
Just to clarify the comments:
Note that placing OPTION(RECOMPILE) after a query means that the query plan is never cached - this might not be a good idea if your query is called frequently.
The WITH RECOMPILE at a PROC level prevents caching of branches through the proc. It is not the same as OPTION(RECOMPILE) at query level.
If there are a large number of permutations of filter in your query, then the 'branching' technique above doesn't scale very well - your code quickly becomes unmaintainable.
You might unfortunately then need to consider using parameterized dynamic SQL. SQL will then at least cache a separate plan for each permutation.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Parameterizing an SQL IN clause?
Every now and then I work on a system that allows the user to select multiple items and then perform a bulk action on them. Typically, I resorted to building the SQL at runtime, something like this:
string inClause = String.Join(", ", selectedIds);
string command = "SELECT * FROM Customer WHERE CustomerId IN ({0})";
command = String.Format(command, inClause);
Of course, this style of code is insecure because of SQL injection. I could solve that by putting in parameter placeholders and creating parameters.
Still, I am wondering if there is another approach that I've just not considered. I certainly don't want to execute the command once for each ID.
There are two good approaches:
Build the string with command placeholders (like you said)
Join to the values of a TVP
Burning the IDs into the SQL is not good because it prevents plan caching and opens the potential for injection.
You can build an XML string and then pass it to a stored proc. Executing it would look like:
EXECUTE getLocationTypes '<IDList><ID>1</ID><ID>3</ID></IDList>'
The stored proc would look something like:
create proc [dbo].[getLocationTypes](#locationIds XML)
as
begin
set nocount on
SELECT locationId, typeId
FROM xrefLocationTypes
WHERE locationId
IN (SELECT Item.value('.', 'int' )
FROM #locationIDs.nodes('IDList/ID') AS x(Item))
ORDER BY 1, 2
end
Notice the data type of the parameter is XML. This is a little more complicated than what you are doing, guess you could do it all in a single SQL string.