getting Mono with firebird-embedded working on 64bit Linux environment - c#

I'm trying to get Firebird-embedded 2.5 (64bit) on Linux with firebird .net provider (FirebirdSql.Data.FirebirdClient) working.
The FB embedded setup for my Test assembly is working on WinX86_64 with the Windows Firebird Embedded version.
On Linux I use the coresponding FB embedded Linux version placed files in the assembly directory:
libfbembed.so*
firebird.msg
security2.fdb
libicu*
libib*
Set the "RootDirectory" to assembly directory in the firebird.conf.
Set the shell environment variables LD_LIBRARY_PATH and FIREBIRD to to assembly directory.
FbConnectionStringBuilder conn = new FbConnectionStringBuilder();
conn.Database = #"/home/dev/firebirdTest/1stDB.FDB";
conn.ServerType = FbServerType.Embedded;
conn.UserID = "SYSDBA";
conn.Password = "masterkey";
conn.Charset = "UTF8";
conn.DataSource = "localhost";
conn.ClientLibrary = "libfbembed.so";
string connStr = conn.ConnectionString;
var dbcon = new FbConnection(connStr);
FbConnection.CreateDatabase(connStr, pageSize: 8192, forcedWrites: true, overwrite: false);
dbcon = new FbConnection(connStr);
dbcon.Open();
what I did before:
Redirecting the Firebird Clientlibrary by mono dllmap doesn't work. Solved by explicit setting the ClientLib in C# code.
manually creating a Database with isql on Linux works.
creating a Database by code on Linux works.
the Firebird .NET provider creates in debug mode the FB_{sanitizedName}.dll and DynamicAssembly.dll
the .NET provider is really silent. Debugging was done by starting the assembly with "strace mono {testAssembly.exe}" on linux.
FbConnection.CreateDatabase crashes with I/O error during "open O_CREAT" (calling FbCreateDatabase), if pagesize is not 8192. Setting explicit pagesize to 8192 solves this.
Now, I run in following errors ( and stuck here for days...):
Opening an existing Databasefile (like in the code here), crashes with:
FirebirdSql.Data.FirebirdClient.FbException: invalid database handle (no active connection) ---> invalid database handle (no active connection)
What's going wrong?

I've stuck with this error too.
FirebirdSql.Data.FirebirdClient.FbException: invalid database handle (no active connection)
Tried with FB 2.5.* and 3.0.0 results are the same.
Also tried using debug builds of FB. Logs did not help.
Maybe somebody here knows what the problem is?

It's 3 years since the original post, and I've run into the same problem. I don't have an "answer" but I do have an explanation. It appears the marshalling of SafeHandle objects isn't fully implemented in mono. From their documentation on SafeHandle: "Notice that “ref SafeHandles” pass a pointer to a slot containing zero to P/Invoked methods, and on return the a new SafeHandle is created with the returned value. “ref SafeHandles” do not actually get the original SafeHandle.handle value."
If you look into the FirebirdClient source, in IFbClient, you'll see the P/Invoke declarations look like:
IntPtr isc_detach_database(
[In, Out] IntPtr[] statusVector,
[MarshalAs(UnmanagedType.I4)] ref DatabaseHandle dbHandle);
DatabaseHandle is derived from SafeHandle, so the second argument is a "ref SafeHandle" argument, and suffers from the problem noted above - it will basically pass in a zero rather than the actual handle value.
There is no fix other than to (a) improve the SafeHandle implementation in mono, or (b) rewrite FirebirdClient to avoid the use of SafeHandles.

Related

SQLite BackupDatabase method is throwing exception after upgrading to version 1.0.111.0

I am upgrading System.Data.SQLite from version 1.0.93.0 to 1.0.111.0
I am having a method which copies the SQLite database on disk to in memory. It is working fine with version 1.0.93.0 and here's the code in VB.Net
Dim sourceConn = CType(_connection, System.Data.SQLite.SQLiteConnection)
Dim destConn = CType(destDBM._connection, System.Data.SQLite.SQLiteConnection)
sourceConn.BackupDatabase(destConn, "main", "main", -1, Nothing, 0)
where path of destination SQLite is in memory by using ":memory:" instead of path.
After upgrading to version 1.0.111.0, it throws the below exception
code = Unknown (-1), message = System.Data.SQLite.SQLiteException (0x80004005): unknown error
failed to initialize backup
at System.Data.SQLite.SQLite3.InitializeBackup(SQLiteConnection destCnn, String destName, String sourceName)
at System.Data.SQLite.SQLiteConnection.BackupDatabase(SQLiteConnection destination, String destinationName, String sourceName, Int32 pages, SQLiteBackupCallback callback, Int32 retryMilliseconds)
Does anyone have any idea that how to get it solved?
I am able to find out the root cause of this issue myself. Actually, I was starting a transaction in destination database before backup. It was working fine in the older version but the behavior is changed in the latest version and exception is not meaningful at all.
To fix it, I have re-ordered the code which was initiating transaction as the next step after taking backup. It's working as expected now and insertions are way too fast in the latest version. Great work by SQLite team!

