a *FUTUREPROOF* Project reference, to connect to SQL Server? - sql-server

Background
i have legacy VB6 code that accesses SQL Server. it produces an error code 0x80004005 when TLS 1.0 is disabled for SQL Server, because the code still uses the provider SQLOLEDB:
[DBNETLIB][ConnectionOpen (SECDoClientHandshake()).]SSL Security
error.
it does not explicitly use TLS, but TLS is always used for credentials according to Microsoft documentation.
Possible Solution
after looking around i have found that Microsoft released the new provider MSOLEDBSQL as a replacement for SQLOLEDB. MSOLEDBSQL supports TLS 1.2 and that will be kept updated, according to their documentation:
https://learn.microsoft.com/en-us/sql/connect/oledb/oledb-driver-for-sql-server?view=sql-server-ver15
https://learn.microsoft.com/en-us/archive/blogs/sqlnativeclient/released-microsoft-ole-db-driver-for-sql-server
i've tested MSOLEDBSQL after installing the drivers, and changing the (ADODB.Connection) connection string from:
c.ConnectionString = "Provider=SQLOLEDB;Data Source=" & svr & ";Initial Catalog=" & db & ";User Id=" & u & ";Password=" & p & ";"
to:
c.ConnectionString = "Provider=MSOLEDBSQL;DataTypeCompatibility=80;Data Source=" & svr & ";Initial Catalog=" & db & ";User Id=" & u & ";Password=" & p & ";"
and this fixes the problem.
Questions
however, i'm not sure, that what i'm doing is futureproof.
is this the provider MSOLEDBSQL indeed future proof, or would you
recommend another one?
should my VB6 project keep referencing ADODB ("msado28.tlb" Microsoft ActiveX Data Objects 2.8 Library), or is there a more
futureproof reference?
for example: would this work with TLS 1.3 in the future?
i would prefer to change as little as possible

MDAC and the VB6 runtime are Windows components, and MSOLEDBSQL is current, and will continue to be maintained. So that is your best combination for running this legacy codebase now and in the future.

Future proofing is a bit of a "Crystal Ball" kind of thing. There's lots we can do in code to make our lives easier, but at the end of the day - when we're using 3rd party libraries - we don't know when a library will be deprecated, what it will support or unsupport.
When it comes to code that we own as developers, we can write abstractions and do our best to be able to be backwards compatible when we suddenly realise there's a better way of doing things (or, in fact, just doing a code-refactor and don't want to break our clients).
With third-party code, this is not practical. At the end of the day, your database connectivity requires a connection string and a provider that supports it. Expect that can possibly change in the future, and your roadmap should be to keep an eye on it. At some point, you'll have to perform an update, as you just have done.

You might consider refactoring the code responsible for establishing the DB connection into its own VB6 DLL. This DLL would manage the connection string, contain the essential references, and would be responsible for establishing the actual connection and returning the correct object.
Set this DLL up with binary compatibility.
In the future should the connection details change, only this single DLL would need to be affected, minimizing retesting & re-deployment.
In addition you could store data like the connection string in a configuration file. In the limited case where only that text would need to be changed, conceivably a user could do that themselves given good instructions. But otherwise I don't think the added complexity of a config file would be worth it; it also creates more pitfalls and points of failure.

Related

Use database with linked tables in Access 2000 or use the ADODB.RecordSet - Which is better?

I am reworking old VB6 apps into VB.NET with Visual Studio 2005 and all of them suffer from the same problems.
One of those is, access the DB2 database by using an Access 2000 file which has links to the tables and second approach is, using ADODB.RecordSet with concatenated string SQL queries directly run on to the database.
I know I can use Linq which is the right tool for the job, but I don't have time to learn it at the moment. I have to finish this job quickly.
Examples:
Function selectNA_FromMyTable_ByNA(ByVal na As String) As String
Dim sql As String = "SELECT na FROM DB2Scheme.MyTable "
sql = sql & "WHERE (na = '" & na & "')"
Return sql
End Function
and
Function selectNA_FromMyTable_ByNA(ByVal na As String) As String
Dim sql As String = "SELECT na FROM DB2Scheme_MyTable "
sql = sql & "WHERE (na = '" & na & "')"
Return sql
End Function
where DB2Scheme_MyTable is link to DB2Scheme.MyTable table.
I don't like mixing approaches although they both work properly.
Which is better approach?
Which approach would be better for debugging? For example, how can I detect that the user using the application does not have privileges to write or read data from a certain table in the scheme?
well certainly eliminating the Access database would be ideal. i assume in the prior model, the Access database also served as the front-end? if you're moving to .net, then i don't see the point in keeping the access database. go directly to the db2 database, just be mindful of the database drivers that may need to be installed when distributing this app. less of a problem if its a web app.
generic error handling in .net should reveal if users have access issues. you may want to check that up front when your application is launched if your application is going to use the users credentials, and not a user id of its own to access the database. I am not sure this should be something of a concern when rewriting the app, are you not using the same authentication, or logon credentials used in the formal app?

