Prompt user in PLSQL - sql

My assignment is to write a PLSQL module to insert data into database. Upon a certain condition, it may need additional information and should prompt the user for one more detail. This should be done directly in PLSQL and wording is straight from the assignment.
I've researched the topic and found some people said this cannot be done in PLSQL? But the ACCEPT PROMPT function does exist.
ACCEPT v_string PROMPT 'Enter your age: ';
While this works directly from SQLPlus, it does not work in PLSQL as it gives me this error:
PLS-00103: Encountered the symbol "V_STRING" when expecting one of the following: := . ( # % ;
Can anyone provide some insight as to how I'm supposed to ask the user from PLSQL, only upon when a certain condition is true (the condition is checked when you get something else from the DB). To clarify, I only need help on how to accept input.
Thanks for your time.

There is a trick that will allow you to do something like this, but (a) it's a bit of a hack, (b) you need to be logged into the database server itself, and (c) it only works on Linux (and perhaps other flavours of Unix).
Generally, it's not possible to ask for user input in PL/SQL, especially if you're connecting to a database on a remote machine. Either your assignment is wrong or you've misunderstood it.
PL/SQL programs are designed to run on the database server, so it doesn't make sense to ask the user for input during them. Using the ACCEPT command, SQL*Plus can ask the user for input while running a script client-side. SQL*Plus will then substitute in the value entered before sending SQL or PL/SQL to the database.

Well, since it's not really a part of SQL, but rather the developer tools you use, here's the ones I know:
SQL*Plus: &Variable
SQL Developer: You can make a procedure or you can use :Variable to be prompted to insert a parameter

I checked and tried following things which might helpful to you. It's just an example which I tried. You can implement your own logic.
declare
c1 varchar2(50);
begin
c1:='&enter_value';
dbms_output.put_line(c1);
exception
when others then
dbms_output.put_line(sqlerrm);
end;
'&' will help you to prompt and ask input to user. Once user feeds some input, it will assign to variable and you can use variable wherever you want.
Hopefully this helps you.

You cannot get user input in pure PL/SQL. It is a server-side language to express business/database logic.
The use of "&" to get input is a "sqlplus" feature and not a PL/SQL strategy. If it was an "assignment" then you need to tell the teacher that it is an invalid assignment - or maybe it was a trick question!

Related

How do I use a dynamic role password in Postgres?

I have a role in postgres as follows:
create role admin login password 'some_password';
What I'd like instead is:
create role admin login (select current_setting('custom.ADMIN_PASSWORD'));
But this fails with the error:
ERROR: syntax error at or near "("
LINE 2: (SELECT ...
I expected this to work, because it works in the following example:
select public.register_account(
email := (SELECT current_setting('custom.SOME_EMAIL')),
password := (SELECT current_setting('custom.SOME_PASSWORD'))
);
How can I use current_setting() to apply a role password?
Bonus Points: Why does my first example fail, while my second succeeds?
The first failed because DDL changes like that aren't your general everyday SQL. Think of a statement like the creation of a role as being special within the context of PostgreSQL. In general the database engine prefers DDL and other structural changes to be explicit, not calculated on the fly like a lot of the rest of SQL.
You can however get around this restriction by using a "do" block, essentially an inline function. Combined with the EXECUTE command and the format() function, you can go dynamic to your heart's content. Only be warned that with great power comes great responsibility. Dynamic SQL like this should be avoided in general unless you truly have no other alternative since it short circuits a lot of the grammar/parser validation. Simple mistakes become a lot harder to see and fix while at the same time—due to it being a structural change to the database rather than just another row of data—far more serious in effect when bugs arise. Many tasks like CREATE ROLE do not allow dynamic shenanigans by default precisely for this reason.
All that said, this will get you going.
DO $$
BEGIN
EXECUTE format('CREATE ROLE admin LOGIN PASSWORD ''%1$s'';',
current_setting('custom.ADMIN_PASSWORD'));
END;
$$ LANGUAGE plpgsql;

Calling a series of stored procedures sequentially SQL

Is it possible (using only T-SQL no C# code) to write a stored procedure to execute a series of other stored procedures without passing them any parameters?
What I mean is that, for example, when I want to update a row in a table and that table has a lot of columns which are all required, I want to run the first stored procedure to check if the ID exists or not, if yes then I want to call the update stored procedure, pass the ID but (using the window that SQL Server manager shows after executing each stored procedure) get the rest of the values from the user.
When I'm using the EXEC command, I need to pass all the parameters, but is there any other way to call the stored procedure without passing those parameter? (easy to do in C# or VB, I mean just using SQL syntax)
I think you are asking "can you prompt for user input in a sql script?". No not really.
You could actually do it with seriously hack-laden calls to the Windows API. And it would almost certainly have serious security problems.
But just don't do this. Write a program in C#, VB, Access, Powerscript, Python or whatever makes you happy. Use an tool appropriate to the task.
-- ADDED
Just so you know how ugly this would be. Imagine using the Flash component as an ActiveX object and using Flash to collect input from the user -- now you are talking about the kind of hacking it would be. Writing CLR procs, etc. would be just as big of a hack.
You should be cringing right now. But it gets worse, if the TSQL is running on the sql server, it would likely prompt or crash on the the server console instead of running on your workstation. You should definitely be cringing buy now.
If you are coming from Oracle Accept, the equivalent in just not available in TSQL -- nor should it be, and may it never be.
Right after reading your comment now I can understand what you are trying to do. You want to make a call to procedure and then ask End User to pass values for Parameters.
This is a very very badddddddddddddddddddd approach, specially since you have mentioned you will be making changes to database with this SP.
You should get all the values from your End Users before you make a call to your database(execute procedure), Only then make a call to database you Open a transaction and Commit it or RollBack as soon as possible and get out of there. as it will be holding locks on your resources.
Imagine you make a call to database (execute sp) , sp goes ahead and opens a transaction and now wait for End user to pass values, and your end user decides to go away for a cig, this will leave your resources locked and you will have to go in and kill the process yourself in order to let other user to go and use database/rows.
Solution
At application level (C#,VB) get all the values from End users and only when you have all the required information, only then pass these values to sp , execute it and get out of there asap.
You can specify the parameters by prefixing the name of the parameter with the # sign. For example, you can call an SP like this:
EXEC MyProc #Param1='This is a test'
But, if you are asking if you can get away with NOT providing required parameters, the answer is NO. Required is required. You can make them optional by providing a default value in the declaration of the SP. Then you can either not pass the value or call it like this:
EXEC MyProc #Param1=DEFAULT
--OR
EXEC MyProc DEFAULT

Make trigger behavior depend on query

My goal is to make trigger behavior to depend on some client identifier.
For example I execute a query
begin;
<specify-some-client-identifier>
insert into some_table
values('value')
commit;
And I have trigger function executing before insert:
NEW.some_filed := some_func(<some-client-identifier-spicified-above>)
So, how do I <specify-some-client-identifier> and get <some-client-identifier-spicified-above>?
You basically need some kind of variables in SQL. It is possible to do it, with multiple ways:
using GUCs
using table with variables
using temp table with variables
using %_SHARED in plperl functions
All this is possible. If you're interested in implementation details and/or comparison - check this blogpost - just in case it wasn't obvious from domain - it's my blog.
You will find this prior answer informative. There I explain how to pass an application-defined username through so it is visible to PostgreSQL functions and triggers.
You can also use the application_name GUC, which can be set by most client drivers or explicitly by the application. Depending on your purposes this may be sufficient.
Finally, you can examine pg_stat_activity to get info about the current client by looking it up by pg_backend_pid(). This will give you a client IP and port if TCP/IP is being used.
Of course, there's also current_user if you log in as particular users at the database level.
As usual, #depesz points out useful options I hadn't thought of, too - using shared context within PL/Perl, in particular. You can do the same thing in PL/Python. In both cases you'll pay the startup overhead of a full procedural language interpreter and the function call costs of accessing it, so it probably only makes sense to do this if you're already using PL/Perl or PL/Python.

Why doesn't this PL/SQL procedure work?

I have a cursor which returns two values: one which I will use (and therefore will assign to an out variable) and another which I've only had returned to make the ROWNUM thing work.
If I run the cursor as a query, it works as expected. But if I execute the procedure the out variable comes empty. Is my approach somehow not supported? I mean, returning two values but only using one of them?
Here is my procedure code: (Don't delve too much on the query itself. It works, I know it's a bit ugly but it works. It was the only way I found to return the second-last row)
procedure retorna_infos_tabela_164(i_nip in varchar,
o_CODSDPANTERIOR out number) is
cursor c_tabela_164 is
select *
from(
select CODSDP,ROWNUM rn
from
(
select NRONIP,CODTIPOMOV,CODSDP
from TB164_HISTORICOMOVIMENTACOES
where NRONIP = i_nip and
CODTIPOMOV='S1'
order by DTHMOV desc
)
)
where rn=2;
v_temp_nr number;
begin
open c_tabela_164;
fetch c_tabela_164 into o_CODSDPANTERIOR,v_temp_nr;
close c_tabela_164;
end retorna_infos_tabela_164;
EDIT The way I've tried to run this procedure was by dbms_output.put_line(o_CODSDPANTERIOR) which didn't work. Then I googled a little bit and saw I should TO_CHAR() my var first and then have it output. Didn't work either.
There's no problem with passing a number to DBMS_OUTPUT.PUT_LINE. Oracle will silently convert other built-in types to VARCHAR2 using the default format. You only need to use TO_CHAR if you want to control the format used -- which is often a good idea, but not generally necessary.
One possibility, though, is that you are not seeing the output because you have not enabled it. If you are running your test in SQLPlus, make sure you SET SERVEROUTPUT ON before running code that includes DBMS_OUTPUT calls. If you are using some other client, consult its documentation for the proper way to enable DBMS_OUTPUT. (You can of course test if it's enabled by adding another call to output a string literal.)
There's nothing inherently wrong with the technique you're using to populate the out parameter. However, it's not necessary to return two columns from the cursor; your select * could simply be select CODSDP. You seem to be under the misconception that any column referenced in the predicates has to be in the select list, but that's not the case. In your innermost query, the select list does not need to include NRONIP or CODTIPOMOV, because they are not referenced in the outer blocks; the WHERE clause in that query can reference any column in the table, regardless of whether it is in the select list.
So, my first guess is that you simply don't have server output enabled. The only other possibility I can think of right now is that you're running your query and the procedure in two different sessions, and one of them has uncommitted transaction against the table, so they are actually seeing different data.
If those suggestions don't seem to be the problem, I'd suggest you run your tests of the standalone query and the procedure in a single SQLPlus session, then copy and paste the entire session here, so we can see exactly what you're doing.
I'm sorry I've had you guys take the time to answer me when the answer was something to do with the tool I'm using. I hope all you guys have learnt something.
The query does work for me at least, I've not come across any edge cases where it doesn't work, but I haven't tested it exhaustively.
The problem was that TOAD, the tool I'm using to run the procedures, sometimes populates the procedures with the parameters I tell it to but sometimes it doesn't. The issue here was that I was trying to execute the procedure with no parameters, yielding no results...
Lesson Learnt: double check the generated procedure code when you run a Procedure using Right Click > Run Procedure on TOAD version 9.

Can parameterized statement stop all SQL injection?

If yes, why are there still so many successful SQL injections? Just because some developers are too dumb to use parameterized statements?
When articles talk about parameterized queries stopping SQL attacks they don't really explain why, it's often a case of "It does, so don't ask why" -- possibly because they don't know themselves. A sure sign of a bad educator is one that can't admit they don't know something. But I digress.
When I say I found it totally understandable to be confused is simple. Imagine a dynamic SQL query
sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND Pass=' + password
so a simple sql injection would be just to put the Username in as ' OR 1=1--
This would effectively make the sql query:
sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS=' + password
This says select all customers where they're username is blank ('') or 1=1, which is a boolean, equating to true. Then it uses -- to comment out the rest of the query. So this will just print out all the customer table, or do whatever you want with it, if logging in, it will log in with the first user's privileges, which can often be the administrator.
Now parameterized queries do it differently, with code like:
sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?'
parameters.add("User", username)
parameters.add("Pass", password)
where username and password are variables pointing to the associated inputted username and password
Now at this point, you may be thinking, this doesn't change anything at all. Surely you could still just put into the username field something like Nobody OR 1=1'--, effectively making the query:
sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND Pass=?'
And this would seem like a valid argument. But, you would be wrong.
The way parameterized queries work, is that the sqlQuery is sent as a query, and the database knows exactly what this query will do, and only then will it insert the username and passwords merely as values. This means they cannot effect the query, because the database already knows what the query will do. So in this case it would look for a username of "Nobody OR 1=1'--" and a blank password, which should come up false.
This isn't a complete solution though, and input validation will still need to be done, since this won't effect other problems, such as XSS attacks, as you could still put javascript into the database. Then if this is read out onto a page, it would display it as normal javascript, depending on any output validation. So really the best thing to do is still use input validation, but using parameterized queries or stored procedures to stop any SQL attacks.
The links that I have posted in my comments to the question explain the problem very well. I've summarised my feelings on why the problem persists, below:
Those just starting out may have no awareness of SQL injection.
Some are aware of SQL injection, but think that escaping is the (only?) solution. If you do a quick Google search for php mysql query, the first page that appears is the mysql_query page, on which there is an example that shows interpolating escaped user input into a query. There's no mention (at least not that I can see) of using prepared statements instead. As others have said, there are so many tutorials out there that use parameter interpolation, that it's not really surprising how often it is still used.
A lack of understanding of how parameterized statements work. Some think that it is just a fancy means of escaping values.
Others are aware of parameterized statements, but don't use them because they have heard that they are too slow. I suspect that many people have heard how incredibly slow paramterized statements are, but have not actually done any testing of their own. As Bill Karwin pointed out in his talk, the difference in performance should rarely be used as a factor when considering the use of prepared statements. The benefits of prepare once, execute many, often appear to be forgotten, as do the improvements in security and code maintainability.
Some use parameterized statements everywhere, but with interpolation of unchecked values such as table and columns names, keywords and conditional operators. Dynamic searches, such as those that allow users to specify a number of different search fields, comparison conditions and sort order, are prime examples of this.
False sense of security when using an ORM. ORMs still allow interpolation of SQL statement parts - see 5.
Programming is a big and complex subject, database management is a big and complex subject, security is a big and complex subject. Developing a secure database application is not easy - even experienced developers can get caught out.
Many of the answers on stackoverflow don't help. When people write questions that use dynamic SQL and parameter interpolation, there is often a lack of responses that suggest using parameterized statements instead. On a few occasions, I've had people rebut my suggestion to use prepared statements - usually because of the perceived unacceptable performance overhead. I seriously doubt that those asking most of these questions are in a position where the extra few milliseconds taken to prepare a parameterized statement will have a catastrophic effect on their application.
Well good question.
The answer is more stochastic than deterministic and I will try to explain my view, using a small example.
There many references on the net that suggest us to use parameters in our queries or to use stored procedure with parameters in order to avoid SQL Injection (SQLi). I will show you that stored procedures (for instance) is not the magic stick against SQLi. The responsibility still remains on the programmer.
Consider the following SQL Server Stored Procedure that will get the user row from a table 'Users':
create procedure getUser
#name varchar(20)
,#pass varchar(20)
as
declare #sql as nvarchar(512)
set #sql = 'select usrID, usrUName, usrFullName, usrRoleID '+
'from Users '+
'where usrUName = '''+#name+''' and usrPass = '''+#pass+''''
execute(#sql)
You can get the results by passing as parameters the username and the password. Supposing the password is in free text (just for simplicity of this example) a normal call would be:
DECLARE #RC int
DECLARE #name varchar(20)
DECLARE #pass varchar(20)
EXECUTE #RC = [dbo].[getUser]
#name = 'admin'
,#pass = '!#Th1siSTheP#ssw0rd!!'
GO
But here we have a bad programming technique used by the programmer inside the stored procedure, so an attacker can execute the following:
DECLARE #RC int
DECLARE #name varchar(20)
DECLARE #pass varchar(20)
EXECUTE #RC = [TestDB].[dbo].[getUser]
#name = 'admin'
,#pass = 'any'' OR 1=1 --'
GO
The above parameters will be passed as arguments to the stored procedure and the SQL command that finally will be executed is:
select usrID, usrUName, usrFullName, usrRoleID
from Users
where usrUName = 'admin' and usrPass = 'any' OR 1=1 --'
..which will get all rows back from users
The problem here is that even we follow the principle "Create a stored procedure and pass the fields to search as parameters" the SQLi is still performed. This is because we just copy our bad programming practice inside the stored procedure. The solution to the problem is to rewrite our Stored Procedure as follows:
alter procedure getUser
#name varchar(20)
,#pass varchar(20)
as
select usrID, usrUName, usrFullName, usrRoleID
from Users
where usrUName = #name and usrPass = #pass
What I am trying to say is that the developers must learn first what an SQLi attack is and how can be performed and then to safeguard their code accordingly. Blindly following 'best practices' is not always the safer way... and maybe this is why we have so many 'best practices'- failures!
Yes, the use of prepared statements stops all SQL injections, at least in theory. In practice, parameterized statements may not be real prepared statements, e.g. PDO in PHP emulates them by default so it's open to an edge case attack.
If you're using real prepared statements, everything is safe. Well, at least as long as you don't concatenate unsafe SQL into your query as reaction to not being able to prepare table names for example.
If yes, why are there still so many successful SQL injections? Just because some developers are too dumb to use parameterized statements?
Yes, education is the main point here, and legacy code bases. Many tutorials use escaping and those can't be easily removed from the web, unfortunately.
I avoid absolutes in programming; there is always an exception. I highly recommend stored procedures and command objects. A majority of my back ground is with SQL Server, but I do play with MySql from time to time. There are many advantages to stored procedures including cached query plans; yes, this can be accomplished with parameters and inline SQL, but that opens up more possibilities for injection attacks and doesn't help with separation of concerns. For me it's also much easier to secure a database as my applications generally only have execute permission for said stored procedures. Without direct table/view access it's much more difficult to inject anything. If the applications user is compromised one only has permission to execute exactly what was pre-defined.
My two cents.
I wouldn't say "dumb".
I think the tutorials are the problem. Most SQL tutorials, books, whatever explain SQL with inlined values, not mentioning bind parameters at all. People learning from these tutorials don't have a chance to learn it right.
Because most code isn't written with security in mind, and management, given a choice between adding features (especially something visible that can be sold) and security/stability/reliability (which is a much harder sell) they will almost invariably choose the former. Security is only a concern when it becomes a problem.
Can parameterized statement stop all SQL injection?
Yes, as long as your database driver offers a placeholder for the every possible SQL literal. Most prepared statement drivers don't. Say, you'd never find a placeholder for a field name or for an array of values. Which will make a developer to fall back into tailoring a query by hand, using concatenation and manual formatting. With predicted outcome.
That's why I made my Mysql wrapper for PHP that supports most of literals that can be added to the query dynamically, including arrays and identifiers.
If yes, why are there still so many successful SQL injections? Just because some developers are too dumb to use parameterized statements?
As you can see, in reality it's just impossible to have all your queries parameterized, even if you're not dumb.
First my answer to your first question: Yes, as far as I know, by using parameterized queries, SQL injections will not be possible anymore. As to your following questions, I am not sure and can only give you my opinion on the reasons:
I think it's easier to "just" write the SQL query string by concatenate some different parts (maybe even dependent on some logical checks) together with the values to be inserted.
It's just creating the query and executing it.
Another advantage is that you can print (echo, output or whatever) the sql query string and then use this string for a manual query to the database engine.
When working with prepared statements, you always have at least one step more:
You have to build your query (including the parameters, of course)
You have to prepare the query on the server
You have to bind the parameters to the actual values you want to use for your query
You have to execute the query.
That's somewhat more work (and not so straightforward to program) especially for some "quick and dirty" jobs which often prove to be very long-lived...
Best regards,
Box
SQL injection is a subset of the larger problem of code injection, where data and code are provided over the same channel and data is mistaken for code. Parameterized queries prevent this from occurring by forming the query using context about what is data and what is code.
In some specific cases, this is not sufficient. In many DBMSes, it's possible to dynamically execute SQL with stored procedures, introducing a SQL injection flaw at the DBMS level. Calling such a stored procedure using parameterized queries will not prevent the SQL injection in the procedure from being exploited. Another example can be seen in this blog post.
More commonly, developers use the functionality incorrectly. Commonly the code looks something like this when done correctly:
db.parameterize_query("select foo from bar where baz = '?'", user_input)
Some developers will concatenate strings together and then use a parameterized query, which doesn't actually make the aforementioned data/code distinction that provides the security guarantees we're looking for:
db.parameterize_query("select foo from bar where baz = '" + user_input + "'")
Correct usage of parameterized queries provides very strong, but not impenetrable, protection against SQL injection attacks.
To protect your application from SQL injection, perform the following steps:
Step 1. Constrain input.
Step 2. Use parameters with stored procedures.
Step 3. Use parameters with dynamic SQL.
Refer to http://msdn.microsoft.com/en-us/library/ff648339.aspx
even if
prepared statements are properly used throughout the web application’s own
code, SQL injection flaws may still exist if database code components construct
queries from user input in an unsafe manner.
The following is an example of a stored procedure that is vulnerable to SQL
injection in the #name parameter:
CREATE PROCEDURE show_current_orders
(#name varchar(400) = NULL)
AS
DECLARE #sql nvarchar(4000)
SELECT #sql = ‘SELECT id_num, searchstring FROM searchorders WHERE ‘ +
‘searchstring = ‘’’ + #name + ‘’’’;
EXEC (#sql)
GO
Even if the application passes the user-supplied name value to the stored
procedure in a safe manner, the procedure itself concatenates this directly into
a dynamic query and therefore is vulnerable.