Data Management Global

Data Management Global

A hub for collaboration, learning, networking, and cultural exchange, and contributing to positive global engagement

 View Only

How to Solve IBM DB2 Connectivity Issues When Packaging with PyInstaller

By JOBIN J posted 2 days ago

  

Introduction

Packaging Python applications with PyInstaller is usually a smooth process—until you introduce IBM DB2 connectivity using the ibm_db package. Suddenly, what should be a simple build turns into a maze of cryptic errors and missing dependencies. If you’ve ever spent hours (or even days) trying to figure out why your executable won’t run, you’re not alone.

Note: This guide focuses on resolving these issues in a Linux environment.

In this guide, we’ll walk you through a real-world issue we faced and share the step-by-step solution that finally worked. By the end, you’ll have a clear roadmap to package your DB2-enabled Python app without headaches.

The Problem: SQL10007N Error

When we packaged our Python application using PyInstaller, everything seemed to work fine during development. However, when we ran the bundled executable, we encountered this error:

Exception: [IBM][CLI Driver] SQL10007N Message "0" could not be retrieved. Reason code: "3". SQLSTATE=42724 SQLCODE=-10007

This error is particularly frustrating because:

  1. The error message itself is cryptic (a message about not being able to retrieve a message!)
  2. It works perfectly in development but fails in the PyInstaller bundle
  3. The reason code "3" doesn't provide obvious clues
  4. Standard PyInstaller configurations don't catch the issue

Understanding the Root Causes

After extensive debugging, we identified four critical issues that cause this problem:

1. Missing ICC Libraries

The IBM DB2 clidriver includes IBM Common Client (ICC) libraries in the clidriver/lib/icc/ directory. These libraries are essential for DB2 connectivity but PyInstaller doesn't automatically detect and bundle them.

Why it matters: Without these libraries, DB2 cannot properly initialize its client components, leading to the SQL10007N error.

2. Locale Mismatch

The DB2 clidriver ships with locale files in a specific format (e.g., en_US.iso88591), but modern Linux systems expect UTF-8 locales (e.g., en_US.UTF-8). When the expected locale directory doesn't exist, DB2 fails to load error messages.

Why it matters: This is the direct cause of the "Message '0' could not be retrieved" error - DB2 literally cannot find the message files.

3. Conflicting libdb2.so.1

PyInstaller's automatic dependency detection sometimes bundles a standalone libdb2.so.1 file that has undefined symbols and conflicts with the complete DB2 client libraries.

Why it matters: This causes symbol resolution errors and prevents proper DB2 initialization.

4. Incomplete Library Path Configuration

Even when libraries are bundled, they need to be in the correct search path, with the ICC directory having the highest priority.

Why it matters: Without proper path configuration, the system may load incorrect or incomplete libraries.

Prerequisites

Before starting, ensure you have:

  • Python 3.8 or higher installed
  • Access to a DB2 database (for connection testing)
  • Basic knowledge of Python and command line

1. Create Project Structure

Create your project directory and basic structure:

# Create project directory mkdir my_db2_app cd my_db2_app # Create source directory mkdir -p src/my_app # Create your main application file touch src/my_app/app.py # Create PyInstaller configuration files touch runtime_hook_db2.py touch my_app.spec touch build.py # Create requirements file touch requirements.txt

Your project structure should look like:

my_db2_app/ ├── src/ │ └── my_app/ │ └── app.py # Your main application ├── runtime_hook_db2.py # DB2 runtime hook (from template) ├── my_app.spec # PyInstaller spec file (from template) ├── build.py # Build script (from template) └── requirements.txt # Python dependencies

2. Create Virtual Environment

On Linux/macOS:

# Create virtual environment python3 -m venv venv # Activate virtual environment source venv/bin/activate # Verify activation (should show venv path) which python

On Windows:

# Create virtual environment python -m venv venv # Activate virtual environment venv\Scripts\activate # Verify activation where python

3. Install Dependencies

Create requirements.txt with these dependencies:

# IBM DB2 driver ibm_db>=3.2.0 # PyInstaller for packaging pyinstaller>=6.0.0

