I tried to solve this all day long but it doesn't seem to work for me. I would like to execute a command and get the result back to a recordset.
The problem is one of two things: either I'm getting an empty response or there is a problem with my code. I know for sure that this command should fetch few lines from the DB. I added response.write inside the loop, but they are never printed.
Here is the code:
Set conn = Server.CreateObject("ADODB.Connection")
conn.open "PROVIDER=SQLOLEDB;DATA SOURCE=X;DATABASE=Y;UID=Z;PWD=W;"
Set objCommandSec = CreateObject("ADODB.Command")
With objCommandSec
Set .ActiveConnection = Conn
.CommandType = 4
.CommandText = "usp_Targets_DataEntry_Display"
.Parameters.Append .CreateParameter("#userinumber ", 200, 1, 10, inumber)
.Parameters.Append .CreateParameter("#group ", 200, 1, 50, "ISM")
.Parameters.Append .CreateParameter("#groupvalue", 200, 1, 50, ismID)
.Parameters.Append .CreateParameter("#targettypeparam ", 200, 1, 50, targetType)
End With
set rs = Server.CreateObject("ADODB.RecordSet")
rs = objCommandSec.Execute
while not rs.eof
response.write (1)
response.write (rs("1_Q1"))
rs.MoveNext
wend
response.write (2)
EDITED
After revising the code, following #Joel Coehoorn answer, the solution is:
set rs = Server.CreateObject("ADODB.RecordSet")
rs.oppen objCommandSec
instead of...
set rs = Server.CreateObject("ADODB.RecordSet")
rs = objCommandSec.Execute
Couple of tips after working with asp-classic for years
There is no need to create a ADODB.Connection you can pass a connection string direct to .ActiveConnection property of the ADODB.Command object. This has two benefits, you don't have instantiate and open another object and because the context is tied to the ADODB.Command it will be released with Set objCommandSec = Nothing.
A common reason for .Execute returning a closed recordset is due to SET NOCOUNT ON not being set in your SQL Stored Procedure, as an INSERT or UPDATE will generate a records affected count and closed recordset. Setting SET NOCOUNT ON will stop these outputs and only your expected recordset will be returned.
Using ADODB.Recordset to cycle through your data is overkill unless you need to move backwards and forwards through and support some of the more lesser used methods that are not needed for standard functions like displaying a recordset to screen. Instead try using an Array.
Const adParamInput = 1
Const adVarChar = 200
Dim conn_string, row, rows, ary_data
conn_string = "PROVIDER=SQLOLEDB;DATA SOURCE=X;DATABASE=Y;UID=Z;PWD=W;"
Set objCommandSec = CreateObject("ADODB.Command")
With objCommandSec
.ActiveConnection = conn_string
.CommandType = 4
.CommandText = "usp_Targets_DataEntry_Display"
.Parameters.Append .CreateParameter("#userinumber", adVarChar, adParamInput, 10, inumber)
.Parameters.Append .CreateParameter("#group", adVarChar, adParamInput, 50, "ISM")
.Parameters.Append .CreateParameter("#groupvalue", adVarChar, adParamInput, 50, ismID)
.Parameters.Append .CreateParameter("#targettypeparam", adVarChar, adParamInput, 50, targetType)
Set rs = .Execute()
If Not rs.EOF Then ary_data = rs.GetRows()
Call rs.Close()
Set rs = Nothing
End With
Set objCommandSec = Nothing
'Command and Recordset no longer needed as ary_data contains our data.
If IsArray(ary_data) Then
' Iterate through array
rows = UBound(ary_data, 2)
For row = 0 to rows
' Return our row data
' Row N column 2 (index starts from 0)
Call Response.Write(ary_data(1, row) & "")
Next
Else
' Nothing returned
Call Response.Write("No data returned")
End If
Looked at this for a few minutes, and it's been a long time since I've worked with classic asp, but I did see three things to look at:
Do you need to Open the connection before calling objCommandSec.Execute?
Can you try writing out a string literal inside the loop, that does not depend at all on the recordset... only that you are in fact looping through the code, so see if records are coming back to the recordset.
Have you checked the html source, to see if perhaps malformed html is hiding your results? I remember this happening a few times with tables in classic asp loops, where data would be hidden somehow between two rows, or a closing table tag in the wrong place would end the table, and later rows would not be visible.
Although this might not answer OPs question directly, it might help someone else looking for a solution.
recently I had a maintenance job that required me to modify something in a running ASP classic code (which I haven't write in ages). Procedure calls were written the same way as OP did and that wasn't how I did it in the past.
Here is the syntax I used in the past and I think it is a little more clean than other solutions provided here.
The following code shows how to read an output parameter, pass parameters to stored procedure, pass null value to parameter, read record count, and iterate in RecordSet.
dim conn, cmd, rs
set conn = Server.CreateObject("ADODB.Connection")
conn.Open "Driver={SQL Server};Server=servername;Uid=username;Pwd=password;Database=dbname;"
set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "procedurename"
cmd.Parameters.Refresh
cmd.Parameters("#nullparam") = null
cmd.Parameters("#strparam") = "1"
cmd.Parameters("#numparam") = 100
set rs = Server.CreateObject ("ADODB.RecordSet")
rs.CursorLocation = adUseClient ' to read recordcount'
rs.open cmd, , adOpenStatic, adLockReadOnly
Response.Write "Return Value: " & cmd.Parameters("#RETURN_VALUE") & "<br />"
Response.Write "Record count: " & rs.RecordCount & "<br />"
while not rs.EOF
' or do whatever you like with data'
Response.Write rs("colname") & "<br>"
rs.MoveNext
wend
Related
OK, I'm missing something obvious here - I have an SP that takes in an integer ID and returns a string. I've used this SP for quite a while with DAO. Now I need to switch to ADO so I can run it under and existing connection (another question I'll post elsewhere).
So my code follows. It returns no errors but it also returns no results. The output parameter is null. What am I missing?
Dim adoCon As ADODB.Connection
Dim adoCMD As ADODB.Command
Dim SQLstr As String
Dim ConStr As String
'--- get connection string from existing object, but strip leading odbc; piece
ConStr = Replace(CurrentDb.TableDefs("[TableName]").Connect, "ODBC;", "")
Set adoCon = New ADODB.Connection
adoCon.ConnectionString = ConStr
adoCon.Open
Set adoCMD = New ADODB.Command
With adoCMD
.ActiveConnection = adoCon
.CommandType = adCmdStoredProc
.Parameters.Append .CreateParameter(, adInteger, adParamReturnValue, , Null) ' return value
.Parameters.Append .CreateParameter("Path", adVarChar, adParamOutput, 500, Null)
.Parameters.Append .CreateParameter("AsyID", adInteger, adParamInput)
.Parameters.Item("AsyID").Value = AsyID
.CommandText = "dbo.spGetAncestry"
.Execute
End With
GetHeritage = adoCMD.Parameters(1).Value 'parm(0) = 0; parm(1) = NULL; parm(2) = AsyID
adoCon.Close
Although your code should work. Please remove the optional expressions in the parameter definition and try the following:
Dim rv as Integer
Set adoCMD = New ADODB.Command
With adoCMD
.ActiveConnection = adoCon
.CommandType = adCmdStoredProc
.Parameters.Append .CreateParameter("RETURN_VALUE", adInteger, adParamReturnValue)
.Parameters.Append .CreateParameter("Path", adVarChar, adParamOutput, 500)
.Parameters.Append .CreateParameter("AsyID", adInteger, adParamInput, , AsyID)
.CommandText = "dbo.spGetAncestry"
.Execute
End With
rv = adoCMD.Parameters("RETURN_VALUE").Value
GetHeritage = adoCMD.Parameters("Path").Value
also make sure your SP is returning the correct data type and size for your output parameter and adjust the code accordingly. If you're returning VARCHAR(MAX), then that is treated as a "BLOB" in ADO, see this related question What are the limits for ADO data types?.
In this case you can try returning varchar(8000) from the SP and updating the code accordingly.
Found it.
Apparently, in the ADO call, it doesn't matter what you set the return value to (I was trying to use "" or even " " before I set it to null) when it executes in SQL batch, it is simply set to NULL as it shows in this trace form. For this run, the Output was initialized as " ", but the batch passed in NULL.
[!SQL trace of the above query being executed with " " in the initialization of the Output variable1]1
Normally, a null wouldn't be a problem as the typical SP assignment would be:
SET #Path = [SELECT value from table]
or, if it was a concatenation, you would initialize the variable:
SET #Path = ''
before stringing together the input.
In this particular case, though, the SP is recursive. It calls itself passing an input and the output values to the new copy. Because of this, you can't initialize the value and you can't use a straight assignment. To get around this, I needed to use:
#path = COALESCE(#path, '') + [SELECT value from table]
to trap any NULL passed in.
I'm trying to UPDATE a table column named "OrigMask" in myfile.sqlite by using an array created in my VBA code. I'm struggling with the syntax. The VBA array is named "NewMask" and has 864 elements as does the table "OrigMask". How do I create the sql statement in VBA and execute. Help is VERY much appreciated !
I'm establishing a statement & connection like so:
Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
conn.Open "DRIVER=SQLite3 ODBC Driver;Database=C:\myfile.sqlite;"
strSQL1 = "UPDATE MyTable SET OrigMask= NewMask;"
rst.Open strSQL1, conn
Set rst = Nothing: Set conn = Nothing
Several issues here:
You need to iterate through you array and not integrate whole object in SQL as NewMask is unrecognized identifier in database.
An update query is an action query and not a resultset to be retrieved in a recordset.
You need a WHERE clause in UPDATE or all records are update not row by row.
Therefore, consider a For Each loop through a parameterized ADO command object:
strSQL1 = "UPDATE MyTable SET OrigMask = ? WHERE id = ?;"
i = 1
For Each var In NewMask
Set cmd = CreateObject("ADODB.Command")
With cmd
.ActiveConnection = conn
.CommandText = strSQL1
.CommandType = adCmdText
.CommandTimeout = 15
.Parameters.Append .CreateParameter("maskparam", adVarChar, adParamInput, 255, var)
.Parameters.Append .CreateParameter("idparam", adInt, adParamInput, , i)
.Execute
End With
i = i + 1
Next var
I am creating one login validation page for my classic asp site(vbscript). as I want prevent my page from SQL Injection, I used parametrized queries in my page but I am unable to retrieve value after writing if Not Recordset.EOF line. value is not passing. please help me to solve this issue. my code is below;
<%
Dim Objrs, objConn, objCmd, str
Set objConn = Server.CreateObject("ADODB.Connection")
Set objCmd = Server.CreateObject("ADODB.Command")
Set Objrs = Server.CreateObject("ADODB.Recordset")
objConn.open MM_connDUdirectory_STRING '(already created)
Set objCmd.ActiveConnection = objConn
str = "SELECT * FROM admin WHERE Ausr=? AND Apwd=?"
objCmd.CommandText = str
objCmd.CommandType = adCmdText
dim objParam1, objParam2
Set objParam1 = objCmd.CreateParameter("param1", adVarChar, adParamInput, len(StrUserName), "")
objCmd.Parameters.Append objParam1
objCmd.Parameters("param1") = StrUserName
Set objParam2 = objCmd.CreateParameter("param2", adVarChar, adParamInput, len(StrPassword), "")
objCmd.Parameters.Append objParam2
objCmd.Parameters("param2") = StrPassword
set objRS = objCmd.execute
'if objRS.EOF <> True and objRS.BOF <> True then
'if Objrs("Ausr") = objCmd.Parameters("param1") then
'response.Write(Objrs("Ausr"))
'response.Write should show username but its showing blank
'end if
'end if
'Do While Not objRS.EOF
'if Objrs("Ausr") = objCmd.Parameters("param1") then
'response.Write(Objrs("Ausr"))
'end if
'objRS.MoveNext
'Loop
If Not objRS.EOF Then
response.write("Granted access to the user:" & StrUserName)
end if
%>
I tried with If..End If as above but its showing same problem, the recordset(objrs) parametrized method is not executing. its show me blank page. code should check if user exist or not. Response.Write("Granted access to the user:" & StrUserName) should show me strusername value but its not showing and page is blank. please help me workout where I'm going wrong?
From i can see with you current code,you have 2 problems:
You have this condition if objRS.EOF <> True and objRS.BOF <> True then with this you are excluding the first and the last record from printing. Don't know why this is needed, but because you are not iterating over all the elements in your recordset (aka Rows). you will never see any record printed.
To overcome the problem #1 you need to enclose all the code in loop (for,while,do while) and use objRS.MoveNext() function in your recordset object to read all the records obtained in your Query.
this is all the problems that i can see with this limited context. I hope this helps.
More Information: Recordset Object Properties, Methods, and Events - MSDN
EDIT: Seeing the edit from OP in the code, and the goal that i think he want to achieve i suggest this code instead:
'Do While Not objRS.EOF'
'if Objrs("Ausr") = objCmd.Parameters("param1") then'
'response.Write(Objrs("Ausr"))'
'end if'
'objRS.MoveNext'
'Loop'
If Not objRS.EOF Then
response.write("Granted access to the user:" & StrUserName)
End if
I'm assuming that you want to check if a single user its logged in.
Debug; Check if you are passing the values to the parameters. Print out the values and see.
Response.write "StrUserName ="& StrUserName &"<br/>"
Response.write "StrPassword ="& StrPassword &"<br/>"
set objRS = objCmd.execute
Also, try passing in the values during creation of the parameter:
Set objParam1 = objCmd.CreateParameter("param1", adVarChar, adParamInput, len(StrUserName), StrUserName)
Actually after looking closer at your code there a few issues
Didn't notice it at first but looks as though your not setting the values correctly, there are two ways to do it;
Specify them during the CreateParameter() method
Call .Parameters.Append(.CreateParameter("param1", adVarChar, adParamInput, 50, StrUserName)
Call .Parameters.Append(.CreateParameter("param2", adVarChar, adParamInput, 50, StrPassword)
Specify after creation of the parameters
Call .Parameters.Append(.CreateParameter("param1", adVarChar, adParamInput, 50)
Call .Parameters.Append(.CreateParameter("param2", adVarChar, adParamInput, 50)
.Parameters("param1").Value = StrUserName
.Parameters("param2").Value = StrPassword
That present your setting the parameter object to a string, which won't give the expected result.
Give this a try;
<%
Dim objRS, objCmd, str
Set objCmd = Server.CreateObject("ADODB.Command")
Set Objrs = Server.CreateObject("ADODB.Recordset")
str = "SELECT * FROM admin WHERE Ausr=? AND Apwd=?"
With objCmd
'No need to create ADODB.Connection as the ADODB.Command will do it
'for you if you pass the Connection string.
.ActiveConnection = MM_connDUdirectory_STRING
.CommandText = str
.CommandType = adCmdText
'Don't pass blank values, just specify the name, data type,
'direction and length.
Call .Parameters.Append(.CreateParameter("param1", adVarChar, adParamInput, 50)
Call .Parameters.Append(.CreateParameter("param2", adVarChar, adParamInput, 50)
'If setting values after the CreateParameter() don't use blank strings in
'the CreateParameter() call.
.Parameters("param1").Value = StrUserName
.Parameters("param2").Value = StrPassword
Set objRS = .Execute()
If Not objRS.EOF Then
Call Response.Write("Granted access to the user:" & StrUserName)
End If
End With
Set objCmd = Nothing
%>
Useful Links
Using Stored Procedure in Classical ASP .. execute and get results - Show how to use ADODB.Command and also return a ADODB.Recordset and convert it to an Array.
I am designing a web page that will fetch records for a specific id and print the information.I am just trying to redirect user to other page if provided id does not exists.I tried the below code but when id is null its showing blank page instead of redirecting to desired page.
code:
<%
Set conn = Server.CreateObject("ADODB.Connection")
conn.ConnectionString= "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=eseva;Data Source=BHAGWAT-PC"
conn.open
set rs=Server.CreateObject("ADODB.recordset")
rs.Open "Select * from saat_bara where id='"&request.form("t1")&"'" , conn
if IsNull(rs.Fields("id").Value) then
response.redirect("end.asp")
else
while not rs.eof
response.Write("Token no:")
response.Write(rs.fields.item(0))
response.write("<br><br>")
response.Write("Name:")
response.Write(rs.fields.item(1))
response.write("<br><br>")
response.Write("Address:")
response.Write(rs.fields.item(2))
response.write("<br><br>")
response.Write("Bdate:")
response.Write(rs.fields.item(3))
response.write("<br><br>")
rs.movenext
wend
end if
%>
You can't check a field that does not exist against null. So:
rs.Open "Select * from saat_bara where id='"&request.form("t1")&"'" , conn
if rs.eof
response.redirect("end.asp")
else
while not rs.eof
...
end if
Update:
Listed somethings you may want to consider for the future;
Look into using the ADODB.Command object to build parameterised queries.
Protects against SQL Injection
Data type negotiation is done for you (no adding apostrophes in your query when dealing with string types).
No need to manual setup ADODB.Connection and close it as .ActiveConnection can take a connection string and build your ADODB.Connection for you and when your ADODB.Command is released so is the associated connection.
Return only the field you need in your SQL query instead of using SELECT * depending on the table size this can be very costly (in your code your only returning four fields).
If you are just displaying data to screen consider using .GetRows() to return an Array rather than using ADODB.Recordset for iterating through your returned resultset. Resources that would be otherwise used by the ADODB.Recordset can be released as all your data is contained in a 2 dimensional array.
Below is an example of your code using ADODB.Command and Arrays;
<%
Dim connstr, sql, cmd, rs, data
Dim row, rows
connstr = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=eseva;Data Source=BHAGWAT-PC"
sql = ""
sql = sql & "SELECT Field0, Field1, Field2, Field3 " & vbCrLf
sql = sql & "FROM saat_bara " & vbCrLf
sql = sql & "WHERE id = ?"
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
.ActiveConnection = connstr
.CommandType = adCmdText
.CommandText = sql
'As you put apostrophes around your id assumed it must be a varchar. If
'this is used as your primary key would be more efficient for it to be
'a numeric type like int, in which case you would use adInteger.
.Parameters.Append(.CreateParameter("#id", adVarChar, adParamInput, 50)
Set rs = .Execute(, Array(Request.Form("t1")))
If Not rs.EOF Then data = rs.GetRows()
'Release memory used by recordset
Call rs.Close()
Set rs = Nothing
End With
'Release memory and close connection used by command.
Set cmd = Nothing
If IsArray(data) Then
rows = UBound(data, 2)
For row = 0 To rows
'Consider not using Response.Write in your loop (taken from Bond's suggestion)
Call Response.Write("Token no:")
Call Response.Write(data(0, row))
Call Response.Write("<br><br>")
Call Response.Write("Name:")
Call Response.Write(data(1, row))
Call Response.Write("<br><br>")
Call Response.Write("Address:")
Call Response.Write(data(2, row))
Call Response.Write("<br><br>")
Call Response.Write("Bdate:")
Call Response.Write(data(3, row))
Call Response.Write("<br><br>")
Next
Else
'No data redirect
Call Response.Redirect("end.asp")
End If
%>
I'm trying to use a prepared statement to call a stored procedure (using ADODB with classic ASP), but when I set CommandType I get the following error:
ADODB.Command error '800a0bb9'
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
I have the following code:
With Server.CreateObject("ADODB.Command")
.ActiveConnection = db 'this is initialized prior
.CommandType = adCmdStoredProc
.CommandText = "procName"
End With
The prepared statement name is correct (I'm able to call it just by executing the string), and if I leave out the .CommandType and try calling .Execute, I get an error specifying:
Procedure or function 'procName' expects parameter '#ParamName', which was not supplied.
Even if I leave out the CommandType, I have no idea how to actually add the parameter (something along the following lines just results in the original error about arguments of the wrong type):
.Parameters.Append .CreateParameter("#ParamName",adVarChar,adParamInput,50,param)
I've also tried the following and got an error "Item cannot be found in the collection corresponding to the requested name or ordinal."
.Parameters.Refresh
.Parameters(0) = param
I've looked at several examples of how to call stored procedures using prepared statements, and it looks like I'm using the right syntax, but anything I try seems to result in some kind of error. Any help would be greatly appreciated.
You want something like this (untested)
Dim cmd, rs, ars, conn
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
'Assuming passing connection string if passing ADODB.Connection object
'make sure you use Set .ActiveConnection = conn also conn.Open should
'have been already called.
.ActiveConnection = conn
'adCmdStoredProc is Constant value for 4 (include adovbs or
'set typelib in global.asa)
.CommandType = adCmdStoredProc
.CommandText = "dbo.procName"
'Define parameters in ordinal order to avoid errors
Call .Parameters.Append(.CreateParameter("#ParamName", adVarChar, adParamInput, 50))
'Set values using parameter friendly name
.Parameters("#ParamName").Value = param
'Are you returning a recordset?
Set rs = .Execute()
'Populate array with data from recordset
If Not rs.EOF Then ars = rs.GetRows()
Call rs.Close()
Set rs = Nothing
End With
Set cmd = Nothing
It is important to remember that the friendly name (as I rule I tend to match my parameter names in my stored procedure to my friendly names in ADO) you give your parameter means nothing to the stored procedure as ADO passes the parameters ordinally and nothing more, the fact you get the error;
Procedure or function 'procName' expects parameter '#ParamName', which was not supplied.
Suggests that the stored procedure is expecting your #ParamName parameter (defined in your stored procedure) value to be passed from ADO in a different ordinal position, which usually means you have not defined all your parameters or passed all the parameter values in the position they are expected.
You can also do a shortened version if your confident of your ordinal positioning and parameter requirements
With cmd
.ActiveConnection = conn
.CommandType = adCmdStoredProc
.CommandText = "dbo.procName"
'Pass parameters as array following ordinal position.
Set rs = .Execute(, Array(param))
'Populate array with data from recordset
If Not rs.EOF Then ars = rs.GetRows()
Call rs.Close()
Set rs = Nothing
End With
Set cmd = Nothing
Working with a 2-dimensional array is easy and negates the overhead of working directly with a ADODB.Recordset.
Dim row, rows
If IsArray(ars) Then
rows = UBound(ars, 2)
For row = 0 To rows
Response.Write "First column from row " & row & " = " & ars(0, row) & "<br />"
Next
Else
Response.Write "No data to return"
End If
Links
Using METADATA to Import DLL Constants - If your having trouble with the ADO constants (adCmdStoredProc etc.) this will fix it for you.
Here is how you call a stored procedure in ASP classic:
'Set the connection
'...............
'Set the command
DIM cmd
SET cmd = Server.CreateObject("ADODB.Command")
SET cmd.ActiveConnection = Connection
'Set the record set
DIM RS
SET RS = Server.CreateObject("ADODB.recordset")
'Prepare the stored procedure
cmd.CommandText = "procName"
cmd.CommandType = 4 'adCmdStoredProc
'Assign value to the parameter
cmd.Parameters("#ParamName ") = ParamValue
'Execute the stored procedure
RS = cmd.Execute
SET cmd = Nothing
'You can now access the record set
if (not RS.EOF) THEN
data = RS("column_name")
end if
'dispose your objects
RS.Close
SET RS = Nothing
Connection.Close
SET Connection = Nothing