asp ADO connection Microsoft VBScript runtime error '800a01a8' - oop

dear all pro programmer here, im totally new in here, and i might dont know how to correctly as a question here..
if i may ask for help, could u pls here here here...
im having problem with simple asp with oop structure...
help me with function savedata pls. when run,
call savedata("insert","test_","name, id","lalala, 222","User_ID=3")
got error :
INSERT INTO test_ (name, id) VALUES (lalala, 222)
... Microsoft VBScript runtime error '800a01a8'
Object required: 'Conn'
<%
function declare_conn(sql,atr)
dim conn, conn_
set conn = Server.CreateObject("ADODB.Connection")
conn = Connect()
set conn_ = Server.CreateObject("ADODB.Recordset")
strConnect = _T("Driver={MySQL ODBC 3.51 Driver};Server=localhost;"
"Database=MyDatabase;User=MyUserName;Password=MyPassword;Option=4;");
if Cstr(atr)="open" then
conn_.CursorLocation = adUseClient
conn_.Open sql, conn, 3, 2
set conn_.ActiveConnection = nothing
set declare_conn=conn_
else if Cstr(atr)="exec" then
conn.Open
conn.Execute sql
end if
end if
end function
function calldata(a,b,c,d)
dim conn_string, sql_string
if c<>"" and d<>"" then
sql_string="SELECT "&Cstr(a)&" FROM "&Cstr(b)&" WHERE "&Cstr(c)&" = '"&Cstr(d)&"'"
response.write(sql_string)
else
sql_string="SELECT "&Cstr(a)&" FROM "&Cstr(b)
response.write(sql_string)
end if
set conn_string = Server.CreateObject("ADODB.Recordset")
set conn_string = declare_conn(sql_string,"open")
set calldata = conn_string
end function
function savedata(a,b,c,d,e)
dim conn_string, sql_string, c_, d_, update_string
update_string = ""
if Cstr(a)="insert" then
sql_string="INSERT INTO "&Cstr(b)&" ("&Cstr(c)&") VALUES ("&Cstr(d)&")"
end if
response.write(sql_string)
'response.end
if Cstr(a)="update" then
c_ = split(c,", ",-1)
d_ = split(d,", ",-1)
response.write(c_)
response.end
if ubound(c_) = ubound(d_) then
do while not c_.eof
update_string=update_string&"("&Cstr(c_)&"="&Cstr(d_)&"),"
c_.MoveNext : d_.MoveNext
loop
else
%><script type="text/javascript">alert("save function error: array out of bound");</script> <%
end if
if Cstr(e)<>"" then
sql_string="UPDATE "&Cstr(b)&" SET "&update_string&" WHERE "&Cstr(e)
else
sql_string="UPDATE "&Cstr(b)&" SET "&update_string
end if
end if
'set conn_string = Server.CreateObject("ADODB.Recordset")
call declare_conn(sql_string,"exec")
end function
%>
wht is tht error actually mean? i create a connection to database ADO in
connect()
still, i can run without problem for
calldata()
editing-dwerty_weird
SOrry for the ruckus..
for this question, i find out, tht i missing "Set" for:
set conn=Connect()
sorry for the trouble... but for other question, i having problem with
call savedata("update","test_","name, id","'lalala', 222","bil=1")
it will get error :
Microsoft VBScript runtime error '800a01a8'
Object required
/bkpi-msn/SPPro/function.asp, line 56 –
can anyone help me?

