Classic ASP: Populating a 3D array. Subscript out of range: 'objRS(...)' - asp-classic

I am working on a Classic ASP organisational chart thingy at work. The problem is I get a "Subscript out of range: 'objRS(...)'" error. If index_one of the fullname array equals the company held in index_one of the department array, and index_two of the fullname array equals index_two of department, then this should, in theory, mean the user is in the department so I will echo out the name
I have the following code
'Define the AD OU that contains our users
dim ADUser, department, fullname, index_one, index_two, index_three
fullname = Array()
department = Array()
index_one = 0
index_two = 0
index_three = 0
...
ADUser = "LDAP://OU=Staff,OU=Users,DC=example,DC=internal"
' Make AD connection and run query
Set objCon = Server.CreateObject("ADODB.Connection")
objCon.provider ="ADsDSOObject"
objCon.Properties("User ID") = "EXAMPLE\user"
objCon.Properties("Password") = "Pasword"
objCon.Properties("Encrypt Password") = TRUE
objCon.open "Active Directory Provider"
Set objCom = CreateObject("ADODB.Command")
Set objCom.ActiveConnection = objCon
objCom.CommandText ="select company, department, givenName, sn, telephoneNumber, mail, title FROM '"& ADUser &"' where company ='*' ORDER BY department ASC"
Set objRS = objCom.Execute
' Loop over returned recordset and output HTML
Do While Not objRS.EOF Or objRS.BOF
'If index_one of the fullname array equals the company held in index_one of the department array, and index_two of the fullname array equals index_two of department, then this should, in theory, mean the user is in the department so I will echo out the name
department(index_one) = objRS("company")
department(index_two) = objRS("department")
fullname(index_one) = objRS("company")
fullname(index_two) = objRS("department")
fullname(index_three) = objRS("givenName") & " " & objRS("sn")
index_one = index_one + 1
index_two = index_two + 1
index_three = index_three + 1
objRS.MoveNext
Response.Flush
Loop
' Clean up
objRS.Close
objCon.Close
Set objRS = Nothing
Set objCon = Nothing
Set objCom = Nothing
and I get the error:
Microsoft VBScript runtime error '800a0009'
Subscript out of range: 'objRS(...)'
/activedirectory/ldap2.asp, line 38
Line 38 is the last line of a comment so I deleted that, then I got the error when I tried to define each array element so just defined them as:
department() = objRS("company")
department() = objRS("department")
but I still get the error

I don't see you actually assigning dimensions to your arrays anywhere. The Array() function without any arguments will create a zero-dimensional array; obviously, any index will be out of range for that. You'll need a Redim in there somewhere, or if you're adding to an array that already has values, Redim Preserve.
Also, I have no idea what you think this will do:
department() = objRS("company")
department() = objRS("department")
...but in VBScript, you don't ever use empty parentheses like that.
(Aside: you're actually working strictly with one-dimensional arrays. A three-dimensional array would be Dim my3D(10,15,100): that's a cube 10 columns wide, 15 columns deep, and 100 rows long. Given that database tables are 2D arrays at most, you almost never need to work with 3D arrays. In fact, in most cases, 3D arrays are a symptom of overcomplicated thinking, not of good code.)

Related

Issue with migration using classic ASP

