How can I use an ADODB.CommandObject with ADODB.RecordSet? - asp-classic

I am trying to make a Classic ASP/VBScript website more secure by making SQL statements parameterized.
I have the following function:
Function OpenUpdateableRS(strSQL)
Dim rs
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open strSQL, cnDZ, adOpenKeyset, adLockPessimistic, adCmdText
Set OpenUpdateableRS = rs
Set rs = Nothing
End Function
I intend to convert it to something like:
Function SecureOpenUpdateableRS(strSQL, strParam1, strParam2)
Dim rs
Dim cmdOB
Set cmdOB = Server.CreateObject("ADODB.CommandObject")
With cmdOB
.ActiveConnection = cnDZ
.CommandText = strSQL
.Parameters(0).value = strParam1
.Parameters(0).value = strParam2
End With
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open cmdOB.Execute, , adOpenKeyset, adLockPessimistic
Set SecureOpenUpdateableRS = rs
Set rs = Nothing
End Function
When I call the function with:
Set rs = SecureOpenUpdateableRS("SELECT CustID, LastActive, LoggedIn, SessionID FROM tblLogins WHERE EMail = ? AND PWord = ?", strEMail, strPassword)
I get a "500 - Internal Server Error" which is probably because I disabled debugging on the server.
Any ideas on how I could make the original function more secure without breaking it?

You'll have to create the parameters and append them to the command's parameter collection. Just assigning the values to (the same!) parameter can't possibly work. Google for a sample; perhaps this VB! sample will get you started.
Added:
I can think of two strategies to derive the parameter types:
If you pass the correct/maximally specified parameter values to the function you can map VarType(value) constants to parameter type constants
If you do a SELECT based on the fieldnames in the command text, you can map the recordset's field .Types to parameter type constants
It won't be trivial to get this right for all possible cases. I would pass pairs of value and desired type to the function.

Related

How to get the total number of records count from a sql ado dB connection in classic asp [duplicate]

I am newbie in VBScript and I've come across with the following problem. I want get data from sql server db and to allow RecordCount properties. Next code get data but RecordCount is disabled. How can I enable this properties
Const DB_CONNECT_STRING = "Provider=SQLOLEDB.1;Data Source=BUG\SQLSERVER2005;Initial Catalog=test;user id ='sa';password='111111'"
Set myConn = CreateObject("ADODB.Connection")
Set myCommand = CreateObject("ADODB.Command" )
myConn.Open DB_CONNECT_STRING
Set myCommand.ActiveConnection = myConn
myCommand.CommandText = ("select * from klienci k where k.indeks = " & oferty(16))
Set klienci = myCommand.Execute
AFAIK you can't change the cursor type when using the Execute method of the Command object, and you can't change the cursor type after you retrieved the recordset. Something like this might work, though:
Const DB_CONNECT_STRING = "Provider=SQLOLEDB.1;Data Source=BUG\SQLSERVER2005;Initial Catalog=test;user id ='sa';password='111111'"
Set myConn = CreateObject("ADODB.Connection")
myConn.Open DB_CONNECT_STRING
query = "select * from klienci k where k.indeks = " & oferty(16)
Set klienci = CreateObject("ADODB.Recordset")
klienci.CursorLocation = 3 'adUseClient
klienci.CursorType = 3 'adOpenStatic
klienci.LockType = 1 'adLockReadOnly
klienci.Open query, myConn
I don't think this is a VBScript issue- I think it is an ADO issue.
I think you are using a default forward-only cursor which won't work with recordcount.
I think you should stick a cursortype=adOpenStatic in there but I'm having a little trouble determining if you are specifying a recordset object - klienci?
If so try
klienci.cursortype=adOpenStatic

ms_access Run time error 3078 in VBA although query runs as saved query [duplicate]

