ASP classic, reading and then writing to database - sql

I have a page where a database lookup is done, and if a value is found some response is sent back to the user and then the database value is deleted.
I'm calling my delete sub after I've checked the variable but it's like this never happened, although i know the sub ran since the value is now gone from the database.
It seems like the page is loading twice and on the second pass the database value has gone and so it shows as if the database value was never found, but it had to have been found in order to have deleted it (as this was a condition for running the delete sub).
I realize this sounds insane but I've been on this for 2 days and have no idea what's going on. I've tried disabling caching from within IIS and also changing my code so that a value is posted to the database instead of deleting a record and I still get the same thing where my server seems to check the future value of the database before calling the routine that changes it.
Has anyone seen similar behavior to this when reading and writing to the same record on a single page?
Code:
referer = Request.ServerVariables ("HTTP_REFERER")
session("testcode") = right(referer,16)
testcode = session("testcode")
set objcommand = server.createObject("adodb.command")
objcommand.activeconnection = strconnect2
objcommand.commandtext="SELECT codeval,stamp,used from code where codeval like '" & testcode & "'"
objcommand.commandtype = 1
set objrs = objcommand.Execute
set objcommand = nothing
countvar = 0
While not objrs.EOF
if not objrs("used") = true then
foundcode = true
countvar = countvar+1
end if
objrs.MoveNext
wend
if foundcode = true then
response.write "Found you!"
set objcomm5 = server.createobject("adodb.command")
objcomm5.activeconnection = strconnect2
objcomm5.commandtext = "update code set used = true where codeval like '"& testcode &"' "
objcomm5.commandtype = &H0001
objcomm5.execute
else
response.write "Can't be found!"
end if

Related

MS Access $ in Table

I made a form that adds info.
With rst
.AddNew
.Fields("a") = b.Value
.Update
It usually works fine. But sometimes I need to put a dollar amount in. So I'll put "$3.43" and it will put the entry in twice. Once at the bottom, and once overwriting the top.
I'm fairly sure this has to do with the "$", because that's the only thing that changes from entry to entry, but I can't find anything about it on Google.
Edit: Full Code
Private Sub Command78_Click()
Dim rst As Recordset
Set rst = CurrentDb.OpenRecordset("Service Calls")
With rst
.AddNew
.Fields("Project Name") = proj.Value
.Fields("Service Address") = address.Value
.Fields("Date of Service") = doS.Value
.Fields("Technician") = tech.Value
.Fields("Total Billed") = billed.Value
.Fields("Zip Code") = zip.Value
.Fields("Description of Work") = work.Value
.Fields("Type of Call") = toC.Value
.Fields("Invoice Number") = invoiceNum.Value
.Fields("Ticket Number") = ticketNum.Value
.Update
End With
End Sub
If Total Billed is of Currency (as it should), you cannot insert a string. Thus, remove a $-sign if present:
.Fields("Total Billed").Value = CCur(Replace(billed.Value, "$", ""))
Looks like you have bound the table to the same form in which the Command78_Click fires, check that and remove the code for the Command78_click event if you have actually bound the table to the form.

vba functions malfunction after repetitive calling

