Cobol DB2 SQL query - NOT IN parameter - sql

Is it possible to have something like this :
MOVE "'xx','yy','mm''" TO WS-TYPE-PARAM;
Then in SQL Query :
SELECT bar
FROM tblfoo
WHERE bar_type NOT IN (:WS-TYPE-PARAM)
I tried but unsucess. Maybe there's an alternative.
Thanks in advance.

99% Sure the answer is no. (With RPG that would be 100%)
You have to pass in a variable for each value
SELECT bar FROM tblfoo WHERE bar_type NOT IN (:WS-TYPE-PARAM1 : WS-TYPE-PARAM2 : WS-TYPE-PARAM3)
You could do it with dynamic SQL (sorry it's RPG)
wSqlStmt = 'SELECT bar FROM tblfoo WHERE bar_type NOT IN (' + WS-TYPE-PARM + ')';
Normally however, such dynamic SQL is a bad idea. For both performance and security reasons;
The above dynamic code is susceptible to SQL Injection attacks. But as long as the values in WS-TYPE-PARM are not coming from a user it's safe.
The last option would be to insert the values into a temporary table, then just
SELECT bar FROM tblfoo WHERE bar_type NOT IN (SELECT type_parm FROM tmptable)

Related

Is it possible to add a multiple value parameter query in SSRS with left()?

I have a query in SSRS where I can search for a title with a certain prefix. The reason why I used left() is because there are some prefixes that have an underscore or a dash so I need my search results to be exact and it wasn't giving me that when I used the like operator.
Here's an example of what my query looks like:
select title
from table1
where left(title, len(#prefix)) = #prefix
This works if my prefix dropdown doesn't allow multiple values. Now, I have also tried this query:
select title
from table1
where left(title, len(#prefix)) in (#prefix)
But this just caused my report to generate a "Query execution failed for dataset" however, this query does work when I try it on SQL Server and when it isn't allowed for multiple values.
As I mentioned in my comment, I hate that SSRS allows the syntax IN (#Parameter); it causes misunderstandings and teaches people incorrect syntax.
When you have statement like SELECT * FROM dbo.MyTable WHERE MyColumn IN (#MyParameter); the SQL that SSRS runs is not that statement. Instead SSRS removes the parameter and then injects the multiple values into the statement. So the statement it actually runs would be something like SELECT * FROM dbo.MyTable WHERE MyColumn IN (N'MyValue1',N'MyValue2',N'MyValue3');
If you were to actually run the SQL SELECT * FROM dbo.MyTable WHERE MyColumn IN (#MyParameter); in SSMS, or any other product, it would be a synonym of SELECT * FROM dbo.MyTable WHERE MyColumn = #MyParameter;. The syntax that SSRS uses is, for all intensive purposes, wrong.
There are multiple problems with that, which I'm not going to cover here.
When you then have a query like you do LEFT(title, LEN(#prefix)) IN (#prefix) you end up with a problem; LEN(#prefix) can't have tuples injected into it (LEN(N'MyValue1',N'MyValue2',N'MyValue3') isn't valid syntax). This just results in a invalid query because SSRS teaches bad habits.
The solution to this is th force SSRS to not be (completely) dumb. Unfortunately SSRS is dumb and still (even in SSRS 2022!) doesn't support Table Table Parameters (TVPs) which would trivialise this. As such you'll need to have SSRS pass a delimited value to a Procedure, and then you can handle the logic in your procedure. As you're using SSRS 2019 then you're also using SQL Server 2019 and thus have access to STRING_SPLIT. Also we can switch to a LIKE here.
This means you need a procedure like the following:
CREATE PROC dbo.YourProc #prefix nvarchar(4000) --Assumed data type
AS
BEGIN
SELECT title
FROM dbo.table1 t1
WHERE EXISTS (SELECT 1
FROM STRING_SPLIT(#prefix,',') SS
WHERE t1.title LIKE SS.value + '%');
END;
Then, instead, you execute the procedure from your report.

SQL injection payload after order by in SQL query

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.

Dynamic pivot columns without dynamic SQL statement?

I'm just wondering if there's any way to do a pivot query, with dynamic column names, without resorting to dynamic sql (declare #sql_text varchar(max) = 'select ...' etc.)
Dynamic SQL just rubs me the wrong way.
Basically I have a query like this (and I had to change all the table/column names to protect IP so if there's a syntax error somewhere don't worry about it)
declare #sec_class_ids table (CLASS_ID varchar(50));
insert #sec_class_ids (CLASS_ID) values
('987987987'), -- END USER - SAVE AND EXPORT [987987987]
('654654654'), -- END USER - SAVE [654654654]
('321321321') -- 'END USER - SPECIAL - SAVE AND EXPORT [321321321]'
select * from (
select
class.NAME as sec_class_name,
sec_attr.NAME as sec_attr,
'YES' as granted
from sec_class class
inner join class_sec_attr
on class.class_id = class_sec_attr.class_id
inner join sec_attr
on sec_attr.sec_attr_id = class_sec_attr.sec_attr_id
inner join #sec_class_ids input
on input.class_id = class.class_id
) as sec_attrs
pivot (
max(sec_attrs.granted)
--for sec_attrs.sec_class_id in (#sec_class_ids)
for sec_points.sec_class_name in ([END USER - SAVE AND EXPORT],[END USER - SAVE],[END USER - SPECIAL - SAVE AND EXPORT])
) as sec_class_comparison
;
I would like to be able to use the table var (shown in the comment) rather than manually setting the columns for each query. I am aware this is possible and quite easy with dynamic SQL, but I'd like to avoid doing that if possible in any way.
Unfortunately there is no way to do this without dynamic SQL. PIVOT requires that the values are known when the query is executed so if you have unknown names, then you have to use dynamic SQL.
I have never heard of a way to do this with a query, however I remember I was able to set this up in a report (SSRS) which was really neat. Depending on what you plan to do with the data this might work for you.

How do you write the SQL for a PreparedStatement using a WHERE x IN clause?

I have a query that looks like this:
SELECT last_name,
first_name,
middle_initial
FROM names
WHERE last_name IN ('smith', 'jones', 'brown')
I need to be able to parameterize the list in the IN clause to write it as a JDBC PreparedStatement. This list could contain any number of names in it.
Is the correct way to do this:
SELECT last_name,
first_name,
middle_initial
FROM names
WHERE last_name IN (?)
and then build a list of parameters? Or is there a better (more correct) way to do that?
In short, you can't out of the box. However, with Spring you can do what you want. See How to generate a dynamic "in (...)" sql list through Spring JdbcTemplate?
Standard SQL doesn't allow the IN clause to be parameterized into a single variable -- only dynamic SQL, the SQL query being constructed as a string prior to execution with the comma separated list of values is supported.
I'm going to research this topic, as well. I've been guilty of writing similar code and never felt 100% comfortable with it. I suppose I'd like to find something on "variable SQL parameter lists".
In code, using hibernate, and given a String of comma-delimited order Ids, I've used:
Session s = getSession();
Criteria crit = s.createCriteria(this.getOrderListingClass());
crit.add(Expression.sql(String.format("{alias}.orderId in (%s)", orderIds)));
crit.add(Expression.eq("status", OrderInfo.Order_STATUS_UNFILLED));
orders = crit.list();
Whereas orderId is really part of a "SELECT x FROM y WHERE IN (%s)".
I did run the orderIds String through a validator prior to passing it to hibernate - being fearful of injections, etc.
Something else that I've been meaning to do is check the limit on SQL parameters and number of characters in the query. I seem to recall hitting a limit somewhere around 2000+ (with MS SQL). That's something to consider if you go with this approach.
I think this is kludgy... to be passing off that many Ids in a Where-clause, but it's a section of code that needs refactoring. Thankfully, the use case has only seen a handful of Ids queried at any one time.
You could also construct your query as a stored procedure that takes the parameterized list as a varchar. For example, in sql server:
CREATE PROCEDURE dbo.[procedure_name]
#IN_LIST VARCHAR(MAX)
AS
BEGIN
DECLARE #SQL VARCHAR(MAX)
SET #SQL = '
SELECT last_name,
first_name,
middle_initial
FROM names
WHERE last_name IN (' + #IN_LIST + ')'
EXECUTE(#SQL)
END
Just make sure your #IN_LIST is formatted as a string that includes the single quotes and commas. For example in java:
String inList = "'smith','jones','brown'";
If You use MS SQL Server, try reshape your TSQL to use UDF, Maybe this my post can help You

Dynamic Query in SQL Server

I have a table with 10 columns as col_1,col_2,.... col_10. I want to write a select statement that will select a value of one of the row and from one of these 10 columns. I have a variable that will decide which column to select from. Can such query be written where the column name is dynamically decided from a variable.
Yes, using a CASE statement:
SELECT CASE #MyVariable
WHEN 1 THEN [Col_1]
WHEN 2 THEN [Col_2]
...
WHEN 10 THEN [Col_10]
END
Whether this is a good idea is another question entirely. You should use better names than Col_1, Col_2, etc.
You could also use a string substitution method, as suggested by others. However, that is an option of last resort because it can open up your code to sql injection attacks.
Sounds like a bad, denormalized design to me.
I think a better one would have the table as parent, with rows that contain a foreign key to a separate child table that contains ten rows, one for each of those columns you have now. Let the parent table set the foreign key according to that magic value when the row is inserted or updated in the parent table.
If the child table is fairly static, this will work.
Since I don't have enough details, I can't give code. Instead, I'll explain.
Declare a string variable, something like:
declare #sql varchar(5000)
Set that variable to be the completed SQL string you want (as a string, and not actually querying... so you embed the row-name you want using string concatenation).
Then call: exec(#sql)
All set.
I assume you are running purely within Transact-SQL. What you'll need to do is dynamically create the SQL statement with your variable as the column name and use the EXECUTE command to run it. For example:
EXECUTE('select ' + #myColumn + ' from MyTable')
You can do it with a T-SQl CASE statement:
SELECT 'The result' =
CASE
WHEN choice = 1 THEN col1
WHEN choice = 2 THEN col2
...
END
FROM sometable
IMHO, Joel Coehoorn's case statement is probably the best idea
... but if you really have to use dynamic SQL, you can do it with sp_executeSQL()
I have no idea what platform you are using but you can use Dynamic LINQ pretty easily to do this.
var query = context.Table
.Where( t => t.Id == row_id )
.Select( "Col_" + column_id );
IEnumerator enumerator = query.GetEnumerator();
enumerator.MoveNext();
object columnValue = enumerator.Current;
Presumably, you'll know which actual type to cast this to depending on the column. The nice thing about this is you get the parameterized query for free, protecting you against SQL injection attacks.
This isn't something you should ever need to do if your database is correctly designed. I'd revisit the design of that element of the schema to remove the need to do this.