classic asp recordset permissions problem - sql-server

I'm trying to return values of a specific column using the below sql string, If I change it out to sql = "select * from a_page" and objRS("P_description") it returns the values but for some reason my page will not load when using the below code.
UPDATE: I turned off on error resume next and the error I'm receiving is select permission denied. How would I give myself permissions with the code below?
SQL = "select P_Name as P_Name, P_Description as P_Description from L_PagePermission inner join A_Permission on p_permissionID = pp_PermissionID inner join A_Page on P_PageID = PP_PageID where P_PageID = 84 order by p_Name"
Page_ID = 84
connectionstring = obj_ADO.getconnectionstring
Set objCon = CreateObject("ADODB.Connection")
Set objRS = CreateObject("ADODB.Recordset")
objCon.Open connectionstring
SQL = "select P_Name as P_Name, P_Description as P_Description from L_PagePermission inner join A_Permission on p_permissionID = pp_PermissionID inner join A_Page on P_PageID = PP_PageID where P_PageID = 84 order by p_Name"
objRS.open SQL, objCon
objRS.MoveFirst
while not objRS.EOF
response.Write objRS("P_Name")
objRS.MoveNext
wend
objRS.close
objCon.close

The error you get plus the code you mentioned that is working means one thing: on either L_PagePermission table or A_Permission (or both) the user passed in the connection string has no Read permissions.
To solve this, you have to either pass "stronger" user in the connection string, or grant Read permissions to the user over those tables via something like SQL Management Studio.
By the way, you can't "grant yourself permissions" through code due to obvious security reasons - permissions exist to prevent code from doing certain things in the first place.

Related

ADO Parameterized Queries with Subqueries Error

I have a legacy classic ASP application running with SQL Server 2012 (also tested with 2016) that I am trying to switch over to using parameterized queries. All the site's queries run through a function which expects a sql statement as a string with parameters represented by question marks as well as an array of those parameters. The function currently filters the parameters to make them sql safe and puts them into the sql string before executing the statement.
Given this, I thought it would be pretty straightforward to switch this to parameterized queries. Initial testing looked good, and everything appeared to be working properly until I hit a sql statement with parameters in subqueries.
Here's a test sample of what works:
Const connectionString = "Provider=SQLNCLI11; DataTypeCompatibility=80; Server=********; Database=********; UID=*******; PWD=*******"
Dim sql, productId, parameters
sql = "SELECT SKU FROM Products WHERE ProductId = ?"
productId = 3
parameters = Array(productId)
Dim conn
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open connectionString
Dim cmd
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandText = sql
cmd.Parameters.Refresh
Dim rs
Set rs = cmd.Execute(, parameters)
Response.Write("SKU: " & rs("SKU"))
No problem, this returns the SKU as expected. However, if I use a subquery:
Const connectionString = "Provider=SQLNCLI11; DataTypeCompatibility=80; Server=********; Database=********; UID=*******; PWD=*******"
Dim sql, productId, parameters
sql = "SELECT SKU FROM ( SELECT SKU FROM Products WHERE ProductId = ? ) AS P"
productId = 3
parameters = Array(productId)
Dim conn
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open connectionString
Dim cmd
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandText = sql
cmd.Parameters.Refresh
Dim rs
Set rs = cmd.Execute(, parameters)
Response.Write("SKU: " & rs("SKU"))
It throws an error on the cmd.Parameters.Refresh line:
Microsoft VBScript runtime error '0x80004005'
Microsoft SQL Server Native Client 11.0
Syntax error, permission violation, or other nonspecific error
If I check cmd.Parameters.Count in the first sample, I correctly get 1. In the bad sample it throws the same error.
Is there any explanation as to why putting the parameter into a subquery causes problems with the parameter collection? I did try manually adding the parameter to the Parameters collection, and that works fine, but it means modifying hundreds of existing sql calls, so for the moment the cmd.Parameters.Refresh round-trip was worth the expense.
For anyone who might stumble across this, I finally figured out the issue thanks to a co-worker. It turns out there is nothing wrong with the code, but rather with the connection string. I somehow left it out of the sample code, but my connection strings included "DataTypeCompatability=80". If that is present, the code throws the error. However, if I remove it, the error no longer occurs and I get the results back as suspected.
My understanding from this KB article on using ADO with the native client is that DataTypeCompatability should be included to ensure newer data types work properly, but so far I have not found any issues with removing it.
You can give cmd.execute what you want, but I haven't used it in a long time.
cmd.execute("SELECT SKU FROM ( SELECT SKU FROM Products WHERE ProductId = ? ) AS P", Array(productId))

