The i18n Issue

Mike's Notes

This is a copy of the March issue of Ajabbi Research.

It is about the history of the effort to make Pipi available in any language, localisation or script (i18n) requested by users.

Ajabbi Research is published on SubStack on the first Friday of each month, and subscriptions are free.

Each issue is a broad historical overview of a research topic, serving as an index to dozens of previously posted related articles. There are now over 650 articles/posts.

This copy of the issue will be updated with additional information as it becomes available. Check the Last Updated date given below.

Eventually, each issue will be reused on the separate Ajabbi Research website as an introduction to a research area comprising multiple research projects.

Resources

References

  • SIL.
  • Unicode

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

03/04/2026

The i18n Issue

By: Mike Peters
Ajabbi Research: 6/03/2026

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

This is the story of the effort to make Pipi available in any human language and script. The steps taken have been part of Pipi's development since 2005, spanning 5 versions.

The NZERN Pipi 2003-2005 Development Plan started it all.

Pipi 4 (2005-2008)

The story starts with Pipi 4. It was a big, successful system that supported community-driven Ecological Restoration in NZ. Here is a history of that Pipi version.

Initially, the large websites that Pipi generated were in English only.  Then, as botanical and zoological information was added, Latin, English, and Maori names were used. Eventually, provision for Chinese was planned to support the Chinese community-led conservation programmes. There were no separate language data structures in the 850-table Pipi 4 database; instead, some entities had additional columns for each language.

English

  • The 25,000 pages websites that Pipi generated were initially in English.

Latin

  • Scientific names were written in Latin in biological data.

Maori

  • Over time, it was realised that support for the Maori Language, Te Reo, was required. As a start, bilingual volunteers provided lists of words to use for regional areas, towns, etc.

