Infor LN BShell Programming: Developer Fundamentals Guide
BShell (BAAN Shell) is the proprietary 4GL programming language that powers all business logic in Infor LN. Every session, report, DAL, and UI trigger in LN is written in BShell. Despite its critical importance, documentation is scarce and tribal knowledge dominates. This guide provides a structured foundation for developers working with BShell—from syntax fundamentals to advanced database operations and debugging workflows.
BShell Language Syntax and Data Types
BShell uses a C-like syntax with domain-specific extensions for ERP operations. Variables are declared with the 'domain' keyword that maps to LN data dictionary domains, ensuring type safety across the entire application stack. Functions use the 'function' keyword and support both pass-by-value and pass-by-reference parameters. The critical distinction from modern languages is that BShell is procedurally compiled per-session and executes within the LN runtime environment, not as standalone binaries.
- Declare variables using domain types: 'domain tcitem i.item' declares variable i.item with the Item Code domain (tcitem), inheriting its length, validation rules, and display format from the data dictionary
- String operations use the $ prefix: $i.desc = strip$(i.desc) removes leading/trailing whitespace; use str.len$() for length, str.pos$() for substring search, and str.seg$() for substring extraction
- Control structures: if/then/else/endif, while/endwhile, for/endfor, select/case/endselect — note the mandatory 'end' keywords unlike C-style braces; missing 'endif' is the most common BShell compilation error
- Error handling uses on.error blocks: 'on.error goto error.handler' must be set at the top of every function that performs database operations; failure to handle errors causes silent transaction rollbacks that corrupt data
- Compile BShell source with 'bshell -c sessionname' from the LN command line; compilation errors are written to the session's .err file in $BSE/lib/errors/ — always check this file after compilation
Database Operations in BShell
BShell provides native database access through the dal (Data Access Layer) functions that abstract the underlying Oracle or SQL Server database. All table operations use domain-aware cursors: db.select, db.fetch, db.update, db.insert, and db.delete. The critical rule is that BShell always operates within an implicit transaction—every db.update or db.insert is part of the current transaction scope, and a db.retry.point/db.retry.hit pair controls transaction boundaries. Failing to set retry points causes the entire session to act as one transaction, leading to massive lock contention.
- Read records: db.select("tcibd001", key.1, i.item) opens a cursor on table tcibd001 (Item Master) using key.1 (primary key) with filter value i.item; db.fetch() retrieves the next matching record; always check db.status for 0 (success) or ENDOFSET
- Update records: db.update("tcibd001") updates the current record in the cursor with modified field values; must be called after a successful db.select/db.fetch within the same cursor scope; db.status returns DBLOCK if another session holds a lock
- Transaction control: db.retry.point() marks the start of a transaction boundary; db.retry.hit() commits all changes since the last retry.point; place retry.point before each logical business transaction, not at the session start, to minimize lock duration
- Bulk operations: use db.set.to.read() before db.select for read-only cursors that skip row locking; this prevents deadlocks during reporting and inquiry sessions that do not modify data
- Multi-table joins: BShell does not support SQL JOINs natively; use nested db.select/db.fetch loops or call dal.get.field() to fetch individual fields from related tables by key value
Debugging and Testing BShell Code
BShell debugging is notoriously difficult because the runtime does not provide a traditional IDE debugger. The primary debugging tools are trace output, the BShell message facility, and the LN audit trail. For complex logic, use the bshell -t flag to enable line-by-line execution tracing that writes every executed statement to a trace file. For production debugging, the mess() function writes messages to the session message log without interrupting execution.
- Enable trace mode: run 'bshell -t sessionname' to generate a trace file at $BSE/tmp/trace_sessionname.log showing every line executed with variable values at each step; WARNING: trace files grow rapidly (100MB+ for complex sessions), so use only in development
- Use mess(1, "debug: i.item = " & str$(i.item)) to write debug messages to the session message area; message priority 1 (information) does not block execution; priority 3 (error) halts the session and displays a dialog
- Test individual functions in isolation: create a test session (bshell script) that calls your function with known input parameters and validates the output; this is the BShell equivalent of unit testing
- Check the LN audit trail (table tcaud001) for database operations: every db.insert, db.update, and db.delete is logged with the session name, user, timestamp, and before/after field values when audit is enabled for the table
- Common runtime error: 'SUBSCRIPT OUT OF RANGE' — this occurs when an array index exceeds the declared array size; BShell arrays are 1-based and statically sized at declaration time with the 'dim' keyword; use the array.size() function to guard against overflow
Accelerate your Infor LN development with Netray's AI agents that understand BShell patterns and generate optimized code—schedule a demo.
Related Resources
Infor LN Session Creation and Modification
Learn to create and modify Infor LN sessions including form design, field triggers, choice fields, zoom sessions, and session-to-session communication patterns.
Infor LNInfor LN Domain Structure and Design Guide
Design robust Infor LN domain structures including data dictionary domains, table relationships, key definitions, and index strategies for BAAN/LN development.
Infor LNInfor LN Table Extensions Development Guide
Extend standard Infor LN tables safely with custom fields, triggers, and validation logic. Avoid upgrade conflicts with proven extension patterns for BAAN/LN.