Buffer is null in ImportMQMDMesageBuffer, causes client application to crash

We are facing a difficult problem, I hope someone can give advice on how we can troubleshoot this.
We encounter following XMSException in our logging:
IBM.XMS.XMSException: CWSMQ0282E: A null value has been used for argument BUFFER = <> NULL within method ImportMQMDMesageBuffer(WmqSession, WmqDestination, MQMD,byte[],int,int).
The preceding method detected an invalid null argument.
If necessary, recode the application to avoid the error condition.
at IBM.XMS.Client.WMQ.WmqReceiveMarshal.ImportMQMDMesageBuffer(MQMessageDescriptor mqmd, Byte[] buffer, Int32 dataStart, Int32 dataEnd)
at IBM.XMS.Client.WMQ.WmqAsyncConsumerShadow.Consumer(Phconn hconn, MQMessageDescriptor mqmd, MQGetMessageOptions mqgmo, Byte[] pBuffer, MQCBC mqcbc)
at IBM.WMQ.Nmqi.UnmanagedNmqiMQ.NmqiConsumerMethodUM(Int32 hconn, IntPtr structMqmd, IntPtr structMqgmo, IntPtr buffer, IntPtr structMqcbc)
After this XMSException, the Windows Service crashes. The difficult part is that we can't reproduce this behavior on our dev environment. We are still troubleshooting, we couldn't find what's the root cause of this issue.
Below you can find information on how we make connection:
Used version: IBM.XMS 8.0.0.5
A connection is created this way:
XMSFactoryFactory factory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
IConnectionFactory cf = factory.CreateConnectionFactory();
cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT_UNMANAGED);
cf.SetStringProperty(XMSC.WMQ_HOST_NAME, hostname);
cf.SetStringProperty(XMSC.WMQ_PORT, port);
cf.SetStringProperty(XMSC.WMQ_CHANNEL, channelname);
cf.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, qmname);
IConnection connection = cf.CreateConnection();
Session is created this way:
ISession session = connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
Destination is created this way:
destination = session.CreateQueue("queuename");
destination.SetIntProperty(XMSC.WMQ_MESSAGE_BODY, XMSC.WMQ_MESSAGE_BODY_MQ);
destination.SetBooleanProperty(XMSC.WMQ_MQMD_WRITE_ENABLED, true);
destination.SetBooleanProperty(XMSC.WMQ_MQMD_READ_ENABLED, true);
Listener is created this way:
IMessageConsumer consumer = session.CreateConsumer(destination);
consumer.MessageListener = listenerDelegate;
The same XMSException is also asked here a few years ago. I see they have opened a PMR for this issue, but without any update...
On March 28th 2019 IBM released an APAR that appears to be an exact match for the issue you reported.
IT28062: While getting an empty message, XMS .Net applications reports CWSMQ0282E and crash.
Unfortunately the APAR is not included in any current releases of MQ (As of March 29th). You will need to either wait for a release to come out which includes this APAR or get your client to open a PMR and ask them for a IFIX for this APAR against the version of MQ you are using.
The APAR is targeted for the following maintenance levels, I also added the target date for each level from IBM MQ planned maintenance release dates.
Version Maintenance Level Planned Release Date
v8.0 8.0.0.12 2Q 2019
v9.0 LTS 9.0.0.7 2Q 2019
v9.1 LTS 9.1.0.3 Not noted yet, 9.1.0.2 is targeted for 2Q 2019
v9.1 CD 9.1.3 CD releases historically have been between
2 and 6 months apart.
9.1.2 was released March 21 2019.

No compatible compatibility setting available for Transfer class in SMO

