VBScript VarType function gives weird value - asp-classic

I've encountered a strange problem with getting data from a Database and casting it to the correct type using VBScript for ASP.
I have a recordset retrieved using the following function:
Public Function vfuncGetRS(strQuery)
'Returns a disconnected paging capable recordset
'Note - Non Windows servers don't support disconnected recordsets so you'll always get a connected recordset on
' a non Windows server!
On Error Resume Next
Err.Clear
Dim objData
Set objData = Server.CreateObject("ADODB.Recordset")
objData.CursorLocation = adUseClient
objData.CursorType = adOpenStatic
objData.LockType = adLockReadOnly
objData.Open vlogSQLFilter(strQuery), objDB
If Not blnUNIXMode Then
Set objData.ActiveConnection = Nothing
End If
Set vfuncGetRS = objData
End Function
If I select a value from the recordset and gets its VarType it returns the value 16 eg.
Set objRS = vfuncGetRS("SELECT * FROM SOME_TABLE")
Response.Write(VarType(objRS("someColumn")))
The weirdness is in two parts
This ONLY happens on a particular server, this code is part of a CMS which I deploy on multiple sites and it's only the instance running on IIS 6.0 that causes me an issue. Also this seems to be dependent on the recordset options.
The value 16 is not a valid value for VarType to return according to the official MSDN reference
I can get round this fairly easily by adding a check to the function that is being affected by the weird values which is as follows
If VarType(strValue) = 16 Then strValue = CInt(strValue)
I have to do the above because I need the function in question to correctly detect that the type is numeric and if the VarType is 16 then IsNumeric() gives false even if the value in the variable is numeric (and it will always be numeric)
So my question is does anyone know why this happens?

As Stijn have stated, the value of 16 means that it's a One Byte Variant, specified in the C++ headers as VT_I1.
And you're only getting this value because of the MySQL connection driver (as you've stated that the environment where you encounter this 16 value is IIS6 with MySQL).
Apparently this is a bug in the MySQL driver that instead of reporting adBoolean for a BIT field it's Reporting VT_I1.

According to this, 16 might stand for VT_I1, thus a single byte signed integer.

Related

Prepared Statements and sanitizing data

When using a prepared statement with Classic ASP such as this:
SQL = "SELECT user_name, user_sign_up_date FROM tbl_users WHERE this = ? AND id = ? "
Set stmt01 = Server.CreateObject("ADODB.Command")
stmt01.ActiveConnection = oConn
stmt01.Prepared = true
stmt01.commandtext = SQL
stmt01.Parameters.Append stmt01.CreateParameter("#x1", adVarChar, adParamInput, 255, card_pwd)
stmt01.Parameters.Append stmt01.CreateParameter("#x2", adInteger, adParamInput, , this_id)
set myRS = stmt01.Execute
Apart from doing the usual sense checking to e.g. make sure that a number is a number and so on, does the process of using this kind of Parameterised Statement mean that I no longer have to worry about, e.g. for a varchar or text field, sanitising the data input from users - e.g. would I no longer need to use a function to push everything input by a user through Server.HTMLencode?
I'm not sure if the parameterised statement route means I can be less strict re. sanitizing user data now?
You are conflating two different types of sanitisation. SQL parameterization prevents the “Bobby Tables” vulnerability — a maliciously written bit of data that tricks SQL into ending the current query and executing a separate query of the attacker’s choosing.
https://bobby-tables.com
Even with SQL parameters, an attacker could try to run a script on your page by (for example) entering “alert(‘Gotcha!’)” in a field. Display the field data on an HTML page and that script is written out and executed. To prevent that you use Server.HTMLencode
If your concern is SQL injection attacks then parameterization should remove the possibility of the SQL string being tampered with because the values are supplied at execution time.
Others are correct that you don't need to worry about the contents of the parameters. You do have to worry about the length of strings. I would pass Left(card_pwd, 255) to CreateParameter() to avoid exceptions crashing your script. I tend to not worry about calling IsNumeric() on integer parameters but that might be worthwhile (try passing nonsense and see what happens).

Output params and Stored Procedure

