PowerBuilder object types
pb-diff does not compare a PowerBuilder export as lines of text. It
reads each object into the parts PowerBuilder itself keeps apart - a
window's controls and scripts, a DataWindow's columns, a query's clauses
- and compares part with part, so a change is named by what changed.
This page says what those parts are for each kind of object. Every
example is one of the Order Desk files installed beside pb-diff, in
docs/examples/order-desk: release 1.4 under
old, release 1.5 under new.
| Object | Export | What pb-diff compares |
|---|---|---|
| Window | .srw |
Variables, functions, events, controls with their properties and scripts |
| User object | .sru |
As a window; a visual one has controls too |
| Menu | .srm |
Each menu item, with its properties and scripts |
| Function | .srf |
The function, with its signature and its script |
| Structure | .srs |
Each member |
| Query | .srq |
Each table, column, join, condition, sort key and argument |
| Data pipeline | .srp |
Each setting, each column of the source and destination tables, and the retrieve query |
| Project | .srj |
Each entry, and each library on its own |
| DataWindow | .srd |
Each band, control, property, database column, and the retrieve SQL |
| Application | .sra |
As a window, with the global variables |
The files that hold an application together beside its objects - workspaces, targets, Solutions and their projects, resource files and PowerGen projects - have a page of their own: Project and build files.
The same reading applies whichever way an object arrives: an export
file, an entry of a .pbl, or a source of a PowerBuilder
2025 Solution. pb-diff-cli parse <file> --format json
prints the parts of any of them.
Windows
A window is read into its declarations, its variables (instance,
shared and global), its external functions, each function and event
script, and each control. A control is a node holding its own property
block and its own scripts, so a button whose text changed and a button
whose clicked script changed are two different findings. A
function is identified by its name: when its signature changes, the old
and the new function are paired as one modified function rather than one
deleted and one added.
Your first comparison walks
through w_order_entry, where release 1.5 changed four
functions, deleted one and added two.
User objects
A user object is read as a window is. A non-visual one,
n_order_service in Order Desk, is its variables, functions
and events; a visual one has controls as well. The signature of
of_price changed in release 1.5, and pb-diff shows one
modified function with both signatures under the panes: see A changed
signature.
Menus
Each item of a menu is a node, with its properties and its scripts,
wherever it sits in the menu. In m_order_desk, release 1.5
replaced Print preview with Export
invoices: the tree shows one item deleted and one new, and the
new item's clicked script reads on its own. See A menu.
Functions
A global function is one function: its signature, its variables and
its script. A change of parameters is a modified function, as it is
inside a window; the signature strip under the panes shows both.
f_round_money is the Order Desk example, and is the same in
both releases.
Structures
Each member of a structure is a node, named by its name and then its
type - unit_price (decimal{2})
- so a member whose type changed is that member modified, and an added member is new. Selecting the structure shows the whole definition with the change in place.
pb-diff-cli compare old/s_order_line.srs new/s_order_line.srs --format json
(result)
Queries
PowerBuilder writes a query as one PBSELECT statement on
one line, often some hundreds of characters long. pb-diff shows the
statement as Query, and beneath it each part of it,
grouped: Tables, Columns,
Joins, Where, Group
By, Having, Order By and
Arguments. Each part is named by what it is -
orders.order_no, orders.status = 'O' - and
shows its exact text.
In release 1.5, q_open_orders also selects the order
total and lists the newest orders first. The tree says exactly that:
orders.total_amount new under Columns, and
orders.order_date modified under Order By.
pb-diff-cli compare old/q_open_orders.srq new/q_open_orders.srq --format json
(result)
A query is only meaningful whole, so the Query node
is what a merge takes or leaves: select it to take the old or the new
query. Two people who each changed the same query meet in a conflict,
which is decided on the query as a whole. A query written as plain SQL
rather than PBSELECT is one statement with nothing beneath
it.
Data pipelines
A data pipeline is four statements, each a node:
- Pipeline: its settings - the source and destination
connections,
type,commit,errors,keyname- each a node beneath it; - Source, named by its table, with a node for each column;
- Retrieve: the query that feeds the pipeline, with
its parts beneath it as for a query. It is written inside a quoted
string with its inner quotes escaped
(
TABLE(NAME=~"orders~")), and pb-diff reads it out of the string and shows each part exactly as the file holds it; - Destination, named by its table, with a node for each column.
In release 1.5, dp_archive_orders copies the customer
too, and commits every 500 rows instead of 100. The tree shows
commit modified under Pipeline, and
customer_id new in the source table, in the retrieve query
and in the destination table.
pb-diff-cli compare old/dp_archive_orders.srp new/dp_archive_orders.srp --format json
(result)
A merge takes or leaves each statement whole. One person who changed the commit interval and another who renamed the destination table changed two statements, and the two changes merge.
Projects
A project is a list of entries, one per line, each a node named for what it holds: Executable (EXE), Compiler options (CMP), Product version (PVS) and so on. A project has one library entry for each library of the application, and each is named and paired by its library - Library orders.pbl (PBD) - so a library added, removed or built differently is that library. The objects a project lists are paired the same way, by the object and its type - Object w_main (OBJ) - and not by the path of their library, which is wherever the project was last saved.
Within a line, pb-diff marks only the field that changed: when the
executable is built against another PowerBuilder runtime, the runtime
version at the end of the Executable line is what is
highlighted, not the whole line. In release 1.5,
p_order_desk moves to the PowerBuilder 2025 runtime, gains
a copyright and carries version 1.5.
pb-diff-cli compare old/p_order_desk.srj new/p_order_desk.srj --format json
(result)
A merge takes or leaves each entry.
DataWindows
A DataWindow is read into its bands, the controls in each band, every property of every control, the table definition with each database column, and the retrieve SQL. Each property is a node of its own and their order is not a difference, so a changed display format is that format and nothing else. The DataWindow Overview at the top summarises it: its processing style, its columns, its bands, how many controls it has, its update table and its retrieve SQL. See A DataWindow, where release 1.5 filters out cancelled lines and shows negative amounts in red.
The application
The application object is read as a window is: its global variables,
its events and its create and destroy scripts, each a node. In
order_desk.sra the open event opens
w_order_entry; the application is the same in both
releases.
In every comparison
Whatever the type, the same tree, the same navigation and the same five reports apply, and a library compare lists each object with its type. A part beneath a statement - a column of a query or of a pipeline, a property of a DataWindow control - is marked and can be selected and read, but the counts, the change navigation and a merge work on the statement that holds it. How a merge decides is in How merging works.