I have a database where data goes through multiple steps, and user can report and 'solve' those errors in the database.
Once an error is added in my tbl_errors, they go on and solve it. Once they have solved the error irl, the 'solve' the error in the database as well, to keep track of time and such.
This all works like a charm, when adding errors I have never encountered any problems. And at first sight, 'solving' the problems goes flawless either. The problem however, is that once I start 'solving' a lot of errors in a row, my code suddenly stops working.
It does not freeze or throw back any errors, and when I step through the code using my breakpoints and f8, all the variables seem to be correct also. Everything goes on just as always, except it just does not do anything anymore. This is only applicable to that specific error. When I add new errors, and try to 'solve' them. It works just as usual.
Important notes:
This ONLY happens when I start fast clicking on my solve button, thus calling the functions real fast behind eachother.
It only freezes for a specific errors. (Can be multiple) All other errors can be solved as usual, indicating that the code is still functioning.
I have stepped through the whole code, while checking all the keys and variables and every variable is correct.
Even though my code goes through the recordset, it does not update anything?
Below is a piece of my relationships screen to give a better understanding of the table structure, as well as the specific parts of code.
Calling the code in the OnClick event:
Private Sub solve_Click()
SolveError getorderid(gvStepDelivery), get_errorID(gvCategory, get_stepsID(gvStepNr))
Me.qry_errors_subform.Requery
Me.Refresh
End Sub
The self-written function SolveError:
Public Function SolveError(Current_order_ID As Long, Category_ID As Long)
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("tbl_errors", dbOpenDynaset)
With rs
.FindFirst "[Error_ID] = " & DLookup("Error_ID", "tbl_errors", "[Current_orders_ID] = " & Current_order_ID & " AND [Category_ID] = " & Category_ID)
.Edit
![Solved_By] = get_user
![Solved_Date] = Date
![Solved_Time] = Time
.update
End With
rs.Close
Set rs = Nothing
End Function
There are other parts of code involved (See the SolveError's parameters), but I don't think they will add some usefull info, since they are just returning the correct values. (They are correct!!)
Ok, it seems I have already found my answer. Since I was probably calling a new iteration before the previous one had completely finished, it simply stopped working. Adding the DoEvents function at the end my SolveErrors function solved it. I have yet to experience the problem again.
Public Function SolveError(Current_order_ID As Long, Category_ID As Long)
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("tbl_errors", dbOpenDynaset)
With rs
.FindFirst "[Error_ID] = " & DLookup("Error_ID", "tbl_errors", "[Current_orders_ID] = " & Current_order_ID & " AND [Category_ID] = " & Category_ID)
.Edit
![Solved_By] = get_user
![Solved_Date] = Date
![Solved_Time] = Time
.update
End With
rs.Close
Set rs = Nothing
DoEvents 'This one did the trick!!
End Function
Info on the DoEvents method can be found here: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1
and here: http://office.microsoft.com/en-001/access-help/doevents-function-HA001228827.aspx

Can't Go To Specific Record on Continuous Form in MS Access

Searched and searched and cannot find a solution to this. I have a form with many continuous form subforms. When I change a value in, lets say FIELD_A on one of the subforms, I run calculations on several other subforms, then the focus returns to FIELD_A. However, during the calculations an update to the PARENT form happens, and needs to happen. So, when I return focus to the original subform, the first record on my subform has the focus. I need to then go to the record I was working on.
I've tried several options, but nothing works. However, if I set a DEBUG breakpoint at the line in the code where it moves to the specified record, then physically RUN the code from that line, it works! I've tried setting a wait period in there to no avail.
Here's a snippet of the code:
Call common.CalculateAllLoadTotals _
(Me, Me.AffiliateID, Me.ClientID, Me.FacilityID, Me.ProposalRevision)
Me.Recordset.FindFirst "[AffiliateID] = '" & Me.AffiliateID & "'" & _
" AND [ClientID] = " & Me.ClientID & _
" AND [FacilityID] = " & Me.FacilityID & _
" AND [ProposalRevision] = " & Me.ProposalRevision & _
" AND [EquipmentID] = " & currItemID
I also tried this:
dim currRecord as Long
currRecord = Me.CurrentRecord
' >>> REST OF CODE HERE <<<
Call common.CalculateAllLoadTotals _
(Me, Me.AffiliateID, Me.ClientID, Me.FacilityID, Me.ProposalRevision)
Me.Form.Recordset.Move = currRecord
As I said, the code works (either one) IF I pause it with a debug then continue executing. Strange.
Sorry that's will not be a complete answer but it is quite lot for a comment.
Regarding your first solution - I'd advise you to try Me.Recordset.Requery
to refresh current record in the main form without moving position.
Regarding you 2nd option - I'd advise to have a look at bookmarks - before update remember bookmark, make some calculations and then move position to the saved bookmark. Something like this -
Dim rs As DAO.Recordset
Set rs = Me.RecordsetClone
rs.FindFirst "[MyPK]=" & Me!cmbFindByPK
If Not rs.NoMatch Then
If Me.Dirty Then
Me.Dirty = False
End If
Me.Bookmark = rs.Bookmark
End If
Set rs = Nothing
taken from here Why clone an MS-Access recordset?
I suspect you are updating the recordset underlying the parent form. This causes the parent form to automatically requery, hence the subform position returning to the first record.
The solution is to update the controls on the parent form instead:
Me.Parent!Controlname = XXXX

Help with protection agains SQL-injection

I need some help regarding SQL-injection. Ive been reading about it, but still don’t understand how to protect myself against it.
I have a simple Access database with a table (“course”) containing names and dates among other things. I then have a old ASP page with a search form. Below the search form I have a div (“schema”) that I want to populate with the search result through AJAX. Everything works fine, but is there something I need to do to protect me from an SQL-injection? Here is a simplified version of my code:
ASP Searchpage with AJAX and form (index.asp)
$("#search").keyup(function() {
var varSearch;
varSearch = $("#search").attr("value").replace(/\s/g,"+");
$("#schema").load('ajax.asp?q=' + varSearch + '');
});
<input type="text" name="search" id="search" value="Search.." />
<div id=”schema”></div>
ASP resultpage (ajax.asp):
q = request.querystring("q")
SQL = "SELECT * FROM course WHERE startDate >= #" & Now & "# AND (courseName like '%" & q & "%');"
While Not dbRS.EOF
str courseName = dbRS("courseName ")
Respone.Write courseName
dbRS.MoveNext
Wend
Any help would be much appreciated. Thanks.
Update:
Here is what I've got so far. This is the whole page. I cant see whats missing. Do I need to do something with the Access database, or is it working straight away?
<!--#include file="includes/adovbs.inc" -->
<%
q = request.querystring("q")
SQL = "SELECT * FROM info WHERE (cNamn Like '%?%');"
Set cn = Server.CreateObject("ADODB.Connection")
set comm = CreateObject("ADODB.Command")
set parameter1 = CreateObject("ADODB.Parameter")
cn.Open ("db.mdb")
Set cn.ActiveConnection = cn
parameter1.Type=adVarChar 'for example
parameter1.Size=25 'for example
parameter1.Direction=adParamInput
parameter1.Value=q
comm.Parameters.Append parameter1
Set recordset = comm.Execute
recordset.Close
cn.Close
Set recordset= Nothing
Set comm = Nothing
Set cn = Nothing
%>
The error I get right now is "[Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified" on the line "cn.Open ("db.mdb")". I've tried with "cn.Open server.mappath("db.mdb")" but the error I get then is "[Microsoft][ODBC Driver Manager] Data source name too long"
SQL injection occurs when you do what you have there: taking user input and directly putting it into a SQL command. Someone with malicious intent could try and submit text that would append additional SQL statements to the one you are trying to run.
The first line of defense would be to try and parse for characters that would allow injection. For example, someone adding a single quote ( ' ) would end your string in the SQL statement, and allow them to try and begin a new statement. If you run your q variable through a parse function you can try and prevent that. Replacing one single-quote with two single-quotes will pass the single-quote through as intended by the user, and prevent SQL injection from someone malicious.
Additionally, you are better served by using stored procedures and parameters if you can.
The danger is in allowing the q variable to be processed by SQL as an instruction.
you can protect yourself by doing:
q = request.querystring("q")
SQL = "SELECT * FROM course WHERE startDate >= #?# AND (courseName like '%?%');"
ConnStr = "driver=Microsoft Access Driver (*.mdb);uid=;dbq=" & Server.MapPath ("db.mdb")
Set cn = Server.CreateObject("ADODB.Connection")
set comm = CreateObject("ADODB.Command")
set parameter1 = CreateObject("ADODB.Parameter")
set parameter2 = CreateObject("ADODB.Parameter")
cn.Open ConnStr
Set comm.ActiveConnection = cn
comm.CommandText = SQL
parameter1.Type=adVarChar 'for example
parameter1.Size=25 'for example
parameter1.Direction=adParamInput
parameter1.Value=value1
parameter2.Type=adVarChar 'for example
parameter2.Size=25 'for example
parameter2.Direction=adParamInput
parameter2.Value=value2
comm.Parameters.Append parameter1
comm.Parameters.Append parameter2
Set recordset = comm.Execute
...you ASP code here...
'when your done dont forget to clean up the resources
recorderset.Close
cn.Close
Set recordset= Nothing
Set comm = Nothing
Set cn = Nothing
Also, if you know a parameter is going to be a number , or a date, checking that it is indeed so , is good protection too.

Is it possible to submit data into a SQL database, wait for that to finish, and then return the ID generated from SQL, using Classic ASP?

I have an ASP form that needs to submit data to two different systems. First the data needs to go into an MS SQL database, which will get an ID. I then need to submit all that form data to an external system, along with that ID.
Pretty much everything in the code works just fine, the data goes into the database, and the data will go to the external system. The problem is I am not getting my ID back from SQL when I execute that query. I am under the impression this is happening because of how fast everything occurs in the code. The database is adding it's row at the same time my post page runs it's query to get the ID back, I think.
I need to know of a way to wait until SQL finished the insert or wait for a specific amount of time maybe. I already tried using the hacks to "sleep" with ASP, that did not help.
I am sure I could accomplish this in .Net, my background is more .Net than ASP, but this is what I have to work with on my current project.
Any ideas?
EDIT: Code from the the function writing to the DB.
driis - That was my understanding of how this should be working, but my follow up query for the ID returns nothing, so my though is that the row hasn't finished being inserted or updated yet. Maybe I am wrong on that, if so, that complicates this more. :(
Either way here is the code from the function to update the DB. Mind you this code is inherited, the rest of my project is being written by me, but I am stuck using these functions from a previous developer.
Sub DBWriteResult
Dim connLeads
Dim sSQL
Dim rsUser
Dim sErrorMsg
Dim sLeads_Connection
' Connect to the Leads database
' -------------------------------------------------------------------
sLeads_Connection = strDatabaseConnection
Set connLeads = CreateObject("ADODB.Connection")
connLeads.Provider = "SQLOLEDB.1"
On Error Resume Next
connLeads.Open sLeads_Connection
If Err.number <> 0 Then
' Bad connection display error
' -----------------------------------------------------------------
Response.Write "Database Write Error: 001 Contact Programmer"
Set connLeads = Nothing
Exit Sub
Else
' Verify the transaction does not already exist.
' -----------------------------------------------------------------------
Set rsUser = Server.CreateObject("ADODB.Recordset")
rsUser.LockType = 3
rsUser.CursorLocation = 3
sSQL = "SELECT * "
sSQL = sSQL & " FROM Leads;"
rsUser.Open sSQL, connLeads, adOpenDynamic
Response.Write Err.Description
If Err.number = 0 Then
' Add the record
' -----------------------------------------------------------
rsUser.AddNew
rsUser.Fields("LeadDate") = Date()&" "&Time()
rsUser.Fields("StageNum") = ESM_StageNum
rsUser.Fields("MarketingVendor") = ESMSourceData
rsUser.Fields("FirstName") = ESM_FirstName
rsUser.Fields("Prev_LName") = Request.Form ("Prev_LName")
rsUser.Fields("LastName") = ESM_LastName
rsUser.Fields("ProgramType") = ESM_ProgramType
rsUser.Fields("ProgramofInterest") = ESM_ProgramofInterest
rsUser.Fields("Phone1") = Phonenumber
rsUser.Fields("Phone2") = ESM_Phonenumber2
rsUser.Fields("Address1") = ESM_Address
rsUser.Fields("Address2") = ESM_Address2
rsUser.Fields("City") = ESM_City
rsUser.Fields("State") = ESM_State
rsUser.Fields("Region") = ESM_Region
rsUser.Fields("Zip") = ESM_Zip
rsUser.Fields("Country") = ESM_Country
rsUser.Fields("Email") = ESM_Email
rsUser.Fields("MilitaryBranch") = ESM_MilitaryBranch
rsUser.Fields("MilitaryStatus") = ESM_MilitaryStatus
rsUser.Fields("BestTimeToCall") = ESM_BestTimeToCall
rsUser.Fields("DateofBirth") = ESM_DateofBirth
rsUser.Update
Else
' There was an error
Response.Write "There was an error. Error code is: "&Err.number&" "&Err.Desc
End if
End If
' Close the recordset
' ---------------------------------------------------------------
Call rsUser.Close
Set rsUser.ActiveConnection = Nothing
Set rsUser = Nothing
' Destroy the connection to the database
' -------------------------------------------------------------------
Set connLeads = Nothing
End Sub
It sounds like you're trying to do this:
Insert some data in DB 1
Retrieve an ID from the inserted data
Send data + the ID to DB 2
It's been a good five years but I believe it looked something like this:
dim connStr1
connStr1 = "[connection string 1]"
dim conn1
set conn1 = server.createobject("adodb.connection")
conn1.open connStr1
dim sql
sql = " SET NOCOUNT ON " & vbCrLf & _
" INSERT FOO (a, b, c) VALUES (1, 2, 3) " & vbCrLf & _
" SET NOCOUNT OFF " & vbCrLf & _
" SELECT SCOPE_IDENTITY() "
dim rs
set rs = conn1.execute(sql)
rs.close
dim id
set id = CInt(rs(0))
conn1.close
dim connStr2
connStr2 = "[connection string 2]"
dim conn2
set conn2 = server.createobject("adodb.connection")
conn2.open connStr2
conn2.execute("INSERT FOO (id, a, b, c) VALUES (" & id & ", 1, 2, 3)")
conn2.close
Good luck, and get off my lawn!
Ok, so I figured this one out. The problem was insane, a typo. I am spoiled with .Net and the fact that if I use a variable that doesn't really exist, I get errors. I guess ASP doesn't care so much.
On the up side, driis was correct. The code does not continue until the database transaction is completed. That was my major concern, that had incorrectly assumed that was the case. I am glad I was right.
Thanks for the help, and hopefully the next time I post it'll be something better than a tyop.
;)