I've googled but none of the solutions seems to work for me!
I have a SPROC in SQL Server which has an input param and also an output parameter being set within the SPROC.
using classic ASP, I want to retrieve the value of that output parameter but nothing seems to get set (but I can see the output parameter working correctly when executing in the SQL Server Management Studio)
OpenConnection
Set cmdTemp = Server.CreateObject("ADODB.Command")
cmdTemp.CommandType = 4 'adCmdStoredProc
Set cmdTemp.ActiveConnection = dbConn
cmdTemp.CommandText = "GetCerts"
cmdTemp.Parameters.Refresh
cmdTemp.Parameters(1) = "ABC123"
cmdTemp.Parameters(2).Direction = 2 'Output
Set reader = cmdTemp.Execute
Response.Write(cmdTemp.Parameters(2)) ' Nothing is displayed at all.
CloseConnection
I tried using the named parameters approach but always got an error saying that the parameters are out of range, wrong arguments or wrong type (Something similar to this).
Really... getting a headache. I just want the OUTPUT param value set from the SPROC (2nd parameter in the SPROC)
Check for errors:
Set reader = cmdTemp.Execute
If Err.number <> 0 or dbConn.Errors.Count <> 0 Then
'Do something to handle the error
End If
Do you have permissions to execute the stored procedure? i.e. the credentials of the ASP user...
Execute Stored Procedure from Classic ASP
It seems after a long long investigation that what I am trying to do is not possible (but it is in .NET). Seems I need to execute the command twice, first time getting the output parameters values then the next time to display the results. Awful. Praise .NET!
Most collections in the COM world use zero-based indexing. Try using Parameters(0) as the input parameter and Parameters(1) as the output parameter.

ADODB.Recordset error '800a0bb9' : Arguments are of the wrong type

Set rsPlanID = Server.CreateObject("ADODB.Recordset")
rsPlanID.CursorLocation = adUseClient
strSQL = "SELECT PlanID FROM ATTJournals WHERE ATTUserDataID = " & ATTUserDataID
rsPlanID.Open strSQL, m_objConn, adOpenStatic, adLockOptimistic
If Not rsPlanID.EOF Then
response.Write "New PlanID:" & rsPlanID("PlanID")
End If
The above code is in classic asp.
I am getting the following error:
ADODB.Recordset error '800a0bb9'
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
Dows anyone know the cause this error and how to fix it?
The most like cause is that you haven't included "ADOVBS.INC" or the equavalent META:-
<!--METADATA
TYPE="TypeLib"
NAME="Microsoft ActiveX Data Objects 2.6 Library"
UUID="{00000206-0000-0010-8000-00AA006D2EA4}"
VERSION="2.6"
-->
Hence the adxxxx constants do not exist. However your primary mistake is not including Option Explicit at the top your script. This will save you bucket loads of time hunting silly mistakes and typos.
BTW What happens if ATTUserDataID contained "0; DELETE ATTJournals;" ?
Avoid composing SQL using concatenation like the plague. Search for "ASP SQL Injection" to find examples of using parameterised command objects instead.
Unless you need to navigate back and forth in the recordset, just use the default settings:
strSQL = "SELECT PlanID FROM ATTJournals WHERE ATTUserDataID = " & ATTUserDataID
Set rsPlanID = m_objConn.Execute(strSQL)
Also, your code is wide open for SQL Injection attacks - you better learn about it and change your code to use Parameters instead.
I feel like I searched the whole internet and couldn't find the solution to this problem, and just as I was about to give up, I realized that I had declared my connection variable within an "If" statement and because the if statement did not execute neither did my command to the database giving the error as mentioned in your question.
First, when I devoleped application with vbscript I used always the numbers to open a recordset. I recommend following line:
rsPlanID.Open strSQL, m_objConn, 3, 3
Make sure that you include the file adovbs.inc first. The numbers are conntected to the different types of recordset properties. And don't foregt to open the databse connection first.
Second, I think you don't need the line
rsPlanID.CursorLocation = adUseClient
Thrird, see also this thread. Maybe it is a good template for you.
Function SQL_getRecordset(strQuery)
'On Error Resume Next
'Create Database connection object
Set objConnection = CreateObject("ADODB.Connection")
'Create Recordset object
Set objrecordset = CreateObject("ADODB.Recordset")
'Specify the connection string
strConnectionstring = "Provider=SQLOLEDB.1;Data Source=*<Server name>*;Initial Catalog=*<database>*;Integrated Security=SSPI"
objConnection.Open strConnectionstring
'Execute the Query
Set objrecordset = objConnection.Execute(strQuery)
'Return Recordset
Set SQL_getRecordset = objrecordset
'Release objects from the memory
Set objConnection = Nothing
Set objrecordset = Nothing
End Function