I have a query called qryAlloc_Source that has two paramaters under one criteria:
>=[forms]![frmReportingMain]![txtAllocStart] And <=[forms]![frmReportingMain]![txtAllocEnd])
A have a separate query that ultimately references qryAlloc_Source (there are a couple queries in between), and that query runs fine when I double click it in the UI, but if I try to open it in VBA, I get an error. My code is:
Dim rst As Recordset
Set rst = CurrentDb.OpenRecordset("qryAlloc_Debits")
I am getting run-time error 3061, Too few parameters. Expected 2. I've read that I may need to build out the SQL in VBA using the form parameters, but it would be pretty complex SQL given that there are a few queries in the chain.
Any suggestions as to a workaround? I considered using VBA to create a table from the query and then just referencing that table--I hate to make extra steps though.
The reason you get the error when you just try to open the recordset is that your form is not open and when you try to access [forms]![frmReportingMain] it's null then you try to get a property on that null reference and things blow up. The OpenRecordset function has no way of poping up a dialog box to prompt for user inputs like the UI does if it gets this error.
You can change your query to use parameters that are not bound to a form
yourTableAllocStart >= pAllocStart
and yourTableAllocEnd <= pAllocEnd
Then you can use this function to get the recordset of that query.
Function GetQryAllocDebits(pAllocStart As String, pAllocEnd As String) As DAO.Recordset
Dim db As DAO.Database
Dim qdef As DAO.QueryDef
Set db = CurrentDb
Set qdef = db.QueryDefs("qryAlloc_Debits")
qdef.Parameters.Refresh
qdef.Parameters("pAllocStart").Value = pAllocStart
qdef.Parameters("pAllocEnd").Value = pAllocEnd
Set GetQryAllocDebits = qdef.OpenRecordset
End Function
The disadvantage to this is that when you call this now on a form that is bound to it it doesn't dynamically 'fill in the blanks' for you.
In that case you can bind forms qryAlloc_debts and have no where clause on the saved query, then use the forms Filter to make your where clause. In that instance you can use your where clause exactly how you have it written.
Then if you want to still open a recordset you can do it like this
Function GetQryAllocDebits(pAllocStart As String, pAllocEnd As String) As DAO.Recordset
Dim qdef As DAO.QueryDef
Set qdef = New DAO.QueryDef
qdef.SQL = "Select * from qryAlloc_Debits where AllocStart >= pAllocStart and pAllocEnd <= pAllocEnd"
qdef.Parameters.Refresh
qdef.Parameters("pAllocStart").Value = pAllocStart
qdef.Parameters("pAllocEnd").Value = pAllocEnd
Set GetQryAllocDebits = qdef.OpenRecordset
End Function
While a [Forms]!... reference does default to a form reference when a QueryDef is run from the GUI, it is actually just another Parameter in the query in VBA. The upshot is you don't have to recode your query/create a new one at all. Also, as #Brad mentioned, whether a parameter is in the final query of a chain of queries or not, you are able to refer to the parameter as if it is in the collection of the final query. That being the case, you should be able to use code similar to this:
Sub GetQryAllocDebits(dteAllocStart As Date, dteAllocEnd as Date)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset
Set db = CurrentDb()
Set qdf = db.QueryDefs("qryAlloc_Debit")
If CurrentProject.AllForms("frmReportingMain").IsLoaded Then
qdf.Parameters("[forms]![frmReportingMain]![txtAllocStart]") = [forms]![frmReportingMain]![txtAllocStart]
qdf.Parameters("[forms]![frmReportingMain]![txtAllocEnd]") = [forms]![frmReportingMain]![txtAllocEnd]
Else
qdf.Parameters("[forms]![frmReportingMain]![txtAllocStart]") = CStr(dteAllocStart)
qdf.Parameters("[forms]![frmReportingMain]![txtAllocEnd]") = CStr(dteAllocEnd)
End If
Set rst = qdf.OpenRecordset
Do Until rst.EOF
'...do stuff here.
Loop
Set rst = Nothing
Set qdf = Nothing
Set db = Nothing
End Function
If the referenced form is open, the code is smart enough to use the referenced controls on the form. If not, it will use the dates supplied to the subroutine as parameters. A gotcha here is that the parameters did not like when I set them as date types (#xx/xx/xx#), even if the field were dates. It only seemed to work properly if I set the params as strings. It didn't seem to be an issue when pulling the values straight out of the controls on the forms, though.
I know it's been a while since this was posted, but I'd like to throw in my tuppence worth as I'm always searching this problem:
A stored query can be resolved:
Set db = CurrentDb
Set qdf = db.QueryDefs(sQueryName)
For Each prm In qdf.Parameters
prm.Value = Eval(prm.Name)
Next prm
Set rst = qdf.OpenRecordset
For SQL:
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", "SELECT * FROM MyTable " & _
"WHERE ID = " & Me.lstID & _
" AND dWeekCommencing = " & CDbl(Me.frm_SomeForm.Controls("txtWkCommencing")) & _
" AND DB_Status = 'Used'")
For Each prm In qdf.Parameters
prm.Value = Eval(prm.Name)
Next prm
Set rst = qdf.OpenRecordset
This assumes that all parameter values are accessible - i.e. forms are open and controls have values.
'I have two parameters in my recordset and I was getting the "Too few parameters. Expected 2" 'error when using an OpenRecordset in MS Access vba, and this is how I got around it and IT WORKS! see the below sub routine:
'Private Sub DisplayID_Click()
'1. I created variables for my two parameter fields xEventID and xExID as seen below:
Dim db As Database
Dim rst As Recordset
Dim xEventID As Integer
Dim xExId As Integer
'2. Sets the variables to the parameter fields as seen below:
Set db = CurrentDb
xEventID = Forms!frmExhibitorEntry!txtEventID
xExId = Forms!frmExhibitorEntry!subExhibitors!ExID
'3. Set the rst to OpenRecordSet and assign the Set the variables to the WHERE clause. Be sure to include all quotations, ampersand, and spaces exactly the way it is displayed. Otherwise the code will break!exactly as it is seen below:
Set rst = db.OpenRecordset("SELECT tblInfo_Exhibitor.EventID,tblInfo_Display.ExID, tblMstr_DisplayItems.Display " _
& "FROM tblInfo_Exhibitor INNER JOIN (tblMstr_DisplayItems INNER JOIN tblInfo_Display ON tblMstr_DisplayItems.DisplayID = tblInfo_Display.DisplayID) ON tblInfo_Exhibitor.ExID = tblInfo_Display.ExID " _
& "WHERE (((tblInfo_Exhibitor.EventID) =" & xEventID & " ) and ((tblInfo_Exhibitor.ExID) =" & xExId & " ));")
rst.Close
Set rst = Nothing
db.Close
'End Sub

