Cannot use parentheses when calling a Sub - sql

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

Related

Option Strict On and DBNull.Value

I've started converting an application of mine to use Option Strict On. I've been doing the CStr,Ctype etc, and it's been going well.
SQLCommand.Parameters.AddWithValue("#TERMINATE", If(IsNothing(txtEarningsTerminated.DateValue), DBNull.Value, txtEarningsTerminated.DateValue))
Then I hit this. The txtEarningsTerminated.DateValue is a custom masked text box. When it's value is Nothing I don't want to store anything in the database. However, it states
Cannot infer a common type, and Option Strict On does not allow 'Object' to be assumed.
When I change DBNull.Value to "" or nothing, the error goes away. However as Nothing, it fails during runtime stating
The parameterized query '(#CONTROL int,#CLIENTCODE nvarchar(10),#NoBill int,#TERMINATE nv' expects the parameter '#TERMINATE', which was not supplied.
I want to put a NULL in the database. This value can be a date and then become a NULL.
How do I translate this so as to not produce an error under Option Strict On?
The reason is because operator If(condition, executeAndReturnIfTrue, executeAndReturnIfFalse) expects that both true and false expressions will return same type.
In your case you return DbNull type if true and String(or some other type you didn't mentioned) if result is false.
If create SqlParameter more explicitly, then you can use next approach:
Dim value As Object = Nothing
If txtEarningsTerminated.DateValue Is Nothing Then
value = DbNull.Value
Else
value = xtEarningsTerminated.DateValue
End If
Dim param As SqlParameter = New SqlParameter With
{
.ParameterName = "#TERMINATE",
.SqlDbType = SqlDbType.VarChar, 'Or use your correct type
.Value = value
}
As mentioned in the comments using AddWithValue will force ADO.NET to decide the sql type automatically for your value, which can lead in different problems. For example everytime you run same query with different values your query plan will be recompiled every time you change value.
You can create extension method for string
Public Module ExtensionsModule
Public Function DbNullIfNothing(this As String) As Object
If this Is Nothing Then Return DBNull.Value
Return this
End Function
End Module
Then use it instead of your "inline If method"
Dim value As String = Nothing
Dim param As SqlParameter = New SqlParameter With
{
.ParameterName = "#TERMINATE",
.SqlDbType = SqlDbType.VarChar,
.Value = value.DbNullIfNothing()
}
So the answer was obvious and in the error. I just had to encase the DBNull.Value in a Ctype Object
CType(DBNull.Value, Object)
And then the code would compile just fine.
Here's one way to do it (assuming you're using stored procedures in your database):
In the stored procedure you're calling, set the date input parameter to equal null, making it an optional field with a default value of null (#terminate DATETIME = NULL).
That way, if you don't include that parameter in your procedure call, the procedure won't fail.
Set the default value of the date field to DateTime.MinValue so it always has some value. Then you can test to see if it is equal to a date other than DateTime.MinValue. If it is a valid date value, add the line to include the date parameter to the procedure call. If it is equal to DateTime.MinValue, don't add the parameter to the call.

Data type mismatch when inserting record

I've this piece of code for inserting records into an Access table.
LastUpdated field is defined as Date/Time at database level. It fails when inserting giving the error
Data type mismatch in criteria expression
I'm using parameterized query which avoid problems with formatting values and it's very weird because I've the same code (with more parameters) to insert records on another table on which LastUpdated is defined in the same way and it's working fine.
Any idea?
SqlQuery = "INSERT INTO History (ActivityID, LastUpdated) VALUES (#p1,#p2)"
With sqlcommand
.CommandText = SqlQuery
.Connection = SQLConnection
.Parameters.AddWithValue("#p1", IDAct)
.Parameters.AddWithValue("#p2", DateTime.Today)
End With
result = sqlcommand.ExecuteNonQuery()
If (result = 1) Then
LabelWarning.Text = "Activity filled"
LabelWarning.BackColor = Color.ForestGreen
LabelWarning.Visible = True
ButtonSave.Visible = False
ButtonBack.Visible = False
ButtonOK.Visible = True
BlockControls()
End If
Maybe the problem is linked to parameter placeholder.
This MSDN doc states that OleDbCommand does not support named parameter (only positional) and the correct placeholder should be "?" and not "#p1".
https://msdn.microsoft.com/en-us/library/yy6y35y8%28v=vs.110%29.aspx
Edit
It turned out in comments that the placeholder have not to be so strictly adherent to the doc syntax. Only the order has to be absolutely preserved.
Explicitly declaring the parameter type however seemed to do the trick:
.Parameters.Add("#p2", OleDbType.DBTimeStamp)
.Parameters("#p2").Value = DateTime.Today

asp ADO connection Microsoft VBScript runtime error '800a01a8'

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

VBA Recordsets: Why does the way I declare my array, in the Fieldvalue parameters of .addnew, matter?

I've been trying to dynamically add to a Recordset but I am unable to do so. The .addnew function of a adodb.recordset seems to not allow just any type of array to be passed to it's fieldvalues, values parameters. For example if after setting up your recordset with the appropriate field values you say:
FieldsArray = array("field1", "field2")
ValuesArray = array("val1","val2")
rs.AddNew FieldsArray, ValuesArray
This works!!
But if you instead write
Dim fieldsarray(0 To 1) As String
FieldsArray(0) = "field1"
FieldsArray(1) = "field2"
ValuesArray = array("val1","val2")
rs.AddNew FieldsArray, ValuesArray
It Fails?!?! (More specifically [Run-Time error '3001': Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another])
Why does the way one declares the field array in the .addnew parameters matter? Is there a way I can get the latter to work?
This is because in the first example you are declaring two arrays of VARIANT data type, while in the second example you are declaring STRING arrays.
The AddNew function is expecting a variant array.
In you second example, change your first line to:
Dim fieldsarray(0 To 1) As Variant
and it should work.

An SqlParameter with ParameterName is not contained?

I have a problem with something I have done many times but this time it just doesn't work.
This is what what I am trying to do (in Visual Studio 2003 and VB.NET)
Earlier in the code:
Private SaveCustomerInformationCommand As System.Data.SqlClient.SqlCommand
Then this in a setup process:
SaveCustomerInformationCommand = New System.Data.SqlClient.SqlCommand("spSaveCustomerInformation")
SaveCustomerInformationCommand.CommandType = Data.CommandType.StoredProcedure
Dim custIdParameter As System.Data.SqlClient.SqlParameter = SaveCustomerInformationCommand.CreateParameter()
custIdParameter.ParameterName = "#CustId"
custIdParameter.SqlDbType = Data.SqlDbType.Int
custIdParameter.Direction = Data.ParameterDirection.Input
SaveCustomerInformationCommand.Parameters.Add(custIdParameter)
And then later:
SaveCustomerInformationCommand.Parameters.Item("#CustId").Value = myValue
And I get this:
System.IndexOutOfRangeException: An SqlParameter with ParameterName '#CustId' is not contained by this SqlParameterCollection.
Any ideas/solutions?
AFAIK, the "#" is not technically part of the name of the parameter... rather it's what you put into your T-SQL to denote that a parameter name is coming afterwards. So I think you'll want to refer to it like this instead (with no "#") :
SaveCustomerInformationCommand.Parameters.Item("CustId").Value = myValue
You could also try the same thing when you initially insert the parameter name-- although since you're not getting an error there, I'd suspect the accessor call is to blame, not the inserter call.