I am writing an SMO application, which copies the schema of one database into another.
For this purpose i use Transfer class available in SmoExtended.dll library.
The sample code is:
Database sourceDatabase = sqlServer.Databases[ASourceName];
Transfer t = new Transfer(sourceDatabase);
t.CopyAllObjects = true;
t.CopyData = false;
t.Options.DriAll = true;
t.Options.Triggers = true;
t.DestinationDatabase = ADestinationName;
t.DestinationServer = sqlServer.Name;
t.DestinationLogin = sqlServer.ConnectionContext.Login;
t.DestinationPassword = sqlServer.ConnectionContext.Password;
Database destinationDatabase = new Database(sqlServer, ADestinationName);
destinationDatabase.CompatibilityLevel = CompatibilityLevel.Version100;
destinationDatabase.Create();
t.TransferData();
destinationDatabase.AutoClose = false;
destinationDatabase.Alter();
I get an error Version100 database compatibility level is not supported.
I am using SMO libraries from the version 100 assembly folder.
The database i am copying and the destination database are both on the same server instance.
The server is SQL Server 2012.
I have tried all the available compatibility levels (80,90,100,110), none work. I get the error every time.
HOWEVER, if i use version 110 SMO libraries, everything works as expected, the database is created and schema is copied.
BUT, there is a reason why i can't use version 110 libs, and it's because our clients are using SQL Server 2008 R2, which is a v100 and machines with 2008R2 do not have SDKs of version 110.
PS: Source database compatibility level is set to 100.
Any idea how can i use v100 libs for both, 2008R2 and 2012 and possibly 2014 (this is the last version supporting v100)?
SOLUTION 1: (Easy, very little work)
As suggested by Ben Thul one could use the libraries of single version (e.g. 110) and ship them with an app, or have clients install SQL server library packs.
I have tested this approach with SQL server 2014 libraries. To achieve the goal, i had to download:
1. Microsoft SQL Server System CLR Types (SQLSysClrTypes.msi)
2. Shared Management Objects (SharedManagementObjects.msi)
I have chosen to use x86 libraries, which is 9.3MB in total. These two libraries are enough to get all the SMO libs required.
SOLUTION 2: (Harder but still quite easy, much more work)
I have come up with an idea which is a bit harder to implement than the solution 1, but it works.
The idea is to create separate DLL file for each version of SQL Server and dynamicaly load those DLLs.
The steps are as follows:
Install or download Unmanaged exports library.
Create a new DLL project for a single targeted SQL Server version.
e.g. 2008.dll, 2012.dll...
Inside each of the dll i reference corresponding SMO libraries. e.g.
2008.dll i reference DLLs from ..\100\SDK\Assembly, for SQL
server 2012 i would do 2012.dll and reference ..\110\SDK\Assemby
and so on.
Export the function(s) that i need for calling at my main
application.
[DllExport("Copy", System.Runtime.InteropServices.CallingConvention.StdCall)]
public static void Copy(string AInstance, string AUser, string APass, string ASourceName, string ADestinationName)
Define functions for loading and unloading DLLs
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
Define function delegate to be used.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate bool CopyDB(string AInstance, string AUser, string APass, string ASourceName, string ADestinationName);
Load, run and unload depending on a SQL Server version
if ( Server.Version.Major == 10 ) {
IntPtr lib8 = LoadLibrary("2008.dll");
IntPtr workFunc = GetProcAddress(lib8, "Copy");
CopyDB dbc = ( CopyDB )Marshal.GetDelegateForFunctionPointer(workFunc, typeof(CopyDB));
dbc(SqlInstance, SqlLogin, SqlPassword, ASourceName, ADestinationName);
FreeLibrary(lib8);
} else if ( Server.Version.Major == 11 ) {
IntPtr lib12 = LoadLibrary("2012.dll");
IntPtr workFunc = GetProcAddress(lib12, "Copy");
CopyDB dbc = ( CopyDB )Marshal.GetDelegateForFunctionPointer(workFunc, typeof(CopyDB));
dbc(SqlInstance, SqlLogin, SqlPassword, ASourceName, ADestinationName);
FreeLibrary(lib12);
} else .....
The last step can be generalised even more. We could skip the version check if we were to build dlls with the name like <version>.dll, e.g. 10.dll,11.dll,12.dll. This way if .. else .. is no longer needed and the library that is being loaded will have its name generated at runtime by the value of Server.Version.Major
The positive side of this approach is that these targeted DLL files only take ~7KB (for my scenario at least), which is much less than CLR and SMO.msi library packs. It also guarantees that supported SMO libraries will be used. Furthermore, one can distribute a single dll to the clients once a new version of SQL Server is released and the app will happily use it for the newly installed instance.

Accessing member of Microsoft.SqlServer.Management.Smo.Server object crashes exactly once