You're missing single quotes in your data. Value for name is a string and should be wrapped in single quotes.
You have already implemented this in calldata() that is why it is working fine. Update the same for savedata too.
Note: This applies for all the string parameters and may apply in some
other way (using #) for date / datetime parameters too.
Please use this as a starting point and follow best-practices for development!
Hope this helps!
Vivek

Related

Why are my database Commands always calling sp_describe_first_result_set?

Background
I'm maintaining a VB.Net (formerly VB6) utility that exports records to a flat file. One of our customers reported that the new version was taking a long time to run, and digging into the trace it was easy to see why: (I've obfuscated this slightly)
exec [sys].sp_describe_first_result_set
N'Update [MAIN].[dbo].[Inventory] Set ExportId = #P1 Where Comp = #P2 and Osite = #P3 and Key = #P4',
N'#P1 numeric(10),#P2 varchar(6),#P3 varchar(6),#P4 int',1
This and statements like it were taking half a second each. The utility has to update the main inventory table with some information about the export, and the table is heavily triggered, so sp_describe_first_result_set has to simulate all the triggers in order to determine the result - I can verify that later down in the trace.
Problem
I can't figure out why exactly my code is calling sp_describe_first_result_set for an update statement, a thing that doesn't even have a result set. The command setup doesn't look like it's doing anything weird:
Dim connection = New ADODB.Connection
connection.ConnectionString = config.AdoConnectionString
connection.CursorLocation = CursorLocationEnum.adUseClient
connection.Open()
cmd = New ADODB.Command
With cmd
.ActiveConnection = connection
.CommandType = CommandTypeEnum.adCmdText
.CommandText = "Update [MAIN].[dbo].[Inventory] " &
"Set ExportId = ? " &
"Where Comp = ? and Osite = ? and Key = ?"
.Parameters.Append(NumericParameter(cmd.CreateParameter("ExportId", DataTypeEnum.adNumeric, ParameterDirectionEnum.adParamInput), 10, 0))
.Parameters.Append(cmd.CreateParameter("Comp", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 6))
.Parameters.Append(cmd.CreateParameter("Osite", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 6))
.Parameters.Append(cmd.CreateParameter("Key", DataTypeEnum.adInteger, ParameterDirectionEnum.adParamInput))
End With
cmd.Parameters("ExportID").Value = lExportId
cmd.Parameters("Comp").Value = sComp
cmd.Parameters("Osite").Value = sOsite
cmd.Parameters("Key").Value = iKey
cmd.Execute()
Is there some setting I'm just missing that's making it run sp_describe_first_result_set all the time? Is there a way to stop it from doing that?
You need to explicitly say you don't want a recordset.
In VB6, an ADODB Command object can tell whether or not it should return a recordset based on whether the value of the Execute() function is being assigned to anything.
In VB.NET, this is no longer done, but execution options flags can be provided as arguments to the Execute() function. Calling the command like this:
cmd.Parameters("ExportID").Value = lExportId
cmd.Parameters("Comp").Value = sComp
cmd.Parameters("Osite").Value = sOsite
cmd.Parameters("Key").Value = iKey
cmd.Execute(Options:=ExecuteOptionEnum.adExecuteNoRecords)
will not call sp_describe_first_result_set to establish the parameters of the record set, but will only execute the command directly, the same way more modern methods such as SqlCommand.ExecuteNonQuery() will.
Out of curiosity, does the modern equivalent to that code also trace as performing this op?
Dim cmd as New SqlCommand( _
"Update [MAIN].[dbo].[Inventory] Set ExportId = #e Where Comp = #c and Osite = #o and Key = #k",
"Data Source=YOUR_SERVER;Initial Catalog=YOUR_DB;User ID=YOUR_USER_EG_sa;Password=YOUR_PASSWORD" _
)
cmd.Connection.Open()
cmd.Parameters.AddWithValue("#e", lExportId)
cmd.Parameters.AddWithValue("#c", sComp)
cmd.Parameters.AddWithValue("#o", sOsite)
cmd.Parameters.AddWithValue("#k", iKey)
cmd.ExecuteNonQuery()
I use AddWithValue for testing/convenience purposes here, but you should probably avoid it in prod because it can cause performance issues with SQLS - see that link for advice on how to craft parameters properly

How can i resolve ExecucuteNonQuery throwing exception Incorrect syntex near '?'