Install all dependencies:

# Upgrade pip first pip install --upgrade pip # Install dependencies pip install -r requirements.txt # Verify ibm_db installation python -c "import ibm_db; print(f'ibm_db version: {ibm_db.__version__}')"

Expected output:

ibm_db version: 3.2.7

Step 4: Create the Application File

Now let's create the main application that will test DB2 connectivity.

File: src/my_app/app.py

#!/usr/bin/env python3 """ DB2 Application with Connection Test This example shows how to connect to DB2 and run queries """ import sys import os def print_environment(): """Print DB2-related environment variables for debugging""" print("\n" + "="*60) print("Environment Variables:") print("="*60) env_vars = ['DB2_HOME', 'IBM_DB_HOME', 'DB2CODEPAGE', 'LD_LIBRARY_PATH'] for var in env_vars: value = os.environ.get(var, 'NOT SET') if len(value) > 80: value = value[:80] + '...' print(f"{var}: {value}") print("="*60 + "\n") def test_import(): """Test if ibm_db can be imported""" print("Testing ibm_db import...") try: import ibm_db version = ibm_db.__version__ if hasattr(ibm_db, '__version__') else 'Unknown' print(f"✓ ibm_db imported successfully (version: {version})") return True except Exception as e: print(f"✗ Failed to import ibm_db: {e}") return False def test_connection(conn_string): """Test DB2 connection and run sample queries""" print(f"\nTesting DB2 connection...") try: import ibm_db # Connect to database print(f"Connecting to database...") conn = ibm_db.connect(conn_string, "", "") print("✓ Connected to DB2 successfully!") # Test 1: Get current timestamp print("\n--- Test 1: Current Timestamp ---") sql = "SELECT CURRENT TIMESTAMP FROM SYSIBM.SYSDUMMY1" stmt = ibm_db.exec_immediate(conn, sql) result = ibm_db.fetch_tuple(stmt) if result: print(f"✓ Current timestamp: {result[0]}") # Test 2: Get database version print("\n--- Test 2: Database Version ---") sql = "SELECT SERVICE_LEVEL, FIXPACK_NUM FROM SYSIBMADM.ENV_INST_INFO" stmt = ibm_db.exec_immediate(conn, sql) result = ibm_db.fetch_tuple(stmt) if result: print(f"✓ DB2 Version: {result[0]}, Fixpack: {result[1]}") # Test 3: List some tables (limit to 5) print("\n--- Test 3: Sample Tables ---") sql = """ SELECT TABSCHEMA, TABNAME, TYPE FROM SYSCAT.TABLES WHERE TABSCHEMA NOT LIKE 'SYS%' FETCH FIRST 5 ROWS ONLY """ stmt = ibm_db.exec_immediate(conn, sql) count = 0 while True: result = ibm_db.fetch_tuple(stmt) if not result: break print(f" {result[0]}.{result[1]} ({result[2]})") count += 1 print(f"✓ Found {count} tables") # Close connection ibm_db.close(conn) print("\n✓ Connection closed successfully") return True except Exception as e: print(f"✗ Connection/Query failed: {e}") import traceback traceback.print_exc() return False def main(): """Main application entry point""" print("\n" + "="*60) print("DB2 Application - Connection Test") print("="*60) # Check if running in PyInstaller bundle if getattr(sys, 'frozen', False): print("✓ Running in PyInstaller bundle") print(f"✓ Bundle directory: {sys._MEIPASS}") else: print("⚠ Running in normal Python environment") # Print environment for debugging print_environment() # Test import if not test_import(): print("\n✗ Import test failed. Exiting.") return 1 # Get connection string from environment or command line conn_string = os.environ.get('DB2_CONN_STRING') if not conn_string and len(sys.argv) > 1: conn_string = sys.argv[1] if not conn_string: print("\n" + "="*60) print("Connection Test Skipped") print("="*60) print("To test DB2 connection, provide connection string:") print("\nOption 1 - Environment variable:") print(" export DB2_CONN_STRING='DATABASE=SAMPLE;HOSTNAME=localhost;PORT=50000;UID=db2inst1;PWD=password'") print(" python src/my_app/app.py") print("\nOption 2 - Command line argument:") print(" python src/my_app/app.py 'DATABASE=SAMPLE;HOSTNAME=localhost;PORT=50000;UID=db2inst1;PWD=password'") print("\nConnection string format:") print(" DATABASE=<dbname>;HOSTNAME=<host>;PORT=<port>;UID=<user>;PWD=<password>") print("="*60) print("\n✓ Import test passed - ibm_db is working!") return 0 # Test connection if test_connection(conn_string): print("\n" + "="*60) print("✓ ALL TESTS PASSED!") print("="*60) return 0 else: print("\n" + "="*60) print("✗ CONNECTION TEST FAILED") print("="*60) return 1 if __name__ == "__main__": sys.exit(main())