Having a problem with migration of a site from one server to another, here is the error I'm getting:
Microsoft Cursor Engine error '80040e21'
Multiple-step operation generated errors. Check each status value.
/common/classes/Cart.asp, line 110
Line 110 is:
fld.Value = Request(fld.Name)
Here is the code that's causing the issue:
public function InsertOrder
set rs = Server.CreateObject("ADODB.Recordset")
rs.ActiveConnection = OrdersConnectionString
rs.Source = "SELECT * FROM "& OrdersTable
rs.CursorType = 3
rs.CursorLocation = 3
rs.LockType = 3
rs.Open()
rs.AddNew
For Each fld in rs.Fields
if Len(Request(fld.Name)) > 0 then
fld.Value = Request(fld.Name)
end if
Next
rs.Update
rs.Requery
rs.Sort=OrderKey &" desc "
OrderID=rs(OrderKey)
end function
It used to use SQL2008 but the new server us running SQL2016.
Thanks for any ideas you can give.
Judging from the code causing this error, this is most likely a problem with type casting behind the scenes. Somehow the database driver fails to properly convert the data to the proper type, so you have to do that yourself.
One way which is pretty flexible, is defining key/value pairs (VBScript Dictionary can fit in this case) where the key will be the field name, and the value will be the type to which to convert the value. (String, Integer, Double, Date)
Sample code would be: (untested, but should work as-is, provided you put correct details)
Const FIELD_TYPE_STRING = 1
Const FIELD_TYPE_INTEGER = 2
Const FIELD_TYPE_DOUBLE = 3
Const FIELD_TYPE_DATE = 4
Const FIELD_TYPE_CURRENCY = 5
Function ConverFieldValue(rawValue, fieldType)
ConverFieldValue = VBNull
Select Case fieldType
Case FIELD_TYPE_STRING:
ConverFieldValue = CStr(rawValue)
Case FIELD_TYPE_INTEGER:
If rawValue<>"" Then ConverFieldValue = CLng(rawValue)
Case FIELD_TYPE_DOUBLE
If rawValue<>"" Then ConverFieldValue = CDbl(rawValue):
Case FIELD_TYPE_DATE:
If rawValue<>"" Then ConverFieldValue = CDate(rawValue)
Case FIELD_TYPE_CURRENCY:
If rawValue<>"" Then ConverFieldValue = CCur(rawValue)
End Select
End Function
Dim typeMapping
Set typeMapping = Server.CreateObject("Scripting.Dictionary")
'''***Add actual field names and types below:****
typeMapping.Add "Field1", FIELD_TYPE_STRING
typeMapping.Add "Field2", FIELD_TYPE_INTEGER
typeMapping.Add "Field3", FIELD_TYPE_DOUBLE
typeMapping.Add "Field4", FIELD_TYPE_CURRENCY
typeMapping.Add "Field5", FIELD_TYPE_DATE
'''*************************************************
Dim currentFieldType, currentFieldValue
Set rs = Server.CreateObject("ADODB.Recordset")
rs.ActiveConnection = OrdersConnectionString
rs.Source = "SELECT * FROM "& OrdersTable
rs.CursorType = 3
rs.CursorLocation = 3
rs.LockType = 3
rs.Open()
rs.AddNew
For Each fld in rs.Fields
if Len(Request(fld.Name)) > 0 then
currentFieldType = typeMapping(fld.Name)
currentFieldValue = ConverFieldValue(Request(fld.Name), currentFieldType)
fld.Value = currentFieldValue
end if
Next
rs.Update
rs.Requery
rs.Sort=OrderKey &" desc "
OrderID=rs(OrderKey)

Dynamically Adding data to jagged array?

I have a recursive function that creates a list of items based on their hierarchy(integer is used to determine which level 1 to 10 max). There can be x number of items in any given level. I want to store all the items that belong the same level at the corresponding index of the jagged array. The items aren't retrieved based on their level so the level can be jumping around all of over the place as the function recurses.
Function RecurseParts(lngPartID1, lngLevel) As Object
'this function will recursivley print the parts lists for the part ID passed in
If IsNumeric(lngPartID1 & "") Then
Dim objRSTemp As Object = Server.CreateObject("ADODB.Recordset")
objRSTemp.CursorLocation = adUseClient
objRSTemp.Open(PART_LIST_SQL & lngPartID1, objConn, adOpenForwardOnly, adLockReadOnly)
'objRSTemp.ActiveConnection = Nothing
If objRSTemp.eof And objRSTemp.bof Then
'PROBLEM, WE HAVE NO RECORDS
Response.Write("There Were No Parts For This Assembly (Part ID #:" & lngPartID1 & ")")
Else
'make output
Dim strTemp As String = String.Empty
If lngLevel <> 1 Then strTemp = " style=""display: none;"">"
Response.Write("<table id='tblparts" & lngCurrentLineNum & "' border=""0"" cellspacing=""0"" width=""100%"" cellpadding=""1"" " & strTemp)
Do Until objRSTemp.EOF
'increase the current line num
lngCurrentLineNum = lngCurrentLineNum + 1
'get current Part ID
lngCurrentPartID = objRSTemp("PartID").value
'reset flag
blnIsAssm = False
'loop thru array of assemblies to see if this is a parent
For ctr = 0 To UBound(arrAssmList, 2)
If arrAssmList(0, ctr) = lngCurrentPartID Then
'the current part is an assembly
blnIsAssm = True
Exit For
ElseIf arrAssmList(0, ctr) > lngCurrentPartID Then
Exit For
End If
Next
If blnIsAssm Then
'recurse these parts
If RecurseParts(objRSTemp("PartID").value, lngLevel + 1) = True Then
'awesome
End If
End If
objRSTemp.MoveNext()
Loop
Response.Write("</table>")
End If
If objRSTemp.State Then objRSTemp.Close()
objRSTemp = Nothing
'RETURN FUNCTION
RecurseParts = True
Else
'no PART ID passed in
Response.Write("No Part ID Passed In")
RecurseParts = False
End If
End Function
It sounds like a Dictionary would work here.
Dim myDict As New Dictionary(Of Integer, List(Of String))
In your recursive function. The parts in the {} are the parts you have to supply.
'this builds the keys as you go
If Not myDict.ContainsKey({{key} -> your Integer}) Then
'add key and use the From statement to add a value if know at this time
myDict.Add({key}, New List(Of String) From {value})
Else
myDict({key}).Add({string to insert at this level})
End If
List of keys in reverse order:
Dim keys = myDict.Keys.OrderByDescending(Function(k) k)
I was able to create a List to store all the partIDs and their levels.
Dim arrSubID As New List(Of List(Of Integer))()
Function RecurseParts(paramenters)
For ctr = 0 To UBound(arrAssmList, 2)
If arrAssmList(0, ctr) = lngCurrentPartID Then
'checks whether we need a new index in the list
If lngLevel + 1 > arrSubID.Count Then
arrSubID.Add(New List(Of Integer))
End If
'adds the partID where it belongs!
arrSubID(lngLevel).Add(lngCurrentPartID)
blnIsAssm = True
Exit For
ElseIf arrAssmList(0, ctr) > lngCurrentPartID Then
Exit For
End If
Next
End Function