Dim StrSql = "update student set id=?"
Updated (StrSql,15)
Public Function Updated (ByVal strSql As String, ByVal ParamArray Parameters As String ())
For Each x In Parameters
cmd.Parameters.AddWithValue("?",x)
Next
cmd.ExecuteNonQuery()
End Function
You didn't leave us much to go on; as jmcilhinney points out, you need to add more detail to future questions. For example in this one you have code there that doesn't compile at all, doesnt mention the types of any variable, you don't give the name of the database...
...I'm fairly sure that "Incorrect syntax near" is a SQL Server thing, in which case you need to remember that it (re)uses named parameters, unlike e.g. Access which uses positional ones:
SQL Server:
strSql = "SELECT * FROM person WHERE firstname = #name OR lastname = #name"
...Parameters.AddWithValue("#name", "Lee")
Access:
strSql = "SELECT * FROM person WHERE firstname = ? OR lastname = ?"
...Parameters.AddWithValue("anythingdoesntmatterwillbeignored", "Lee")
...Parameters.AddWithValue("anythingdoesntmatterwillbeignoredalso", "Lee")
This does mean your function will need to get a bit more intelligent; perhaps pass a ParamArray of KeyValuePair(Of String, Object)
Or perhaps you should stop doing this way right now, and switch to using Dapper. Dapper takes your query, applies your parameters and returns you objects if you ask for them:
Using connection as New SqlConnection(...)
Dim p as List(Of Person) = Await connection.QueryAsync(Of Person)( _
"SELECT * FROM person WHERE name = #name", _
New With { .name = "John" } _
)
' use your list of Person objects
End Using
Yep, all that adding parameters BS, and executing the reader, and converting the results to a Person.. Dapper does it all. Nonquery are done like connection.ExecuteAsync("UPDATE person SET name=#n, age=#a WHERE id=#id", New With{ .n="john", .a=27, .id=123 })
http://dapper-tutorial.net
Please turn on Option Strict. This is a 2 part process. First for the current project - In Solution Explorer double click My Project. Choose Compile on the left. In the Option Strict drop-down select ON. Second for future projects - Go to the Tools Menu -> Options -> Projects and Solutions -> VB Defaults. In the Option Strict drop-down select ON. This will save you from bugs at runtime.
Updated(StrSql, 15)
Your Updated Function calls for a String array. 15 is not a string array.
Functions need a datatype for the return.
cmd.Parameters.AddWithValue("?", X)
cmd is not declared.
You can't possible get the error you mention with the above code. It will not even compile, let alone run and produce an error.
It is not very helpful to write a Function that is trying to be generic but is actually very limited.
Let us start with your Update statement.
Dim StrSql = "update student set id=?"
The statement you provided will update every id in the student table to 15. Is that what you intended to do? ID fields are rarely changed. They are meant to uniquely identify a record. Often, they are auto-number fields. An Update command would use an ID field to identify which record to update.
Don't use .AddWithValue. See http://www.dbdelta.com/addwithvalue-is-evil/
and
https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
and another one:
https://dba.stackexchange.com/questions/195937/addwithvalue-performance-and-plan-cache-implications
Here is another
https://andrevdm.blogspot.com/2010/12/parameterised-queriesdont-use.html
Since you didn't tell us what database you are using I guessed it was Access because of the question mark. If it is another database change the connection, command and dbType types.
Using...End Using block ensures you connection and command are closed and disposed even if there is an error.
Private ConStr As String = "Your Connection String"
Public Function Updated(StudentNickname As String, StudentID As Integer) As Integer
Dim RetVal As Integer
Using cn As New OleDbConnection(ConStr),
cmd As New OleDbCommand("Update student set NickName = #NickName Where StudentID = #ID", cn)
cmd.Parameters.Add("#NickName", OleDbType.VarChar, 100).Value = StudentNickname
cmd.Parameters.Add("#ID", OleDbType.Integer).Value = StudentID
cn.Open()
RetVal = cmd.ExecuteNonQuery
End Using
Return RetVal
End Function
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim RowsUpdated = Updated("Jim", 15)
Dim message As String
If RowsUpdated = 1 Then
message = "Success"
Else
message = "Failure"
End If
MessageBox.Show(message)
End Sub
This code keeps your database code separated from user interface code.

Check DB settings --> Variable '<variablename>' is used before it has been assigned a value

I'm writing a simple function that returns me true if my sqlDB connection is ok. I read my DB settings from an XML file and i'm sure this part works because my values (server, database, user, password) get a value assigned after my xml read. When i want to use these variables in my connectionstring is says i'm using them without any value?
Public Function TestDBconnection() As Boolean
'Read settings from XMLfile'
Dim server, database, user, password As String
Try
If System.IO.File.Exists(defaultdirectory & "\Settings.xml") = True Then
Using XmlSettingsReader As XmlReader = New XmlTextReader(defaultdirectory & "\Settings.xml")
While (XmlSettingsReader.Read())
Dim type = XmlSettingsReader.NodeType
If (type = XmlNodeType.Element) Then
If (XmlSettingsReader.Name = "Server") Then
server = XmlSettingsReader.ReadInnerXml.ToString
End If
If (XmlSettingsReader.Name = "Database") Then
database = XmlSettingsReader.ReadInnerXml.ToString
End If
If (XmlSettingsReader.Name = "User") Then
user = XmlSettingsReader.ReadInnerXml.ToString
End If
If (XmlSettingsReader.Name = "Password") Then
password = XmlSettingsReader.ReadInnerXml.ToString
End If
End If
End While
XmlSettingsReader.Close()
End Using
End If
Using sqlcon As SqlConnection = New SqlConnection("server=#server ;uid=#user ;password=#password ;database=#database")
sqlcmd.Parameters.AddWithValue("#server", server)
sqlcmd.Parameters.AddWithValue("#user", user)
sqlcmd.Parameters.AddWithValue("#database", database)
sqlcmd.Parameters.AddWithValue("#password", password)
sqlcon.Open()
Return (sqlcon.State = ConnectionState.Open)
sqlcon.Close()
End Using
Catch result1 As SqlException
Return False
Catch result2 As Exception
Return False
End Try
End Function
Did you try to set a stop mark and walk through step by step? What is the programm reading into the XmlReader? What happens at all the If?
I'm sure the lines where you set a value to your variables aren't touched at all. Therefore your variables remain not initialized.
Try to set default values to them and you will not get the error you've got before... But you'll have to find out, which variables are not set.
Might be, that there is no file at all...

