I have copied some code from an example for accessing an sqlite database. It uses an agent to get the returned rows:
check_db (input_line: STRING)
local
df_db: SQLITE_DATABASE
df_db_query: SQLITE_QUERY_STATEMENT
test_val: STRING
do
test_val := "whatever"
create df_db.make_open_read_write ("Large.db")
create df_db_query.make ("SELECT * FROM test_table WHERE test_val =%
% :TEST_VAL%
% ;", df_db)
check df_db_query_is_compiled: df_db_query.is_compiled
end
df_db_query.execute_with_arguments (agent (returned_row: SQLITE_RESULT_ROW): BOOLEAN
do
if returned_row.is_null (1) then
insert_into_db
end
end,
<< create {SQLITE_STRING_ARG}.make (":TEST_VAL", test_val) >>)
end -- check_db
The problem I have is that I would like to pass input_line to the procedure insert_into_db.
The inline procedure used by execute_with_arguments isn't able to see any variables outside its scope, but I presume there must be a way to pass an extra parameter to it? Everything I have tried simply refuses to compile with syntax errors.
In this case, I simply want to add a database entry if it doesn't already exist, but I can easily see the case where I would want to send the returned row along with some extra data to another procedure, so it must be doable.
As you correctly point out, at the moment, local variables in Eiffel are not automatically passed into inline agents. The solution is to add explicit formal arguments to an inline agent and to pass the corresponding actual arguments to it.
The inline agent from the example can be adapted as follows (the outer context with the argument input_line is omitted for brevity):
agent (returned_row: SQLITE_RESULT_ROW; s: STRING): BOOLEAN
do
-- `s` is attached to `input_line` here.
if returned_row.is_null (1) then
insert_into_db
end
end (?, input_line)
In addition to the formal argument s that will get the value of input_line, you can see an explicit list of actual arguments (?, input_line). The question mark denotes an open argument, that will be passed to the agent by execute_with_arguments as before. input_line stands for a closed argument.
When the list has no closed arguments, as in the original code, it can be omitted. However, one could have written (?) after the keyword end of the inline agent in the original code to be absolutely explicit.
Related
I have a tMSSqlSP element calling a procedure that receives two params and returns two values. If I connect a tLogRow right after that, I can see that the procedure is being called correctly and returning the correct values. However, I need to use those values in a tJava element, which means calling them explicitly somehow.
The schema for the tMSSqlSP looks like:
Column Db Column
entityTIN EntityTIN (IN)
qtdDoc QtdDoc (IN)
nextMsg NextMsg (OUT)
nextDoc NextDoc (OUT)
The only global variable tMSSqlSP has is an error message, and I tried checking the "Is function" box and setting "Return result in" to nextMsg, but trying to use this variable on tJava results in compilation errors.
Any idea how I would go about accessing these values explicitly?
EDIT: Here's a screenshot of this section of the job. The tLogRow connected to the tMSSqlSPprints correctly the values of the two input variables and the two output variables, but the two deactivated components on the right are only able to see null values when connected.
You can link your tMSSqlSP component to a tSetGlobalVar, and add 2 global variables to it (NextMsg and NextDoc) that take their values from the column of your input flow (rowX.column).
You can then reference them in the next subjob by referencing them in a tJava like so : (String)globalMap.get("NextMsg")
If you need to process them in the same subjob as tMSSqlSP, you can instead connect tMSSqlSP to a tJavaFlex or a tJavaRow (as tJava doesn't handle input main flows) and just use something like row18.NextMsg.
I had succeeded to create the following function in PG 8.4.x
CREATE OR REPLACE FUNCTION foo()
RETURNS VOID
AS $function$
BEGIN
select concat('a','b');
END;$function$
LANGUAGE plpgsql;
The function is created without any errors
But when I try to use the function I got :
select foo();
ERROR: function concat(unknown, unknown) does not exist
LINE 1: select concat('a','b') ^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: select concat('a','b')
CONTEXT: PL/pgSQL function "foo" line 2 at SQL statement
How comes that PG succeed to create a function that actually calls an unknown function? (CONCAT is supported only in PG 9.x)
The PLpgSQL checks only syntax of embedded SQL in validation time. The semantic - identifiers, functions, ... is checked immediately before first evaluation in run-time. You can search plpgsql_check extension. It does complete check of embedded SQL.
Because functions get compiled the first time you call them. Else it would not be possible to define a set of recursive functions where one calls the other :).
EDIT (thanks to Nick Barnes): Somewhat unrelated to the question there is a switch
SET check_function_bodies = true;
but this only enables basic syntax checks for PL/pgSQL functions. The binding will be done on first call nonetheless. Postgres will only attempt to resolve function / table names for LANGUAGE sql.
I am trying to build a scenario that would allow me to expose additional data from a server (for case-demo purposes). The server calls a vulnerable SQL code:
EXEC my_storeProc '12345'
where "12345" (not the single quotes) is the parameter. This performs a SELECT statement. I would like to eliminate this execution and instead call my own select statement, however the server side code will only accept the first select statement called, contained within the aforementioned EXEC call. Calling the second statement is easy:
EXEC my_storeProc '12345 ' select * from MySecondTable--
(the -- at the end will block the closing single quote added by the server to prevent errors). My problem is that although there are 2 select statements, the server will only parse the first one. Is there a way to cancel the first EXEC call without throwing an error so that the second one would be taken instead? Perhaps even a UNION but there isn't much I can do with only one variable open to exploit (variable being 12345 in this case).
You have to think of how it will be executed, specifically you want it called so it doesn't raise an exception and put the kabosh on the whole statement. You can't set the result to always true with a proc call, so there is no real way escape the proc. Instead, you'll want to slip a second command in, Your desired code looks like;
exec my_Storeproc '1234'; select * from mysecondtable
So we need to close the quotes, and make a new statement. That would mean the string with the insert needs to be;
1234'; select * from mysecondtable where 1 = '1
There is a flaw in this, whatever command you are executing is not being returned to the UI. To get the data you'll have to add a server connection to the second command.
To make the second command unnecessary you would have to inject code into the proc, which is a non starter since the proc is already complied and sql injection relies on confusing the compiler as to what is data and what is commands. For a more verbose explanation of that check out this answer:
https://security.stackexchange.com/a/25710
I've been converting an oracle schema to an sql server one and got the following error
Invalid use of a side-effecting operator 'SET COMMAND' within a function.
In my case modifying the database involved this
set #originalDateFirst = ##DateFirst;
set datefirst 1;
set #DayOfWeek = datepart(weekday,#DATE); -- 1 to 5 = Weekday
set datefirst originalDateFirst;
Ideally this wouldn't have modified the database but the datepart function uses static state.
I'm not really from a database background so was slightly baffled by this but reading other answers it looked like all I needed to do was swap the word function for procedure and I'd be away. However I then got the following error
Incorrect syntax near 'RETURNS'.
Reading around a bit about stored procedures aren't allowed to return anything they like - only integers. However the integers normally have the same semantics as a console application's return code - 0 is success and anything else is an error.
Luckily the type I wanted to return was an integer so fixing the next error:
Incorrect syntax near 'RETURNS'.
Involved just removing
RETURNS INTEGER
from the function/procedure. However I'm unsure if there are any weird side effects caused by this error code interpretation that will be outside of my control. The function actually just returns either 0 or 1 basically as a true or false flag (where 1 is true and 0 is false as you might expect). Therefore one of my return values would count as an 'error'.
What if any are the consequences of piggybacking on the return code of a procedure rather than using an out parameter? Is it just a bad practice? If it's safe to do this I'd certainly prefer to so I don't need to change any calling code.
This isn't an answer to your question as posed, but may be a better solution to the overall problem.
Rather than having to rely on a particular DATEFIRST setting, or changing the DATEFIRST setting, why not use an expression that always returns reliable results no matter what the DATEFIRST setting is.
For example, this expression:
select (DATEPART(weekday,GETDATE()) + 7 - DATEPART(weekday,'20140406')) % 7
always returns 1 on Mondays, 2 on Tuesdays, ..., 5 on Fridays. No matter what settings are in effect.
So, your entire original block of 4 lines of code could just be:
set #DayOfWeek = (DATEPART(weekday,#Date) + 7 -
DATEPART(weekday,'20140406')) % 7; -- 1 to 5 = Weekday
And now you should be able to continue writing it as a function rather than a stored procedure.
If it's safe to do this I'd certainly prefer to so I don't need to change any calling code.
Which you would have to do if you did change your function into a stored procedure. There's no syntax where you can look at the call and ever be in doubt of whether a stored procedure or a function is being invoked - they always use different syntaxes. A procedure is executed by being the first piece of text in a batch or by being preceded by the EXEC keyword and no parentheses.
A function, on the other hand, always has to have parentheses applied when calling it, and must appear as an expression within a larger statement (such as SELECT). You cannot EXEC a function, nor call one by it being the first piece of text in a batch.
An out param could be of (almost) any valid datatype, RETURN is always an int, not necessarily 0 or 1.
Because you can't use a procedure as a query source (it's not a table), to consume a return value from a procedure, declare a variable and exec the procedure like this:
create procedure p as
-- some code
return 13
go
declare #r int
exec #r = p
select #r
I wouldn't call it piggybacking, it's a regular way to return a success/error code for example. But how you interprete the return value is entirely up to calling code.
Functions, otoh, can be used as a query source, if table-valued, or as a scalar value in select list or where clause etc. But you can't modify data inside functions, and there are other restrictions with them (as you've learned already). Furthermore, functions can have nasty impact on performance (except the inline table-valued functions, they're pretty much safe to use).
In Ado.net, the code is calling a stored procedure with input and output parameters.
I understand that if some of the input parameters are optional (have default values in the SP), the code doesn't need to define and send the parameters values unless needed to.
My question is:
Does the same apply to the optional output parameters? can the code ignore the optional (has a default value) SP output parameters?
I could have tested it myself but I don't have a working example right now, and I am short of time.
Thanks you.
Yes. If a parameter has a default value then it may be safely omitted, irrelevant of the parameter direction (INPUT or OUTPUT). The fact that the procedure is called from ADO.Net is entirely irrelevant. Eg:
create procedure usp_test
#a int = 1 output,
#b int = 2
as
begin
set #a = #b;
end
go
exec usp_test
Whether is safe to do from a business rules point of view (ie. ignoring an OUTPUT parameter returned value), is entirely up to the specifics of the procedure and your app.
EDIT: Turns out I was wrong here, but I'm going to leave my answer because the information on SqlParameter might be useful. Sorry for the inaccuracy though.
I don't believe so. You must send in an OUTPUT parameter and in ADO.NET this is accomplished by adding a SqlParameter with it's ParameterDirection property set to ParameterDirection.Output.
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlparameter.direction.aspx
http://msdn.microsoft.com/en-us/library/system.data.parameterdirection.aspx