How to access SQL Server from VBA in a non-deprecated way?

It appears that all ways to directly access an SQL Server database from a VBA project have been deprecated:
DAO with ODBCDirect: Support has been dropped with Access 2007.
DAO via JET: You're not serious, right? Anyway, it's considered obsolete by Microsoft.
ADO with the SQLOLEDB provider: Deprecated.
ADO with the SQL Server Native OLEDB provider: Won't be supported after SQL Sever 2012.
ADO with the Microsoft OLE DB provider for ODBC: Not supported: "SQL Server Native Client is not supported from the Microsoft OLE DB provider for ODBC (MSDASQL)."
What did I miss? What is the official, Microsoft-approved way to access an SQL Server database from VBA (which is, after all, not deprecated and still the official development language included with Office 2013)?
What did I miss?
Plain old ODBC. In VBA projects for Office applications other than Access, ODBC via ADO is the most straightforward:
Sub AdoOdbcExample()
Dim con As Object
Set con = CreateObject("ADODB.Connection")
con.Open _
"Driver={SQL Server Native Client 11.0};" & _
"Server=.\SQLEXPRESS;" & _
"Database=myDb;" & _
"Trusted_Connection=yes;"
con.Execute "UPDATE Clients SET FirstName='Gord' WHERE ID=5;"
con.Close
Set con = Nothing
End Sub
For VBA projects in Access, we also have the option to use ODBC linked tables and pass-through queries via ACE DAO like we always have
Sub DaoOdbcExample()
Dim cdb As DAO.Database, qdf As DAO.QueryDef
Set cdb = CurrentDb
Set qdf = cdb.CreateQueryDef("")
qdf.Connect = "ODBC;" & _
"Driver={SQL Server Native Client 11.0};" & _
"Server=.\SQLEXPRESS;" & _
"Database=myDb;" & _
"Trusted_Connection=yes;"
qdf.sql = "UPDATE Clients SET FirstName='Gord' WHERE ID=5;"
qdf.ReturnsRecords = False
qdf.Execute dbFailOnError
Set qdf = Nothing
Set cdb = Nothing
End Sub
Notes:
SQL Server Native Client 11.0 is the version that ships with SQL Server 2014 (ref: here).
The cited list of Obsolete Data Access Technologies says "DAO 3.6 is the final version of this technology. It will not be available on the 64-bit Windows operating system.". That refers to Jet DAO ("Microsoft DAO 3.6 Object Library"). ACE DAO ("Microsoft Office 14.0 Access database engine Object Library") is indeed available to 64-bit applications if the 64-bit version of the Access Database Engine is installed.
The correct and future way is to use the ACE object model. You are 100% correct that native oleDB is being dropped from SQL server. It ALSO very important to note that the “general” developer community started dropping ADO when .net came out (the ado.net provider is a VERY different beast and one not reliant on oleDB, but the sqlprovider).
So because of this, significant trends are occurring in our industry.
We are moving away from oleDB. This is in general a Windows-only technology. With the rise of iPads, smartphones, Android etc, then you don’t have such platform specific providers and they don't have oleDB. You thus have to revert back TOWARDS using Open Database Connectivity standards (ODBC). Oracle, Microsoft, MySQL have all stated this is the future road and choice.
While JET is considered obsolete, ACE is not.
SINCE Access 2007 (that is now fully 3 versions), you DO NOT and SHOULD NOT have a reference to DAO. So for the last 3 versions of Access you don’t need nor want or use a reference to the DAO object library.
You now should use the new built in ACE database engine. This means you do NOT need a separate reference to DAO.
There are several advantages to the ACE engine:
You don’t need a DAO reference anymore.
Once reference to the data engine takes care of previous two library references.
There is both an x32 and x64 bit edition available (so .net applications etc. can use an x64 bit edition of this data engine). JET was x32 bit only.
The ACE provider continues to receive updates and enhancements. The same cannot be said for JET or in fact much for ADO either.
ACE now supports store procedures and table triggers. It also has support for SharePoint lists which is web services based.
Also changes were made to Access/ACE to work with SQL Azure.
For using Access with SQL server, you simply use ACE and linked tables. As noted the trend away from ADO MUCH started about 13 years ago when .net came on the scene.
Thus the standard approach and recommend now is ACE + odbc.
So you not missed anything here. The confusion stems much from article that state JET is deprecated but THEN leaves out the VERY important detail that Access for THE LAST 3 versions now does NOT use JET, but uses a new library called ACE.
It is SIGNIFICANT that you don’t need nor want a reference to DAO in your Access applications anymore.
You are certainly using a compatible DAO library, and it still even recommend that you prefix your reocrdset code with DAO (so older existing code will work just fine when if you done this in the past, or you always left out the DAO qualifier when declaring recordsets.
And for things like sql passthrough, you simple can use a saved passthrough query, and do this:
CurrentDb.QueryDefs("MyPass").Execute
or how about some t-sql, you can do this:
With CurrentDb.QueryDefs("MyPass")
.SQL = "ALTER TABLE Contacts ADD MiddleName nvarchar(50) NULL"
.Execute
End If
or call a store procedure of your choice "on the fly" with a parameter
With CurrentDb.QueryDefs("MyPass")
.SQL = "Exec MyStoreProc " & strMyParm1
.Execute
End If
Are not the above so nice and clean? As noted the above code examples tend to be FAR less code and hassle then using oleDB/ADO examples posted.
For the long time users of Access that developed their skills around ODBC and sql server, you don’t have to do anything as the industry much decided what you been doing all along is the recommend approach.
While JET-DIRECT is not supported in ACE, I cannot think of any case when this choice is missed by using the passthrough querydef examples as per above in place of JET direct.
When initializing an adodb.connection in vba we replaced
.Provider = "sqloledb"
.Properties("Data Source").Value = sServer
.Properties("Initial Catalog").Value = sDB
.Properties("Integrated Security").Value = "SSPI"
with
.ConnectionString = _
"DRIVER={ODBC Driver 11 for SQL Server}; " & _
"SERVER=" & sServer & "; " & _
"Trusted_Connection=Yes; " & _
"DATABASE=" & sDB & "; "
That uses .Provider = "MSDASQL.1" but you don't have to add that.

Connectionstring not connecting in Visual Studios

I recently started working with Visual Studios and to get some practice with its conventions, I'm trying to design a simple application that connects to a database file - in this case, just the Northwind.accdb sample that came along Microsoft Access - and transfers some selected information to an XML file.
I have the bulwark of the code written out to perform the task, but whenever I try to execute it, the program throws some exception that reads, "Could not find installable ISAM." I researched this error for quite a while, and after downloading the MS Access redistributable to no avail, I'm almost sure the problem lies with my connection string:
strDataPath = My.Computer.FileSystem.GetParentPath("Northwind.accdb")
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Driver={Microsoft Access Driver (*.mdb, *.accdb)}; Data Source=" + strDataPath + ";Persist Security Info=False;"
I've tried writing this out maybe a dozen different ways with all sorts of different attributes, but no matter what I try I always end up with the same error message(even though it compiles just fine). What syntax do I need to get this connection string working? Or could there be another source of error somewher ein my code?
Try this:
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" + strDataPath + ";Persist Security Info=False;"
The Driver portion of your connection string is used in ODBC connection strings. Don't need it in OleDB connection strings.

Error deploying my visual studio project in another computer

I had a deployed visual project 2010 connected to sql and I had installed it in another computer but the database can't connect to the final project. I want to install it in other computers that will be connected to database. I think I have a problem in my connection:
Dim con As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;" & _
"Initial Catalog=enrollment")
The information provided at this link will provide you with a good idea of how to manage connection strings in VS. The problem with your SqlConnection object is that your data source is still listed as 'localhost'. You need to change this to point to the location of your database.
Ideally the application should have a user friendly way of specifiying the settings for the connection, this will make connecting from different locations far easier and makes your application more portable.
I think this example here will help you