Insert long string into Access DB using parametrised query in classic ASP

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

How to run a stored procedure with param and store result as a record set in classic asp

I wasn't able to find a question/answer that covers this fully hence why I am asking. What I need to do is run a stored procedure that takes 1 parameter. It will return a set of results which I need to store in a record set. I plan to loop through this recordset later. I'm pretty inexperienced when it comes to older asp, but here is what I have to far:
dim myConn
Set myConn = Server.CreateObject("ADODB.Connection")
myConn.Open = ("DSN=example-dsn;SERVER=example-server;DATABASE=example-db;UID=user;PWD=pass;")
dim oStoredProc : Set oStoredProc = Server.CreateObject("ADODB.Command")
With oStoredProc
.ActiveConnection = myConn
.CommandType = adCmdStoredProc
.CommandText = "myStoredProcedure"
.Parameters.Append(.CreateParameter("#PARAM1", ADODB.adInteger, ADODB.adParamInput, 10, 2012))
Dim rs : Set rs = .Execute()
End With
// Will loop through it here.
My guess is that I'm not setting up the recordset right, but like I said, I'm not really sure. If anyone can point me in the right direction I'd appreciate it!
You will want to make sure your result set is the correct object
set rs = Server.CreateObject("ADODB.Recordset")
Then you will use the open method I think it works something like this:
rs.Open oStoredProc
Then use the other members of the Record Set object to loop through the results.
Alright there were a few things I was doing wrong but here is what ended up working for me. First off it turns out I didn't need a parameter passed in, but that was not the problem anyway. One of the main issues what that 'adCmdStoredProc' wasn't recognized, which is odd because I've seen it used everywhere else, but replacing it with it's corresponding value, 4, did work.
dim myConn, cmd
Set myConn = Server.CreateObject("ADODB.Connection")
myConn.Open = ("DSN=[BLAH];SERVER=[SERVER];DATABASE=[BLAH];UID=[User];PWD=[Pass];")
dim oStoredProc : Set oStoredProc = Server.CreateObject("ADODB.Command")
oStoredProc.CommandType = 4
oStoredProc.CommandText = "StoredProcedureName"
oStoredProc.ActiveConnection = myConn
// Add parameters here if needed.
Dim rs
Set rs = oStoredProc.Execute()
// I Loop through here
rs.Close
myConn.Close
Set rs = Nothing
Set oStoredProc = Nothing
Set myConn = Nothing
I hope this helps if anyone else needs it.
Dim rsStk As New ADODB.Recordset
Set rsStk = cnnPck.Execute("SP_JOB_ALL '" & Trim(te_Item) & "'")
Set Recordset= CONNECTION .Execute()
This one is simple way to do this thing

ASP Classic Named Parameter in Paramaterized Query: Must declare the scalar variable

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

Resources