We are trying to access the DefaultFile member of an Microsoft.SqlServer.Management.Smo.Server object. After a lot of debugging, it turns out that accessing the member crashes the first time, but can then be accessed just fine. Looking at the variable in a debug window returns an exception the first time, the correct value the second and all following times.
The first access of either server.DefaultFile or server.DefaultLog throws an exception like this:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Microsoft.SqlServer.Management.Smo.BitStorage.SetBit(Int32 itemIndex, BitIndex bitIndex, Boolean value)
at Microsoft.SqlServer.Management.Smo.PropertyCollection.SetRetrieved(Int32 index, Boolean val)
at Microsoft.SqlServer.Management.Smo.SqlSmoObject.AddObjectPropsFromDataReader(IDataReader reader, Boolean skipIfDirty, Int32 startColIdx, Int32 endColIdx)
at Microsoft.SqlServer.Management.Smo.SqlSmoObject.ImplInitialize(String[] fields, OrderBy[] orderby)
at Microsoft.SqlServer.Management.Smo.SqlSmoObject.Initialize(Boolean allProperties)
at Microsoft.SqlServer.Management.Smo.SqlSmoObject.OnPropertyMissing(String propname, Boolean useDefaultValue)
at Microsoft.SqlServer.Management.Smo.PropertyCollection.GetValueWithNullReplacement(String propertyName, Boolean throwOnNullValue, Boolean useDefaultOnMissingValue)
at Microsoft.SqlServer.Management.Smo.Server.get_DefaultFile()
at my function... etc etc
The first-access-crash is very concistent, so doing something terrible like below gets around the problem completely:
using (var sqlConnection = new SqlConnection(sourceDatabaseConnectionString.ConnectionString))
{
var svrConnection = new ServerConnection(sqlConnection);
var server = new Server(svrConnection);
// begin mega hack
try
{
// crashes on first access
var dummy = server.DefaultFile;
}
catch
{
// do absolutely nothing
}
// end mega hack
// business as usual...
var defaultFile = server.DefaultFile;
}
Of course, we don't like code like this (even if it's only in our internal tools) so any ideas of why this might be happening is welcome. Our only clue is that we've recently upgraded some instances of SQL Server 2012 to SQL Server 2014. We can sometimes get around the issue when running the code locally on a machine with SQL Server 2014 installed. The production machine that runs this code does not have an installation at all, but references DLLs. However, we can't find any differences in the versions used when debug printing the assembly versions while running the code.
I've seen similar messages when using an older version of SMO, especially when trying to use 2008R2 SMO to access 2012. Upgrading to the installs from 2008R2 Featurepack SP3 fixed my issues.
Check that there's not a more recent version of the Shared Management Objects + CLR Types + Native client driver that you could use.

c# to AS400 / JD Edwards - run program - Data source name not found and no default driver specified

UPDATE: The code example below works. I changed the connection string. That was the problem. For an alternative (non-ADO) solution, see Mike Wills's link in the comments.
I have a c# class that (if I ever get it working) runs a program written in RPG code on AS/400 - JD Edwards. I know next to nothing about AS/400 and/or JD Edwards.
I've got other classes in my (intranet) web app that connect to JD Edwards, running SQL queries and setting/getting data. All of these are using the IBM.Data.DB2.iSeries dll and are working great.
For this, I wrote a similar class using the aforementioned dll, but it wasn't working. I even read somewhere online that you can't run a program using this dll. I found that a little fishy, but on suggestion from my JD Edwards co-worker, I scrapped the class and re-wrote it using the adodb dll. No data need be returned from this program run. I just want the program to run.
Here is a dummified version of the class:
private void runJDEProgram() {
ADODB.Connection cn = new ADODB.Connection();
cn.ConnectionString = "Provider=ABABAB;Data Source=111.111.111";
ADODB.Command cmdDetail = new ADODB.Command();
cn.Open(); //has to be open before setting an active connection.
cmdDetail.ActiveConnection=cn;
cmdDetail.CommandType = ADODB.CommandTypeEnum.adCmdText;
cmdDetail.CommandText = "{{CALL BLAH.BLAH(?,?)}}";
cmdDetail.Prepared = true;
cmdDetail.Parameters.Append(cmdDetail.CreateParameter("P1", ADODB.DataTypeEnum.adChar, ADODB.ParameterDirectionEnum.adParamInput, 10, "BLAH123"));
cmdDetail.Parameters.Append(cmdDetail.CreateParameter("P2", ADODB.DataTypeEnum.adChar, ADODB.ParameterDirectionEnum.adParamInput, 10, "BLAH456"));
object dummy = Type.Missing; //otherwise, we couldn't get past this.
cmdDetail.Execute(out dummy, ref dummy, 0);
cn.Close();
}
Here's the error I get when it runs:
{"[Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified"}
Where am I screwing up? Thanks!
EDIT: The connection string works when querying the AS/400 to get/set data. Does it need to be modified for an operation like this, or for use with ADO?
The connection string has to be different for this, for some reason. I don't use the same connection string for the other classes that just run queries. The above connection string worked fine (with the appropriate values, of course).
It will prompt for password, but the JDE folks here wanted that.

Categories

Resources