How do I get ms-access to connect to ms-sql as a different user?

How do I get ms-access to connect (through ODBC) to an ms-sql database as a different user than their Active Directory ID?
I don't want to specify an account in the ODBC connection, I want to do it on the ms-access side to hide it from my users. Doing it in the ODBC connection would put me right back in to the original situation I'm trying to avoid.
Yes, this relates to a previous question: http://www.stackoverflow.com/questions/50164/
I think you can get this to work the way you want it to if you use an "ODBC DSN-LESS connection"
If you need to, keep your ODBC DSN's on your users' machines using windows authentication. Give your users read-only access to your database. (If they create a new mdb file and link the tables they'll only be able to read the data.)
Create a SQL Login which has read/write permission to your database.
Write a VBA routine which loops over your linked tables and resets the connection to use you SQL Login but be sure to use the "DSN-Less" syntax.
"ODBC;Driver={SQL Native Client};" &
"Server=MyServerName;" & _
"Database=myDatabaseName;" & _
"Uid=myUsername;" & _
"Pwd=myPassword"
Call this routine as part of your startup code.
A couple of notes about this approach:
Access seems to have an issue with the connection info once you change from Read/Write to Read Only and try going back to Read/Write without closing and re-opening the database (mde/mdb) file. If you can change this once at startup to Read/Write and not change it during the session this solution should work.
By using a DSN - Less connection you are able to hide the credentials from the user in code (assuming you're giving them an mde file you should be ok). Normally hard-coding connection strings isn't a good idea, but since you're dealing with an in-house app you should be ok with this approach.
I think you'd have to launch the MS Access process under the account you want to use to connect. There are various tools that let you do this, such as CPAU. This tool will let you encrypt the password as well.
We admit here that you are using an ODBC connexion to your database with Integrated Security on, so that you do not have/do not want to write a username/pasword value in the connexion string (which is according to me the right choice).
In this case, there is fortunately no way to "simulate" another user when connecting to the data. Admit with me that being able to make such a thing would be a huge break in integrated security!
I understood from your previous post that you wanted users to be able to update the data or not depending on the client interface they use. According to me, the idea would be to create for each table a linked 'not updatable' view. Let's say that for each table called Table_Blablabla you create a view (=query in Access) called View_Table_Blablabla ...).
When using Access, you can then decide at runtime wether you want to open the updatable table or the read-only view. This can be done for example at runtime, in the form_Open event, by setting the form recordsource either to the table or the view.
#Philippe
I assume that you are using the word admit as being roughly equivalent to understand or perhaps agree; as opposed to the opposite of deny.
I understand the implications of having all the users login to the database using one ID and password (and having them stored in the application). That to me is a smaller risk than the problem I'm facing right now.
#off
Some more background to the problem:
I have ODBC connections set up on each of the users workstations using Windwos NT authentication. Most of the time the users connect using an MDE setup to use that ODBC connection - in this case they ALWAYS have the ability to add/update/delete data.
The problem comes that some of the users are educated enough about MS-Access to create a new mdb and link it to the MS-SQL server. They can then edit the data right within the tables rather than going through the application which does a certain amount of validation and hand holding. And they like doing this, but sometimes the mess it up and cause me problems.
What I was hoping to do (which I just experimented with) was to refresh the links to the database something like this for each table (Note: I've switched the ODCB connection to SQL Server authentication for this experiment, and added the accounts to the SQL server as well: readonly - which can't to any updates, and readwrite - which has full privileges on the table).
myTable.Connect = _
"ODBC;" & _
"DATABASE=" & "MyTestDB" & ";" & _
"UID=readonly;" & _
"PWD=readonly_password;" & _
"DSN=" & "MyTestDB" & ";"
myTable.RefreshLink
this stops them from editing, but I can't get a later readwrite to work
myTable.Connect = _
"ODBC;" & _
"DATABASE=" & "MyTestDB" & ";" & _
"UID=readwrite;" & _
"PWD=readwrite_password;" & _
"DSN=" & "MyTestDB" & ";"
myTable.RefreshLink
It seems that whichever permission I connect with first, sticks permenantly. If I started readwrite and then go to readonly, the table remains with the readwrite privileges
Why not use integrated/windows security. You can grant an active directory group the rights you want the users and then add the users accounts to that group. I believe you can also use sql server's roles feature in addition to this to limit functionality based on the client application being used.

Resources