Insert using ADO with classic ASP

' Setting variables
Dim con, sql_insert, data_source
data_source = "project_db"
sql_insert = "insert into cart ( UserID,Count,ProductName,ProductDescription,ProductPrice) values ('"&user_id&"','"&count&"','"&product_name&"','"&product_description&"','"&product_price&"')"
' Creating the Connection Object and opening the database
Set con = Server.CreateObject("ADODB.Connection")
con.Open data_source
' Executing the sql insertion code
con.Execute sql_insert
' Done. Now Close the connection
con.Close
Set con = Nothing
AS you can see , it is a simple code . and it worked in my local host for 5 or 6 times. but now it didn't work. What's the problem ? I think , it's about my database or memory. i setup 2 different iis in 2 different computer and they behave same... please help..
Thanks
Does it give you any error message? Make sure all the values you are inserting actually have values and are not blank or null. You can check this by response.write all the values and then response.end to see if they contain any values.
I bet it's a data-dependent error. You should be using ADO parameters. Those will ensure that extraneous SQL-unfriendly characters in your input do not adversely affect your database operation. You should also use them to guard against SQL injection issues.
Some docs are available at http://msdn.microsoft.com/en-us/library/ms675869(VS.85).aspx, and you can google for "ADO parameters" and find many relevant examples.
I believe that 'data_source' should be focused on (and agreed with Tom Gullen as regards to error messages. Always use Option Explicit at the top of your pages).
con.Open either expects some DSN parameters or a database connection string to be passed within 'data_source'.
Examples, respectively :
data_source = DSN_Database, DSN_User, DSN_Password
(these 'DSN_' parameters are found/set in your DSN configuration)
OR :
data_source = "Driver={SQL Server};Server=server.domain.com;Database=project_db;uid=MyUser;pwd=MyPass;""

ASP Classic page quit working

I've had a set of legacy pages running on my IIS7 server for at least a year. Sometime last week something changed and now this line:
Response.Write CStr(myRS(0).name) & "=" & Cstr(myRS(0).value)
which used to return nothing more exciting than the string: 'Updated=true' (the sproc processing input params, stores them to a table, checks for errors and when that's all done returns a success code by executing this statement:
select 'true' as [Updated]
Now my pageside error handler is being involved and offers:
myError=Error from /logQuizScore.asp
Error source: Microsoft VBScript runtime error
Error number: 13
Error description: Type mismatch
Important to note that all lots of pages use the same framework - same db, same coding format, connecitonstrings and (so far as I can tell) all others are working.
Troubleshot to this point:
The call to the stored procedure is working correctly (stuff is stored to the given table). The output from the stored procedure is working correctly (i can execute a direct call with the given parameters and stuff works. I can see profiler calling and passing. I can replace all code with 'select 'true' as updated' and the error is the same.
everything up to the response.write statement above is correct.
So something changed how ADO renders that particular recordset.
So i try: Response.Write myRS.Item.count
and get:
Error number: 424
Error description: Object required
The recordset object seems not to be instantiating but the command object _did execute. Repeat - lots of other pages just the same basic logic to hit other sprocs without a problem.
full code snippet
set cmd1 = Server.CreateObject("ADODB.Command")
cmd1.ActiveConnection = MM_cnCompliance4_STRING
cmd1.CommandText = "dbo._usp_UserAnswers_INSERT"
...
cmd1.CommandType = 4
cmd1.CommandTimeout = 0
cmd1.Prepared = true
set myRS = cmd1.Execute
Response.Write CStr(myRS(0).name) & "=" & Cstr(myRS(0).value)
It seems to me that the sproc has changed and returns a scalar instead of a result set.
Changing CommandType = 1 (adCmdText) is need to match with your query changed to SELECT 'whateveryouwannatry' AS [updated].
Since you stated that nothing in the asp code changed we can rule out that the return type of your command/sproc was altered by specifying an output parameter.

Resources