Chinese

  • There was an Auckland-based Chinese Community-driven initiative to reach older residents who didn't speak English about conservation.

    Pipi 6 (2017-2019)

    When Pipi was rebuilt from memory, based on the limited experience with Pipi 4, foundational work was done to prepare Pipi for better multilingual support. This would require extra databases.

    Metadata using international codes was added to every database table to enable future language usage. The codes used were ISO 639-3, Country, Unicode, and CLDR/LDML

    ISO 639-3

    ISO 639 gives comprehensive provisions for the identification and assignment of language identifiers to individual languages, and for the creation of new language code elements or for the modification of existing ones (Terms of Reference of the ISO639/MA). - ISO 639-3

    *** 

    It defines three-letter codes for identifying languages. The standard was published by the International Organisation for Standardisation (ISO) on 1 February 2007. As of 2023, this edition of the standard has been officially withdrawn and replaced by ISO 639:2023.

    ISO 639-3 extends the ISO 639-2 alpha-3 codes with an aim to cover all known natural languages. The extended language coverage was based primarily on the language codes used in the Ethnologue (volumes 10–14) published by SIL International, which is now the registration authority for ISO 639-3.[2] It provides an enumeration of languages as complete as possible, including living and extinct, ancient and constructed, major and minor, written and unwritten. However, it does not include reconstructed languages such as Proto-Indo-European.

    ISO 639-3 is intended for use as metadata codes in a wide range of applications. It is widely used in computer and information systems, such as the Internet, in which many languages need to be supported. In archives and other information storage, it is used in cataloging systems, indicating what language a resource is in or about. The codes are also frequently used in the linguistic literature and elsewhere to compensate for the fact that language names may be obscure or ambiguous. Wikipedia

    Examples

    • Eng (English
    • Fra (French)

    ISO_3166-1_alpha-3

    ISO 3166-1 alpha-3 codes are three-letter country codes defined in ISO 3166-1, part of the ISO 3166 standard published by the International Organization for Standardization (ISO), to represent countries, dependent territories, and special areas of geographical interest. They allow a better visual association between the codes and the country names than the two-letter alpha-2 codes (the third set of codes is numeric and hence offers no visual association). They were first included as part of the ISO 3166 standard in its first edition in 1974. - Wikipedia

     Examples

    • ABW  (Aruba)
    • AFG  (Afghanistan)
    • AGO  (Angola)

    Unicode

    Unicode (also known as The Unicode Standard and TUS) is a character encoding standard maintained by the Unicode Consortium designed to support the use of text in all of the world's writing systems that can be digitized. Version 17.0[A] defines 159,801 characters and 172 scripts used in various ordinary, literary, academic and technical contexts. - Wikipedia

    Examples

    • Latn (Latin)
    • Lina (Linear B)
    • Hebr (Hebrew)

    CLDR/LDML

    The Common Locale Data Repository (CLDR) is a project of the Unicode Consortium to provide locale data in XML format for use in computer applications. CLDR contains locale-specific information that an operating system will typically provide to applications. CLDR is written in the Locale Data Markup Language (LDML). - Wikipedia

    Example

     <?xml version="1.0" encoding="UTF-8" ?>
    <ldml>
      
        <version number="1.1">ldml version 1.1</version>
        <generation date="2024-03-06"/>
        <language type="en"/>
        <territory type="US"/>
      
      <!-- other locale data sections follow -->
    </ldml>

    Localisation (L10N)

    Language localisation (or language localisation) is the process of adapting a product's translation to a specific country or region. It is the second phase of a larger process of product translation and cultural adaptation (for specific countries, regions, cultures or groups) to account for differences in distinct markets, a process known as internationalisation and localisation. - Wikipedia

    ***

    Pipi internally automatically stores and uses 3-letter language codes, 4-letter Unicode and 3-letter country codes to define Locales.

    Examples

    • eng-Latn-NZD (New Zealand English)
    • eng-Latn-USA (United States English)

    Customers can configure the options for their own websites.

    Examples

    • en-NZ
    • en-uk

    More information

    Pipi 7 (2020)

    Small, simple, static HTML mockups of websites were created to test how different languages could be used. Experiments with HTML and CSS were conducted to display text on a website in Left-to-Right (LTR) and Right-to-Left (RTL) word order.

    Pipi 8 (2021-2022)

    System-wide i18n and L10N namespaces were implemented in all parts of Pipi to enable reliable automation and rapid scaling across multiple languages.

    Pipi 9 (2023-2026)

    Joining up all the built systems to self-generate documentation and a front end User Interface (UI).

    Experiments were conducted to determine how to integrate i18n support with Pipi's other features. It was confirmed that the Pipi core is written in British Standard English and checked by Grammarly.

    A source-target data model structure was created to store i18n scripts. It was greatly influenced by the system used by Wikipedia (MediaWiki) and OpenOffice.

    Experiments were done using 23 languages and writing scripts to test the CMS Engine (cms), data storage, UI layout, etc.

    String Translation

    Community translation will be required using a dedicated workspace for this purpose.

    Account Settings

    Each Pipi is built in 1 language and script. Each account can have many languages. An account has many deployments, each of which is in only one language. A deployment can have many workspaces.

    Localisation

    API Endpoints

    All API connections include a choice of API version and language/script.

    Scripts

    Noto from Google was chosen as the default font for Ajabbi due to the number of scripts it supports.

    KeyMan

    SIL provides an open-source KeyMan that enables keyboards for 2500 different languages to be added to websites. Pipi will use a Keyboard Engine (kyb) to provide this integration. This will be built as part of Pipi 10.

    Url Naming Pattern

    Many experiments were conducted to determine a URL structure that could accommodate websites in many languages. Wikipedia was the main influence.

    Examples

    • eng.example.com
    • example.com/eng/
    • en-uk.example.com
    • example.com/en-nz/

    Documentation

    Documentation and Learning material will need to be provided in many languages. The data models are ready for this. As the British English documentation is completed, it could be auto-translated into US English using Grammarly and into the 9 world languages using Google Translate. It would then need to be checked by volunteer users. This is speculative and will require trial and error to confirm.

    Language Prioritisation

    English > 9 world languages > 7000 local languages + localisation.

    Priority will be given to English, which will then serve as the source for translation into 9 world languages.

    • Arabic
    • Bhasa Indonesian
    • Chinese
    • French
    • German
    • Japanese
    • Hindi
    • Portugese
    • Russian
    • Spanish

    Carefully edited material in those languages can then be translated into any of the other 7,000 languages by volunteers, based on user requests.

      Model-driven UI

      The User Interface Description Language (UIDL) was an EU-funded project that was abandoned in 2010 after 10 years of excellent work. It was to enable accessibility on different screens and devices. The research results were reverse-engineered to build a User Interface Engine (usi) that would run in reverse to generate accessibility solutions for Pipi. The CSS Engine (css) replaced some redundant components of the UIDL project. Additional engines for localisation and personalisation were created.


      Pipi CMS Engine (cms)

      For a first teaching customer, a decision was made early on to autogenerate a separate website for each language (English, Māori, NZ Sign Language, and AAC picture language). This was the simplest solution for the CMS and the users.

      Creating UI for each natural language, including sign languages (i18n), requires user requests and volunteer testers.

      Sign Language

      The scheme was dreamed up to embed NZ Relay Video Interpreting on any webpage and in user workspaces. This is an ongoing experiment, driven by deaf people.

      Picture Language

      Professor Stephen Hawking used AAC via a computer-generated voice. There are many forms of AAC, including picture language. Providing this as a UI is being explored, with other AAC to follow. Important for the millions of people with Cerebral Palsy and Motor Neurone Disease.

      Invented Languages

      This system will be able to provide support for Klingon, Elvish, and other invented languages from books and movies, upon request and with volunteers prepared to do the work. This could be useful for fan communities.

      Dead Languages

      This system will be able to provide support for long-dead languages often studied by linguists and historians, such as Ancient Egyptian, Sumerian, Sanskrit, and Ancient Greek, upon request, with volunteers prepared to do the work. This could be useful for museums and faith communities.

      Workspace personalisation

      The workspace settings will eventually offer complete personalisation of the UI in other languages. This will use a personalisation form in account settings.

      Future Ajabbi Foundation Sponsorship

      Once Ajabbi has established ongoing sponsorship for Ortus for providing open-source BoxLang, the Ajabbi Foundation will generously sponsor open-source SIL KeyMan on an ongoing basis.

      Whats next

      Pipi 9 is available only in English. However, users can request any other language through their profile. Pipi 10 (2027-) will feature those multiple languages.

      The most useful and inspiring resource has been SIL Global.

      Dedication

      Every child has the right to be educated in the language of their people and of their birth. This is dedicated to those working tirelessly to record, strengthen or revive human languages.

      CFML 64-bit and 32-bit datasource

      Mike's Notes

      Pipi 9 uses multiple Application.cfc to configure data sources programmatically. Each agent engine has its own embedded database to store config and state. Sometimes there are several embedded databases, and sometimes non-embedded ones like PostgreSQL. There are hundreds of databases in total.

      This is part of the problem I have to solve to fully automate the Pipi Core data centre. Each agent needs to be able to autonomously create or add databases and data sources. It's the last major issue to resolve before moving on to Workspace rendering.

      Once automation is complete, productivity will increase by at least x10.

      I asked Google Search AI Mode (powered by Google Gemini) how to use 32-bit and 64-bit data sources with a 64-bit ColdFusion Server versions 11 and 12 (2016).

      The Google output has been reformatted but not edited, and the code needs to be tested. The questions were turned into headings. There is a lot of duplication.

      I find that carefully using Gemini to write CFML code and then checking everything is making me more productive.

      Later, I will also find out how this works with different versions of LuceeBlue Dragon and BoxLang, which also run CFML. This enables future customers to choose their CFML server, version and OS. Pipi runs on any CFML server that supports ColdFusion Components (CFC) and embedded databases.

      Since the release of ColdFusion MX (version 6.0) in 2002, the engine has been completely rewritten in Java and runs on a Java Virtual Machine (JVM).

      Key Technical Details

      • Java EE Foundation: ColdFusion is built on the Java Enterprise Edition (JEE) technology platform.
      • Bytecode Execution: ColdFusion Markup Language (CFML) code is compiled into Java bytecode, similar to how Java source code is processed.
      • Application Servers: It can be deployed as a standalone server (using an embedded version of Apache Tomcat) or as a web application on third-party JEE servers like IBM WebSphere, JBoss, or Oracle WebLogic.
      • Seamless Integration: Developers can directly invoke Java classes, use Java objects, and integrate existing Java libraries within their ColdFusion applications. 

      Historical Context

      Prior to version 6.0, ColdFusion was written in C++ and was primarily limited to Microsoft Windows. The transition to Java (originally codenamed "Neo") was implemented to improve cross-platform portability and security.

      Because they are all Java-based, Adobe ColdFusion, Lucee, and BoxLang are highly cross-platform and can run on any operating system that supports a Java Runtime Environment (JRE) or Java Development Kit (JDK).

      Pipi platform history

      • Pipi 1: Linux, Apache
      • Pipi 2: Linux, Apache
      • Pipi 3: Windows 2000 Server, ColdFusion 6 MX, and MS SQL 6.
      • Pipi 4: Windows 2000 Server, ColdFusion 6 MX, and MS SQL 6.
      • Pipi 5: ArcPad
      • Pipi 6: Windows
      • Pipi 7: Windows
      • Pipi 8: Windows
      • Pipi 9 core: Windows, JVM 21, Adobe, Lucee and BoxLang Servers, PostgreSQL 18, MS Access
      • Pipi 9 open-source: Debian, JVM 21, Adobe, Lucee and BoxLang Servers, PostgreSQL 18
      • Pipi 10 core: Debian, JVM 21, BoxLang, PostgreSQL, Derby, HSQLDB, H2, SQLite.
      • Pipi 10 open-source: Debian, JVM 21, BoxLang, PostgreSQL. Customers can additionally choose
        •  a production CFML server (Adobe, Lucee, BoxLang)
        • or run a deploy the ColdFusion application, in an enterprise application archive (EAR) or web application archive (WAR) format, on a JEE application server
        • a production database for customer data (PostgreSQL, MS SQL, Oracle, Couchbase, etc.)

      Adobe ColdFusion

      Adobe officially supports specific enterprise-grade operating systems to ensure stability and compatibility with their installers. 

      • Windows: Windows Server 2025 (latest), 2022, 2019, 2016, and consumer versions like Windows 11 and 10.
      • Linux: Red Hat Enterprise Linux (RHEL) 9.5+, Ubuntu 24 LTS, and SUSE Linux Enterprise Server 15.5+.
      • macOS: macOS 15 (Sequoia) and later, supporting both Intel and Apple Silicon (ARM64).
      • Solaris: Historically supported (up to version 2021) but less common in recent release matrices. 

      Lucee 

      Lucee is more flexible and can run "almost everywhere" that supports Java, including small devices like the Raspberry Pi. 

      • Main OSs: Windows (all editions), Linux, and macOS.
      • Linux Distributions: Extensively tested on Debian, Fedora, Arch Linux, AlmaLinux, Rocky Linux, Mint, and Gentoo.
      • Other Platforms: FreeBSD and Solaris.

      BoxLang

      As a modern, dynamic JVM language, BoxLang is designed for high portability across standard and emerging runtimes. 

      • Operating Systems: Windows, macOS, and all *nix-based systems (Linux distributions).
      • Specialised Environments:
        • Chromebooks: Supported via the Linux development environment (ChromeOS).
        • Mobile: Can target Android and iOS devices.
        • Cloud/Serverless: Native support for AWS Lambda and DigitalOcean App Platform.
        • WebAssembly: Can be deployed to run in browser environments via WASM.

      Embedded databases

      Adobe ColdFusion, Lucee, and BoxLang all support embedded databases, allowing you to run a fully functional database directly within the application server without a separate installation (like SQL Server or MySQL).

      1. Adobe ColdFusion

      Adobe ColdFusion has historically bundled Apache Derby as its default embedded database solution. 
      • Apache Derby (Embedded Mode): Included in the installer, it runs in the same Java Virtual Machine (JVM) as ColdFusion.
      • Use Cases: Ideal for small applications, development environments, or "Query-of-Query" (QoQ) logic that requires a temporary SQL engine to process memory-resident data.
      • Configuration: You can create a Derby datasource in the ColdFusion Administrator by selecting the Apache Derby Embedded driver. 

      2. Lucee

      Lucee is highly extensible and supports several embedded or lightweight database engines. 
      • HSQLDB (Hypersonic SQL): This is the default engine Lucee uses for its native Query of Queries (QoQ) when the internal engine is not sufficient.
      • H2 Database Engine: A popular, high-performance embedded Java database often used in the Lucee ecosystem for portable applications.
      • SQLite: While not bundled, Lucee can easily connect to SQLite .db files via a JDBC driver, offering a serverless, file-based database experience. 

      3. BoxLang

      BoxLang is designed for modern, portable deployment and leverages the best of the JVM’s embedded options.

      • Built-in Derby/H2 Support: Like its predecessors, BoxLang supports Apache Derby and H2 out of the box for lightweight storage.
      • In-Memory Databases: It is optimised to work with in-memory versions of these databases for high-speed automated testing or temporary data processing.
      • Mobile & Serverless: Because it can run on Android or in Lambda functions, using an embedded database like H2 allows BoxLang applications to remain entirely self-contained.

      Apache Derby

      • Retired: As of October 2025, the Apache Derby project has been officially retired and moved into a read-only state.
      • No Further Updates: Development and bug fixes have concluded, and no new releases will be published.
      • Availability: Existing releases and documentation remain available for download on an as-is basis from the official Apache Derby website. 

      H2 Database

      Modes of Operation:

      • In-Memory: Data is stored in RAM and lost when the application stops, making it ideal for unit testing.
      • Embedded: The database runs within the same process as your Java application, storing data in a local file (typically with a .mv.db extension).
      • Server Mode: Runs as a standalone process that applications connect to via TCP/IP

      SQLLite

      Key Characteristics

      • Single File Storage: A complete database (tables, indexes, and metadata) is stored in a single cross-platform disk file.
      • Serverless and Zero-Config: There is no server process to install, manage, or troubleshoot. It reads and writes directly to disk.
      • Compactness: The library is very small (roughly 600KB to 1MB), making it ideal for resource-constrained environments.
      • Dynamic Typing: By default, SQLite uses "manifest typing," allowing you to store any data type in any column (e.g., a string in an integer column). Note: Recent versions added "Strict Tables" for developers who prefer standard static typing.
      • Reliability: It is ACID-compliant and highly resistant to corruption even during system crashes or power failures.

      HSQLDB database

      Key Features

      • Operating Modes: Supports In-Memory (fastest, no disk persistence), Embedded/Standalone (persistent local files), and Server Mode (accessible via TCP/IP or HTTP).
      • Table Types:
        • Memory Tables: Default type; data is kept in RAM but persisted to a script on disk for recovery.
        • Cached Tables: For large datasets, only a portion is kept in memory to save RAM.
        • Text Tables: Can directly use CSV or delimited files as SQL tables.
      • Transactions: Features fully multi-threaded MVCC (Multiversion Concurrency Control) and two-phase locking for high-performance transaction processing.
      • Small Footprint: The entire engine is contained in a single JAR file (around 1.3–2.6 MB depending on the version).

      Test results 02/04/2026

      • On the test machine
      • UCanAccess unzipped, and 5 JAR files were successfully added to Adobe 64-bit ColdFusion Servers 11 and 12. <path>\cfusion\lib\
      • MS Access 32-bit Datasource successfully added via Administrator Portal
      • Datasource successfully added to Application.cfc
      • Simple <cfquery> test successful

      Resources

      References

      • Reference

      Repository

      • Home > Ajabbi Research > Library >
      • Home > Handbook > 

      Last Updated

      02/04/2026

      CFML 64-bit and 32-bit datasource

      By: Mike Peters and Gemini
      On a Sandy Beach: 02/04/2026

      Mike is the inventor and architect of Pipi and the founder of Ajabbi.

      Google Gemini is cool.

      In ColdFusion 11, you can define application-specific datasources directly in your Application.cfc, removing the requirement to pre-configure them in the ColdFusion Administrator. [1, 2] 

      Defining Datasources in Application.cfc

      To create a datasource within your application, use the this.datasources structure. This allows your application to be more portable across different environments. [2, 3] 

      // Application.cfc
      component {
          this.name = "myApp";
          
          this.datasources = {
              myDSN = {
                  driver = "MSSQLServer", // e.g., MSSQLServer, MySQL, etc.
                  host = "localhost",
                  database = "myDatabase",
                  username = "db_user",
                  password = "db_password"
              }
          };
          
          // Set as the default for the entire app
          this.datasource = "myDSN"; 
      }

      32-bit vs. 64-bit Considerations

      The bitness of your ColdFusion installation (32-bit vs. 64-bit) primarily impacts ODBC connections and legacy drivers: [4] 

      • Driver Compatibility: 64-bit ColdFusion 11 requires 64-bit JDBC drivers. Most modern databases (SQL Server, MySQL, [Oracle](https://www.oracle.com/)) use JDBC, which is generally platform-independent.
      • Microsoft Access/Excel: On 64-bit ColdFusion 11, connecting to Access databases is often problematic because the "ODBC Agent and Server" typically runs as a 32-bit process. This can lead to errors like "Unable to update the NT registry" when trying to create a DSN via the Administrator.
      • Solution for Legacy Apps: If you must use 32-bit drivers (like certain Access versions), you may need to use a 32-bit version of ColdFusion or configure a 32-bit ODBC bridge, though utilizing [modern JDBC drivers](https://helpx.adobe.com/coldfusion/configuring-administering/data-source-management-for-coldfusion.html) is the recommended path for 64-bit environments. [5, 6, 7, 8, 9] 

      Key Benefits in ColdFusion 11

      References

      The specific JDBC connection string parameters for a particular database like MySQL or Oracle.

      Connecting a 64-bit ColdFusion 11 instance to a 32-bit MS Access database via Application.cfc is generally not supported directly because 64-bit Java applications (which power ColdFusion) cannot natively load 32-bit DLL-based ODBC drivers. [1, 2, 3]

      To achieve this, you must use a bridge or a specific driver configuration.

      Recommended Workaround: Using an ODBC Socket

      Instead of a direct file path, you must first register a 32-bit System DSN on your Windows server and then call it via the ODBC Socket driver in your Application.cfc. [4] 

      1. Create a 32-bit System DSN:
        • Open the 32-bit ODBC Administrator located at C:\Windows\SysWOW64\odbcad32.exe.
        • Create a System DSN (e.g., named myAccess32bit) pointing to your .mdb or .accdb file using the Microsoft Access Driver.
      2. Configure Application.cfc:
        • Define the datasource using the ODBC Socket driver, which allows the 64-bit ColdFusion engine to communicate with the Windows ODBC layer. [5, 6, 7, 8] 
      // Application.cfc
      component {
          this.name = "accessApp";

          this.datasources = {
              myAppDSN = {
                  driver = "ODBCSocket",
                  dsn = "myAccess32bit", // Must match the System DSN name exactly
                  username = "",
                  password = ""
              }
          };

          this.datasource = "myAppDSN";
      }

      Critical Troubleshooting Tips

      • Driver Availability: Ensure the Microsoft Access Database Engine is installed on the server. If you have 64-bit Office installed, you may need to install the 32-bit runtime using the /passive command-line flag to avoid conflicts.
      • NT Registry Error: If you see "Unable to update the NT registry," it typically means ColdFusion is trying (and failing) to create a 64-bit DSN for a 32-bit driver. Manually creating the DSN in the SysWOW64 ODBC tool as described above bypasses this.
      •  JDBC Alternative: For a cleaner 64-bit setup without ODBC, consider using a third-party Type 4 JDBC driver (like UCanAccess), which is platform-independent and can be dropped into your cfusion/lib folder. [2, 9, 10, 11, 12, 13]

      References

      The UCanAccess JDBC configuration steps to avoid using Windows ODBC entirely

      Using the UCanAccess JDBC driver is the most reliable way to connect 64-bit ColdFusion 11 to a 32-bit MS Access database because it bypasses the Windows ODBC layer entirely. [1, 2, 3]

      1. Download and Prepare the Driver

      1.    1. Download the latest UCanAccess "bin" zip file from [SourceForge](https://sourceforge.net/projects/ucanaccess/).
      2.    2. Extract the zip file. You will need the following 5 JAR files:
        • ucanaccess-x.x.x.jar (the main driver)
        • lib/commons-lang3-x.x.jar
        • lib/commons-logging-x.x.jar
        • lib/hsqldb-x.x.jar
        • lib/jackcess-x.x.jar [3, 4, 5, 6, 7] 

      2. Add to ColdFusion Classpath [8] 

      To make the driver "visible" to ColdFusion, place these files in the server's library folder: [6, 8] 

      • Location: Copy all 5 JAR files to {ColdFusion_Install_Dir}\cfusion\lib (e.g., C:\ColdFusion11\cfusion\lib).
      • Restart: You must restart the ColdFusion Application Server service for these changes to take effect. [4, 6, 9, 10, 11] 

      3. Configure Application.cfc

      Define the datasource using the "Other" driver type syntax. Note that the connection string uses forward slashes even on Windows. [12, 13] 

      // Application.cfc
      component {
          this.name = "myAccessApp";

          this.datasources = {
              accessJDBC = {
                  // "class" tells ColdFusion which JDBC driver to load
                  class = "net.ucanaccess.jdbc.UcanaccessDriver",
                  // Use forward slashes for the file path
                  url = "jdbc:ucanaccess://C:/path/to/your/database.accdb",
                  // Access usually doesn't require a username/password unless protected
                  username = "",
                  password = ""
              }
          };

          this.datasource = "accessJDBC";
      }

      Key Implementation Notes

      • No Admin Needed: Once configured in Application.cfc, you do not need to add anything to the [ColdFusion Administrator](https://helpx.adobe.com/coldfusion/configuring-administering/data-source-management-for-coldfusion.html) UI.
      • File Paths: If your path contains spaces, ensure they are handled correctly. UCanAccess generally supports standard Windows paths if formatted with forward slashes.
      • Performance: UCanAccess is a "pure Java" driver, meaning it is often faster and more stable than the old ODBC-JDBC bridge for 64-bit environments. [1, 2, 12, 13, 14] 

      References

      How to handle encrypted or password-protected Access files using this driver.

      To rewrite this using tag-based syntax, you will define the this scope variables inside a <cfcomponent> block.

      For the UCanAccess JDBC driver to work, ensure you have already placed the 5 required JAR files in your CFUSION/lib folder and restarted the ColdFusion service.

      Application.cfc (Tag-Based)

      <cfcomponent>
          <cfset this.name = "myAccessAppTag version">
          
          <!--- Define the UCanAccess JDBC Datasource --->
          <cfset this.datasources = {
              accessJDBC = {
                  class = "net.ucanaccess.jdbc.UcanaccessDriver",
                  url   = "jdbc:ucanaccess://C:/path/to/your/database.accdb",
                  username = "",
                  password = ""
              }
          }>

          <!--- Set as the default datasource for all <cfquery> tags --->
          <cfset this.datasource = "accessJDBC">

          <cffunction name="onApplicationStart" returnType="boolean">
              <!--- Application initialization code here --->
              <cfreturn true>
          </cffunction>

      </cfcomponent>

      Important Details for Tag-Based Setup:

      • Case Sensitivity: While ColdFusion tags are not case-sensitive, the class string (net.ucanaccess.jdbc.UcanaccessDriver) is case-sensitive because it refers to a Java class.
      • Forward Slashes: Even in the tag version, use forward slashes (/) in the url path to avoid escaping backslash characters.
      • Placement: This file must be named Application.cfc (not .cfm) and placed in your application's root directory.

      How to add a connection timeout or limit the number of connections within this structure?

      In ColdFusion 11, you can control connection limits and timeouts by adding specific keys to your this.datasources structure.

      Tag-Based Application.cfc with Advanced Settings [1]

      To limit connections and set timeouts, use the limitConnections, restrictConnectionsTo, and timeout keys. Note that for UCanAccess, certain timeouts like loginTimeout are often passed within the url string as JDBC parameters. [2, 3, 4, 5] 

      <cfcomponent>
          <cfset this.name = "myAccessAppAdvanced">

          <cfset this.datasources = {
              accessJDBC = {
                  class = "net.ucanaccess.jdbc.UcanaccessDriver",
                  <!--- loginTimeout (seconds) and inactivityTimeout (minutes) can be appended to the URL --->
                  url = "jdbc:ucanaccess://C:/data/db.accdb;loginTimeout=30;inactivityTimeout=5",
                  username = "",
                  password = "",
                  
                  <!--- ColdFusion Connection Pooling Settings --->
                  maintainConnections = true,
                  limitConnections = true,
                  restrictConnectionsTo = 10,   <!--- Max simultaneous connections --->
                  timeout = 20,                 <!--- Idle timeout in minutes before CF closes a connection --->
                  loginTimeout = 30             <!--- Seconds to wait for a login attempt --->
              }
          }>

          <cfset this.datasource = "accessJDBC">
      </cfcomponent>

      Key Property Explanations

      • limitConnections: Set to true to enable the cap on the number of simultaneous database hits.
      • restrictConnectionsTo: The maximum number of concurrent connections allowed for this specific datasource. For MS Access, keeping this low (e.g., 5-15) is recommended to prevent file locking issues.
      • timeout: The number of minutes ColdFusion will keep an unused connection in the pool before destroying it to save resources.
      • loginTimeout: The maximum time (in seconds) ColdFusion will wait to establish the initial connection before throwing an error.
      • inactivityTimeout (URL parameter): A [UCanAccess-specific setting](https://spannm.github.io/ucanaccess/20-getting-started.html) that shuts down the underlying HSQLDB instance if no connections are active for the specified minutes, releasing file system locks. [3, 6, 7, 8]

      References

      How to handle read-only access or exclusive locking through these connection parameters

      In ColdFusion 11, you can control read-only access and exclusive file locking for MS Access through the UCanAccess connection URL. These parameters directly instruct the Java driver how to handle the physical .accdb or .mdb file.

      1. Read-Only Access

      To ensure the database is accessed in a strictly read-only mode, append readOnly=true to the JDBC URL. This is useful for reporting or preventing accidental data modification. [1, 2] 

      2. Exclusive Locking

      To prevent other processes (like the MS Access GUI or other ColdFusion instances) from modifying the file while your application is connected, use the openExclusive=true parameter. [3]

      Updated Tag-Based Application.cfc

      <cfcomponent>
          <cfset this.name = "myAccessAppAdvanced">

          <cfset this.datasources = {
              accessJDBC = {
                  class = "net.ucanaccess.jdbc.UcanaccessDriver",
                  <!--- 
                      URL Parameters:
                      - readOnly=true: Prevents any INSERT/UPDATE/DELETE operations.
                      - openExclusive=true: Locks the file from other processes.
                  --->
                  url = "jdbc:ucanaccess://C:/data/db.accdb;readOnly=true;openExclusive=true",
                  username = "",
                  password = "",
                  
                  <!--- Pool management --->
                  maintainConnections = true,
                  limitConnections = true,
                  restrictConnectionsTo = 5,   <!--- Lower limit recommended for Access to avoid locks --->
                  timeout = 20
              }
          }>

          <cfset this.datasource = "accessJDBC">
      </cfcomponent>

      Critical Usage Notes

      • Property Separation: Multiple parameters in the url must be separated by semicolons (;).
      • Driver Evolution: In modern versions of UCanAccess, openExclusive replaces the older lockMdb parameter.
      • File Permissions: Even with readOnly=true in the code, the ColdFusion service account must have Read and Execute permissions on the folder containing the database file so it can create the temporary .laccdb locking file if needed.
      • Concurrency: Using openExclusive=true will cause other applications (including the MS Access desktop app) to fail to open the database for editing while ColdFusion has it open. [3, 4, 5, 6, 7]

      References

      How to implement row-level locking for specific queries using <cfquery>

      In ColdFusion 2016 (v12), the core logic for defining datasources in Application.cfc remains identical to version 11, but the 32-bit vs. 64-bit conflict becomes more rigid as newer server environments drop legacy support.

      Application.cfc (Version 2016/12 Tag Syntax)

      The syntax below works for the 64-bit version of ColdFusion 2016, utilizing a DSN defined via the 64-bit ODBC Administrator. [1, 2] 

      <cfcomponent>
          <cfset this.name = "myAppCF2016">
          
          <cfset this.datasources = {
              myAccessDSN = {
                  <!--- 
                      In 64-bit CF2016, you must use a 64-bit driver. 
                      "ODBCSocket" acts as the bridge to the Windows ODBC service.
                  --->
                  driver = "ODBCSocket",
                  dsn = "My64BitSystemDSN",
                  username = "",
                  password = "",
                  
                  <!--- Advanced Pooling for CF2016 --->
                  limitConnections = true,
                  restrictConnectionsTo = 10,
                  maintainConnections = true,
                  timeout = 20
              }
          }>

          <cfset this.datasource = "myAccessDSN">
      </cfcomponent>

      Key Differences & Setup for CF 2016 (v12)

      • Architecture Mismatch: 64-bit ColdFusion 2016 cannot talk to 32-bit ODBC drivers. If you try to use a 32-bit System DSN, you will receive an "Architecture Mismatch" error.
      • The "64-bit Access Engine" Fix: To use Access on a 64-bit CF 2016 server, you must install the 64-bit Microsoft Access Database Engine. This allows you to create a 64-bit System DSN that ColdFusion can actually see and use.
      • Service Requirements: For the ODBCSocket driver to work, the ColdFusion ODBC Server and ColdFusion ODBC Agent services must be running on the Windows machine.
      • UCanAccess as the Best Practice: Adobe and community experts increasingly recommend the [UCanAccess JDBC driver](https://helpx.adobe.com/coldfusion/configuring-administering/data-source-management-for-coldfusion.html) for CF 2016 and above to avoid the headache of Windows ODBC bitness entirely. [2, 3, 4, 5, 6, 7, 8] 

      Why Bitness Still Matters in CF 2016

      While you can run a 32-bit version of ColdFusion 2016 on a 64-bit Windows OS, it is not common for production. If you are on 64-bit CF 2016, you have two paths: [9] 

      1. Install 64-bit Access drivers and use a 64-bit System DSN.
      2. Use the UCanAccess JDBC driver (Java-based), which doesn't care about 32-bit or 64-bit Windows environments. [8, 10]

      References

      The specific UCanAccess configuration again, and help installing the 64-bit Microsoft Access Engine for the ODBC method

      To configure the UCanAccess JDBC driver for ColdFusion 2016 (v12) using Application.cfc, follow these steps to bypass the 32-bit/64-bit ODBC limitations. [1, 2, 3] 

      1. Driver Installation

      Download the UCanAccess bin zip from [SourceForge](https://sourceforge.net/projects/ucanaccess/) and extract these 5 JAR files into your ColdFusion lib directory (typically C:\ColdFusion2016\cfusion\lib): [4, 5] 

      • ucanaccess-x.x.x.jar
      • commons-lang-x.x.jar (or commons-lang3)
      • commons-logging-x.x.jar
      • hsqldb.jar
      • jackcess-x.x.x.jar [3, 4, 5, 6, 7] 

      Important: You must restart the ColdFusion 2016 service after adding these files. [8, 9]

      2. Application.cfc Configuration (Tag-Based) [4]

      Define the datasource using the class and url properties. This tells ColdFusion to use the specific Java driver instead of the built-in ones. [4, 10, 11] 

      <cfcomponent>
          <cfset this.name = "myAccessAppCF2016">

          <cfset this.datasources = {
              accessDSN = {
                  <!--- The exact Java class name of the UCanAccess driver --->
                  class = "net.ucanaccess.jdbc.UcanaccessDriver",
                  
                  <!--- JDBC URL using forward slashes for the file path --->
                  url = "jdbc:ucanaccess://C:/path/to/your/database.accdb",
                  
                  <!--- Required even if Access has no password; use 'admin' as default --->
                  username = "admin",
                  password = "",
                  
                  <!--- Recommended settings for performance and stability --->
                  maintainConnections = true,
                  limitConnections = true,
                  restrictConnectionsTo = 10,
                  timeout = 20
              }
          }>

          <!--- Automatically use this DSN for all queries in this app --->
          <cfset this.datasource = "accessDSN">
      </cfcomponent>

      3. Advanced Parameters

      You can append these parameters to the url string (separated by semicolons) to fine-tune the connection: [3, 12, 13] 

      • ;memory=false: Recommended for large databases to prevent high RAM usage by the driver.
      • ;openExclusive=true: Locks the file to prevent other applications from editing it while ColdFusion is connected.
      • ;readOnly=true: Forces a read-only connection, useful for security or reporting. [6, 13, 14, 15, 16] 

      Verification

      Once saved, any <cfquery> without a datasource attribute will use this configuration. You can verify it by running a simple query like SELECT * FROM yourTable. If it fails, check the exception.log for ClassNotFound errors, which usually mean the JAR files aren't in the correct lib folder or the service wasn't restarted. [3, 17, 18, 19]

      References

      The specific SQL syntax adjustments often required when switching from standard ODBC to UCanAccess

      When switching from the standard Microsoft Access ODBC driver to the UCanAccess JDBC driver in ColdFusion 11 or 2016, you may need to adjust your SQL syntax. UCanAccess is based on HSQLDB, which follows ANSI SQL standards more strictly than the legacy Access engine. [1, 2, 3] 

      1. Date and Time Literals

      UCanAccess supports the traditional Access # delimiter but is stricter about the format. [1, 4] 

      • ODBC Standard: Often allowed various string formats depending on regional settings.
      • UCanAccess: Prefers #MM/dd/yyyy# or #yyyy-MM-dd#. Avoid dd/MM/yyyy unless it is unambiguous.
      • Example: SELECT * FROM Orders WHERE OrderDate > #01/01/2024#. [1, 4] 

      2. Wildcard Characters

      UCanAccess is flexible and supports both Access-style and standard SQL wildcards. [1] 

      • Multi-character: Use % (standard) or * (Access).
      • Single-character: Use _ (standard) or ? (Access).
      • Example: WHERE LastName LIKE 'Sm%' or WHERE LastName LIKE 'Sm*' both work. [1] 

      3. Case Sensitivity

      By default, UCanAccess text comparisons are case-insensitive, matching standard Access behaviour. [1, 5] 

      • Column Names: While UCanAccess may return column names in UPPERCASE in metadata, you can still refer to them in your SQL using their original case.
      • Comparison: If you need case-sensitive searches, you must add ;ignoreCase=false to your JDBC connection URL in Application.cfc. [3, 5] 

      4. Join and Update Syntax

      Complex Access-specific JOINs in UPDATE statements often fail because HSQLDB (the underlying engine) requires standard ANSI syntax. [2] 

      • Access ODBC: UPDATE TableA INNER JOIN TableB ON ... SET TableA.Col = TableB.Col
      • UCanAccess Recommendation: Use subqueries for updates involving multiple tables.
      UPDATE TableA SET Col = (SELECT Col FROM TableB WHERE TableA.ID = TableB.ID)WHERE EXISTS (SELECT 1 FROM TableB WHERE TableA.ID = TableB.ID)

      [2] 

      5. Built-in Functions

      UCanAccess supports core Access functions like IIf(), Date(), and Now(), but VBA-specific or user-defined functions (UDFs) saved within the .accdb file will not work. [1, 6, 7] 

      • Supported: Left(), Right(), Mid(), Year(), Month(), DateAdd(), IIf().
      • Not Supported: Custom VBA modules or complex Access-only functions like Replace() (in some contexts) or Domain Aggregate functions (DLookup, DSum). [1, 6, 7, 8] 

      6. Reserved Words and Brackets

      Always use square brackets [] for table or column names that contain spaces or match SQL reserved words to avoid "Unexpected Token" errors. [1] 

      • Correct: SELECT [First Name] FROM [User Table] WHERE [Order] = 1. [1]

      References

      A list of common UCanAccess error codes to help troubleshoot existing queries that might fail after the switch

      When troubleshooting UCanAccess in ColdFusion 11 or 2016, most errors are wrapped in a net.ucanaccess.jdbc.UcanaccessSQLException or surface as standard Java exceptions. [1, 2, 3, 4] 

      Common JDBC & Connection Errors

      • java.lang.ClassNotFoundException: net.ucanaccess.jdbc.UcanaccessDriver:
        • Meaning: ColdFusion cannot find the driver files.
        • Fix: Ensure all 5 JAR files are in {CF_Install}\cfusion\lib and that you have restarted the ColdFusion service.
      • UcanaccessSQLException: Unsupported newer version: 32:
        • Meaning: You are trying to open a database version (often a very new Access format) that the current version of the Jackcess library (within UCanAccess) does not yet support.
      • given file does not exist:
        • Meaning: The path in your url string is incorrect or the ColdFusion service account lacks permissions to see it.
        • Fix: Use absolute paths with forward slashes (e.g., C:/data/my.accdb) and ensure the Windows service is running as a user with folder access. [2, 4, 5, 6, 7, 8] 

      Common SQL Syntax Exceptions

      • UCAExc::: user lacks privilege or object not found: [Name]:
        • Meaning: The table or column name you referenced does not exist, or you are using a reserved word without brackets.
        • Fix: Wrap the name in square brackets: [Name].
      • Unexpected Token: [Token]:
        • Meaning: Syntax error, often caused by using Access-specific SQL that isn't ANSI-compliant (like complex INNER JOIN updates) or unquoted aliases containing special characters.
      • data exception: invalid datetime format:
        • Meaning: The date string being inserted doesn't match the required format.
        • Fix: Use <cfqueryparam cfsqltype="cf_sql_timestamp"> to let the driver handle the conversion automatically.
      • incompatible data type in operation:
        • Meaning: Typically occurs when trying to perform math on non-numeric fields or when inserting a string into a numeric/boolean column. [4, 9, 10, 11, 12, 13, 14] 

      Internal Driver Errors

      • Feature not supported:
        • Meaning: You are attempting an operation that UCanAccess or the underlying HSQLDB engine does not support, such as DROP CONSTRAINT.
      • File marked as read only / Concurrent process access:
        • Meaning: Another application (like MS Access itself) has an exclusive lock on the file, or you haven't enabled openExclusive=true while another process is active. [15, 16, 17, 18] 

      Check the [ColdFusion Administrator logs](https://helpx.adobe.com/coldfusion/configuring-administering/basic-troubleshooting-and-faqs.html) (exception.log or application.log) for the full stack trace to identify exactly which line in your code triggered the exception. [3, 19]

      References

      Help setting up a global error handler in Application.cfc to catch and log these specific database exceptions [18] 

      To catch UCanAccess or other database errors globally, you can use the onError function in your Application.cfc. This prevents users from seeing raw Java stack traces and allows you to log the specific JDBC error message.

      Global Error Handler (Tag-Based)

      Add this function inside your <cfcomponent> block:


      <cffunction name="onError" returnType="void" output="true">
          <cfargument name="exception" type="any" required="true">
          <cfargument name="eventName" type="string" required="true">

          <!--- 1. Log the error to ColdFusion's application.log --->
          <cflog file="#this.name#_errors" 
                 type="error" 
                 text="Event: #arguments.eventName#, Message: #arguments.exception.message#">

          <!--- 2. Check specifically for UCanAccess/Database errors --->
          <cfif structKeyExists(arguments.exception, "rootCause") AND 
                findNoCase("ucanaccess", arguments.exception.rootCause.type)>
              
              <h2>Database Connection Error</h2>
              <p>There was a problem communicating with the Access database.</p>
              
              <!--- Optional: Show details only in development environment --->
              <cfif cgi.remote_addr eq "127.0.0.1">
                  <cfoutput>
                      <p><strong>Detail:</strong> #arguments.exception.rootCause.message#</p>
                  </cfoutput>
              </cfif>

          <cfelse>
              <!--- Handle non-database errors --->
              <h2>Application Error</h2>
              <p>An unexpected error occurred. Please try again later.</p>
          </cfif>

          <!--- 3. Stop further processing --->
          <cfabort>
      </cffunction>

      Why this is useful for UCanAccess:

      • Root Cause Analysis: JDBC errors are often nested. Accessing arguments.exception.rootCause gets you the actual UCanAccess driver message (e.g., "user lacks privilege") rather than a generic ColdFusion "Query Error."
      • Environment Filtering: The check for cgi.remote_addr ensures that sensitive database path information (often revealed in JDBC errors) is only shown to you on the local server, not to external users.
      • Custom Logging: By using <cflog>, you create a dedicated log file (e.g., myAccessApp_errors.log) in the ColdFusion logs directory, making it easier to track driver-specific crashes.

      Testing the Handler

      To test this, temporarily change your url in this.datasources to a file path that doesn't exist. Refresh your app, and you should see your custom "Database Connection Error" message instead of a standard CF error page.

      How to wrap individual queries in cftry/cfcatch for more granular error handling

      To handle errors at the query level, use <cftry> and <cfcatch> blocks. This is especially useful for UCanAccess because it lets you catch specific database issues—like a locked file or a syntax error—without crashing the entire page.

      Example: Granular Query Error Handling

      <cftry>
          <cfquery name="getUsers">
              SELECT [User ID], [User Name] 
              FROM Users
              WHERE Status = <cfqueryparam value="Active" cfsqltype="cf_sql_varchar">
          </cfquery>

          <!--- If the query succeeds, display data --->
          <cfoutput query="getUsers">
              #getUsers["User Name"]#<br>
          </cfoutput>

          <cfcatch type="database">
              <!--- Handle UCanAccess specific database errors --->
              <cfif findNoCase("ucanaccess", cfcatch.message) OR findNoCase("jackcess", cfcatch.detail)>
                  <p style="color:red;">
                      <strong>Database Error:</strong> 
                      The Access database is currently locked or unavailable. 
                      Please try again in a moment.
                  </p>
              <cfelse>
                  <p>A general database error occurred: <cfoutput>#cfcatch.message#</cfoutput></p>
              </cfif>
              
              <!--- Log the full error for the admin --->
              <cflog file="app_db_errors" type="error" text="SQL State: #cfcatch.sqlstate# | Message: #cfcatch.message#">
          </cfcatch>
          
          <cfcatch type="any">
              <!--- Handle other non-DB errors (like coding typos) --->
              <p>An unexpected application error occurred.</p>
          </cfcatch>
      </cftry>

      Why use cfcatch type="database"?

      1. Access Locking: Since MS Access is file-based, it’s prone to "File already in use" errors. A cfcatch block allows you to show a friendly "Please retry" message instead of a broken page.
      2. SQL State: The cfcatch.sqlstate variable often contains the specific vendor code from UCanAccess/HSQLDB, which helps identify if the error is a syntax problem or a connection timeout.
      3. Graceful Degraded Mode: If a non-essential query (like "Recent News") fails, you can catch the error and simply hide that section of the page while the rest of the application continues to work.

      Pro-Tip: Using cfqueryparam

      Always use <cfqueryparam> inside your queries. It not only prevents SQL injection but also helps the UCanAccess driver correctly map ColdFusion data types to Access/Java types, reducing the "Incompatible data type" errors common in 64-bit environments.

      How to use transactional processing with <cftransaction> to ensure multiple Access updates succeed or fail together

      In ColdFusion 11 and 2016, <cftransaction> ensures that multiple database operations are treated as a single "unit of work." If one query fails (e.g., a file lock occurs or a constraint is violated in Access), all previous queries in that block are rolled back.

      Transactional Processing for MS Access

      When using the UCanAccess driver, you must ensure that your Application.cfc datasource does not have readOnly=true enabled for these operations to work.

      <cftry>
          <cftransaction action="begin">
              
              <!--- 1. Insert into the main table --->
              <cfquery name="addOrder">
                  INSERT INTO Orders (OrderDate, CustomerID)
                  VALUES (
                      <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
                      <cfqueryparam value="#form.custID#" cfsqltype="cf_sql_integer">
                  )
              </cfquery>
              <!--- 2. Get the last ID (UCanAccess/HSQLDB specific syntax) --->
              <cfquery name="getID">
                  SELECT IDENTITY() AS lastID FROM Orders
              </cfquery>
              <!--- 3. Insert into the related table --->
              <cfquery name="addItems">
                  INSERT INTO OrderDetails (OrderID, ProductID, Qty)
                  VALUES (
                      <cfqueryparam value="#getID.lastID#" cfsqltype="cf_sql_integer">,
                      <cfqueryparam value="#form.prodID#" cfsqltype="cf_sql_integer">,
                      <cfqueryparam value="#form.qty#" cfsqltype="cf_sql_integer">
                  )
              </cfquery>
              <cftransaction action="commit" />
              <p>Order processed successfully!</p>
          </cftransaction>
          <cfcatch type="database">
              <!--- If ANY query fails, roll back everything in the transaction --->
              <cftransaction action="rollback" />
              
              <p>Error: Transaction failed. No data was saved.</p>
              <cflog file="db_transactions" type="error" text="Rollback occurred: #cfcatch.message#">
          </cfcatch>
      </cftry>

      Key Considerations for MS Access Transactions

      • ACID Compliance: UCanAccess (via HSQLDB) provides full ACID support, meaning your .accdb file remains consistent even if the ColdFusion service crashes mid-transaction.
      • Identity Selection: While standard Access uses SELECT @@IDENTITY, UCanAccess often prefers SELECT IDENTITY() or SELECT LAST_INSERT_ID() to retrieve the most recent AutoNumber value within the current transaction.
      • Isolation Levels: Access is a file-based database, so complex isolation levels (like Serializable) are limited. The default behavior is usually sufficient for standard web apps.
      • Locking: Transactions can hold locks on the .accdb file longer than single queries. Keep your transaction blocks short to avoid "File already in use" errors for other users.

      How to handle multi-table updates using this transactional logic

      To perform multi-table updates in ColdFusion 11/12 (2016) using the UCanAccess driver, you wrap your queries in a <cftransaction> block. This ensures that if the update to the second table fails (e.g., due to a validation error or file lock), the first update is automatically reversed.

      Multi-Table Update Pattern (Tag-Based)

      In this example, we update a product's stock levels in one table and log the change in an audit table simultaneously.

      <cftry>
          <cftransaction action="begin">
              
              <!--- 1. Update the Inventory table --->
              <cfquery name="updateStock">
                  UPDATE Inventory 
                  SET UnitsInStock = UnitsInStock - <cfqueryparam value="#form.qty#" cfsqltype="cf_sql_integer">
                  WHERE ProductID = <cfqueryparam value="#form.prodID#" cfsqltype="cf_sql_integer">
              </cfquery>
              <!--- 2. Log the transaction in the Audit table --->
              <cfquery name="logChange">
                  INSERT INTO StockLog (ProductID, ChangeQty, LogDate, UserID)
                  VALUES (
                      <cfqueryparam value="#form.prodID#" cfsqltype="cf_sql_integer">,
                      <cfqueryparam value="-#form.qty#" cfsqltype="cf_sql_integer">,
                      <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
                      <cfqueryparam value="#session.userID#" cfsqltype="cf_sql_integer">
                  )
              </cfquery>
              <!--- If we reach here without errors, save both changes permanently --->
              <cftransaction action="commit" />
              <p>Inventory updated and logged successfully.</p>
          </cftransaction>
          <cfcatch type="database">
              <!--- If either query fails (e.g., ProductID doesn't exist), undo everything --->
              <cftransaction action="rollback" />
              
              <p style="color:red;">
                  <strong>Error:</strong> The update could not be completed. 
                  No changes were made to the database.
              </p>
              
              <cflog file="inventory_errors" type="error" 
                     text="Rollback on Product #form.prodID#: #cfcatch.message#">
          </cfcatch>
      </cftry>

      Critical Implementation Details

      • The Identity Function: If your second table needs an ID generated by the first query, use SELECT IDENTITY() immediately after the first INSERT within the same transaction.
      • Access File Locking: Because MS Access uses file-level locking, keep these transactions as fast as possible. If a transaction stays open too long, other users might receive a "Database is already in use" error.
      • UCanAccess Versioning: Ensure your Application.cfc does not have readOnly=true in the connection string, or these update/insert queries will fail instantly.
      • Constraint Checking: If your Access database has "Relationships" with "Enforce Referential Integrity" enabled, the rollback will trigger automatically if a foreign key violation occurs.