SQL.REQUEST Excel function Alternative? Create one with VBA?

I am looking to execute SQL SELECT statement inside a single cell in Excel, using other cells as inputs to the SELECT statement. After some searching, I found that the sql.request function would have done exactly what I'm looking for. However, that function was deprecated in after 2002, and I'm running Excel 2007 and 2010 here at work. Citation
I have tried to create a Macro / VBA script that does the same thing, but haven't been able to get very far with it. I do all my programming in LabVIEW, Mathematica, and SQL; I have no idea what's going on in VBA. This is what I've managed to come up with:
Sub Test2()
' Declare the QueryTable object. I'm not actually sure why this line is here...
Dim qt As QueryTable
' Set up the SQL Statement
sqlstring = "SELECT `Substrate ID` FROM temp_table WHERE `id`=" & Range("A1").Value
' Set up the connection string, reference an ODBC connection
connstring = "ODBC;DSN=OWT_x64;"
' Now implement the connection, run the query, and add
' the results to the spreadsheet
With ActiveSheet.QueryTables.Add(Connection:=connstring, Destination:=Range("A22"), Sql:=sqlstring)
.Refresh BackgroundQuery:=False
End With
End Sub
There are three primary issues with the above code:
This code returns the column ID ("Substrate ID") in cell A22, and the result of the SQL query in cell A23. I only want the result, and I only want it in cell A22. All queries are forced to return only 1 row and 1 column.
I don't know how to make it so that the output cell, A22, is whatever cell is active when the script is run. Also, the input cell, A1, should be the cell directly to the left (column-1) of the active cell.
I don't know how to turn this into an Excel function
=sql.request(connection_string,[output_ref],[driver_prompt],[query_text],[col_names_logical])
which is my final goal. This way, I can give this code to others at my company and they can easily use it.
The connection is a ODBC connection to a MySQL 5.6 database. The query is pretty simple, and along the lines of:
SELECT column FROM table WHERE id=excel_cell_value
as you can see from the VBA code that I have.
Currently, I run a query in a different Excel worksheet that returns all rows of the "id" and "Substrate ID" columns and then run VLOOKUP to find the item of interest. This is starting to become an issue, as our database size is growing quite fast.
So, I ask:
How can I get rid of the column ID in the result?
How can I turn this into a custom excel function? I've looked at Office.com and it doesn't seem too difficult, but I need a working script first.
-OR- Has anyone already made a custom function that they're willing to share?
Thanks!
EDIT: Managed to get something working thanks to Tim's link.
Function SQLQuery(sqlString As String, connString As String, Optional TimeOut As Integer) As String
SQLQuery = Error 'Assume an error happened
Dim conn As ADODB.Connection
Dim record As ADODB.Recordset
Set conn = New ADODB.Connection
conn.ConnectionString = connString
conn.Open
Set record = New ADODB.Recordset
If TimeOut > 0 Then
conn.CommandTimeout = TimeOut
End If
record.Open sqlString, conn
Dim cols As Long
Dim i As Long
cols = record.Fields.Count 'Count how many columns were returned
If Not record.EOF Then 'Put results into comma-delimited string
record.MoveFirst
s = ""
If Not record.EOF Then
For i = 0 To cols - 1
s = s & IIf(i > 0, ",", "") & record(i)
Next i
End If
End If
SQLQuery = s
End Function
However, it's quite slow. Any ideas on how to speed it up?
Here's a quick test of caching the connection. On a test worksheet with 100 lookups it reduced calculation time from about 18 sec to about 0.5 sec
Remember though it will keep a connection open until you close Excel (or the VB environment gets reset).
If you want to test the difference in your environment, you can comment out the marked line (don't forget to also press the "stop" button in the VBE to clear the static variables).
Function SQLQuery(sqlString As String, connString As String, _
Optional TimeOut As Integer) As String
Static cs As String
Static conn As ADODB.Connection
SQLQuery = Error 'Assume an error happened
Dim s
If conn Is Nothing Or connString <> cs Then
Set conn = New ADODB.Connection
conn.ConnectionString = connString
conn.Open
If TimeOut > 0 Then conn.CommandTimeout = TimeOut
cs = connString '###comment this out to disable caching effect
End If
Dim record As New ADODB.Recordset
record.Open sqlString, conn
Dim cols As Long
Dim i As Long
cols = record.Fields.Count 'Count how many columns were returned
If Not record.EOF Then 'Put results into comma-delimited string
record.MoveFirst
s = ""
If Not record.EOF Then
For i = 0 To cols - 1
s = s & IIf(i > 0, ",", "") & record(i)
Next i
End If
End If
SQLQuery = s
End Function

Cannot use parentheses when calling a Sub

I have a Classic ASP page that contains the following code to attempt a parametised query;
<%
Set cmdEmail = Server.CreateObject("ADODB.Command")
Set rsEmail = Server.CreateObject("ADODB.Recordset")
cmdEmail.CommandText = "SELECT * FROM VWTenantPropertiesResults WHERE ContentID = ?"
cmdEmail.CommandType = 1
cmdEmail.ActiveConnection = MM_dbconn_STRING
cmdEmail.Parameters.Append
cmdEmail.CreateParameter("#ContentID", 3, 1, , request.Form("ContentID"))
rsEmail.Open cmdEmail
%>
However, the page is now reporting the following error;
Cannot use parentheses when calling a Sub
/welcome/default2.asp, line 436
cmdEmail.CreateParameter("#ContentID", 3, 1, , request.Form(ContentID))
-----------------------------------------------------------------------^
Is this some bug with ASP or do I need to change how I attempt parametised queries?
Thank you.
Did you tried just to remove those parenthesis?
cmdEmail.CreateParameter "#ContentID", 3, 1, , Request.Form("ContentID")
As far as I remember, that always happens when you call a function and doesn't use its return value.
UPDATE: Seems the real problem is the line break:
cmdEmail.Parameters.Append _ '' note this "_" character
cmdEmail.CreateParameter("#ContentID", 3, 1, , Request.Form("ContentID"))
Aren't you missing the "Set" statement in there?
ie:
<%
Set cmdEmail = Server.CreateObject("ADODB.Command")
Set rsEmail = Server.CreateObject("ADODB.Recordset")
UPDATE:
In response to Neil's comment of:
Thanks CraigTP. It seems to be
creating the instance of ADODB.Command
and ADODB.Recordset, but having issues
witht he last 4 lines of the code.
I think the last lines of code, should read something like:
cmdEmail.CommandText = "SELECT * FROM VWTenantPropertiesResults WHERE ContentID = ?"
cmdEmail.CommandType = 1
cmdEmail.ActiveConnection = MM_dbconn_STRING
Set adoParam = cmdEmail.CreateParameter("#ContentID", 3, 1, , request.Form("ContentID"))
adoParam.Type = [the datatype of the parameter]
cmdEmail.Parameters.Append(adoParam)
Note that the .CreateParameter method will return a Parameter object. You should assign this returned object to a variable which you then use as a parameter to the .Append method on the Command object's Parameters collection.
See these links for more information:
CreateParameter Method (ADO)
Parameters Collection (ADO)
Append Method (ADO)
Note the section headed "Remarks Parameters Collection" where it states:
You must set the Type property of a
Parameter object before appending it
to the Parameters collection.
The .Type property of the Parameter object takes a value from the DataTypeEnum enumeration to specify the data type of the parameter. Replace the [the datatype of the parameter] bit of my code above with the relevant data type enum value.
UPDATE 2:
Sorry, didn't notice the question title text had changed!
Ah.. The old classic "Cannot use parentheses when calling a Sub" error, eh?
Well, this is explained here:
Cannot use parentheses when calling a Sub
In a nutshell:
You invoked a subroutine without the
Call statement, but used parentheses
(). When calling a subroutine without
the Call statement, do not use
parentheses.
To correct this error:
Remove the parentheses from the subroutine invocation.
Use the Call statement to invoke the subroutine instead.
There's also a blog post from Eric Lippert that addresses this common error:
What do you mean "cannot use parentheses?"
set cmdEmail = Server.CreateObject("ADODB.Command")
Try and put some debug statements to check, if it is creating an instance of ADODB.Command.
e.g.
If (cmdEmail is Nothing) Then
Response.Write("could not create the instance")
Else
Response.Write("created the instance")
End If
Also, remove the With block and see if that makes any difference
dim paramContentID
cmdEmail.CommandText = "SELECT * FROM VWTenantPropertiesResults WHERE ContentID = ?"
cmdEmail.CommandType = 1
cmdEmail.ActiveConnection = MM_dbconn_STRING
set paramContentID = cmdEmail.CreateParameter("#ContentID", 3, 1, , request.Form("ContentID"))
cmdEmail.Parameters.Append paramContentID