Microsoft VBScript runtime error '800a0009'

I recently inherited a website in ASP, which I am not familiar with. Yesterday, one of the pages began to throw an error:
Microsoft VBScript runtime error '800a0009'
Subscript out of range: 'i'
default.asp, line 19
Here is the code from lines 13-27:
<%
set rs = Server.CreateObject("ADODB.Recordset")
rs.open "SELECT * FROM VENDORS_LIST_TBL WHERE inStr('"& dVendorStr &"','|'&ID&'|')", Cn
DIM dTitle(100), dDescription(100), dLink(100)
i = 0 : Do while NOT rs.EOF : i = i + 1
dTitle(i) = rs.fields.item("dTitle").value
dDescription(i) = rs.fields.item("dDescription").value
dLink(i) = rs.fields.item("dLink").value : if dLink(i) <> "" then dTitle(i) = "" & dTitle(i) & ""
if NOT rs.EOF then rs.movenext
Loop
x = i
rs.Close : Set rs = Nothing
%>
Any ideas on what's going on here and how I can fix it?
Thank you!
You've declared dTitle, dDescription and dLink as Arrays with a size of 100. As you are walking through the recordset, you are assigning elements to those arrays. It would appear that you have more than 100 records in your recordset, so the logic is trying to do something like:
dTitle(101) = rs.fields.item("dTitle").value
This will throw an error because your array isn't big enough to hold all of your data.
The "solution" you chose is not very good. What if within 2 years there will be more than 500? You will forget all about this and waste hours yet again.
Instead of fixed size arrays you can just use dynamic arrays:
DIM dTitle(), dDescription(), dLink()
ReDim dTitle(0)
ReDim dDescription(0)
ReDim dLink(0)
i = 0
Do while NOT rs.EOF
i = i + 1
ReDim Preserve dTitle(i)
ReDim Preserve dDescription(i)
ReDim Preserve dLink(i)
dTitle(i) = rs.fields.item("dTitle").value
dDescription(i) = rs.fields.item("dDescription").value
dLink(i) = rs.fields.item("dLink").value
If (Not(IsNull(dLink(i)))) And (dLink(i) <> "") Then
dTitle(i) = "" & dTitle(i) & ""
End If
rs.movenext
Loop
This will start with one (empty) item in each array - for some reason the code seems to need this - then on each iteration one more item will be added, preserving the others.
Note that I've also fixed small issue that might have caused trouble - in case of NULL value in "dLink" field, you would get blank anchors in your HTML because NULL is not empty string in VBScript.
This how GetRows can be used to achieve the same goal.
<%
Function VendorSearch(sVendor)
Dim cn: Set cn = SomeLibraryFunctionThatOpensAConnection()
Dim cmd: Set cmd = Server.CreateObject("ADODB.Command")
cmd.CommandType = adCmdText
cmd.CommandText = "SELECT dTitle, dDescription, dLink FROM VENDORS_LIST_TBL WHERE inStr(?,'|'&ID&'|')"
cmd.Parameters.Append cmd.CreateParameter("Vendor", adVarChar, adParamInput, Len(sVendor), sVendor)
Set cmd.ActiveConnection = cn
Dim rs : Set rs = cmd.Execute()
VendorSearch = rs.GetRows()
rs.Close()
cn.Close()
End Function
Dim arrVendor : arrVendor = VendorSearch(dVendorStr)
Const cTitle = 0, cDesc = 1, cLink = 2
Dim i
For i = 0 To UBound(arrVendor, 2)
If IsNull(arrVendor(cLink, i) Or arrVendor(cLink, i) = "" Then
arrVendor(cTitle, i) = "" & arr(cTitle, i) & ""
End If
Next
%>
Notes:
The Select statement contains only those fields required in the results, the use of * should be avoided
A parameterised command is used to avoid SQL Injection threat from SQL contactenation.
Constants used for field indices into the resulting 2 dimensional array.
Whilst this code replicates the original munging of the title value this is here as an example only. In reality construction of HTML should be left as late as possible and outputing of all such strings as title and description should be passed through Server.HTMLEncode before sending to the response.

Converting null string to date

I have searched high and low to no avail, and this is last step before completing my project so please help! Thanks in advance!
The user will select an entry in a gridview, which then redirects them to a form that is populated with the data from the selected row (thus making the gridview editable in a more user friendly way). Null values are accepted by the DB and I would like to show null date values as blank (or " ") in the corresponding text boxes. Instead I get the error:
Conversion from type 'DBNull' to type 'Date' is not valid.
Here is my code:
'preceded by connection code
Dim sqlcmd As String = "SELECT * from Master WHERE RecNum = #recnum"
'Dim sqlCmd As New OleDb.OleDbCommand("SELECT * from Master WHERE RecNum = #recnum", connection)
Dim FileCommand3 As New OleDb.OleDbCommand(sqlcmd, connection)
FileCommand3.Parameters.AddWithValue("#recnum", user)
Dim Reader3 As OleDb.OleDbDataReader = FileCommand3.ExecuteReader()
If Reader3.Read Then
stock = myCStr(Reader3("StockNum"))
make = myCStr(Reader3("Make"))
color = myCStr(Reader3("Color"))
stockin = myCStr(Reader3("Stockin"))
ucistart = myCStr(Reader3("UCIStartDate"))
repairs = Reader3("Repairs")
tires = Reader3("tiresneeded")
onlot = Reader3("onlot")
sold = Reader3("sold")
year = myCStr(Reader3("year"))
model = myCStr(Reader3("model"))
location = Reader3("location")
srvcRO = myCStr(Reader3("svcROnum"))
ucicompldate = myCStr(Reader3("uciestcompletedate"))
collRO = myCStr(Reader3("collisionROnum"))
other = myCStr(Reader3("other"))
offprop = Reader3("offProperty")
detail = (Reader3("detail")
End If
connection.Close()
SoldCheckBX.Checked = sold
DetailTXTbox.Text = detail
'etc, etc
End Sub
I used the function mycstr to fix the dbnull to string error but it does not seem as simple to adapt to "date" data type
Function myCStr(ByVal test As Object) As String
If isdbnull(test) Then
Return ("")
Else
Return CStr(test)
End If
End Function
try this when you read the values from the reader with all your dates, this will first test to see if the date is dbnull, if it is then it will assign a nothing value and you should get your desired empty cell, otherwise it will show the date:
ucistart = IIf(reader3("UCIStartDate") Is DBNull.Value, Nothing, reader3("UCIStartDate"))
Have you tried using the Convert.IsDBNull function?
Here is the official documentation.

ASP.Net String Split not working

Here's my code
Dim RefsUpdate As String() = Session("Refs").Split("-"C)
Dim PaymentsPassedUpdate As String() = Session("PaymentsPassed").Split("-"C)
Dim x as Integer
For x = 1 to RefsUpdate.Length - 1
Dim LogData2 As sterm.markdata = New sterm.markdata()
Dim queryUpdatePaymentFlags as String = ("UPDATE OPENQUERY (db,'SELECT * FROM table WHERE ref = ''"+ RefsUpdate(x) +"'' AND bookno = ''"+ Session("number") +"'' ') SET alpaid = '"+PaymentsPassedUpdate(x) +"', paidfl = 'Y', amountdue = '0' ")
Dim drSetUpdatePaymentFlags As DataSet = Data.Blah(queryUpdatePaymentFlags)
Next
I don't get any errors for this but it doesn't seem to working as it should
I'm passing a bookingref like this AA123456 - BB123456 - CC123456 - etc and payment like this 50000 - 10000 - 30000 -
I basically need to update the db with the ref AA123456 so the alpaid field has 50000 in it.
Can't seem to get it to work
Any ideas?
Thanks
Jamie
I'm not sure what isn't working, but I can tell you that you are not going to process the last entry in your arrays. You are going from 1 to Length - 1, which is one short of the last index. Therefore, unless your input strings end with "-", you will miss the last one.
Your indexing problem mentioned by Mark is only one item, but it will cause an issue. I'd say looking at the base your problem stems from not having trimmed the strings. Your data base probably doesn't have spaces leading or trailing your data so you'll need to do something like:
Dim refsUpdateString as string = RefsUpdate(x).Trim()
Dim paymentsPassedUpdateString as string = PaymentsPassedUpdate(x).Trim()
...
Dim queryUpdatePaymentFlags as String = ("UPDATE OPENQUERY (db,'SELECT * FROM table WHERE ref = ''" & refsUpdateString & "'' AND bookno = ''" & Session("number") & "'' ') SET alpaid = '" & paymentsPassedUpdateString & "', paidfl = 'Y', amountdue = '0' ")
Also, I would recommend keeping with the VB way of concatenation and use the & character to do it.

Resources