Friday, January 8, 2021

Firebird Embedded in a sandboxed MacOS App

For those who might not be aware, Firebird on MacOS is now relocatable, in that you don't necessarily have to install it as a Framework, this also means that you can create an embedded version out of the current installer.

A typical structure would look like this

|-- firebird.conf
|-- firebird.msg
|-- intl
| |-- fbintl.conf
| `-- libfbintl.dylib
|-- lib
| |-- libfbclient.dylib
| |-- libib_util.dylib
| |-- libicudata.dylib
| |-- libicui18n.dylib
| |-- libicuuc.dylib
|`-- plugins
    `-- libEngine12.dylib

And the firebird.conf file would then typically be amended for the following

Providers = Engine12
ServerMode = Classic
 
For the last few weeks Alex and I (along with a Firebird user) have been working on getting Firebird embedded to work properly in a sandboxed app that can then be deployed on the App Store...
 
To do this we had to solve issues with temp files, the use of inter process communications by the
Firebird lock manager and the location of the Firebird log file.

Note: adding LSEnvironment to the plist file defining new locations for FIREBIRD_TEMP and FIREBIRD_LOCK does not work.

<key>LSEnvironment</key>
<dict>
    <key>ENV_VAR</key>
    <string>value</string>
</dict>
 
So the first issue to be addressed was the following

macosx    Wed Dec  2 15:33:57 2020
    ConfigStorage: Cannot initialize the shared memory region
    Can not access lock files directory /tmp/firebird.tmp.YDzrhQ

It seems thats sandboxed Apps cannot to write into /tmp at all, they have to use their own /tmp-folder. We can detect whether we are running in a sandboxed environment using the following calls to the Mac security subsystem

task = SecTaskCreateFromSelf(nil),        
value = SecTaskCopyValueForEntitlement(task, "com.apple.security.app-sandbox" as CFString, nil),

Now if we now know if we are sandboxed we can use  NSTemporaryDirectory() for the location of the relevant Firebird temporary files.

Having fixed that issue, it was time to move onto the lock manager.
 
[FireDAC][Phys][FB]lock manager error.)
 
macosx    Thu Dec 17 17:37:00 2020
    event_init()
     operating system directive semctl failed
     Operation not permitted
 
According to the Apple sandbox guide restricting IPC (Inter Process Communication) is also part of MacOS sandbox implementation. After some serious head scratching we tried the following test
 
#include <stdio.h>
#include <pthread.h>
 
#define ER(x) { int tmpState = (x); if (tmpState) { printf("Failed %s error %d\n", #x, tmpState); } }
 
int main() {
 
    pthread_mutex_t mutex;
     pthread_mutexattr_t mutexattr;
 
     ER(pthread_mutexattr_init(&mutexattr));
     ER(pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED));
     ER(pthread_mutex_init(&mutex, &mutexattr));
     ER(pthread_mutex_lock(&mutex));
     ER(pthread_mutex_unlock(&mutex));
     ER(pthread_mutex_destroy(&mutex));
 
c++ test.cpp -pthread
 
In case of failure it will print error messages, on success we should get nothing. We got nothing.

For many years Firebird worked with system V IPC on MacOS which is different to many other *nixes where mutexes and conditional variables in shared memory were used instead. The use of system V IPC was caused by a lack of  for shared mutexes on MacOS when Firebird was originally ported to it. Currently (as was proved by test above) MacOS now supports such mutexes. Based on this it we decided to stop using system V IPC in Firebird and a perform a cleanup of the lock manager code as part of the effort to provide sandbox support. As a side effect Firebird should now run faster using shared mutexes.
 
At the same time as we worked on the lock manager issue we also had an issue with the firebird log file, we were not allowed to write to its normal default location by the sandbox. Because we now know we are running in a sandbox we can relocate the placement of the log file within utils.cpp
 
Supposedly using something like ~/Library/Application Support/Firebird/ should work
 
case Firebird::IConfigManager::DIR_LOG:
             s = "~/Library/Application Support/Firebird/";
             s += name;
             return s;
 
Unfortunately it seems this workaround was removed relatively recently forcing us to resort to putting the log file within the App itself ~/LibraryContainers/Company.App/Data/Library/Application Support/Company/
 
Changing the location of the log file is relatively easy but  although this allowed the App to run and resolved the issue, it was not an ideal solution since the location of the log file is now hard coded within Firebird and is App dependent and this would mean that every time somebody wanted an embedded Firebird for a sandboxed App they would have to change the path to the log file and recompile Firebird.
 
The solution was to do away with the Firebird log file and use the OSLog framework instead, and use this to capture any messages from the database engine, so if you are running embedded Firebird in a sandboxed App you can access the Firebird log messages using the Console or a terminal command like the following
 
log show --predicate 'eventMessage contains "macpro.home"' --start '2021-01-06 14:00:00' --end '2021-01-06 14:30:00' --info
 
where macpro.home is the name of the computer. You don't need the start and end, but it does help reduce the number of messages.
 
There is an added plus from using this. The OSLog framework is also supported on IOS 10+ and now that the App Store will accept dynamic libraries, this means that we should be able to compile an embedded version of Firebird for IOS that can also run sandboxed Apps. If anyone is interested in sponsoring this work please contact me.  

This work was sponsored by kiC Gesellschaft für Softwareentwicklung mbH.

Wednesday, September 11, 2019

Firebird 3 Embedded on MacOSX


I have finally managed to get around to preparing a mechanism for creating an embedded Firebird Framework on MacOSX (many thanks to the customer who sponsored the work). I will be committing the updated makefile embed.darwin shortly to B3_0_Release.
You can use the makefile to create a 32bit or 64 bit framework, depending on the build of Firebird you want.
Once you have a build of Firebird, you need to run make.platform.postfix, and then embed.darwin. The embeded framework is created in gen/Release/frameworks.

If you can't build Firebird from scratch you can download a copy of the embedded framework (currently Firebird 3.0.4) from IBPhoenix. (Approx 15mb)

32bit Embedded Framework
64bit Embedded Framework

Below is the embed.darwin makefile (updated 01-Oct-2019)

# Makefile script to generate an embedded Firebird Framework from a sucessful Firebird build
# To be run from the gen directory of a Firebird Release build
# Your application needs to be placed in the Resources/app directory.

    FBE=../gen/Release/frameworks/FirebirdEmbedded.framework
    BINLOC=../gen/Release/frameworks/FirebirdEmbedded.framework/Versions/A/Resources/bin
    LIBLOC=../gen/Release/frameworks/FirebirdEmbedded.framework/Versions/A
    INTLOC=../gen/Release/frameworks/FirebirdEmbedded.framework/Versions/A/Resources/intl
    PLULOC=../gen/Release/frameworks/FirebirdEmbedded.framework/Versions/A/Resources/plugins
    UTILOC=../gen/Release/frameworks/FirebirdEmbedded.framework/Versions/A/Libraries
    OLDPATH=/Library/Frameworks/Firebird.framework/Versions/A/Libraries

all:

    -$(RM) -rf $(FBE)
    mkdir -p $(FBE)/Versions/A/Resources
    mkdir -p $(FBE)/Versions/A/Resources/intl
    mkdir -p $(FBE)/Versions/A/Resources/plugins
    mkdir -p $(FBE)/Versions/A/Resources/bin
    mkdir -p $(FBE)/Versions/A/Resources/app
    mkdir -p $(FBE)/Versions/A/Headers
    mkdir -p $(FBE)/Versions/A/Libraries
    ln -s Versions/Current/Headers $(FBE)/Headers
    ln -s Versions/Current/Resources $(FBE)/Resources
    ln -s Versions/Current/Libraries $(FBE)/Libraries
    ln -s A $(FBE)/Versions/Current

    cp ../gen/Release/firebird/firebird.conf $(FBE)/Versions/A/Resources/firebird.conf
    cp ../gen/Release/firebird/plugins.conf $(FBE)/Versions/A/Resources/plugins.conf
    cp ../gen/Release/firebird/firebird.msg $(FBE)/Versions/A/Resources/firebird.msg
    cp ../gen/Release/firebird/lib/libfbclient.dylib $(FBE)/Versions/A/libfbclient.dylib
    cp ../gen/Release/firebird/plugins/libEngine12.dylib $(FBE)/Versions/A/Resources/plugins/libEngine12.dylib
    cp ../gen/Release/firebird/lib/libicudata.dylib $(FBE)/Versions/A/libicudata.dylib
    cp ../gen/Release/firebird/lib/libicui18n.dylib $(FBE)/Versions/A/libicui18n.dylib
    cp ../gen/Release/firebird/lib/libicuuc.dylib $(FBE)/Versions/A/libicuuc.dylib
    cp ../gen/Release/firebird/bin/gbak $(FBE)/Versions/A/Resources/bin/gbak
    cp ../gen/Release//firebird/bin/isql $(FBE)/Versions/A/Resources/bin/isql
    cp ../gen/Release/firebird/intl/fbintl.conf $(FBE)/Versions/A/Resources/intl/fbintl.conf
    cp ../gen/Release/firebird/intl/libfbintl.dylib $(FBE)/Versions/A/Resources/intl/libfbintl.dylib
    cp ../gen/Release/firebird/lib/libib_util.dylib $(FBE)/Versions/A/Libraries/libib_util.dylib


    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Firebird \
     @loader_path/../../libfbclient.dylib $(BINLOC)/isql
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Firebird \
     @loader_path/../../libfbclient.dylib $(PLULOC)/libEngine12.dylib
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicuuc.dylib \
    @loader_path/../../libicuuc.dylib $(BINLOC)/isql
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicudata.dylib \
    @loader_path/../../libicudata.dylib $(BINLOC)/isql
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicui18n.dylib \
    @loader_path/../../libicui18n.dylib $(BINLOC)/isql
   
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Firebird \
    @loader_path/../../libfbclient.dylib $(BINLOC)/gbak
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicuuc.dylib \
    @loader_path/../../libicuuc.dylib $(BINLOC)/gbak
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicudata.dylib \
    @loader_path/../../libicudata.dylib $(BINLOC)/gbak
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicui18n.dylib \
    @loader_path/../../libicui18n.dylib $(BINLOC)/gbak
   
    install_name_tool -change $(OLDPATH)/libicuuc.dylib @loader_path/libicuuc.dylib \
    $(LIBLOC)/libfbclient.dylib
    install_name_tool -change $(OLDPATH)/libicudata.dylib @loader_path/libicudata.dylib \
    $(LIBLOC)/libfbclient.dylib
    install_name_tool -change $(OLDPATH)/libicui18n.dylib @loader_path/libicui18n.dylib \
    $(LIBLOC)/libfbclient.dylib
    install_name_tool -change $(OLDPATH)/libicudata.dylib @loader_path/libicudata.dylib \
    $(LIBLOC)/libicuuc.dylib
    install_name_tool -change $(OLDPATH)/libicuuc.dylib @loader_path/libicuuc.dylib \
    $(LIBLOC)/libicui18n.dylib
    install_name_tool -change $(OLDPATH)/libicudata.dylib @loader_path/libicudata.dylib \
    $(LIBLOC)/libicui18n.dylib

    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Firebird \
    @loader_path/../../libfbclient.dylib $(INTLOC)/libfbintl.dylib

    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicuuc.dylib \
        @loader_path/../libicuuc.dylib $(INTLOC)/libfbintl.dylib
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicudata.dylib \
        @loader_path/../libicudata.dylib $(INTLOC)/libfbintl.dylib
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicui18n.dylib \
        @loader_path/../libicui18n.dylib $(INTLOC)/libfbintl.dylib

    install_name_tool -id @rpath/libfbclient.dylib $(LIBLOC)/libfbclient.dylib
    install_name_tool -id @rpath/libicudata.dylib $(LIBLOC)/libicudata.dylib
    install_name_tool -id @rpath/libicui18n.dylib $(LIBLOC)/libicui18n.dylib
    install_name_tool -id @rpath/libicudata.dylib $(LIBLOC)/libicudata.dylib
    install_name_tool -id @rpath/libicuuc.dylib $(LIBLOC)/libicuuc.dylib
    install_name_tool -id @rpath/libicudata.dylib $(LIBLOC)/libicudata.dylib
    install_name_tool -id @rpath/libib_util.dylib $(UTILOC)/libib_util.dylib
    install_name_tool -id @rpath/libfbintl.dylib $(INTLOC)/libfbintl.dylib
    install_name_tool -id @rpath/libEngine12.dylib $(PLULOC)/libEngine12.dylib

Wednesday, December 20, 2017

Firebird and Windows 10 Fall Creators Update



Windows 10 is well known for encouraging a love/hate relationship with its users. From the beginning Microsoft implemented a policy of uninstalling users' software without their consent during installation or update of Windows 10. Many articles on the net discuss this, for example however, until now, Firebird seemed to be unaffected.

Not any more. Windows 10 Creators Edition (Build 1709), released in September 2017 seems to have added Firebird to its hit list of dangerous applications. This problem was first reported here.
Because the report mentioned Firebird 1.5 it seemed unfortunate but, hey, Firebird 1.5 has been out of support for eight years. It was first released back in 2003 in the heyday of Windows XP and fourteen years is a long time in the software industry. But not only had Firebird been uninstalled, it was impossible to re-install it. This was likely to affect one of our clients so we spent a long time trying to work around that problem.

Since then we have heard reports from other clients whose customers use Firebird 2.5. After updating Windows 10 to build 1709 Firebird was nowhere to be seen. We have also heard that Windows 10 Enterprise is affected so this is not isolated to the so-called Creators edition. And, at the time of writing we haven't had any feedback about the status of Firebird 3.0.

Luckily, Windows 10 does not block installation of any version of Firebird from V2.0 onwards. But having to re-install is still very annoying, and who knows when Microsoft might decide to change the rules on that?
We spent a long time with our client trying to work out how to re-install Firebird 1.5. Manually setting the configuration using the Properties | Compatibility page and choosing an older version of Windows didn't work. However, running the compatibility troubleshooter did, even though the same setting were being chosen.

Unfortunately, there is so much clicking required that no ordinary user could be relied upon to achieve the desired goal. And trying to talk someone through that over the phone or by email would be extremely frustrating for all involved.

Rebuilding the installer with a newer, Windows 10 aware version of InnoSetup didn't work. But weirdly, a rapidly hacked version using an InterBase template for InstallShield did. Hmmm. And hacking an InnoSetup based installer together with the Firebird 1.5 zip package also worked. So what was going on there?

What criteria does Windows 10 use to decide which programs to ban from installation? There is a known bug in the cpl applet that ships with Firebird 1.5 that can crash Windows Explorer so we tried building an installer without that applet. But no, that wasn't it either.

Finally our client had a brainwave. What happens if Firebird-1.5.6.5026-0-Win32.exe was renamed to, say, setup.exe? Well, what do you know? It works. So simple that we really wanted to kick ourselves for not thinking of it first. And as for the poor Brazilian guy in the forum above, I hope he is sitting down when/if he finds out the solution. It is enough to make anyone want to run screaming into the woods.

Thursday, March 10, 2016

DYLD_LIBRARY_PATH and El Capitan


With the release of Firebird 3 RC2 it is time to concentrate properly on the port of Firebird on MacOSX, Firebird 3 was buildable but we don't have a proper installer, ICU is no longer directly included and there
are a number of other bits and pieces that need to be addressed.

The last time I built Firebird 3 was before I upgraded to El Capitan. I did the upgrade to address some issues with the Firebird installer.

Lets just say when I started ny first build I wasn't expecting too many problems....

When we build Firebird on OSX we arbitrarily point to the ICU location (build_environment/firebird/lib), after copying over the files from the initial ICU build, the Firebird build then finds the ICU libraries dynamically (when needed) because DYLD_LIBRARY_PATH is sey to point to the location via prefix.darwin (make.platform).

While the ICU libraries are being built we set the final actual framework install names and locations of the ICU libraries (using -install_name) and they then placed in the appropriate directory of the framework
when the installer is packaged and built.

Every time I tried to build Firebird it would fall over when trying to build msg.fdb with ISQL.
The error was:
 "Could not find acceptable ICU library"
which seemed very strange as I know it was placed exactly where it should be and where DYLD_LIBRARY_PATH should be picking it up.

Setting DYLD_LIBRARY_PATH in my default terminal worked successfully, checking DYLD_PRINT_ENV seeemed to show the path being set etc., after much head scratching I eventually put the following line of code into unicode_util.cpp at the function:
UnicodeUtil::ConversionICU& UnicodeUtil::getConversionICU()

printf("DYLD_LIBRARY_PATH=%s\n", getenv("DYLD_LIBRARY_PATH"));

When I next ran the build, this is what was returned..

DYLD_LIBRARY_PATH=(null)

Something very strange was definitely going on. Some further research eventually turned up this thread on the
PostgreSQL forums

http://www.postgresql.org/message-id/561E73AB.8060800@gmx.net

"Apparently the behaviour is that DYLD_LIBRARY_PATH is prevented from being inherited into any system binaries. E.g. a shell. But specifying it inside a shell script will allow it to be inherited to children of
that shell, unless the child is a protected process in turn."

My reaction was the same as Tom Lane's but expressed in much stronger terms.

The simplest solution to the problem is to turn off System Integrity Protection

via Recovery Mode (Command-R), and then set csrutil disable in a terminal and reboot.

Note that this is a development only issue and will not affect anybody using the built
binaries when the port is complete.

Wednesday, October 7, 2015

How to install/upgrade Firebird manually on El Capitan


Background: The current Firebird automatic installer on El Capitan is no longer working, its format has been
finally deprecated. The installer is currently undergoing a complete re-write to comply with the Flat Package Format. Until this work is completed, you can manually install Firebird using the following method.

Classic

Download FirebirdCS-2.5.4-26856-x86_64.pkg.zip
Unzip it
cd FirebirdCS-2.5.4-26856-x86_64.pkg
cd Contents
gunzip Archive.pax
pax -r -f Archive.pax (or unpack the file using Finder)
as sudo
cp -r Firebird.framework /Library/Frameworks/Firebird.framework
cd Resources
./postinstall

If you are upgrading from a previous version use:
./preupgrade
and then
./postupgrade

SuperServer

Download FirebirdSS-2.5.4-26856-x86_64.pkg.zip
Then follow the same steps as above, and ignore any errror messages that reference
a, /Resources/doc/doc: No such file or directory
b, chmod /Library/StartupItems/Firebird/Firebird: No such file or directory
c, /Library/LaunchDemons/org.firebird.gds.plist: service is already loaded.

a ps -eaf should show both fbserver and fbguard running.

Monday, July 27, 2015

gbak -stat

From the Bug Tracker:

Vlad Khorsun commented on CORE-1999:
------------------------------------

gbak now has a new command-line switch

    -ST(ATISTICS) TDRW    show statistics:
        T                  time from start
        D                  delta time
        R                  page reads
        W                  page writes

Sample output:

firebird>gbak -v -stat tdrw -r o a.fbk a.fdb
gbak:opened file a.fbk
gbak: time     delta  reads  writes
gbak:    0.173  0.173      0      0 transportable backup -- data in XDR format
gbak:    0.175  0.002      0      0             backup file is compressed
gbak:    0.177  0.001      0      0 backup version is 10
gbak:    0.270  0.092      0    650 created database s:\Temp\A+.FDB, page_size 8192 bytes
gbak:    0.273  0.002      0      2 started transaction
gbak:    0.274  0.001      0      0 restoring domain RDB$29
gbak:    0.275  0.001      0      0 restoring domain RDB$12
...
gbak:   18.661  0.002      0      0 restoring data for table TEST1
gbak:   18.698  0.036      0      0    10000 records restored
gbak:   18.735  0.036      0      0    20000 records restored
...
gbak:   25.177  0.036      0      0    1770000 records restored
gbak:   25.220  0.042      0   1633    1780000 records restored
gbak:   25.256  0.036      0      0    1790000 records restored
...
gbak:   38.702  0.002      0      0     restoring privilege for user SYSDBA
gbak:   38.707  0.004     22      0 creating indexes
gbak:   45.015  6.308     82  38394     activating and creating deferred index T2_VAL
gbak:   45.132  0.116      3      9     activating and creating deferred index TEST_S_UNQ
gbak:   46.486  1.354      0  10775     activating and creating deferred index RDB$PRIMARY1
gbak:   46.566  0.079      0      9     activating and creating deferred index T1_IDX
gbak:   46.661  0.095      5     15 committing metadata
gbak:   46.665  0.003      8     10 fixing views dbkey length
gbak:   46.666  0.001      1     18 updating ownership of packages, procedures and tables
gbak:   46.671  0.005      0      0 adding missing privileges
gbak:   46.673  0.001      0      0 fixing system generators
gbak:   46.682  0.008      4     13 finishing, closing, and going home
gbak:   46.684  0.002    171  82442 total statistics
gbak:adjusting the ONLINE and FORCED WRITES flags

Monday, June 1, 2015

The semantics of isc_tpb_autocommit

From Vlad Horsun:

A simplified overview of the autocommit code:

When a transaction, marked as TRA_autocommit performs any of following actions, it is marked also as TRA_perform_autocommit

  • insert
  • update
  • delete
  • select with lock
  • post event
The TRA_perform_autocommit flag is checked when
  • the engine receives input message
  • the engine sends an output message
  • the engine starts to execute a request
  • the engine finishes executing a DDL request
When the TRA_perform_autocommit flag is detected, the engine runs on-commit triggers (not for DDL, that looks like a bug) and performs commit retaining. A new transaction will have TRA_autocommit flag set and TRA_perform_autocommit not set.

Wednesday, February 18, 2015

Yosemite, SuperServer, and StartupItems


There seems to be a small problem with Firebird on Yosemite (OSX 10.10), it looks like Apple have finally deprecated StartupItems, and currently SuperServer uses this to start itself on reboot.

Apple state:
"Startup Items
Deprecation Note: Startup items are a deprecated technology. Launching of daemons through this process may be removed or eliminated in a future release of OS X."

Which is obviously what has happened.

This is followed by

"Unless your software requires compatibility with OS X v10.3 or earlier, use the launchd facility instead."

Which is currently what Classic does.


If you install Firebird after upgrading to Yosemite, you can start the server manually by simply using

/Library/StartupItems/Firebird/Firebird start

However if Firebird was already installed, it looks as if the StartupItems folder is removed during the upgrade, but you should be able to start the server using the following....

/Library/Frameworks/Firebird.framework/Resources/bin/fbguard -daemon -forever

But if you want Firebird SuperServer to start automatically on reboot you could use the following org.firebird.gds.plist file in /Library/LaunchDaemons



and the command

launchctl load org.firebird.gds.plist

should now start Firebird immediately and also on reboot.

Update 2nd July 2015

I got an email from David Nock suggesting that the following plist would do a better job at managing SuperServer on Yosemite (10.10). Some brief tests suggest that he is right. I will be committing the following for 2.5.5, but I am documenting this here in case anybody wants to use this.



Wednesday, November 12, 2014

Services API extension - Nbackup Support

From docs/README.services_extension.

Services API extension - Nbackup support.
(Alex Peshkov, peshkoff@mail.ru, 2008)

Nbackup performs two logical groups of operations - locking and unlocking a database and backup and restoring it. It doesn't make much sense duplicating locking and unlocking in using services, because that functionality is present remotely in via the SQL language interface (ALTER DATABASE). But backup and restore must be run on localhost and the only way to access them is via nbackup utility.

Therefore expanding the services API to support this functionalty is useful.

The following actions were added:

isc_action_svc_nbak - incremental nbackup,
isc_action_svc_nrest - incremental database restore.

The following parameters were added:
isc_spb_nbk_level - backup level (integer),
isc_spb_nbk_file - backup file name (string),
isc_spb_nbk_no_triggers - do not run DB triggers (option).

Samples of use of new parameters in fbsvcmgr utility (supposing login and
password have been set using some other method):

 Create backup level 0:
  fbsvcmgr service_mgr action_nbak dbname employee nbk_file e.nb0 nbk_level 0
 Create backup level 1:
  fbsvcmgr service_mgr action_nbak dbname employee nbk_file e.nb1 nbk_level 1
 Restore database from this files:
  fbsvcmgr service_mgr action_nrest dbname e.fdb nbk_file e.nb0 nbk_file e.nb1

Thursday, September 26, 2013

An update about Firebird on iOS


Based on a comment I made in response to someone asking about the availability of Firebird on IOS (after someone mentioned that the recent release of Delphi XE5 has support for an embedded version of InterBase for iOS and Android), I thought I would write a few more details of the hows and wherefores here.

1. I can confirm that yes, I have managed to cross-compile Firebird for iOS on my Mac. But note, cross-compiling in Firebird 2.5 is difficult and not for the faint hearted (especially ICU). The ability to cross-compile is only really available in the Firebird 3.0 tree.

2. The current build I have created is a normal Mac framework, and it needs to be finessed into an embedded bundle using this script.

Firebird embedded on MacOSX

The script is available in svn in the B2_5_Release tree, located in the builds/install/arch-specific/darwin directory. This will take an existing new build of Firebird 2.5 and convert it into an appropriate bundle format. However the current code still has a few issues. The current (2.5.2) code expects Firebird to be created as a framework, so the config_root module for darwin doesn't have the necessary "smarts" to be able to work out where things are automatically depending on whether the install is a framework, or if its embedded. However new code committed recently to B2_5_Release does. The build I currently have doesn't use this new code and as such requires that the environment variable FIREBIRD must me set.

3. I had planned to rebuild the code using the new embedded support for locating various important files that embedded needs, when my Mac died. The Mac is now currently being repaired and having a new motherboard fitted. Cost 600.00 Euros. It seems this is common fault on Macs of this age. So any further work will have to wait.

4. To test the build currently, it seems you will need an iOS device (iPhone or iPad) running iOS 6.1+ as the code was compiled with the following switch -miphonos-version-min=6.1. You also need to be need to be registered as a developer at Apple, and you will need to get the relevant certificate ids from them for the devices that you will test or use. Firebird like InterBase will never be availble via the App Store as it relies on dynamically linked libraries. Only statically linked applications are allowed in the App Store (security issues).

5. I now have an iPad I can use to start testing (thanks to a very generous donation), but haven't yet signed up as an official Apple developer and logged my devices.

If anyone wants to help/assist in anyway, please feel free to contact me.

18th December 2013


An updated build of embedded Firebird for IOS can now be downloaded from

http://www.ibphoenix.com/downloads/FirebirdIOSembed.tar

There were some issues with loading dylibs, these have been corrected using the install_name_tool -change
command. The default embedded script I used to build the embedded package forgets that I had to cross compile ICU 5.1 rather than build ICU with Firebird.

isql/gbak (or any other firebired utility) can now find the relevant libs they need by searching the directory above them i.e. MacOS. There was however an issue if you used

symbolic links, symbolic links, extra ``/'' characters, and references to /./ and /../ in the file_name.

This has now been corrected using the realpath function.
I haven't tested this myself yet on IOS, so once again feedback would be appreciated.



  

Thursday, August 1, 2013

Some Analytics


Known new Firebird installations (direct via the /afterinstall page) between 4th June 2011 and 31th July 2013 (since the transition to new Firebird website)

Total: 1,584,731

The following numbers don't just count only the above direct visits (as there are about 1%-2% of installs coming from other sources)

By Country:

1. Brazil    555,483
2. Russia    160,982
3. Turkey    104,448
4. Poland    75,960
5. Germany    65,597
6. Ukraine    57,509
7. South Korea    46,202
8. China    44,076
9. Italy    38,526
10.USA        33,064
11.Mexico    26,688
12.Spain    25,654
13.Czech Rep.    25,035
14.Indonesia    22,732
15.Colombia    21,964
16.France    21,758
17.Bulgaria    19,602
18.(not set)    16,827
19.Belarus    16,414
20.South Africa    14,466
21.Japan    14,289
22.UK        13,314
23.Hungary    11,189
24.India    10,451
25.Malaysia    10,421

Others are below 10,000

By Sub Continent Region:

1. South America    604,253
2. Eastern Europe    381,068
3. Eastern Asia        114,604
4. Western Asia        113,098
5. Western Europe    109,585
6. Southern Europe    84,432
7. South-Eastern Asia    55,412
8. Northern America    37,434
9. Central America    31,323
10.Northern Europe    24,592

By Continent:

1. Americas    676,227
2. Europe    599,677
3. Asia        308,592
4. Africa    37,020
5. (not set)    16,827
6. Oceania    10,008

We know that Brazil is the world leader in Firebird installations (one installation of Firebird per 362 citizens), but it still quite amazing that one single South American country has more Firebird installations than Europe in total.

Third place for Turkey is very interesting. I wonder what they are using Firebird for? It must be something quite large as 100k installations is not a small amount (one Firebird installation per 725 citizens, where for example the Russian Federation has one installation per 881).

Fourth for Poland is not so surprising, but perhaps it does indicate that it would be a good place for some kind of regional Firebird event.

South Korea and China taking 7th and 8th place is also interesting. Although total numbers are "small" for China, almost one hundred thousand installations combined is an interesting foothold. (It's about 1/3 of the approximately 300,000 installations in Asia). We previously assumed that the strong regional leader was Japan (installations per capita), but it's actually South Korea with one Firebird installation per 1086 citizens)

So we took these 1,584,731 servers and calculated an equivalent cost of buying InterBase for a single user at (200.00 Euros + 38.00 VAT), then thats a saving to Firebird users of  377 million Euros, or 2,262 million Euros if these installations were all translated into 10 user servers (1,200.00 Euros + 228.00 Euros VAT), or
4,714 million Euros if they were all 25 user servers (2,500 Euros + 475.00 VAT).

Very little of those savings make their way back to the Firebird project (less than 0.1%), assuming that we took the lowest figure (377 Million Euros) indicated by single user installs.

(cuurent prices taken from Embarcadero online shop)

IBConsole


I had to do some research on behalf of a customer, to see how viable IBConsole (released with InterBase 6.0) would be with Firebird 2.5.2 Classic. (remember it was developed for SuperServer via the Services API only). The results were a little surprising.

1. Creating and adding users works
2. Sweep works
3. Backup works
4. Restore works (Although it does generate an access violation in the console on completion)
5. Transaction Recovery (limbo's) generates an unavailable database error.
6. Shutdown - Database shutdown completed successfully, database has been shut down
and is currently in single user mode. A gstat -h indicates that the database is in multi-user maintenace mode, so the database has been closed for maintenance and multiple connections are allowed only for SYSDBA or the database owner only.
7. Restart completes sucessfully, and gstat -h indicates that  the database is now in normal mode.
8. View Metadata generates a RDB$CHARACTER_SET not found error.
9. The SQL tool seems to work ok.

So in general - its still usable with some restrictions

Personally if you want a sraightforward tool,  I would recommend FlameRobin. Its free and it supports interactive SQL, backup/restore etc and user management. Its also cross platform so you can run it locally on Linux and MacOSX if you want.

Friday, May 31, 2013

How to backup a working Firebird database using a third party backup tool.


One of the basic problems of trying to use a third party backup tool, or simple file copy of a Firebird database whilst a database is active and online, is that the tool or utility has no concept of transactions, so all you get is a copy of what is in the O/S buffer or disk of the database at the time you make the backup.  However this "copy" of the database might be changing as new or active transactions are committed to the database while the copy is taking place. This is likely to produce at best, an inconsistent database, or at worst something that is corrupt and can't be used. Prior to Firebird 2.0 (other than using gbak) the only way you could do a backup or copy like this was to shut the database down, and make sure that no users were accessing the database before you invoked the third party backup tool or copy.

However it is possible to use Nbackup to achieve the functional equivalent of a gbak and use a third party backup tool.

The first thing you need to do is start a "freeze" on your database using the following syntax.

nbackup -U username -P password -L database.fdb

This will effectively lock the database, a flag is placed on the database header page, and it is set to "Locked" to let the engine know that all amended database pages that are written to the database are now being redirected to a delta file.

Changes are flushed from the internal (Firebird) database cache to the O/S cache when a transaction is committed, if forced writes are on then these changes are flushed directly to disk, the final task on commit is to mark the transaction as committed in the Transaction Inventory Page. Once the database is locked, all commits are written to the delta file rather than the database, thus ensuring that the database is kept in a consistent state.

Once the lock is applied, a simple gstat -h on the database wil show the "LOCKED" status as an optional database attribute. Once the -L command has done its work, a dela file will now be capable of receiving any committed changed database pages.

You can now use your an alternative backup tool whilst database users continue to work. When your backup tool has finished doing what it needs to do to take a copy of the database, you can "unfreeze" the database using the nbackup -N (unlock) command.

nbackup -U username -P password -N database.fdb

The unfreeze causes nabckup to merge the changed pages from the delta file back into the main database, when completed the delta file is removed and the database header is changed back to its normal state.
The backup you made of the database in its frozen state will still be in a "LOCKED" state, so if you need to restore it users will be unable to attach to it until you perform a "fixup". The fixup will reset the locked flag on the database header page back to normal, even though there isn't a delta file associated with the database.

Note: If you are going to use this capability, please make sure that you are using the latest version of Firebird, as a number of bugs in nbackup have been fixed since its original release.

Thursday, May 23, 2013

CORE-4100


An attempt to explain the rationale behind Vlads fix for CORE-4100.

When a sweep has successfully finished its work it advances the Oldest Interesting Transaction (OIT) up to the value of the Oldest Snapshot Transaction (OST) that was recorded when the sweep started. The OIT transaction is the first transaction in a state other than committed in the database’s Transaction Inventory Pages (TIP), while the OST is the oldest transaction that was started in Snapshot mode.

If while the sweep is running, there are more new transactions started than is the sweep interval (by default, when the OIT is 20,001 transactions less then the Oldest Snapshot Transaction), it is possible that the new OIT value could again be more than the sweep interval less the OST value, thus ensuring that a new sweep could start immediately.

After a sweep has completed the first new transaction will pick up the updated OIT value from the saved OST on the database header page that was recorded when the sweep began, it will also read the actual OST from the header page, as well as the Oldest Active Transaction (OAT), the first transaction marked as active in the TIP pages. If the sweep condition is then met, a sweep begins.

Ideally what should happen is that the transaction should pick up the recalculated OIT from (in transaction) rather than the OIT from the header page in order to determine whether a sweep should start or not.

An example:

1. Transaction 1000 was rolled back, therefore the next transaction when it calculates the OIT will use 1000 and is now considered a stuck or “interesting” value.

2. By the time transaction 21001 occurs we have the following numbers:
OIT     1000
OST     21000,
Next     21001

3. An automatic  sweep is started, and it makes a note that the OST is 21000

4. While the sweep is running 30000  new transactions get started and committed.

5. When the sweep has finished doing its garbage collection and is about to advance the OIT, the numbers on the database header page are in effect
OIT     1000
OST     51000
Next    51001

6. The sweep then advances the OIT up to previously noted OST (21000)

7. A new transaction is started and it then obtains the following numbers from the database header page:
tra_oldest (OIT)            21000
tra_oldest_active (OAT)        51002
tra_number (OST)        51002
 
However within the transaction it has also recalculated the new oldest interesting transaction number as 51001 which will be written to the database header page at the end of the transaction.

8. However based on the OIT read from the database header page the following condition below is true

tra_oldest_active (OAT) - tra_oldest (OIT) > sweep_interval
51002 – 21000 > 20000 therefore a sweep will be started again.

9. However when sweep starts the database header page will have been updated to contain an OIT of 51001, so instead of doing the above, we really should check the local OIT that is going to be written out to the header page rather than the header page itself, before deciding on whether to do a sweep or not.



Thursday, September 20, 2012

Firebird Embedded on MacOSX


Based on a document written by Fulvio, a while ago, I finally spent time writing a make file that will automatically create an embedded version of Firebird that will run on MacOSX as a bundle. All you do is make a normal build of Firebird Classic and then use this make file to create the Firebird.app folder which is set up in a way that allows you to access a database via isql for example without the need for a full framework. The make file detailed below was written for Firebird 2.5.x

 (updated 15th April 2014)

file embed.darwin - committed to svn B2_5_Release/builds/install/arch-specific/darwin and also to trunk
Code was added to config_root.cpp to simulate binreloc (posix) on MacOSX. Find the name of the excutable in the directory below firebird, strip the executable name, strip the lowest directory, now use the remainder to find the configuration file, firebird.conf, now read the conf file to get the actual RootDirectory for Firebird.

embed.darwin updated below, to fix a couple of other issues.

To make a Classic version of Firebird for MacOSX:
./configure
make
cd gen
make -B -f Makefile.install

Then you can use the following make file to create an embedded version.
copy embed.darwin from builds/install/arch-specific/darwin

make -B -f embed.darwin

# Makefile script to generate an embedded Firebird bundle from an existing Framework

    FBE=../gen/firebird/Firebird.app
    BINLOC=../gen/firebird/Firebird.app/Contents/MacOS/firebird/bin
    LIBLOC=../gen/firebird/Firebird.app/Contents/MacOS/firebird
    INTLOC=../gen/firebird/Firebird.app/Contents/MacOS/firebird/intl
    OLDPATH=/Library/Frameworks/Firebird.framework/Versions/A/Libraries

all:
    -$(RM) -rf $(FBE) ../gen/firebird/Firebird.app
    mkdir -p $(FBE)/Contents
    mkdir -p $(FBE)/Contents/MacOS
    mkdir -p $(FBE)/Contents/MacOS/firebird
    mkdir -p $(FBE)/Contents/Resources
    mkdir -p $(FBE)/Contents/Frameworks
    mkdir -p $(FBE)/Contents/Plugins
    mkdir -p $(FBE)/Contents/SharedSupport
    mkdir -p $(FBE)/Contents/MacOS/firebird/bin
    mkdir -p $(FBE)/Contents/MacOS/firebird/intl

    cp ../gen/install/misc/firebird.conf $(FBE)/Contents/MacOS/firebird/firebird.conf
    cp ../gen/firebird/firebird.msg $(FBE)/Contents/MacOS/firebird/firebird.msg
    cp ../gen/firebird/lib/libfbembed.dylib $(FBE)/Contents/MacOS/firebird/libfbembed.dylib
    cp ../gen/firebird/lib/libicudata.dylib $(FBE)/Contents/MacOS/firebird/libicudata.dylib
    cp ../gen/firebird/lib/libicui18n.dylib $(FBE)/Contents/MacOS/firebird/libicui18n.dylib
    cp ../gen/firebird/lib/libicuuc.dylib $(FBE)/Contents/MacOS/firebird/libicuuc.dylib
    cp ../gen/firebird/lib/libib_util.dylib $(FBE)/Contents/MacOS/firebird/libib_util.dylib
    cp ../gen/firebird/security2.fdb $(FBE)/Contents/MacOS/firebird/security2.fdb
    cp ../gen/firebird/bin/gbak $(FBE)/Contents/MacOS/firebird/bin/gbak
    cp ../gen/firebird/bin/isql $(FBE)/Contents/MacOS/firebird/bin/isql
    cp ../builds/install/misc/fbintl.conf $(FBE)/Contents/MacOS/firebird/intl/fbintl.conf
    cp ../gen/firebird/intl/libfbintl.dylib $(FBE)/Contents/MacOS/firebird/intl/fbintl.dylib
    cp ../builds/install/arch-specific/darwin/embed.Info.plist $(FBE)/Contents/Info.plist

    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Firebird \
     ../libfbembed.dylib $(BINLOC)/isql
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicuuc.dylib \
    ../libicuuc.dylib $(BINLOC)/isql
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicudata.dylib \
    ../libicudata.dylib $(BINLOC)/isql
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicui18n.dylib \
    ../libicui18n.dylib $(BINLOC)/isql
  
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Firebird \
     ../libfbembed.dylib $(BINLOC)/gbak
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicuuc.dylib \
    ../libicuuc.dylib $(BINLOC)/gbak
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicudata.dylib \
    ../libicudata.dylib $(BINLOC)/gbak
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicui18n.dylib \
    ../libicui18n.dylib $(BINLOC)/gbak
  
    install_name_tool -change $(OLDPATH)/libicuuc.dylib @loader_path/libicuuc.dylib \
    $(LIBLOC)/libfbembed.dylib
    install_name_tool -change $(OLDPATH)/libicudata.dylib @loader_path/libicudata.dylib \
    $(LIBLOC)/libfbembed.dylib
    install_name_tool -change $(OLDPATH)/libicui18n.dylib @loader_path/libicui18n.dylib \
    $(LIBLOC)/libfbembed.dylib
    install_name_tool -change $(OLDPATH)/libicudata.dylib @loader_path/libicudata.dylib \
    $(LIBLOC)/libicuuc.dylib
    install_name_tool -change $(OLDPATH)/libicuuc.dylib @loader_path/libicuuc.dylib \
    $(LIBLOC)/libicui18n.dylib
    install_name_tool -change $(OLDPATH)/libicudata.dylib @loader_path/libicudata.dylib \
    $(LIBLOC)/libicui18n.dylib

    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicuuc.dylib \
        @loader_path/../libicuuc.dylib $(INTLOC)/fbintl.dylib
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicudata.dylib \
        @loader_path/../libicudata.dylib $(INTLOC)/fbintl.dylib
    install_name_tool -change /Library/Frameworks/Firebird.framework/Versions/A/Libraries/libicui18n.dylib \
        @loader_path/../libicui18n.dylib $(INTLOC)/fbintl.dylib

    install_name_tool -id @rpath/libfbembed.dylib $(LIBLOC)/libfbembed.dylib
    install_name_tool -id @rpath/libicudata.dylib $(LIBLOC)/libicudata.dylib
    install_name_tool -id @rpath/libicui18n.dylib $(LIBLOC)/libicui18n.dylib
    install_name_tool -id @rpath/libicudata.dylib $(LIBLOC)/libicudata.dylib
    install_name_tool -id @rpath/libicuuc.dylib $(LIBLOC)/libicuuc.dylib
    install_name_tool -id @rpath/libicudata.dylib $(LIBLOC)/libicudata.dylib
    install_name_tool -id @rpath/libib_util.dylib $(LIBLOC)/libib_util.dylib


You can now tar a copy of the Firebird.app directory (and underlying), place anywhere on your system,
and set the RootDirectory in the firebird.conf (17th July 2013 - this now works, previously it didn't), or set the FIREBIRD environment variable to the relevant location of the firebird directory in Firebird.app, If your application is under launchctl, you can set the FIREBIRD variable in the Info.plist file provided and your application should run if placed in the same directory. Unfortunately OS X Mavericks does not use the environment.plist, so you need to set the environment variable using launchctl a simple script like the following should do the trick.

 (setup.command)
DIR=$(cd $(dirname "$0"); pwd)
launchctl setenv FIREBIRD $DIR/Firebird.app/Contents/MacOS/firebird
echo setenv FIREBIRD $DIR/Firebird.app/Contents/MacOS/firebird | sudo tee
/etc/launchd.conf

Should we produce a dedicated MacOSX embedded build along with the others (32bit/64bit/lipo)?

The (Firebird.app) can be downloaded from www.ibphoenix.com/downloads/firebirdApp.zip should anybody want it.

Friday, September 7, 2012

CORE-3740 and Firebird V2.5.2


CORE-3740 - SELECT using IN list with 153 or more elements causes crash.
This problem only occurs on MacOS, and cannot be reproduced on Linux or Windows. Initial analysis showed that adjusting the optimisation level of the code as it links (O1 instead of O3) would increase the number of INS that could be supported but you would still get a crash eventually if the number of INS was large enough.
The consensus of opinion was that this was a stack issue, so we increased the stack from the default 8mb in launchctl to 64mb, our test still crashed.

We then tried embedded (local) firebird and increased the cache there using ulimit, strangely enough this worked. So it definitely was a stack issue but where? Some debugging code and some careful googling showed the problem. Even Classic launches a forked inet_server via a new thread.

From an Apple Technical Q&A
"Each Mac OS X process is launched with a default stack size of 8 Megabytes. This allocation is used exclusively for the main thread's stack needs. Each subsequent thread created is allocated its own default stack, the size of which differs depending on the threading API used. For example, the Mac OS X implementation of Pthreads defines a default stack size of 512 Kilobytes, while Carbon MPTasks are created with a 4 Kilobyte stack."

Patch applied to src/jrd/ThreadStart.cpp

-#ifdef _AIX
-// adjust stack size for AIX
+#if defined(_AIX) || defined(DARWIN)
+// adjust stack size

 // For AIX 32-bit compiled applications, the default stacksize is 96 KB,
 // see . For 64-bit compiled applications, the default stacksize
 // is 192 KB. This is too small - see HP-UX note above

+// For MacOS default stack is 512 KB, which is also too small in 2012.
+
     size_t stack_size;
     state = pthread_attr_getstacksize(&pattr, &stack_size);
     if (state)
         Firebird::system_call_failed::raise("pthread_attr_getstacksize");

-    if (stack_size < 0x40000L)
+    if (stack_size < 0x400000L)
     {
-        state = pthread_attr_setstacksize(&pattr, 0x40000L);
+        state = pthread_attr_setstacksize(&pattr, 0x400000L);
         if (state)
             Firebird::system_call_failed::raise("pthread_attr_setstacksize", state);

Monday, June 18, 2012

An ODBC driver for Firebird on MacOSX


I was recently contacted by a Firebird user on MacOSX who was trying to get the Firebird ODBC driver to build on MacOSX. I thought I would try and step in to help.

For those of you who follow the CVS checkins for OdbcJdbc you might have noticed the addition of a number of a new directory in the Builds directory called Gcc.darwin containing a makefile, a readme and a .sh file to create a lipo'ed dylib. The driver sucessfully builds and passes some simple tests. Feel free to contact me for a copy of the dylib to test further.

The readme contains the following information:

These instructions should allow a user to get a working user DSN for ODBC to connect
to Firebird on MacOS. Comments please to Paul Beach (pbeach at ibphoenix.com.

To build the library, edit makefile.darwin, and select the ARCH (i386 or X86_64).
then make -B -f makefile.darwin all

The Firebird ODBC library can be built in both 64bit or 32bit format.
lipo.sh creates a fat libary that can be used on either version of Firebird.

1. Download the MacOSX ODBC Administrator from support.apple.com
http://support.apple.com/downloads/ODBC_Administrator_Tool_for_Mac_OS_X
and install.

2. Once installed it can be accessed via Applications/Utilities/ODBC Administrator

3. Place the libOdbcFB.dylib in $HOME/odbc for example then add the Firebird driver
(dylib) name and location to the Drivers tab in the Administrator.
e.g
Description: Firebird ODBC Driver
Driver file: /Users/username/odbc/libOdbcFB.dylib
Define as: User
This will create an odbcinst.ini file in $HOME/Library/ODBC

4. Now you need to create a User DSN via an odbc.ini file.
Use the text below as an example, copy and paste into an odbc.ini
file placed in $HOME/Library/ODBC
Make sure that you modify the text so it points to your database
and uses your username and password.


[ODBC Data Sources]
Test = Firebird

[Test]
Driver               = /Users/username/odbc/libOdbcFb.dylib
Description          = Test Firebird ODBC
Dbname               = localhost:/Users/databases/test.fdb
Client               =
User                 = SYSDBA
Password             = masterkey
Role                 =
CharacterSet         = NONE
ReadOnly             = No
NoWait               = No
Dialect              = 3
QuotedIdentifier     = Yes
SensitiveIdentifier  = No
AutoQuotedIdentifier = No

[ODBC]
Trace         = 0
TraceAutoStop = 0
TraceFile     =
TraceLibrary  =

This User DSN should appear in the User DSN tab the next time you load the
ODBC Administrator.

5. You can test whether it works using iodbctest and then using the dsn
dsn=Test, if all is well it should connect and you can issue SQL statements.

To create a System wide version of the ODBC driver, copy the libOdbcFB.dylib
to /usr/lib make sure the Administrators Drivers tab now points to this file.

Copy the DSN above to /Library/ODBC and modify.

Note: (13th June 2012)
The ODBC library is linked to libfbclient.dylib found in the Firebird framework
Libraries directory. Not all SuperServer builds of Firebird have this library installed
by default. If this is the case get a copy of the Firebird Classic build and extract
the libfbclient library and place it in
/Library/Frameworks/Firebird.framework/Versions/A/Libraries

Note: (30th Nov 2015)
Since Mavericks (10.9) Apple no longer ship the default odbc header files as part of their SDK, so you need to get the files from an older SDK e.g. /Developer/SDKs/MacOSX10.7.sdk/usr/include or download the files you need from http://www.iodbc.org/

Wednesday, February 22, 2012

Firebird V2.0.7


We are currently preparing to release Firebird 2.0.7, since I take responsibility for the Mac builds, I did a 2.0.7 build on MacOSX 10.7 using the development tools installed by XCode 4.1 (gcc 4.2.1 etc). I set up the relevant environment variables for this older 32bit only build CFLAGS, CXXFLAGS, LD_FLAGS and also set the MACOSX_DEPLOYMENT_TARGET=10.4. The builds completed without any problems, some simple tests on MacOSX 10.7 showed no problems.

Now - Imagine my surprise when Philippe told me that when he tried to QA the builds on MacOSX 10.5 we got this error on SuperServer startup.

Process: fbserver [623]
Path:
/Library/Frameworks/Firebird.framework/Resources/English.lproj/var/bin/fbserver
Identifier: fbserver
Version: ??? (???)
Code Type: X86 (Native)
Parent Process: fbguard [310]

Date/Time: 2012-02-09 09:42:13.939 +0100
OS Version: Mac OS X 10.5.8 (9L31a)
Report Version: 6
Anonymous UUID: FA7F8C0C-581B-4153-ADBE-2BCB59C5F823

Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000002, 0x0000000000000000
Crashed Thread: 0

Dyld Error Message:
Symbol not found: ___moddi3
Referenced from:
/Library/Frameworks/Firebird.framework/Resources/English.lproj/var/bin/fbserver
Expected in: /usr/lib/libSystem.B.dylib

A simple nm and grep shows the following for the 10.5 libSystem.B.dylib

nm /usr/lib/libSystem.B.dylib | grep moddi3
00083490 t ___moddi3
0003df70 t ___umoddi3

On 10.5 ___moddi3 is defined in libgcc_s.1.dylib which links to libsystem.B.dylib

From what I can gather these *moddi3 symbols are routines for doing 64bit maths on 32bit systems.

However the same on 10.7 returns nothing, however the symbols can be found in libgcc_s.10.5.dylib which does not link to libgcc_s.1.dylib hence the missing symbols message.

Supposedly this can be fixed by linking explicity to to libgcc_s.10.5.dylib
using -lgcc_s.10.5. I got round it by booting up my copy of Snow Leopard (10.6) and
building Firebird 2.0.7 there instead of on MacOSX 10.7

So basically if you want to buld an application that is deployable on 10.5 or less, you can't - unless you know how to get around the above problem. Its as if although you can build 32bit applications for 32bit versions of MacOSX, they won't run, because they are incompatible with any version of the OS less than 10.6.

Tuesday, July 26, 2011

Firebird 2.5 SuperServer and MacOSX 10.7 (Lion)


There is a small problem with Firebird 2.5 SuperServer and MacOSX 10.7 (Lion)...
SuperServer will not start, and produces a crash report header similar to this

Update 26th August 2011
Its not just 2.5 SuperServer, reports have come in that SuperServer for Firebird 2.1.4 will not start, also the same problem exists for Firebird 2.5 SuperClassic.

Process: fbserver [706]
Path: /Library/Frameworks/firebird.framework/Versions/A/Resources/bin/fbserver
Identifier: fbserver
Version: ??? (???)
Code Type: X86 (Native)
Parent Process: fbguard [166]

Date/Time: 2011-06-10 07:59:42.374 -0400
OS Version: Mac OS X 10.7 (11A480b)
Report Version: 9

Anonymous UUID: B7EDF790-CE72-4B21-A982-B9EA4F4E2088

Crashed Thread: 1 Dispatch queue: com.apple.libdispatch-manager

Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000

Application Specific Information:
BUG IN CLIENT OF LIBDISPATCH: Do not close random Unix descriptors

The bug is fixed in Firebird 2.5.1 but Firebird 2.5.1 is not available yet. So I have fixed the problem also in the Firebird 2.5 code and produced 32bit and 64bit builds that work properly.

I have had new builds uploaded to Sourceforge to fix the problem with Firebird
2.1.4 SuperServer, you can distinguish the new builds from the old by the build no.
Old = 18393, New = 18393. Because we have some issues with 2.5.1 that are currently being investigated, I plan to update the 2.5 builds on Sourceforge soon.

Update 28th Sep 2011
The Firebird 2.5 builds have also been replaced on Sourceforge, so you just need to download the latest build. However Firebird 2.5 will be replaced by Firebird 2.5.1 very shortly, builds are now taking place and will be QA'd and released shortly.

Any problems - please let me know.

Monday, July 4, 2011

Firebird V2.1 Error: value exceeds the range for valid dates


You are restoring a backup of a Firebird 1.5 or 2.0 database to Firebird 2.1 and you see an error similar to this:

gbak: writing data for table xyz
gbak:20000 records written
gbak: Error: value exceeds the range for valid dates
gbak: Error: gds_$receive failed
gbak:Exiting before completion due to errors

How do you go about solving the problem?
Well first of all a quick visit to the Firebird bug tracker reveals
http://tracker.firebirdsql.org/browse/CORE-1714 and a couple of comments from Dimitry Yemanov.

“The error means to say that some column has an invalid date value (outside the supported range). Prior to V2.1, it was possible to store such invalid values in the database, but now it's prohibited. A verbose output should point you to a problematic table.” Also “The current behavior is intended and is unlikely to be changed.”

1. Firstly use the –v (verbose option of gbak) to find out the table that is causing the problem.
2. Check the table xyz for date columns
3. Perform the following SQL operation on all the date columns you found in 2.

isql> update XYZ set MY_DATE_COLUMN = MY_DATE_COLUMN;

At some point during the process you will see the same error that gbak produced, but now you will know which column is causing the problem.

4. Install Firebird 1.5 or 2.0, by going back to the version of Firebird that allows for invalid dates, you will be at least able to correct the invalid date to something more appropriate.

5. Now lets check for dates that are outside of their proper range (01 Jan 0001 - 31 Dec 9999)

Below date zero:

isql> select PRIMARY_KEY from XYZ where MY_DATE_COLUMN < '0001-01-01'

if an error occurs correct the date to something more appropriate and meaningful

Maximum date

isql> select PRIMARY_KEY from XYZ where MY_DATE_COLUMN > '9999-12-31'

if an error occurs correct the date to something more appropriate and meaningful

6. You can now backup the database using Firebird 1.5 or 2.1 and successfully restore under 2.1

 For anyone interested, the following is a shell script provided by a friend that can be used on Linux to correct the above errors automagically across multiple databases.

#!/bin/bash -u
# correct OLD invalid dates in a DB
#
#    Ray Holme, July 2013 -  207-583-6613
#       Rainbow Applications Inc., Waterford, ME 04088
#
ARGCNT=$#
MYNAME=`/bin/basename $0`
DATEL="'1/1/0001'"
DATEH="'12/31/9999'"
DRYRUN=0
ERRCNT=0
FLDS=/tmp/$$.flds
ISQL=/opt/firebird/bin/isql
ListDBS=""
LOG=/tmp/$$.out
NOFILE="could not find"
NOTNULL="is not null"
RANGE="not between $DATEL and $DATEH"
RM=/bin/rm
SQL=/tmp/$$.sql
USAGE="usage: $MYNAME <-d> DBname1 ...>"
WORK=/tmp/$$.wrk

ABORT()       { $RM -f $FLDS $SQL $WORK; echo $MYNAME aborted; exit $1; }
INCR_ERRCNT() { ERRCNT=`echo $ERRCNT + 1 | /bin/bc`;  }

ANSWER_ME() {
  OK=2; until [ $OK -ne 2 ];
   do
    echo "Please type '$2' or '$3'."; echo -n "$1 [$2]: "; read ANS
    if [ "$ANS" = "$2" -o "$ANS" = "" ]; then OK=1
    elif [ "$ANS" = "$2" ];              then OK=0
    fi
   done
}

#get list of dbs to do
until [ $# -eq 0 ];
 do case "$1" in
     -d) DRYRUN=1; ARGCNT=`echo $ARGCNT - 1 | /bin/bc`    ;;
      *) if [ ! -f $1 ]; then echo $NOFILE $1; INCR_ERRCNT;
         else ListDBS="$ListDBS $1"                       ;
         fi                                               ;;
    esac
    shift
 done
if [ "$ListDBS" = "" ]; then echo "$USAGE"; exit 1; fi
trap "ABORT 1" 1 2 3

if [ ! -w /etc/passwd ]; then echo you must be root to execute $MYNAME; exit 1; fi
$RM -f $LOG        # get what we need to do (worst case)
for DB in $ListDBS
 do
  $RM -f $FLDS
  if [ $ARGCNT -gt 1 ]; then
    ANSWER_ME "about to check $DB - c to continue, s to skip" c s
    if [ $OK -eq 0 ]; then continue; fi   # skipped
  fi
  $ISQL $DB -pag 9999 > /dev/null 2> $WORK <output $FLDS;
select r.rdb\$relation_name, rf.rdb\$field_name
  from  rdb\$relations r
  inner join rdb\$relation_fields rf on (r.rdb\$relation_name = rf.rdb\$relation_name)
  inner join rdb\$fields f on (f.rdb\$field_name = rf.rdb\$field_source)
  where r.rdb\$view_source is null and r.rdb\$system_flag = 0
    and f.rdb\$field_type = 35
  order by 1, 2;
EOF
  if [ -f $WORK ];     then XXX=`cat $WORK`; else XXX="";            fi
  if [ "$XXX" != "" ]; then echo problems working $DB; INCR_ERRCNT;  continue;    fi
  /bin/egrep -v "RELATION_NAME|==========" < $FLDS | grep -v '^$' \
  | /bin/awk '{printf("%-32.32s %s\n", $1, $2)}'> $WORK
  /bin/mv $WORK $FLDS
  if [ -f $FLDS ];     then XXX=`cat $FLDS`; else XXX="";            fi
  if [ "$XXX" = "" ];  then echo "no dates in $DB - curious (skip)"; continue;    fi
# pass 1 - we show the records with errors embedded
  echo "Listing effected records in DB: $DB"        >> $LOG
  echo "output $LOG;"                     > $SQL
  LastTable=""
  while read TABLE FIELD
   do
    if [ "$TABLE" != "$LastTable" ]; then
      if [ "$LastTable" != "" ]; then echo ";"        >> $SQL; fi
      LastTable="$TABLE"
      echo "select distinct 'table: $TABLE' from rdb\$database;" >> $SQL
      echo "select * from $TABLE where "        >> $SQL
    else echo -n " or "                     >> $SQL
    fi
    echo "( $FIELD $NOTNULL and ($FIELD $RANGE ))"    >> $SQL
   done < $FLDS
  if [ "$LastTable" != "" ]; then echo ";"        >> $SQL; fi
  $ISQL $DB -pag 9999 -i $SQL
# pass 2 - do clean up
  $RM $SQL
  while read TABLE FIELD
   do
    echo "update $TABLE set $FIELD = $DATEL where $FIELD $NOTNULL and $FIELD < $DATEL;" >> $SQL
    echo "update $TABLE set $FIELD = $DATEH where $FIELD $NOTNULL and $FIELD > $DATEH;" >> $SQL
    echo "commit;"                    >> $SQL
   done < $FLDS
  echo "exit;"                        >> $SQL
  if [ $DRYRUN -eq 0 ]; then $ISQL $DB -pag 9999 -i $SQL
  else echo "Would run this sql on $DB"; /bin/more $SQL
  fi
 done                     # end of outer (DB) loop

$RM -f $FLDS $SQL $WORK
echo file $LOG contains a list of all effected records
exit $ERRCNT