I have been trying to move all queries to use prepared statements. I have been able to get INSERT and UPDATE commands to work fine, but for some reason SELECT statements are not working. Using a standard query, i am able to obtain a row using the following.
strSQL = "SELECT username FROM users WHERE id = " & request.querystring("id")
Set rs = objConnection.Execute(strSQL, ,adCmdText)
When i convert this into a prepared statement, it appears to return a result, but nothing is there .
set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = objConnection
cmd.CommandText = "SELECT username FROM users WHERE id = ?"
cmd.CommandType = adCmdText
cmd.Prepared = true
cmd.Parameters.Append(cmd.CreateParameter("#id", adVarChar, adParamInput, 255, request.querystring("id")))
rs = cmd.Execute()
The query returns no data, but for some reason, the following If statement passes as if there was some data. The first query will output the username when this line runs. When the prepared statement runs, it outputs nothing, but the if statement passes as if were true. It doesnt appear to be throwing any errors.
if not (rs.eof and rs.bof) Then Response.Write(rs("username"))
The comment from #TimWilliams was one of the issues, there was also a second issue. ID was an integer field and the prepared statement was sending it as a varchar. seems crazy that there are datatypes but the following combined with the comment from Tim resolved the issue.
cmd.Parameters.Append(cmd.CreateParameter("#id", adVarChar, adParamInput, 255, request.querystring("id")))
Changes to
cmd.Parameters.Append(cmd.CreateParameter("#id", 3, 1, , request.querystring("id")))
Related
I have the following stored procedure:
alter proc SPCP_ProgramUpdate
#ID int,
#UserID int,
#Name nvarchar(150),
#University int,
#Level tinyint,
#isActive bit
as
update tblUniversityProgram set University_Fkey = #University, Level_Fkey = #Level, Program_Name = #Name, EditDate = GETDATE(), EditUser = #UserID, isActive = #isActive
where tblUniversityProgram.ID = #ID
When I run the stored procedure from SSMS, it works as intended.
However, when I run that stored procedure from ASP.NET using this code:
Dim varDbconn As New SqlConnection
Dim varDbcomm As SqlCommand
Dim varDbRead As SqlDataReader
varDbconn.ConnectionString = ConfigurationManager.ConnectionStrings("CPDB_ConnectionString").ToString
varDbconn.Open()
If Request.QueryString("program") <> "" Then
varDbcomm = New SqlCommand("SPCP_ProgramUpdate", varDbconn)
varDbcomm.CommandType = CommandType.StoredProcedure
varDbcomm.Parameters.AddWithValue("#ID", Request.QueryString("program")).DbType = DbType.Int32
varDbcomm.Parameters.AddWithValue("#UserID", Session("UserID")).DbType = DbType.Int32
varDbcomm.Parameters.AddWithValue("#University", Session("DecryptID")).DbType = DbType.Int32
varDbcomm.Parameters.AddWithValue("#Level", ddlLevel.SelectedValue).DbType = DbType.Byte
varDbcomm.Parameters.AddWithValue("#isActive", chkisActive.Checked).DbType = DbType.Boolean
varDbcomm.Parameters.AddWithValue("#Name", txttitle.Text).DbType = DbType.String
varDbcomm.ExecuteNonQuery()
varDbcomm.Dispose()
Else
....
End IF
varDbconn.Close()
nothing happens.
Any ideas?
The most likely answer to your question is that the value you are getting out of the querystring for program is not the Id in your database that you expect.
At the minute, your code is reading in input values and passing them to a stored procedure without any validation of your expected values - missing session for example could cause you all sorts of unexpected issues.
Debug your code and see exactly what parameters you are passing to your DB. Check your connection string to see that you are hitting the database where you have amended your stored procedure.
What you have should work. I would use parmaters.Add in place of addwith, but that should not really matter.
Try adding this code right after you are done setting up the parmaters:
Debug.Print("SQL = " & varDbcomm.CommandText)
For Each p As SqlParameter In varDbcomm.Parameters
Debug.Print(p.ParameterName & "->" & p.Value)
Next
That way in the debug window (or immediate depending on VS settings), you see a list of param values, and the parameter names. I suspect one of the session() values is messed up here.
Set cmd = Server.CreateObject("adodb.command")
cmd.CommandText = "sp"
cmd.CommandType = adCmdStoredProc
cmd.Parameters.Append cmd.CreateParameter("#starttime", adVarChar, adParamInput, 120)
cmd("#starttime") = CDate(trim(dateadd("d",daynumber,startday)))
The following outputs, "13/12/2015".
Response.Write CDate(trim(dateadd("d",daynumber,startday)))
The following outputs, "12/13/2015", which ultimately appears in the generated SQL string.
Response.Write cmd("#starttime")
How do I stop ADO from changing the date format?
I gave up trying to get the config right and changed the code by changing the type of the parameter to adDBTimeStamp, which is obviously what it should have been all along. Any other instances of this I will have to change similarly.
cmd.Parameters.Append cmd.CreateParameter("#starttime", adDBTimeStamp, adParamInput)
I'm trying to update a classic ASP application and as part of the update I've tried to replace dynamic SQL using string concatenation with a parametrised query.
The problem is that the parameters won't accept a value which is longer than 210 characters.
I get the following error...
ADODB.Parameter error '800a0d5d'
Application uses a value of the wrong type for the current operation.
/admin/Save_product_subcategories.asp, line 30
My first attempt looks like this...
SQLString = "UPDATE Product_SubCategories
SET SubCategory=?, Description=?
WHERE SubCategoryID=?"
Set courseCommand = Server.CreateObject("ADODB.Command")
courseCommand.ActiveConnection = objConn
courseCommand.CommandText = SQLString
courseCommand.Parameters(0).value = cleanCategory
courseCommand.Parameters(1).Value = cleanDescription
courseCommand.Parameters(2).value = cleanSubCategoryId
I've tried manually setting the parameter type and increasing the size of the parameter...
courseCommand.Parameters(1).Type = 203
courseCommand.Parameters(1).Size = 300
courseCommand.Parameters(1).Type = adLongVarWChar
I've also tried creating a parameter with the command.CreateParameter method but that gives the same error.
param = courseCommand.CreateParameter(,,,,cleanDescription)
'or
param = courseCommand.CreateParameter(,adLongVarWChar,,,cleanDescription)
'or
param = courseCommand.CreateParameter(,adLongVarWChar,,300,cleanDescription)
courseCommand.Parameters(1) = param
I'm beginning to think that my only option is to go back to dynamic sql.
Edit:
I tried to Append the parameter instead of adding it to the collection using the array index but none of the parameters worked after that.
Provider error '80020005'
Type mismatch.
/admin/Save_product_subcategories.asp, line 31
For anyone else looking for this the answer is to use a Recordset.
SQLString = "select * from Product_SubCategories where 1=0"
Set rs= Server.CreateObject("ADODB.Recordset")
rs.open SQLString , objConn, 1,3 'open as keyset ,lock optimistic that will create empty recordset for you
' Add new record
rs.AddNew
'assign values
rs("SubCategoryID")=cleanSubCategoryId
rs("Description")=cleanDescription
rs("SubCategory")=cleanCategory
' send new record with values to database
rs.Update
'close recordset
rs.close
'destroy recordset object
se rs=nothing
I'm using SQL Server 2005 with classic ASP and on a form repost (I post back to the same page), I replace each text field as follows:
course = trim(replace(request("course"),"'","''"))\
The problem with this is if I have to repost the form multiple times in case of validation errors, the tick marks I replace multiply.
Is there another way to safely vet the string fields without doing this kind of replace?
you better use a parametrized query:
dim cmd : set cmd = server.createObject("ADODB.Command")
dim param
dim sql : sql = "INSERT INTO table(course) VALUES (?)"
cmd.ActiveConnection = yourDBconnection
cmd.CommandType = adCmdText
set param = cmd.CreateParameter("course", adVarChar, , 20, request("course"))
cmd.Parameters.Append param
cmd.CommandText = sql
cmd.Execute
so you are completely safe with sql injection
Only replace the ' for use in the sql string. (which you should better do with parameterized queries..)
The easiest way would be to only do the SQL escaping when you're actually inserting into the database:
course = trim(request("course"))
Make a SafeSQL function:
function SafeSQL(TempStr)
SafeSQL = Replace(TempStr,"'","''")
end function
Then, when you're inserting:
"INSERT INTO table(course) VALUES ('" & SafeSQL(course) & "')"
Disclaimer: I only have a working knowledge of ASP, I don't really know the best practices.
you can do this
course = trim(replace(request("course"),"'","&apos ;"))
I'm trying to write a parameterized query in ASP Classic, and it's starting to feel like i'm beating my head against a wall. I'm getting the following error:
Must declare the scalar variable "#something".
I would swear that is what the hello line does, but maybe i'm missing something...
<% OPTION EXPLICIT %>
<!-- #include file="../common/adovbs.inc" -->
<%
Response.Buffer=false
dim conn,connectionString,cmd,sql,rs,parm
connectionString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Data Source=.\sqlexpress;Initial Catalog=stuff"
set conn = server.CreateObject("adodb.connection")
conn.Open(connectionString)
set cmd = server.CreateObject("adodb.command")
set cmd.ActiveConnection = conn
cmd.CommandType = adCmdText
cmd.CommandText = "select #something"
cmd.NamedParameters = true
cmd.Prepared = true
set parm = cmd.CreateParameter("#something",advarchar,adParamInput,255,"Hello")
call cmd.Parameters.append(parm)
set rs = cmd.Execute
if not rs.eof then
Response.Write rs(0)
end if
%>
Here's some sample code from an MSDN Library article on preventing SQL injection attacks. I cannot find the original URL, but googling the title keywords (Preventing SQL Injections in ASP) should get you there quick enough. Hope this real-world example helps.
strCmd = "select title, description from books where author_name = ?"
Set objCommand.ActiveConnection = objConn
objCommand.CommandText = strCmd
objCommand.CommandType = adCmdText
Set param1 = objCommand.CreateParameter ("author", adWChar, adParamInput, 50)
param1.value = strAuthor
objCommand.Parameters.Append param1
Set objRS = objCommand.Execute()
See the following page on MSDN, near the bottom, referring specifically to named parameters.
MSDN example
ADO is going to expect question marks instead of actual parameter names in this case. Right now, the SQL "select #something" is not actually parameterized: it sees the "#something" as an (undeclared) SQL variable, not as a parameter. Change your CommandText line to this:
cmd.CommandText = "select ?"
And I think you will get the result you are looking for.
Good luck!
with server.createobject("adodb.command")
.activeConnection = application("connection_string")
.commandText = "update sometable set some_col=? where id=?"
.execute , array(some_value, the_id)
end with
I'm not sure what your query is intended to accomplish. I'm also not sure that parameters are allowed in the select list. MSDN used to have (many years ago, probably) a decent article on where parameters were allowed in a query, but I can't seem to find it now.
OTTOMH, your attempts to supply the parameter values to ADO look correct. Does your query execute if you do something like this?
SELECT 1 FROM sometable WHERE somefield = #something