What this file does: This is your main application file that demonstrates DB2 connectivity. It includes three main functions:

  • test_import() - Verifies that the ibm_db module can be imported successfully
  • test_connection() - Connects to a DB2 database and runs sample queries
  • print_environment() - Displays DB2-related environment variables for debugging

The application can run in two modes: with or without a database connection. If no connection string is provided, it will only test the import functionality, which is useful for verifying that PyInstaller has bundled everything correctly.

Customizable parts:

  • You can modify the SQL queries in test_connection() to match your specific needs
  • Add additional test functions for your application logic
  • Customize the connection string format if needed

Step 5: Create the Runtime Hook

The runtime hook is crucial—it runs before your application starts and sets up the DB2 environment correctly.

File: runtime_hook_db2.py

import os import sys # Set DB2 environment variables for the bundled clidriver if getattr(sys, 'frozen', False): # Running in PyInstaller bundle bundle_dir = sys._MEIPASS clidriver_path = os.path.join(bundle_dir, 'clidriver') if os.path.exists(clidriver_path): print(f"✓ Using bundled CLI driver: {clidriver_path}") # Set DB2 environment variables BEFORE any imports os.environ['DB2_HOME'] = clidriver_path os.environ['IBM_DB_HOME'] = clidriver_path os.environ['DB2CODEPAGE'] = '1208' # UTF-8 # Set DB2 message catalog paths - CRITICAL for error messages msg_path = os.path.join(clidriver_path, 'msg') if os.path.exists(msg_path): os.environ['DB2_MSG_PATH'] = msg_path os.environ['DB2_CLI_MSG_PATH'] = msg_path # CRITICAL FIX: Fix locale mismatch # Create en_US.UTF-8 from en_US.iso88591 try: import shutil iso88591_path = os.path.join(msg_path, 'en_US.iso88591') en_us_path = os.path.join(msg_path, 'en_US') en_us_utf8_path = os.path.join(msg_path, 'en_US.UTF-8') # Rename iso88591 to en_US if os.path.exists(iso88591_path) and not os.path.exists(en_us_path): os.rename(iso88591_path, en_us_path) print(f"✓ Renamed message catalog: en_US.iso88591 -> en_US") # Copy en_US to en_US.UTF-8 if os.path.exists(en_us_path) and not os.path.exists(en_us_utf8_path): shutil.copytree(en_us_path, en_us_utf8_path) print(f"✓ Copied message catalog: en_US -> en_US.UTF-8") except Exception as e: print(f"⚠ Warning: Could not create locale directories: {e}") # Set library paths with ICC directory having HIGHEST priority lib_path = os.path.join(clidriver_path, 'lib') icc_path = os.path.join(lib_path, 'icc') # Build library path list: icc first, then lib, then bundle dir lib_paths = [] if os.path.exists(icc_path): lib_paths.append(icc_path) if os.path.exists(lib_path): lib_paths.append(lib_path) lib_paths.append(bundle_dir) if lib_paths: lib_path_str = os.pathsep.join(lib_paths) if sys.platform == 'darwin': # macOS os.environ['DYLD_LIBRARY_PATH'] = lib_path_str + os.pathsep + os.environ.get('DYLD_LIBRARY_PATH', '') elif sys.platform.startswith('linux'): # Linux os.environ['LD_LIBRARY_PATH'] = lib_path_str + os.pathsep + os.environ.get('LD_LIBRARY_PATH', '') elif sys.platform == 'win32': # Windows os.environ['PATH'] = lib_path_str + os.pathsep + os.environ.get('PATH', '') print(f"✓ Library paths configured") print(f"✓ DB2 environment ready")

