I am looking through some old code and found a piece that i cant' seem to understand the point of....As far as i can tell, it's just a simple insert. but why did they do it this way? would it be okay to rewrite into an insert, or could i potentially break something?
please see below:
Set TextRS = Server.CreateObject("ADODB.RecordSet")
Set TextRS.ActiveConnection = Conn
TextRS.Source = "SELECT IDX,TIMESTAMP,CURRENTFLAG,TEXT FROM " & TextTable & " WHERE 1=2 FOR UPDATE"
TextRS.CursorLocation = 2
TextRS.CursorType = 3
TextRS.Open ,,,3
TextRS.AddNew
TextRS(0).Value = IDX
TextRS(1).Value = Timestamp
TextRS(2).Value = "Y"
TextRS(3).AppendChunk TextPiece
TextRS.Update
TextRS.Close
This part of the source confused me a bit.... where 1 = 2???
Apparently it had a purpose to ensure no match.
Anyway this style of programming is fairly old using ADO technology and people coming from DAO to ADO would often open up a cursor to iterate over the database this way... it does not follow modern best practices on how to do things, you can and should replace it with an insert statement!
It is possible that it was written pre jet4.0/access 2000 in which case it was an attempt to simulate a parameterized stored procedure. Though if the system is at all more modern than that I would strongly recommend using a stored procedure as it has multiple benefits. Cached Execution Plans, Parameters to reduce the chances of SQL injection
I actually used to write code very much like that 12 years ago or so :p Mostly because I just didn't know better, regardless of the tech in use.
Ah, good old classic ASP ;)
The 1 = 2 forces the sql to never return a match. It's basically a way of building up the command (?) so that you can then "conveniently" change the values and then an update will store it.
I've seen it done before, but never did it that way myself. As others have said, a simple paremetised INSERT statement will be better, IMO.
I would rewrite this using parameterized ADO query. The method being used has an unnecessary SELECT, which makes the INSERT slower.
That code seems a bit obscure, but all they are doing is creating an empty instance of a recordset row so the values can be set and the recordset resaved. This is bound to be much slower than doing a straight INSERT.
I would utilize an insert statement. The above mentioned code seems a little bit "lazy"... as in "let ADO do the work for me". However, there is nothing really wrong with it. The where 1=2 part was there to return an "empty table"... um... I mean recordset.
Related
I use UPDATE a SET GR_P = REPLACE(GR_P,'','') FROM mytable a to replace things.
But replace function is not working for below charter:
In Query analyzer it works but when I used SSIS Execute SQL task or OLEDB Source then it is giving me error:
No Connection manager is specified.
In Toad against Oracle (since that's one of your tags), I issued this (pressing ALT-12 to get the female symbol) and got 191 as a result. note selecting it back using CHR(191) shows an upside-down question mark though.
select ascii('♀') from dual;
Given that, this worked but it's Oracle syntax, your mileage may vary.
UPDATE mytable SET GR_P = REPLACE(GR_P, CHR(191));
Note if it does not work, that symbol could be for another control character. You may need to use a regular expression to eliminate all characters not in a-zA-Z0-9, etc. I suspect you'll need to update your tags to get a more accurate answer.
Maybe this info will help anyway. Please post back what you find out.
I have a problem I just can't figure out, my Google-fu has failed me too, so I signed in just to get some expert help.
The problem is complex, with a few red herrings, for what I can figure out, plus as we deal with sensitive information, I can't give the exact code. Please bear with me, I'll try to be as precise and descriptive as I can.
Short version of the problem: I have a stored procedure (on a SQL Server 2008 R2 server) which returns one row when executed directly on the server. When the same stored procedure is executed via VB.net code (Visual Studio 2013 environment), one of the column's value is changed to DBNull.
Long version with code example:
Here is a cleaned up version of the stored procedure
Create PROCEDURE MySP
#inputParms [five of them]
AS
BEGIN
DECLARE #UserCanRun int
DECLARE #ThisApp INT
EXEC #UserCanRun = dbname.dbo.CheckUserCanRun #InputParm1, #ThisApp --security check
IF #UserCanRun = 0 --Means no problem, can continue
BEGIN
DECLARE #ExtraInfo varchar(100)
SELECT #ExtraInfo = typeID + ' - ' + typeName
FROM [three joined tables]
WHERE [conditions using some #InputParm4]
SELECT DISTINCT
col1, ..., [colN-1], #ExtraInfo as colN, [colN+1], ..., colM
FROM
[8 joined tables and subqueries]
WHERE
[more conditions with #InputParms2 to 5]
END
END
GO
This stored procedure runs just fine when executed directly on the database; it returns one row, with all the (available) info having their value set correctly. (You'll notice colN; it's the one giving me trouble; co-workers assure me the fact it is using value from a variable shouldn't be a problem.)
Now, when I call it from VB.net code:
dim rTable As DataTable
dim myCmd = New SqlCommand(SPName, myConnectionString)
dim parameter As SQLParameter
dim rValue As Integer = 0
[set SQL parameters]
If not myCmd is Nothing Then
If myCmd.Connection.State = connectionstate.Closed Then
[bit of security check code]
command.Connection.Open()
End If
Dim myAdapter As New SqlDataAdapter
myAdapter.SelectCommand = myCmd
myAdapter.Fill(rTable) 'problem!
ReturnValue = CInt(myCmd.Parameters(RETURN_VALUE_FIELD).Value)
End If
[more code]
If I do a quick watch on the rTable after the myAdapter.Fill command has executed, the value rTable.Rows(0).Item([M]) returns DBNull, while it was not DBNull when fetched directly in the SP, using exactly the same parameters.
I don't have a data set for that table; you can see it uses a generic DataTable (the code is adapted from an application specific object to simplify all stored procedure calls, so I can't create a dataset and use it at this level either). So I don't think.
I have checked for the validity of the value; I have even checked the Unicode value of each character of the #ExtraInfo value to make sure there was not some control character that would have been put in accidentally. It matched the value shown, so no bad character messing up the value.
This is used in a few places in the code, but seems to fail for one specific set of data on our production environment; I haven't been able to reproduce the problem on our development environment. So I can't just go in and play with it.
Would anyone know what else could cause a column's value to go from a non-null, non-empty varchar to DBNull by going through SqlDataAdapter.Fill()? I can't step into that call, so I am blind.
(Also worth of note, maybe: I have been using VB.net for only about two years, debugging existing systems, so I may be missing something obvious; although my more experienced colleagues don't understand it either.)
Edited to add the final word on the problem: I never found the solution, except good old Murphy's Law. After letting this aside for a while, I asked a co-worker to take a look. As I was showing him, the problem didn't occur. Another test later confirmed it was behaving normally. I can't promise anyone Murphy's law is a sure solution, but I can only suggest there was some transient error that disappeared on its own. If it happens to you, good luck, and please let us know if you find a solution, or even a way to diagnose it. Thank you!
Your stored procedure needs SET NOCOUNT ON at the beginning
I wrote a dBase procedure and I'm having a hard time converting it to a SQL Server stored procedure.
This is what I have for dbase:
CLOSE ALL
SELECT A
USE DDCS_OLD
SELECT B
USE CROSSELL
DO WHILE .NOT. EOF()
mLAT1 = IND_LAT
mLONG1 = IND_LONG
IF mLAT1 > 0 .AND. mLONG1 < 0
SELECT A
GOTO TOP
DO WHILE .NOT. EOF()
mLAT2 = LAT
mLONG2 = LONG
mPROP_CODE = PROP_CODE
mDISTANCE = 3963.0 * ACOS(SIN(mLAT1/57.2958) * SIN(mLAT2/57.2958) + COS(mLAT1/57.2958) * COS(mLAT2/57.2958) * COS(mLONG2/57.2958 - mLONG1/57.2958))
SELECT B
REPLACE &mPROP_CODE WITH mDISTANCE
SELECT A
SKIP
ENDDO
ENDIF
SELECT B
SKIP
END DO'
I have never written a stored procedure before so I'm not sure how to go about a do while loop while using the two tables ddcs_old and crossell.
That looks like a tremendously complicated calculation that I would consider moving out of the database and into the application that is using this data, if at all possible.
However, I'm guessing that what DO WHILE .NOT. EOF() does in dbase is basically read one row at a time from the table, until it reaches the end. In a SQL Stored Procedure you would achieve this with a cursor:
DECLARE crDDCS_Old CURSOR LOCAL FORWARD_ONLY FOR
SELECT LAT, LONG, PROP_CODE FROM ddcs_old
OPEN crDDCS_Old
FETCH NEXT FROM crDDCS_Old
WHILE ##FETCH_STATUS = 0
BEGIN
-- Do your calculations here
FETCH NEXT FROM crDDCS_Old
END
CLOSE crDDCS_Old
DEALLOCATE crDDCS_Old
As I said, I would strongly recommend reconsidering the best way of implementing this functionality, a direct conversion to a stored procedure is highly unlikely to be the best approach. Cursors are inefficient and, apparently, more lines of code than the dbase equivalent. You'd need in-depth knowledge of what it was doing in dbase and how that data is being used, to come up with the best alternative.
You don't use sql like DBase. If at all possible, you want to execute any operation using a set based operation that update all corresponding rows with a single update command -- I.e., you avoid loops based on a cursor 99.97% of the time. Also, without column definitions for your DBase tables (and hopefully corresponding columns for your SQL tables), I don't know how you expect to get any help as it is not really possible to figure out what your existing code does.
However it also looks a like you you are doing great circle calculations, beginning in Sql 2008, you can use the geography data type, which has build in functions for a number of geographic features, including great circle distances.
You really need to get a little understanding of how SQL works instead of asking for some magic and opaque answer -- the time will be well spent and when you get stuck, S/O is a good source for getting unstuck.
I know this is more of a comment, but it is too long for a comment.
My co-worker is being unsafe with his code and is allowing a user to upload an SQL file to be run on the server.
He strips out any key words in the file such as "EXEC", "DROP", "UPDATE", "INSERT", "TRUNC"
I want to show him the error of his ways by exploiting his EXEC ( #sql )
My first attempt will be with 'EXEXECEC (N''SELECT ''You DRDROPOPped the ball Bob!'')'
But he might filter that all out in a loop.
Is there a way I can exploit my co-worker's code? Or is filtering out the key words enough?
Edit: I got him to check in his code. If the code contains a keyword he does not execute it. I'm still trying to figure out how to exploit this using the binary conversion.
Tell your co-worker he's a moron.
Do an obfuscated SQL query, something like:
select #sql = 0x44524f5020426f627350616e7473
This will need some tweaking depending on what the rest of the code looks like, but the idea is to encode your code in hex and execute it (or rather, let it be executed). There are other ways to obfuscate code to be injected.
You've got a huge security hole there. And the funny part is, this is not even something that needs to be reinvented. The proper way to stop such things from happening is to create and use an account with the correct permissions (eg: can only perform select queries on tables x, y and z).
Have a look at ASCII Encoded/Binary attacks ...
should convince your friend he is doomed.. ;)
And here some help on how to encode the strings ..
Converting a String to HEX in SQL
I've been battling this one for a while now. I have a stored proc that takes in 3 parameters that are used to filter. If a specific value is passed in, I want to filter on that. If -1 is passed in, give me all.
I've tried it the following two ways:
First way:
SELECT field1, field2...etc
FROM my_view
WHERE
parm1 = CASE WHEN #PARM1= -1 THEN parm1 ELSE #PARM1 END
AND parm2 = CASE WHEN #PARM2 = -1 THEN parm2 ELSE #PARM2 END
AND parm3 = CASE WHEN #PARM3 = -1 THEN parm3 ELSE #PARM3 END
Second Way:
SELECT field1, field2...etc
FROM my_view
WHERE
(#PARM1 = -1 OR parm1 = #PARM1)
AND (#PARM2 = -1 OR parm2 = #PARM2)
AND (#PARM3 = -1 OR parm3 = #PARM3)
I read somewhere that the second way will short circuit and never eval the second part if true. My DBA said it forces a table scan. I have not verified this, but it seems to run slower on some cases.
The main table that this view selects from has somewhere around 1.5 million records, and the view proceeds to join on about 15 other tables to gather a bunch of other information.
Both of these methods are slow...taking me from instant to anywhere from 2-40 seconds, which in my situation is completely unacceptable.
Is there a better way that doesn't involve breaking it down into each separate case of specific vs -1 ?
Any help is appreciated. Thanks.
I read somewhere that the second way will short circuit and never eval the second part if true. My DBA said it forces a table scan.
You read wrong; it will not short circuit. Your DBA is right; it will not play well with the query optimizer and likely force a table scan.
The first option is about as good as it gets. Your options to improve things are dynamic sql or a long stored procedure with every possible combination of filter columns so you get independent query plans. You might also try using the "WITH RECOMPILE" option, but I don't think it will help you.
if you are running SQL Server 2005 or above you can use IFs to make multiple version of the query with the proper WHERE so an index can be used. Each query plan will be placed in the query cache.
also, here is a very comprehensive article on this topic:
Dynamic Search Conditions in T-SQL by Erland Sommarskog
it covers all the issues and methods of trying to write queries with multiple optional search conditions
here is the table of contents:
Introduction
The Case Study: Searching Orders
The Northgale Database
Dynamic SQL
Introduction
Using sp_executesql
Using the CLR
Using EXEC()
When Caching Is Not Really What You Want
Static SQL
Introduction
x = #x OR #x IS NULL
Using IF statements
Umachandar's Bag of Tricks
Using Temp Tables
x = #x AND #x IS NOT NULL
Handling Complex Conditions
Hybrid Solutions – Using both Static and Dynamic SQL
Using Views
Using Inline Table Functions
Conclusion
Feedback and Acknowledgements
Revision History
If you pass in a null value when you want everything, then you can write your where clause as
Where colName = IsNull(#Paramater, ColName)
This is basically same as your first method... it will work as long as the column itself is not nullable... Null values IN the column will mess it up slightly.
The only approach to speed it up is to add an index on the column being filtered on in the Where clause. Is there one already? If not, that will result in a dramatic improvement.
No other way I can think of then doing:
WHERE
(MyCase IS NULL OR MyCase = #MyCaseParameter)
AND ....
The second one is more simpler and readable to ther developers if you ask me.
SQL 2008 and later make some improvements to optimization for things like (MyCase IS NULL OR MyCase = #MyCaseParameter) AND ....
If you can upgrade, and if you add an OPTION (RECOMPILE) to get decent perf for all possible param combinations (this is a situation where there is no single plan that is good for all possible param combinations), you may find that this performs well.
http://blogs.msdn.com/b/bartd/archive/2009/05/03/sometimes-the-simplest-solution-isn-t-the-best-solution-the-all-in-one-search-query.aspx