Query a SQL Database & Edit the found data set - sql

I know this question has probably been asked before I just can't manage to get mine going. I set up my SQL to have two tables but in this instance I will only be using one called 'Book'. It has various columns but the ones I want to work with is called 'WR', 'Customer', 'Contact', 'Model', 'SN', 'Status', 'Tech', 'WDone' and 'IN'.
I want to enter text into a editbox called edtWR and I want the button btnSearch to search the 'WR' column until it has a match (all of the entries will be different). Once it has that it must write 'Customer', 'Contact', 'Model', 'SN', 'Status' to labels, lets call them lblCustomer lblContact lblModel lblSN & lblStatus.
Once the person has verified that that is the 'WR' that they want the must enter text into edit boxes and one memo called edtTech, mmoWDone and edtIN and click on btnUpdate. that should then update that record.
I have 3 ADO Connections on called dtbOut thats my ADOConnection1, tableOut thats my ADOTable and dataOut thats by ADODataSet. dataOut's command text is Select * From Book if it helps.
I can get the whole process to work perfectly on a access database but with almost no experience on SQL I need help. I will add code for the Access database in case it is needed for reference.
procedure TFOut.btnSearchClick(Sender: TObject);
begin
dataout.Filter := 'WR = ''' + 'WR ' + edtwr.Text + '''';
dataout.Filtered := True;
dataout.First;
lblcustomer.Caption := 'Customer: ' + dataout.FieldByName('Customer').AsString;
lblcontact.Caption := 'Contact: ' + dataout.FieldByName('Contact').AsString;
lblSN.Caption := 'SN: ' + dataout.FieldByName('SN').AsString;
lblModel.Caption := 'Model: ' + dataout.FieldByName('Model').AsString;
lblstatus.Caption := 'Status: ' + dataout.FieldByName('Status').AsString;
procedure TFOut.btnUpdateClick(Sender: TObject);
begin
dataout.Edit;
dataout.FieldByName('Tech').AsString := edtTech.Text;
dataout.FieldByName('WDone').AsString := mmoWDone.Lines.GetText;
dataout.FieldByName('IN').AsString := edtIN.Text;
dataout.Post;
end
Do I need any additional components on my form for me to be able to do this in SQL, what do I need and how do I even start. Ive read a lot of things and it seems line I will need to get a ADOQuery1 but when it comes to the ADOQuery1.SQL part I fall off the wagon. I have also tried it the Access way and I can search but as soon as I try to update I get a "Insufficient key column information for updating or refreshing" Error, witch I also have no idea how to address.
If I need to state the question otherwise, please explain how to change to make it more clear and if I need to add anything in the whole explanation or code, please inform me of what.

SO isn't really the place for database tutorials, so I'm not going to
attempt one but instead focus on one basic thing that it's crucial to understand and get right in your database design before you even begin
to write a Delphi db app. (I'm going to talk about this in terms of
Sql Server, not MS Access.)
You mentioned getting an error "Insufficient key column information for updating or refreshing" which you said you had no idea how to address.
A Delphi dataset (of any sort, not just an ADO one) operates by maintaining a logical cursor which which points at exactly one row in the dataset. When you open a (non-empty) dataset, this cursor is pointing at the first row in the dataset and you can move the cursor around using various TDataSet methods such as Next & Prior, First, Last and MoveBy. Some, but not all, types of TDataSet implement its Locate method which enables you to go to a row which matches criteria you specify, other types, not. Delphi's ADO components do implement Locate (btw, Locate operates on rows you're already retrieved from the server, it's not for finding rows on the server).
One of the key ideas of Sql-oriented TDataSets such as TAdoQuery is that you can leave it to automatically generate Sql statements to do Updates, Deletes and Inserts. This is not only a significant productivity aid, but it avoids coding errors and omissions when you try to do it yourself.
If you observe ADO doing its stuff against an MS Sql Server table using SS's Profiler utility, then with a well-designed database, you'll find that it does this quite nicely and efficiently provided the database design follows one cardinal rule, namely that there must be a way to uniquely identify a particular row in a table. The most common way to do this is to include in each table, usually as the first column, an int(eger) ID column, and to define it as the "Primary key" of the table. Although there are other methods to generate a suitable ID value to go in this column, Sql Server has a specific column type, 'Identity' which takes care of this on the server.
Once a table has such a column, the ADO layer (which is a data-access layer provided by Windows that dataset components such as TAdoQuery sit upon) can automatically generate Sql statements to do Updates and Deletes, e.g.
Delete from Table1 where Table1ID = 999
and
Update Table1 set SomeCharField = 'SomeValue' where Table1ID = 666
and you can leave it to the AdoQuery to pick up the ID value for a newly-inserted row from the server.
One of the helpful aspects of leaving the Sql to be generated automatically is that it ensures that the Sql only affects a single row and so avoids affecting more rows than you intend.
Once you've got this key aspect of your database design correct, you'll find that Delphi's TDataSet descendants such as TAdoQuery and its DB-aware components can deal with most simple database applications without you having to write any Sql statements at all to update, insert or delete
rows. Usually, however, you do still need to write Sql statements to retrieve the rows you want from the server by using a 'Where' clause to restrict the rows retrieved to a sub-set of the rows on the server.
Maybe your next step should be to read up on parameterized Sql queries, to reduce your exposure to "Sql Injection":
https://en.wikipedia.org/wiki/SQL_injection
as it's best to get into the habit of writing Sql queries using parameters. Btw, Sql Injection isn't just about Sql being intercepted and modified when it's sent over the internet: there are forms of injection where a malicious user who knows what they're doing can simply type in some extra Sql statements where the app "expects" them simply to specify some column value as a search criterion.

Related

How to update and select records in the same sql query

As a typical scenario in any prod environment, we have multiple nodes which fetches and processes items from the database (oracle).
We want to make sure that each node fetches unique set of items from database and acts on it. To make this possible we are looking whether it is possible to update the records status (for e.g., Idle to In-Process), and the same update query returning the records which it updated. In this way every node will act on its own set of records and not interfere with each others' set.
We want to avoid pl/sql due to maintenance reasons. We tried with "select for update", but in few cases it was leading to database locks getting hold up for longer period of time.
Any suggestions on how to achieve this through simple sql or hibernate (since we have hibernate option available as well)?
A couple of thoughts on this. First up in Oracle you can use the RETURNING clause as part of an update statement to return select columns (such as the primary key) from the table being updated into a collection. But this method does require PL/SQL to work since you need to work with collections, although BULK transactions will mitigate some of the drawbacks of using PL/SQL.
Another option would be to add a column to your table where you can indicate which node is processing the record(s), similar to your idea of a status column indicating Idle, or Processing statuses. This one would be NULL for not being handled, or a value uniquely identifying the node or process working on the record.
A little extra research led to this post here on Stack about using Oracles RETURNING INTO statement with Java. It also leads right back to Oracle's own documentation on the subject of Oracles DML Returning feature as supported by Java
Finally we were able to find the solution for our problem. Our problem statement: Claim the top 100 items from the list order by time of their creation. So the logic that we wanted to apply was based on FIFO. So in this case each node will pick-up top 100 items from the database and start processing on it. In this way each node will work on its own set of items, without overlapping on each others path.
We achieved this by creating a TYPE in oracle database, and then used hibernate to claim the items and store the claimed items temporarily in TYPE. Here is the code:
create type TMP_TYPE as table of VARCHAR2(1000);
//Hibernate code
String query = "BEGIN UPDATE OUR_TABLE SET OUR_TABLE_STATUS = 'IP' WHERE OUR_TABLE_STATUS = 'ID' AND ID_OUR_TABLE IN (SELECT ID_OUR_TABLE FROM (SELECT ID_OUR_TABLE FROM OUR_TABLE ORDER BY AGEING_SINCE ASC ) ) AND ROWNUM < 101 RETURNING UUID BULK COLLECT INTO ?;END;";
Connection connection = getSession().connection();
CallableStatement cStmt = connection.prepareCall(query);
cStmt = connection.prepareCall(query);
cStmt.registerOutParameter(1, Types.ARRAY, " TMP_TYPE ");
cStmt.execute();
String[] updateBulkCollectArr = (String[]) (cStmt.getArray(1).getArray());
`
Got idea from here Oracle Type and Bulk Collect
Thanks #Sentinel

SQL Injection Query

I am writing a report on SQL injection attacks. I've found an example on Owasp as shown bellow.
Since this is an example and to me, it seems as a simple query getting a row with the specific ID, does it do anything else or my assumption is correct?
String query = "SELECT * FROM accounts WHERE custID='" +
request.getParameter("id") + "'";
// Since this is an online example i don't know what getParameter("id") method does.
to me it seems as a simple query getting a row with specific ID
Thats the magic of injection. The query should only get a row that fits a certain criteria that comes from a request (like a GET or POST from html for example).
So request.getParameter("id") provides a parameter submitted by the user (or a very bad guy).
Usually whoever wrote that peace of code expected something like this:
id = 12
which would result in
SELECT * FROM accounts WHERE custID='12'
Now image what happens if the user (a bad one in this case) sends this instead:
id = 0'; DROP TABLE accounts; --
This would execute as
SELECT * FROM accounts WHERE custID='0'; DROP TABLE accounts; --'
Step-by-step:
Make sure the intended query executes without error (0)
End the query before the intended point (';)
Inject your malicous code (DROP TABLE accounts;)
Make sure everything that is left of the original query is treated as a comment (--)
The problem in the OWASP example isn't the query itself, but the fact that parameters that come from 'outside' (request.getParameter("id")) are used to generate a query, without escaping any potential control characters.
This style of writing code basically allows any user to execute code on your SQL-Server.
The problem with this query is that the SQL is created dynamically. Request.getparameter is probably just a function which returns the id of the row for the specific web request.
But if the webpage allows filling this parameter through a text box or the function is called directly from JavaScript any value can be set in id.
This could contain any SQL statement, which with the correct authentication, could even contain 'DROP Database'
request.getParameter("id")
will get a the parameter "id" from the http-request, e.g. for: http://test.com/?id=qwertz request.getParameter("id") will return "qwertz". SQL injection is possible in this case, since the value of this parameter wasn't checked at all and can contain anything

MSAccess SQL Injection

Situation:
I'm doing some penetration testing for a friend of mine and have total clearance to go postal on a demo environment. Reason for this is because I saw a XSS-hole in his online ASP-application (error page with error as param allowing html).
He has a Access DB and because of his lack of input-validation I came upon another hole: he allows sql injection in a where-clause.
I tried some stuff from:
http://www.krazl.com/blog/?p=3
But this gave limited result:
MSysRelationships is open, but his Objects table is shielded.
' UNION SELECT 1,1,1,1,1,1,1,1,1,1 FROM MSysRelationships WHERE '1' = '1 <-- worked so I know the parent table has at least 9 columns. I don't know how I can exploit the relation table to get tablenames ( I can't find any structures explanation so I don't know on what to select.
Tried brute-forceing some tablenames, but to no avail.
I do not want to trash his DB, but I do want to point out the serious flaw with some backing.
Anyone has Ideas?
Usually there are two ways to proceed from here. You could try to guess table names by the type of data which is stored in them which often works ("users" usually stores the user data ...). The other method would be to generate speaking error messages in the application to see if you can fetch table or column names from there.

Move SELECT to SQL Server side

I have an SQLCLR trigger. It contains a large and messy SELECT inside, with parts like:
(CASE WHEN EXISTS(SELECT * FROM INSERTED I WHERE I.ID = R.ID)
THEN '1' ELSE '0' END) AS IsUpdated -- Is selected row just added?
as well as JOINs etc. I like to have the result as a single table with all included.
Question 1. Can I move this SELECT to SQL Server side? If yes, how to do this?
Saying "move", I mean to create a stored procedure or something else that can be executed before reading dataset in while cycle.
The 2 following questions make sense only if answer is "yes".
Why do I want to move SELECT? First off, I don't like mixing SQL with C# code. At second, I suppose that server-side queries run faster, since the server have more chances to cache them.
Question 2. Am I right? Is it some sort of optimizing?
Also, the SELECT contains constant strings, but they are localizable. For instance,
WHERE R.Status = "Enabled"
"Enabled" should be changed for French, German etc. So, I want to write 2 static methods -- OnCreate and OnDestroy -- then mark them as stored procedures. When registering/unregistering my assembly on server side, just call them respectively. In OnCreate format the SELECT string, replacing {0}, {1}... with required values from the assembly resources. Then I can localize resources only, not every script.
Question 3. Is it good idea? Is there an existing attribute to mark methods to be executed by SQL Server automatically after (un)registartion an assembly?
Regards,
Well, the SQL-CLR trigger will also execute on the server, inside the server process - so that's server-side as well, no benefit there.
But I agree - triggers ought to be written in T-SQL whenever possible - no real big benefit in having triggers in C#.... can you show the the whole trigger code?? Unless it contains really odd balls stuff, it should be pretty easy to convert to T-SQL.
I don't see how you could "move" the SELECT to the SQL side and keep the rest of the code in C# - either your trigger is in T-SQL (my preference), or then it is in C#/SQL-CLR - I don't think there's any way to "mix and match".
To start with, you probably do not need to do that type of subquery inside of whatever query you are doing. The INSERTED table only has rows that have been updated (or inserted but we can assume this is an UPDATE Trigger based on the comment in your code). So you can either INNER JOIN and you will only match rows in the Table with the alias of "R" or you can LEFT JOIN and you can tell which rows in R have been updated as the ones showing NULL for all columns were not updated.
Question 1) As marc_s said below, the Trigger executes in the context of the database. But it goes beyond that. ALL database related code, including SQLCLR executes in the database. There is no client-side here. This is the issue that most people have with SQLCLR: it runs inside of the SQL Server context. And regarding wanting to call a Stored Proc from the Trigger: it can be done BUT the INSERTED and DELETED tables only exist within the context of the Trigger itself.
Question 2) It appears that this question should have started with the words "Also, the SELECT". There are two things to consider here. First, when testing for "Status" values (or any Lookup values) since this is not displayed to the user you should be using numeric values. A "status" of "Enabled" should be something like "1" so that the language is not relevant. A side benefit is that not only will storing Status values as numbers take up a lot less space, but they also compare much faster. Second is that any text that is to be displayed to the user that needs to be sensitive to language differences should be in a table so that you can pass in a LanguageId or LocaleId to get the appropriate French, German, etc. strings to display. You can set the LocaleId of the user or system in general in another table.
Question 3) If by "registration" you mean that the Assembly is either CREATED or DROPPED, then you can trap those events via DDL Triggers. You can look here for some basics:
http://msdn.microsoft.com/en-us/library/ms175941(v=SQL.90).aspx
But CREATE ASSEMBLY and DROP ASSEMBLY are events that are trappable.
If you are speaking of when Assemblies are loaded and unloaded from memory, then I do not know of a way to trap that.
Question 1.
http://www.sqlteam.com/article/stored-procedures-returning-data
Question 3.
It looks like there are no appropriate attributes, at least in Microsoft.SqlServer.Server Namespace.

SQL Server stored procedures - update column based on variable name..?

I have a data driven site with many stored procedures. What I want to eventually be able to do is to say something like:
For Each #variable in sproc inputs
UPDATE #TableName SET #variable.toString = #variable
Next
I would like it to be able to accept any number of arguments.
It will basically loop through all of the inputs and update the column with the name of the variable with the value of the variable - for example column "Name" would be updated with the value of #Name. I would like to basically have one stored procedure for updating and one for creating. However to do this I will need to be able to convert the actual name of a variable, not the value, to a string.
Question 1: Is it possible to do this in T-SQL, and if so how?
Question 2: Are there any major drawbacks to using something like this (like performance or CPU usage)?
I know if a value is not valid then it will only prevent the update involving that variable and any subsequent ones, but all the data is validated in the vb.net code anyway so will always be valid on submitting to the database, and I will ensure that only variables where the column exists are able to be submitted.
Many thanks in advance,
Regards,
Richard Clarke
Edit:
I know about using SQL strings and the risk of SQL injection attacks - I studied this a bit in my dissertation a few weeks ago.
Basically the website uses an object oriented architecture. There are many classes - for example Product - which have many "Attributes" (I created my own class called Attribute, which has properties such as DataField, Name and Value where DataField is used to get or update data, Name is displayed on the administration frontend when creating or updating a Product and the Value, which may be displayed on the customer frontend, is set by the administrator. DataField is the field I will be using in the "UPDATE Blah SET #Field = #Value".
I know this is probably confusing but its really complicated to explain - I have a really good understanding of the entire system in my head but I cant put it into words easily.
Basically the structure is set up such that no user will be able to change the value of DataField or Name, but they can change Value. I think if I were to use dynamic parameterised SQL strings there will therefore be no risk of SQL injection attacks.
I mean basically loop through all the attributes so that it ends up like:
UPDATE Products SET [Name] = '#Name', Description = '#Description', Display = #Display
Then loop through all the attributes again and add the parameter values - this will have the same effect as using stored procedures, right??
I dont mind adding to the page load time since this is mainly going to affect the administration frontend, and will marginly affect the customer frontend.
Question 1: you must use dynamic SQL - construct your update statement as a string, and run it with the EXEC command.
Question 2: yes there are - SQL injection attacks, risk of mal-formed queries, added overhead of having to compile a separate SQL statement.
Your example is very inefficient, so if I pass in 10 columns you will update the same table 10 times?
The better way is to do one update by using sp_executesql and build this dynamically, take a look at The Curse and Blessings of Dynamic SQL to see how you have to do it
Is this a new system where you have the freedom to design as necessary, or are you stuck with an existing DB design?
You might consider representing the attributes not as columns, but as rows in a child table.
In the parent MyObject you'd just have header-level data, things that are common to all objects in the system (maybe just an identifier). In the child table MyObjectAttribute you'd have a primary key of with another column attrValue. This way you can do an UPDATE like so:
UPDATE MyObjectAttribute
SET attrValue = #myValue
WHERE objectID = #myID
AND attrName = #myAttrName