What this file does: The runtime hook is executed by PyInstaller before your application starts. It performs several critical tasks:

  1. Detects PyInstaller environment - Checks if the app is running in a bundled executable
  2. Sets DB2 environment variables - Configures DB2_HOME, IBM_DB_HOME, and DB2CODEPAGE to point to the bundled clidriver
  3. Fixes locale mismatch - Creates the en_US.UTF-8 locale directory that Linux systems expect (this solves the SQL10007N error)
  4. Configures library paths - Sets LD_LIBRARY_PATH to include both the main lib directory and the ICC subdirectory, with ICC having priority

This file addresses all four root causes we identified earlier. The locale fix is particularly important—without it, DB2 cannot load error messages, resulting in the cryptic SQL10007N error.

Customizable parts:

  • If you need to support additional locales, add them in the locale fix section
  • For Windows deployment, you may need to adjust the library path configuration

Step 6: Create the PyInstaller Spec File

The spec file tells PyInstaller exactly what to bundle and how to build your executable.

File: my_app.spec

# -*- mode: python ; coding: utf-8 -*- import os import importlib.util def get_package_path(package_name): """Find where ibm_db is installed""" spec = importlib.util.find_spec(package_name) if spec and spec.submodule_search_locations: return spec.submodule_search_locations[0] elif spec and spec.origin: return os.path.dirname(spec.origin) return None # Find the clidriver that comes with ibm_db ibm_db_path = get_package_path('ibm_db') clidriver_path = os.path.join(ibm_db_path, 'clidriver') if ibm_db_path else None a = Analysis( ['src/my_app/app.py'], pathex=[], binaries=[], datas=[(clidriver_path, 'clidriver')] if clidriver_path and os.path.exists(clidriver_path) else [], hiddenimports=['ibm_db', 'ibm_db_dbi'], hookspath=[], hooksconfig={}, runtime_hooks=['runtime_hook_db2.py'], excludes=[], noarchive=False, optimize=0, ) # CRITICAL FIX #1: Filter out conflicting libdb2 libraries filtered_binaries = [] for name, path, typecode in a.binaries: # Skip libdb2 libraries that are NOT from clidriver if ('libdb2.' in name or 'libdb2.so' in name) and 'clidriver' not in path: print(f"Excluding conflicting library: {name} from {path}") continue filtered_binaries.append((name, path, typecode)) a.binaries = filtered_binaries # CRITICAL FIX #2 & #3: Explicitly add clidriver libraries including ICC if clidriver_path and os.path.exists(clidriver_path): lib_path = os.path.join(clidriver_path, 'lib') if os.path.exists(lib_path): import glob # Add all .so files from clidriver/lib for lib_file in glob.glob(os.path.join(lib_path, '*.so*')): lib_name = os.path.basename(lib_file) if not any(name == lib_name for name, _, _ in a.binaries): a.binaries.append((lib_name, lib_file, 'BINARY')) print(f"Adding clidriver library: {lib_name}") # Add ICC libraries (IBM Common Client) - CRITICAL! icc_path = os.path.join(lib_path, 'icc') if os.path.exists(icc_path): for lib_file in glob.glob(os.path.join(icc_path, '*.so*')): lib_name = os.path.basename(lib_file) if not any(name == lib_name for name, _, _ in a.binaries): a.binaries.append((lib_name, lib_file, 'BINARY')) print(f"Adding clidriver/icc library: {lib_name}") pyz = PYZ(a.pure) exe = EXE( pyz, a.scripts, a.binaries, a.datas, [], name='my_app', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=True, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, )

