In our VB6 application, we use ADODB.Recordsets and make use of the Data provider for MSDataShape to create a relational recordset with SHAPE commands.
In the latest Windows 10 Feature (1809) our code breaks with the following error: -
"-2147217900 Length of NEW column SiteCode cannot be zero"
from the following macro in excel (where MDAC is a reference)
Public Sub TestRun()
Dim rsStockCheck As Recordset
On Error GoTo ErrorHandler
' set up shape recordset
Set rsStockCheck = New Recordset
With rsStockCheck
.ActiveConnection = "Provider=MSDataShape;Data Provider=None"
.CursorLocation = adUseClient
.CursorType = adOpenStatic
.LockType = adLockBatchOptimistic
.Open "SHAPE APPEND new adInteger as StockCheckID, new adInteger as SiteID, new adVarChar(8) as SiteCode"
.ActiveConnection = Nothing
End With
ErrorHandler:
If Err.Number <> 0 Then
MsgBox "failed: " & Err.Description
Else
MsgBox "works ok"
End If
Set rsStockCheck = Nothing
End Sub
This might be related to this being eventually removed as mentioned here.
... but I'm not sure if it is just yet. Has anyone come across this problem?
EDIT: I've tried this on an upgraded machine and Fresh install of 1809 and it's broken on both.
EDIT 2: List of other forum threads regarding this issue:
Microsoft "Data Platform Development > ADO.NET DataSet" forum
(Reported by someone else, and it affects Server 2019 too)
Microsoft "Windows Desktop Development > General Windows Desktop Development Issues" forum
Microsoft "Windows 10 IT Pro > Windows 10 Insider Preview Builds" forum
Microsoft " Windows Server Windows > Server Insiders" forum
EDIT 3: Latest Nov 13 update for Windows 1809, still does not fix this issue. For a workaround however, read this.
Same problem with me ... However, I have found the workaround for this issue ...
Replacing adVarChar(##) with adLongVarChar does the job for me ...
Please reply, if anyone has another solution
Edited:
This workaround is not applicable to queries like
SHAPE APPEND NEW adLongVarChar As INVNO, NEW adLongVarChar As iCP,
((SHAPE APPEND NEW aadLongVarChar As INVNO,NEW adLongVarCharAs iCP,NEW adLongVarChar As F1,NEW adLongVarChar As F2,NEW adLongVarChar As F3)
AS Trans RELATE INVNO TO INVNO,iCP TO iCP)
Finding a solution to get out of this issue
EDIT : This error has been fixed in recent windows update (Version: 1809 OS Build : 17763.475). Everything working fine for me.
I've found a solution that works in all scenarios.
Instead of adVarChar(size) use the OLEDB datatype DBTYPE_BSTR. For example, instead:
SHAPE APPEND NEW adVarChar(8) As INVNO, NEW adVarChar(8) As iCP,
((SHAPE APPEND NEW adVarChar(8) As INVNO,NEW adVarChar(8) As iCP...)
AS Trans RELATE INVNO TO INVNO,iCP TO iCP)
write:
SHAPE APPEND NEW DBTYPE_BSTR As INVNO, NEW DBTYPE_BSTR As iCP,
((SHAPE APPEND NEW DBTYPE_BSTR As INVNO,NEW DBTYPE_BSTR As iCP...)
AS Trans RELATE INVNO TO INVNO,iCP TO iCP)
Notes:
DBTYPE_BSTR doesn't accept the size of the field, so it's not exactly a varchar
I had to use DBTYPE_BSTR keyword, using adBSTR produced an error message in the command (?!).
While this doesn't directly answer your question, MSDataShape is obsolete and being removed.
Suggest that you port your queries to FROM XML and change your client to parse the response using SAX or a pull parser.
It seems changing SHAPE APPEND new adVarChar(8) as SiteCode to
SHAPE APPEND new adLongVarChar as SiteCode causes that SiteCode can not be a sort key.
However it seems SiteCode_Calc of SHAPE APPEND new adLongVarChar as SiteCode,calc(Left$(SiteCode,8)) as SiteCode_Calc can be a sort key.
However it seems MoveNext/EOF won't work correctly when the value of SiteCode_Calc is gotten.
As #Shrikant has mentioned, this was fixed in a recent windows update (Version: 1809 OS Build : 17763.475) and also confirm it's fixed in 1903.
Related
Dim cat As New Catalog()
Dim con As New OleDbConnection()
Dim cmd As New OleDbCommand
Dim ds1 As New DataSet
Dim conn As ADODB.Connection
' Open the Access database.
conn = New Connection
conn.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;" &
"Data Source=" + openExcel + "\Test" + ".mdb; Persist Security Info=False"
con.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;" &
"Data Source=" + openExcel + "\Test" + ".mdb; Persist Security Info=False"
conn.Open()
xlWorkSheet1.Columns(5).Insert
Dim cellValue As String = ""
Dim newValue As String = ""
Dim sh1 As String = ""
Dim qty As String = ""
Dim matchText As String = ""
Dim sql As String = ""
con.Open()
sh1 = LTrim$(xlWorkSheet1.Cells(i, 1).Text)
sql = "SELECT Num_ber, Q_ty FROM good WHERE Na_me LIKE 'staff%' And Ty_pe = 'ORD'"
Dim cmd As New OleDbCommand(sql, con)
Dim myReader As OleDbDataReader = cmd.ExecuteReader()
conn.Execute(sql)
myReader = cmd.ExecuteReader() ' HERE'S THE PROBLEM
xlWorkSheet1.Cells(1, 5) = myReader.GetString(0)
xlWorkSheet1.Cells(1, 11) = myReader.GetString(1)
myReader.Close()
conn.Close()
conn = Nothing
**I wanted to retrieve a specific value from mdb and then write it to excel.
Here's my code, I got this error so many times and I can't find it out. Can anybody help me? Thanks.**
[1]: https://i.stack.imgur.com/6Fuvg.png
Ok, you first have to decide when usng .net what "provider" you are going to use, AND THEN decide what kind of data objects you want to use.
You can use a oracle provider, a sql server provider, or in this case, since we using Access, then we can use EITHER oleDB, or ODBC. Either choice is fine. Most use oleDB providers for Access, but often ODBC is a good choice, especially if down the road you plane to swap out Access for say SQL server.
What the above means in plain English?
You don't want to adopt the external ADODB code and library. That code is NOT .net, and thus you REALLY but REALLY do not want to write your .net code that way. ADODB was written LONG before .net, and is what we call un-managed code (non .net). I strong, but strong suggest you do NOT add a reference to ADODB to your project, and I beyond strong recommend you avoid introduction of a non .net library for doing this!!! We certainly can adopt the oleDB provider in .net, but we will NOT have a direct reference to JET/ACE (the access database engine) in our applcation. As noted, there are some exceptions to this suggesting, but they don't apply to you and here.
Next up:
The design pattern in .net is to create the connection, get the data, and CLOSE the connection. This "pattern" will then be 100% sure that the data base is always closed, and you NEVER have to worry about if the connection is open, closed, or even if you forgot to close the connection!!! So, do this correct, and some "open" connection will never bite you, or will you have to worry about this issue.
You can in some operations keep the connection open for performance, but lets learn to walk before we run so to speak.
next up:
We certainly do NOT want to place and have connection strings all over in our code. Not only is this going to wear out your keyboard, but if you ever need to change the connection, then you going to have to hunt down all that code.
Best to let Visual Studio save that connection in ONE location, and MORE important MANAGE this for you!!!
Next up:
Do you ONLY need to work with mdb files, or do you plan/need to work with accDB files? This is a HUGE issue, and one that you cannot ignore.
next up:
Are you going to use the x32 bit version of the Access database system, or the x64 bit version?
Since your example posted code uses JET (access data engine for mdb files ONLY x32 bit version)?
Then this ALSO means you MUST (and I repeat MUST) force your .net project to run as x32 bits. You cannot use "any cpu", and you cannot use x64 bits, you MUST choose x86 bit size for your .net project. Failure to do so will result in the project not working.
Ok, with the above information?
First up, force/set/be 100% sure your project is set to run as x32 bits.
That setting is this one:
and remove the reference you have to ADO if you created one.
Ok,
next up:
Create the connection to the database.
Project ->properties.
This here:
And then:
and then
Now, you can browse, and select the access mdb file.
But, you MUST not skip the next step - you have to choose JET (older, mdb files), or choose the newer ACE (for accDB format files).
So, this:
now this:
As noted, you choose JET or ACE here.
now, we have this and you can use test connection.
BUT BE VERY careful!!!!
If you are using vs2022, then keep in mind vs2022 is the FIRST version of VS that is now x64 bits. As a result, vs can't pass the test connection!!! Your connection is in fact ok, but will fail with vs2022.
If you using a previous version of VS (before 2022), then the test connection button should work. and you see this:
Ok, now that we have a valid working conneciton setup, we can now write code, and we will NOT use ADODB!!!!
The typical code pattern to read and load a data table (like a access VBA recordset) will be like this:
Now, I became RATHER tired of writing that same using block over and over. So, in a global module, I have this code now:
Public Function MyRst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using conn As New OleDbConnection(My.Settings.AccessDB)
Using cmdSQL As New OleDbCommand(strSQL, conn)
conn.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
So, now with the above handy dandy helper routine?
Your code becomes this:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim Sql As String =
"SELECT Num_ber, Q_ty FROM good WHERE Na_me LIKE 'staff%' And Ty_pe = 'ORD'"
Dim rstData As DataTable = MyRst(Sql)
Debug.Print("Na_me is " & rstData.Rows(0).Item("Na_me"))
End Sub
Or, display all return rows from that data table
Debug.Print("Na_me is " & rstData.Rows(0).Item("Na_me"))
For Each OneRow As DataRow In rstData.Rows
Debug.Print("na_me = " & OneRow("Na_me"))
Next
So, you really don't need (or want) a reader anyway. Just load the results into a nice clean, easy to use data table, and from that you can loop the table, grab rows, or do whatever you want.
We have this VB.net code that connects to an MS Access Database and tries to insert a new entry:
Dim conn As New OleDbConnection
conn.ConnectionString = "Provider="Microsoft.ACE.OLEDB.16.0; Data Source=" & DATABASE_PATH & ";Jet OLEDB:Database Password=pass;"
conn.Open()
Dim SqlString As String = "INSERT INTO tblNotes" &
" ([NotesNumber" &
"], [NotesTitle" &
"], [HasAdditionalLogic" &
"], [TypeId]) Values (?,?,?,?)"
Dim cmd As New OleDbCommand(SqlString, conn)
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("NotesNumber", 1234)
cmd.Parameters.AddWithValue("NotesTitle", "the title")
cmd.Parameters.AddWithValue("HasAdditionalLogic", False)
cmd.Parameters.AddWithValue("TypeId", 14)
cmd.ExecuteNonQuery()
conn.close()
Nothing too fancy, right?
This code worked fine with Access 2016 installed.
Now with the recent upgrade to Office 365 the line
cmd.ExecuteNonQuery()
causes this error:
'Microsoft.ACE.OLEDB.16.0' failed with no error message available, result code: E_OUTOFMEMORY(0x8007000E)
Googling for that error message lead to several ideas like using Integer instead of Long Integer in the database, but that did not help either.
And personally, I doubt that the root cause is a lack of memory because the machine has 32GB RAM installed and is set to 32GB of Virtual Memory. The process itself never uses more than 100MB, Windows Process Explorer tells us that the whole RAM uses about 5GB total. So I just cannot believe we are actually running out of memory here.
Any idea?
Update:
Okay, we seem to have found the underlying issue here.
You see this line:
cmd.Parameters.AddWithValue("TypeId", 14)
In the Access database, the field "TypeId" has been defined as a Primary Key of Data Type "AutoNumber" and Field Size "Long Integer".
Now, if we write the code like this:
cmd.Parameters.AddWithValue("TypeId", 14I)
it runs without an error, but as soon as we change it to:
cmd.Parameters.AddWithValue("TypeId", 14L)
we get the crash.
Let me state again that the code with a Long works fine with Access 2016, it crashes with the Access from Office 365.
I may be mistaken, but this seems like a bug in Access.
Of course we can now change all the app code from Long to Integer (or UInteger), but this seems like treating the symptoms instead of the root cause.
Can somebody confirm this? Or tell me why exactly this happens? Using a Long seems to be correct to me, using an Integer instead seems pretty wrong to me.
To anybody who might face the same problem: we "fixed" the issue by installing "Microsoft Access Database Engine 2010 Redistributable"
https://www.microsoft.com/en-US/download/details.aspx?id=13255
and then using
Microsoft.ACE.OLEDB.12.0
instead of
Microsoft.ACE.OLEDB.16.0
That did the trick.
The hint with .add instead of .addWithValue did not make any difference.
I'm fairly new to working with Access/VB (started 2 months ago) so bear with me.
I inherited a database that has an ADODB connection to Oracle that works perfect on the Windows 7 machines that it's been tested on (a total of 5), but gives the following error when tested on Windows 10 machines (total of 2). (All machines are running Access 2010).
Run-time Error '3709': The connection cannot be used to perform this operation. It is either closed or invalid in this context.
Here's the code:
Public Function PTMNConnect() As ADODB.Connection
Dim Cn As ADODB.Connection
Dim Conn As String
Conn = "DRIVER={Microsoft ODBC for Oracle};CONNECTSTRING=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)" & _
"(HOST=host)(PORT=port))(CONNECT_DATA=(SERVICE_NAME=PROD)));uid=username;pwd=password"
Set Cn = New ADODB.Connection
With Cn
.ConnectionString = Conn
.CursorLocation = adUseServer
.Open '**Errors Out on Open**
End With
Set PTMNConnect = Cn
End Function
I've been racking my brain and searching everywhere for a possible solution to this for the past two days with no luck.
Here's what I've tried/verified so far based on other posts I'd seen:
Verified that the Oracle client was installed
Ensured that the Path variable contained the necessary paths
Verified the references and file paths are the same on all machines
Any insight or references that you may be able to provide would be greatly appreciated!
I was able to come up with a fix for this!
It turns out that Windows 7 and Windows 10 have different versions of the {Microsoft ODBC for Oracle} driver which I believe is what was causing the error. I decided to use the Oracle supplied driver (which remains the same for each PC) rather than the Microsoft supplied driver (which, as I found out, varies).
Replacing the Conn string from above with the following code fixed my issue. (This route requires an existing DSN):
Conn = "DRIVER={Oracle in OraClient11g_home1}; Dbq=DSN_TNSServiceName; uid=username; pwd=password"
I have a tool which reads dBase files and uploads the contents to SQL Server, part of a system to import shapefiles. It works but now we have a requirement to import files that include non-English characters (Norwegian in this case, could be other languages later) and they're being corrupted.
The dBase files are being read using an OleDbDataAdapter. Stepping through the code I can see that the text is wrong as it is read in. I'm assuming it's something to do with code pages or Unicode but I have no idea how to fix it.
A dBase Reader application tells me the DBFs are in code page 1252 - I don't know if this is correct. My upload tool runs on Win7 with English (UK) regional settings.
Examples:
ÅSGARD in DBF becomes +SGARD in VB.Net & SQL Server.
RINGHORNE ØST in DBF becomes RINGHORNE ÏST in VB.Net & SQL Server.
The code that reads the DBF:
dbfConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strPath & ";Extended Properties=dBASE IV"
Cnn.ConnectionString = dbfConnectionString
Cnn.Open()
strSQL = "SELECT * FROM [" & strDBF & "]"
DA = New OleDb.OleDbDataAdapter(strSQL, Cnn)
DS = New DataSet
DA.Fill(DS)
If DS.Tables(0).Rows.Count > 0 Then
dtDBF = DS.Tables(0)
Else
dtDBF = Nothing
End If
Data is read like: Name = dtDBF.Rows(index)("NAME_1")
Is there a way to tell OleDbDataAdapter what code page to use or a better way to read dBase files from VB.Net?
Try adding this to your DSN:
CollatingSequence=Norwegian-Danish
You might also be able to use:
CollatingSequence=International
Check whether the shapefile contains codepage information. There are two places to look
Look in the language driver ID (LDID), which is found in the header of the shapefile’s DBF table (in the 29th byte).
Look for an associated separate file with extension .cpg.
If the code page is not specified in those locations, it defaults to the codepage on the PC that generated the shapefile. You will just have to know that :(
I've never used it, but maybe Shape2SQL takes care of this for you? Or shp2text? I believe the PostGIS shapefile loader handles code pages: maybe you could import into PostGIS and then export in another format??
Old question, but this may answer it for future readers...
You might try adding a property setting in your connection string:
Locale Identifier=1044
This property (and a list of values including this one) is documented for ADO in conjunction with Jet 4.0's OLDB Provider but I have no reason to believe it isn't also supported by ADO.Net. This value (1044) is Norwegian/Danish.
Untested, but something else to try.
I'm using the following code (System.Data.SQLite within VB.net):
Dim SQLconnect As New SQLite.SQLiteConnection()
Dim SQLcommand As SQLiteCommand
SQLconnect.ConnectionString = "Data Source=vault.db;"
SQLconnect.Open()
SQLcommand = SQLconnect.CreateCommand
SQLcommand.CommandText = "INSERT INTO entries VALUES ('" & appinput.Text & "','" & userinput.Text & "','" & passinput.Text & "')"
SQLcommand.ExecuteNonQuery()
SQLcommand.Dispose()
SQLconnect.Close()
Me.Hide()
I get an error back that says it can't find the table "entries"
I know the table exists because I can write to it via the command line through sqlite and through Autoit and can see it and edit it in the SQLite browser when I open the database. I don't understand why VB can't see it (I know it sees and opens the database file just fine). Any ideas?
Most likely your problem is with relative paths (directories).
sqlite will create a database file if it does not exist so you will never get a "db file not found message". The first indication of an incorrect path is "table missing".
My personal experience is that although it goes against my programmers instinct is to alway use an absolute (fully qualified) path/file name for an sqlite database.
If you put in the full file location like "/var/myapp/vault.db" you should be OK.
If this is likly to move around store pick up the file name from a properties/config file -- 'config file not found' is much easier to deal with than "table not found".
Argh! There are 3 big issues in that code. Please update it like this to fix two of them:
Using cn As New SQLite.SQLiteConnection("Data Source=vault.db;"), _
cmd As New SQLiteCommand("INSERT INTO entries VALUES (#AppInput, #UserInput, #PassInput)", cn)
cmd.Parameters.AddWithValue("#AppInput", appinput.Text);
cmd.Parameters.AddWithValue("#UserInput", userinput.Text);
cmd.Parameters.AddWithValue("#PassInput", passinput.Text);
cn.Open()
cmd.ExecuteNonQuery()
End Using
This will prevent sql injection by parameterizing your query instead of substituting values directly and prevent db locking issues by making sure your connection is disposed properly, even if an exception is thrown.
The third problem is that you should NEVER store plain-text passwords in your database (or anywhere else for that matter). Go read up on how to hash values in .Net and hash and salt your password before storing or comparing it.
Once you've done that re-test your code to see if you still get the same errors reported as before. We need to make sure this didn't solve the problem or introduce something new. Then we can start addressing the missing table issue, perhaps by checking your connection string.
I had a similar error with SQLite (via .Net) refusing to believe the table existed, even though direct access confirmed it was there. The error could be produced only on one individual machine and not others. Hard coding the path didn't seem to fix the problem. The fix was either to run the program as Administrator or change the DB file to be available to Everyone. Apparently the .Net assembly raises a missing table error when the actual problem is access restrictions.