MS Access - SQL Server Login Prompt won't go away

So I have this application and I moved all local tables to SQL Server using upsizing, now they are currently linked tables. I'm able to access tables and forms related to tables can be accessed with no problems. But when I programmatically fetch a record, or perform a sql operation in VBA script, a SQL Server Login prompt pops up asking me to enter in the SQL Authentication login to access the database.
I followed this link here:
https://support.microsoft.com/en-us/kb/177594
Where this is my end code:
Dim db1 As Database
Dim db2 As Database
Dim rs As Recordset
Dim strConnect As String
Set db1 = OpenDatabase("C:\Workspace\ms1.mdb")
strConnect = UCase(db1.TableDefs("dbo_TableA").Connect) & ";UID=User1;PWD=Password1"
Set db2 = OpenDatabase("", False, False, strConnect)
db2.Close
Set db2 = Nothing
Set rs = db1.OpenRecordset("dbo_TableA")
rs.Close
db1.Close
Set rs = Nothing
Set db1 = Nothing
DoCmd.RunCommand acCmdSaveRecord
'Sql Server login prompt pops up after running the below code;'
If DCount("*", "TableA", "[ColA] = [forms]![FRM_LOGS]![USER]") = 0 Then
MsgBox "User ID not found - contact HelpDesk", vbCritical
DoCmd.Quit
Exit Sub
End If
The DCount is triggering the SQL Server Login Prompt. I need this prompt to go away. If I open up a form, query, report, anything where the access object is bound to the data, I get no message. It ONLY happens in VBA when I'm trying to access the data object.
Edit! I did find the culprit. I deleted the linked table to the TableA in sql server, and I relinked it again, and clicked the Save password checkbox. I did this before, and it didn't work. Did it again, and it fixed everything. Not sure why this didn't work the first time. I marked the below as an answer because that did solve the problem given the circumstances.
Not sure what you're doing here with two database connections and using DCOUNT on an internal table?
It looks like your database connection has linked tables that have stored passwords
Why not just use your recordset that works to check for a valid user?
Set db1 = OpenDatabase("C:\Workspace\ms1.mdb")
Set rs = db1.OpenRecordset("SELECT [ColA] FROM [dbo_TableA] WHERE [ColA] = """ & [forms]![FRM_LOGS]![USER] & """")
if rs.EOF Then
MsgBox "User ID not found - contact HelpDesk", vbCritical
DoCmd.Quit
Exit Sub
End If
rs.Close
db1.Close
Set rs = Nothing
Set db1 = Nothing

Running 'SET' command in SQL, prior to SELECT

Following this question, I need to add something like
SET LANGUAGE German;
before my SELECT query.
I am running the query in an ASP/VBScript web environment, which basically limits me, as far as I know, to a single query at a time.
If I run a query such as -
SET LANGUAGE German; SELECT.....
I get a no results message, because the 'data' returned is from the SET query and not the SELECT that follows it.
Is there anything that can be done to run the SET and the SELECT together in the ASP/VBScript environment?
UPDATE:
As per Lankymarts suggestion:
set rs = SERVER.CreateObject("ADODB.recordset")
rs.open sql, conn, 1, 2
Do While (rs.State = 0 Or rs Is Not Nothing) // also tried: Do While (rs.State = 0 AND rs Is Not Nothing)
Set rs = rs.NextRecordset
Loop
do while not rs.eof
response.write ...
UPDATE 2:
Now that the closed recordset issue is solved, I am still not getting rows from the main recordset.
This is my VBScript code, below.
There are definitely results (because 21/feb/16 - was on Sunday, and i have matching records for this) - but they are not being displayed. In fact even displaying via SSMS sometimes i dont get the results - maybe its getting all confused with the language changes?
sql = " SET LANGUAGE German; "
sql = sql & " SELECT [tblstudentrakazot].studentid, firstname, lastname, tblRakezetSchedule.* FROM tblRakezetSchedule"
sql = sql & " INNER join [tblstudentrakazot] on [tblstudentrakazot].scheduleID = tblRakezetSchedule.scheduleid "
sql = sql & " INNER join tblstudents on [tblstudentrakazot].studentid = tblstudents.studentid"
sql = sql & " WHERE CONVERT(int,scheduleday) = datepart(d,convert(datetime,'" & cleanSQL(planneddate) & "',103)) AND "
sql = sql & " tblRakezetSchedule.rakezetID = " & CleanSQL(x_rakezetID)
sql = sql & " ORDER BY replace(scheduletimefrom, ':', '')"
response.Write("### " & sql)
set rs = SERVER.CreateObject("ADODB.recordset")
rs.open sql, conn, 1, 2
Do While rs.State = 0 And Not rs Is Nothing
Set rs = rs.NextRecordset
loop
do while not rs.eof
' we now proceed to loop through the actual result recordset : studentid, firstname etc...
By the way - does the language remain in German after the query has run, or does it return to its default language?
I guess what i need here is a language setting whose default is dd/mm/yyyy (because of other legacy requirements in the system) and one that the DATEFIRST is Sunday (1).
ALSO:
I tried to make a stored procedure, as such:
ALTER PROCEDURE [dbo].[procListRakezetSlotsByDay] #planneddate nvarchar(10), #rakezetID int
AS
BEGIN
SET NOCOUNT ON;
SET LANGUAGE German;
SELECT [tblstudentrakazot].studentid, firstname, lastname, tblRakezetSchedule.* FROM tblRakezetSchedule
INNER join [tblstudentrakazot] on [tblstudentrakazot].scheduleID = tblRakezetSchedule.scheduleid
INNER join tblstudents on [tblstudentrakazot].studentid = tblstudents.studentid
WHERE CONVERT(int,scheduleday) = datepart(d,convert(datetime,#planneddate,103)) AND tblRakezetSchedule.rakezetID = #rakezetID
ORDER BY replace(scheduletimefrom, ':', '')
END
and then run it:
DECLARE #return_value int
EXEC #return_value = [dbo].[procListRakezetSlotsByDay]
#planneddate = N'28/2/2016',
#rakezetID = 182
SELECT 'Return Value' = #return_value
GO
and here too, it returns no results - even within SSMS...
I am VERY confused. thanks to all who have helped so far.
This is a misconception. Neither ASP/VBScript limits you, the limit is imposed by the provider ADODB uses to perform the command. In terms of SQL Server though there is no limit (I know of) when executing a command that contains multiple queries.
First
SET LANGUAGE German;
isn't really a returning query but the Provider will return it as a closed ADODB.Recordset object, which isn't ideal but there is a simple fix.
SET NOCOUNT ON;
Will inhibit DONE_IN_PROC messages from being sent to say the executing line was successful which is interpreted by ADODB as a closed ADODB.Recordset object.
Another way to deal with this but not as straight-forward as SET NOCOUNT ON is to use the NextRecordSet() method of the ADODB.Recordset object to step through the various resultsets until you find the actual query result.
Assuming rs is our starting ADODB.Recordset object
Do While (rs.State = adStateClosed And Not rs Is Nothing)
Set rs = rs.NextRecordset
Loop
will return the first ADODB.Recordset object that isn't in the closed state.
From MSDN - NextRecordset Method (ADO)
As long as there are additional results and the Recordset containing the compound statements is not disconnected or marshaled across process boundaries, the NextRecordset method will continue to return Recordset objects. If a row-returning command executes successfully but returns no records, the returned Recordset object will be open but empty. Test for this case by verifying that the BOF and EOF properties are both True. If a non–row-returning command executes successfully, the returned Recordset object will be closed, which you can verify by testing the State property on the Recordset. When there are no more results, recordset will be set to Nothing.

self-join query on global catalog

I need to retrieve information about an employee (strUser variable stores their sAMAccountName )ID and their manager by querying the global catalog, using classic ASP. This works:
'=========Account and connection string information for LDAP=======
Set objDomain = GetObject ("GC://RootDSE")
objADsPath = objDomain.Get("defaultNamingContext")
Set objDomain = Nothing
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.provider ="ADsDSOObject"
objConn.Properties("User ID") = "..." 'domain account with read access to LDAP
objConn.Properties("Password") = "..." 'domain account password
objConn.Properties("Encrypt Password") = True
objConn.open "Active Directory Provider"
Set objCom = CreateObject("ADODB.Command")
Set objCom.ActiveConnection = objConn
objCom.CommandText ="select name, givenName, sn, distinguishedName, manager, telephonenumber, mobile, mail, company, title, department, sAMAccountName,userAccountControl, msexchhidefromaddresslists FROM 'GC://"+objADsPath+"' where sAMAccountname='"+strUser+"'"
'=======Executre query on LDAP for all accounts=========
Set objRS = objCom.Execute
Now if I'm trying to use an alias for GC e.g.:
FROM 'GC://"+objADsPath+"' AS e
I get into an infinite loop.
What I need is a way to self-join query on global catalog (as e for employee, and m for manager) where e.manager = m.distinguishedName, in other words the relationship for the self-join in that the employee's manager is the manager's distinguished name.
How to do this?
I would also appreciate any hint to documentation.
Many thanks!
Another approach that works is to embed a second query for manager details within the outer query for employee details.
objCom2.CommandText ="select sAMAccountName, name, givenName, sn, distinguishedName, manager FROM 'GC://"+objADsPath+"' where distinguishedName='" + manager + "'"
I would still like to know if GC self-join query is possible or not.

ASP DataConnectivity Error

I am a Student and ASP is my subject this year. I am trying to do the Database Connectivity for the First time. It gave me this Error while i was connecting my ASP file with MSAccess.
Code:
<%
Dim objConn, strConn, objRS
Set objConn = Server.CreateObject("ADODB.Connection")
strConn = "PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE =" & _
"C:\demo.accdb"
objConn.Open strConn
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open "Student", objConn, 2, 2
objRS.AddNew
objRS("idnum") = Request.Form("idnum")
objRS("firstname") = Request.Form("firstname")
objRS("lastname") = Request.Form("lastname")
objRS.Update
objRS.close
%>
**The Above code Gives the Following Error:*
ADODB.Recordset error '800a0cc1'
Item cannot be found in the collection corresponding to the requested name or ordinal.
/MyWeb/choice1.asp, line 12*
.. I also tried doing this..
..
..
Dim objConn, strConn, objRS
Set objConn = Server.CreateObject("ADODB.Connection")
strConn = "DSN=Stud"
objConn.Open strConn
and it gives me the same error.
My Database name is demo.accdb
My Table name is Student.
ApplicationPool Settings for IIS is set to "true" for using Windows 32bit.
I have also installed OLEDB ACE 12.
Please help as am totally in mess.. All I want is to insert a record in an Access Database.
Help would be appreciated.
That error has nothing to do with your connection, setup, IIS settings, or anything esoteric, and everything to do with what columns exist (or rather, don't exist) in the recordset you're opening.
What is in line 12 of your code? (In the snippet you've posted, line 12 is the "lastname" field, but I don't know if that's true for your actual code.) Check the setup of the Student table: did you spell that column name correctly? If the table column is LastN, then your code should have objRS("LastN") = Request.Form("LastName")1, not objRS("LastName").... Thankfully, neither VBScript nor SQL are case-sensitive, so you don't need to be anal, but you do need to spell things correctly.
Note that it may help you "see" what you're doing better if you write an explicit SELECT statement to return just the columns (and rows) you want, instead of opening the entire table. Also, when you're working with actual databases (which tend to have many thousands or even millions of records, rather than the half a dozen you probably have in your test database), opening entire tables is A Very Bad Idea. Well, unless you like timeout errors.
objRS.Open "SELECT TOP 0 id, firstname, lastname FROM Student", objConn, 2, 2
(Since all you're doing is adding a row, you don't actually need to return any records; hence the TOP 0.2)
1 All you "OMG! Your code is vulnerable to SQL injection!!1!" types can insert your customary rant here.
2 It's been a while since I've worked with Access; if it chokes on TOP 0 with no ORDER BY clause, try SELECT ... WHERE 1 = 2.

Resources