What this file does: The spec file is PyInstaller's configuration file that controls the build process. It performs several key functions:

  1. Locates the clidriver - Uses importlib to find where ibm_db is installed and locates its bundled clidriver
  2. Bundles the clidriver - Adds the entire clidriver directory (including message files and configs) to the executable
  3. Filters conflicting libraries - Removes standalone libdb2.so.1 files that PyInstaller might find, which would conflict with the complete clidriver libraries
  4. Explicitly adds all necessary libraries - Ensures both the main lib directory and the ICC subdirectory libraries are included
  5. Configures the runtime hook - Tells PyInstaller to run runtime_hook_db2.py before the application starts

The three "CRITICAL FIX" sections address the library-related root causes we identified. Without these fixes, the executable would either fail to find libraries or load conflicting versions.

Customizable parts:

  • Line 19: Change 'src/my_app/app.py' to point to your main Python file
  • Line 21: Add any additional hidden imports your application needs (e.g., 'sqlalchemy', 'fastapi')
  • Line 69: Change name='my_app' to your desired executable name
  • Line 77: Set console=False if you're building a GUI application

Step 7: Create the Build Script

The build script automates the PyInstaller build process.

File: build.py

#!/usr/bin/env python3 import os import sys import subprocess def main(): print("="*60) print("Building with PyInstaller") print("="*60) # Check if spec file exists spec_file = 'my_app.spec' if not os.path.exists(spec_file): print(f"✗ Spec file not found: {spec_file}") sys.exit(1) # Build command cmd = ['pyinstaller', '--clean', '--noconfirm', spec_file] print(f"\nRunning: {' '.join(cmd)}\n") print("="*60) result = subprocess.run(cmd) if result.returncode != 0: print("\n" + "="*60) print("✗ Build failed!") print("="*60) sys.exit(1) print("\n" + "="*60) print("✓ Build completed successfully!") print("="*60) print(f"\nExecutable: dist/my_app") print("\nTo test:") print(" ./dist/my_app") print("="*60) if __name__ == "__main__": main()

What this file does: This is a simple Python script that automates the build process. It:

  1. Checks for the spec file - Verifies that my_app.spec exists before attempting to build
  2. Runs PyInstaller - Executes PyInstaller with the --clean flag (removes previous build artifacts) and --noconfirm flag (overwrites without prompting)
  3. Reports the result - Displays success or failure messages and shows where the executable was created

Using this script is more convenient than typing the PyInstaller command manually, and it ensures consistent build parameters.

Customizable parts:

  • Line 11: Change 'my_app.spec' if you renamed your spec file
  • Line 32: Update the executable path if you changed the app name in the spec file

How to Build and Test

Now that all files are in place, let's build and test the application.

Build the Application

# Make sure you're in the project directory and virtual environment is activated python build.py

What happens during the build:

  1. PyInstaller analyzes your application and its dependencies
  2. It bundles the clidriver directory (including all libraries and message files)
  3. It filters out conflicting libraries
  4. It explicitly adds ICC libraries
  5. It creates a standalone executable in the dist/my_app/ directory

Expected output:

============================================================ Building with PyInstaller ============================================================ Running: pyinstaller --clean --noconfirm my_app.spec ============================================================ ... (PyInstaller output) ... Excluding conflicting library: libdb2.so.1 from /usr/lib/... Adding clidriver library: libdb2.so.1 Adding clidriver library: libdb2o.so.1 Adding clidriver/icc library: libibmc++.so.1 Adding clidriver/icc library: libibmdb2.so.1 ... (more libraries) ... ============================================================ ✓ Build completed successfully! ============================================================ Executable: dist/my_app To test: ./dist/my_app ============================================================

Test the Application

Test 1: Import Test (No Database Required)

This test verifies that PyInstaller bundled everything correctly:

./dist/my_app

Expected output:

✓ Using bundled CLI driver: /tmp/_MEIRhQQgx/clidriver ✓ Renamed message catalog: en_US.iso88591 -> en_US ✓ Copied message catalog: en_US -> en_US.UTF-8 ✓ Library paths configured ✓ DB2 environment ready ============================================================ DB2 Application - Connection Test ============================================================ ✓ Running in PyInstaller bundle ✓ Bundle directory: /tmp/_MEIRhQQgx ============================================================ Environment Variables: ============================================================ DB2_HOME: /tmp/_MEIRhQQgx/clidriver IBM_DB_HOME: /tmp/_MEIRhQQgx/clidriver DB2CODEPAGE: 1208 LD_LIBRARY_PATH: /tmp/_MEIRhQQgx/clidriver/lib/icc:/tmp/_MEIRhQQgx/clidriver/lib:/tmp/_MEIRhQQgx:... ============================================================ Testing ibm_db import... ✓ ibm_db imported successfully (version: 3.2.7) ============================================================ Connection Test Skipped ============================================================ To test DB2 connection, provide connection string: Option 1 - Environment variable: export DB2_CONN_STRING='DATABASE=SAMPLE;HOSTNAME=localhost;PORT=50000;UID=db2inst1;PWD=password' python src/my_app/app.py Option 2 - Command line argument: python src/my_app/app.py 'DATABASE=SAMPLE;HOSTNAME=localhost;PORT=50000;UID=db2inst1;PWD=password' Connection string format: DATABASE=<dbname>;HOSTNAME=<host>;PORT=<port>;UID=<user>;PWD=<password> ============================================================ ✓ Import test passed - ibm_db is working!

If you see this output, PyInstaller bundling is working correctly!

Test 2: Connection Test (Requires DB2 Database)

To test with an actual DB2 database, provide a connection string:

Option 1: Using environment variable

export DB2_CONN_STRING='DATABASE=SAMPLE;HOSTNAME=localhost;PORT=50000;UID=db2inst1;PWD=password' ./dist/my_app

Option 2: Using command line argument

./dist/my_app/my_app 'DATABASE=SAMPLE;HOSTNAME=localhost;PORT=50000;UID=db2inst1;PWD=password'

Expected output:

... (environment setup output) ... Testing DB2 connection... Connecting to database... ✓ Connected to DB2 successfully! --- Test 1: Current Timestamp --- ✓ Current timestamp: 2025-12-05 16:00:00.000000 --- Test 2: Database Version --- ✓ DB2 Version: DB2 v11.5.9.0, Fixpack: 0 --- Test 3: Sample Tables --- MYSCHEMA.CUSTOMERS (T) MYSCHEMA.ORDERS (T) MYSCHEMA.PRODUCTS (T) ✓ Found 3 tables ✓ Connection closed successfully ============================================================ ✓ ALL TESTS PASSED! ============================================================

Understanding PyInstaller's Temporary Directory

How PyInstaller Works

When you run a PyInstaller executable, it:

  1. Extracts to a temporary directory - Creates /tmp/_MEIxxxxxx/ (Linux) or C:\Users\...\AppData\Local\Temp\_MEIxxxxxx\ (Windows)
  2. Unpacks all bundled files - Extracts the clidriver, libraries, and your application code
  3. Runs your application - Executes from this temporary location
  4. Cleans up on exit - Deletes the temporary directory when the app closes

What's in the dist/ Directory?

The dist/ directory contains a single executable file:

dist/ └── my_app # Single executable (71MB) - everything bundled inside

Note: We're using PyInstaller's onefile mode, which packages everything into a single executable. All files (clidriver, libraries, your code) are embedded inside this one binary file.

What Happens at Runtime?

1. User runs: ./dist/my_app 2. PyInstaller creates: /tmp/_MEI6wsSpq/ 3. Extracts clidriver to: /tmp/_MEI6wsSpq/clidriver/ 4. Runtime hook runs and sets: DB2_HOME=/tmp/_MEI6wsSpq/clidriver 5. Your app runs with DB2 pointing to the temp location 6. On exit: /tmp/_MEI6wsSpq/ is deleted

Important: The /tmp/_MEI... path changes every time you run the app. This is normal PyInstaller behavior.


Troubleshooting

1. Problem: Import test fails with "undefined symbol: sqloRemStgDelete"

Cause: Conflicting libdb2 libraries

What's happening: PyInstaller found a standalone libdb2.so.1 file (usually from system libraries) that has incomplete symbols. This conflicts with the complete clidriver libraries.

Solution:

# 1. Check if filtering is working during build python build.py 2>&1 | grep "Excluding conflicting" # Should show: Excluding conflicting library: libdb2.so.1 from /usr/lib/... # 2. Verify the spec file has the binary filtering code grep -A 10 "CRITICAL FIX #1" my_app.spec # 3. Check what's actually in the dist directory find dist/my_app/_internal -name "libdb2*" # Should only show files from clidriver path

If still failing: The filtering logic in my_app.spec may need adjustment for your system's library paths.


2. Problem: Import test fails with "SQL10007N Message '0' could not be retrieved"

Cause: Missing locale directories or ICC libraries

What's happening: DB2 is trying to load error messages but can't find the locale files, or the ICC libraries aren't bundled.

Solution:

# 1. Run the app and check the temporary directory ./dist/my_app/my_app & APP_PID=$! # 2. Find the temp directory (while app is running) ls -la /tmp/_MEI*/clidriver/msg/ # Should show: en_US en_US.UTF-8 # 3. Check ICC libraries ls -la /tmp/_MEI*/clidriver/lib/icc/ # Should show: libibmc++.so.1 libibmdb2.so.1 etc. # 4. Kill the test app kill $APP_PID # 5. Check runtime hook output ./dist/my_app/my_app 2>&1 | grep "✓" # Should show: # ✓ Using bundled CLI driver: /tmp/_MEI.../clidriver # ✓ Renamed message catalog: en_US.iso88591 -> en_US # ✓ Copied message catalog: en_US -> en_US.UTF-8 # ✓ Library paths configured

If locale not created: Check that runtime_hook_db2.py is in your project root and referenced in the spec file.

If ICC libraries missing: Check the spec file has the ICC bundling code (CRITICAL FIX #3).


3. Problem: Connection test fails but import test passes

Cause: This is NOT a packaging issue—it's environment/network related

What's happening: PyInstaller bundling is working correctly (import succeeded), but the database connection is failing due to network, credentials, or database configuration issues.

Common error codes:

  • SQL30081N - Communication link failure (network issue)
  • SQL1336N - Invalid credentials
  • SQL1013N - Database not found
  • SQL30082N - Connection timeout

Debug steps:

# 1. Test network connectivity telnet your_hostname your_port # or nc -zv your_hostname your_port # 2. Test credentials outside PyInstaller (in normal Python) # Note: Use single quotes to avoid bash special characters in password python -c 'import ibm_db; conn = ibm_db.connect("DATABASE=SAMPLE;HOSTNAME=localhost;PORT=50000;UID=db2inst1;PWD=password", "", ""); print("Connected!")' # Or if password has special characters, escape them: python -c "import ibm_db; conn = ibm_db.connect('DATABASE=SAMPLE;HOSTNAME=localhost;PORT=50000;UID=db2inst1;PWD=pass\!word', '', ''); print('Connected\!')" # 3. Check DB2 server logs # On DB2 server, check: ~/sqllib/db2dump/db2diag.log # 4. Verify database is running db2 list active databases # 5. Test with localhost if DB2 is on same machine ./dist/my_app/my_app 'DATABASE=SAMPLE;HOSTNAME=localhost;PORT=50000;UID=db2inst1;PWD=password'

Remember: If import test passes, PyInstaller is working correctly. Connection failures are database/network issues.


4. Problem: "Permission denied" when running executable

Cause: Executable doesn't have execute permissions

Solution:

chmod +x dist/my_app/my_app ./dist/my_app/my_app

5. Problem: Executable works on build machine but fails on target machine

Cause: Missing system libraries on target machine

Solution:

# On target machine, check for missing libraries ldd dist/my_app/my_app # Look for "not found" entries # Common missing libraries on minimal systems: sudo apt-get install libglib2.0-0 libsm6 libxext6 libxrender1

Additional Resources


Note: This solution was developed through extensive debugging and testing on production Linux systems. The approach has been validated with DB2 v11.5 and Python 3.8-3.13.

0 comments
13 views

Permalink