Finding Free Text Annotations in COMOS P&ID Queries

David Krause16 min read
Other TopicSiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Finding Free Text Annotations in COMOS P&ID Queries

Free text placed on a Siemens COMOS P&ID is not represented as a queryable object in the standard navigation tree. Unlike attribute-bound labels (which are exposed as CDOs with attributes that can be filtered), text drawn with the toolbar "A" button is stored as geometry on the report document. This makes finding, auditing, and translating free text a recurring pain point for plant engineers, particularly on legacy projects where hundreds of P&IDs contain unstructured remarks.

This article documents three working methods to locate free text across a COMOS project: the built-in Bulk Translation Query, a scripted Report.Open walk using the ITEXT class, and a database-level search using SQL Server FREETEXT or Oracle Text. Each method is detailed with verification steps, error handling, and a comparison of when to use which approach.

Scope. This article applies to COMOS 10.2, 10.3, and 10.4 deployments on SQL Server and Oracle back ends. Menu paths, class names, and exact object-model members can shift between minor versions and between localized (DE/EN/CN) builds — always verify in the Object Debugger for your installed build before deploying a query against a production project.

What "Free Text" Means in a COMOS Report

A COMOS report can contain text originating from four sources. The distinction matters because only some of them are addressable through standard queries.

Source Created via Object in nav tree? Addressable as ITEXT?
Object-bound label Attribute on a CDO (e.g., Tag, Description) Yes Via ITextAttributeObject subclass
Free text / remark Toolbar "A" text tool on the report No Yes, directly as ITEXT
Smart text ||placeholder|| token in a label No (resolved at generation time) Resolved text appears; token does not
Hyperlink / cross-reference Insert > Cross-reference No (target is the linked doc) Yes, as ITEXT with hyperlink flag

The remainder of this article targets the second row: user-typed remarks that have no CDO behind them. These are invisible to Navigator queries, OwnAttributes searches, and standard Find dialogs.

The COMOS Object Model for Text

The COMOS report object model exposes the relevant interfaces in a flat hierarchy that is easy to traverse in VBScript queries.

Class / Property Role
Report Represents a COMOS report document. Opened via doc.Report.Open or by opening the document from the navigator.
Reportdocument The document object inside the report. Accessed as doc.Report.Reportdocument.
Reportdocument.Item(i) Indexed collection of items on the report. Indexing is 1-based (the source material references I-1 to convert to a 0-based loop counter).
ITEXT Base class for text items. Discovered in the COMOS Object Debugger (Tools > Object Debugger).
ITextAttributeObject Subclass of ITEXT for object-bound text. Carries a back-reference to the source CDO.
ItemCount Total number of items on the report, including lines, polylines, symbols, and text.

To filter free text from object-bound text in a script, test the TypeName(item) string against the value "ITEXT". Object-bound text typically resolves to a longer class name (e.g., "ITextAttributeObject"), so an exact-match test excludes it. Note that on some COMOS 10.4 builds the TypeName may return a different string for compound text objects — verify against the Object Debugger for your installation before relying on the comparison.

Database Architecture: Where Free Text Is Stored

COMOS stores report geometry — including the text and its position, font, and content — in the project database. The two standard back ends are Microsoft SQL Server (typical for COMOS 10.x) and Oracle Database (used in larger enterprise rollouts). Free text values are not in a generic Documents table; they live in COMOS-specific geometry tables whose names depend on the COMOS version and database layer.

For SQL Server deployments, the FREETEXT predicate is the natural-language match operator documented at Microsoft Learn — FREETEXT (Transact-SQL). It operates on full-text indexed columns, supports word stemming and inflectional forms, and is the closest analogue to a user-typed search.

For Oracle deployments, the equivalent functionality is delivered by Oracle Text (formerly Oracle Context). The general free-text search concept is documented at Oracle Help Center — Free Text Search.

For background on the technique itself — tokenization, ranking, indexing — the Google Cloud — Full-Text Search Explained overview is a useful primer, even though it is not COMOS-specific.

Schema names. This article intentionally does not name specific COMOS tables, because they are renamed between minor versions and some are subject to localization. Inspect your live database with SQL Server Management Studio or Oracle SQL Developer, or refer to the COMOS Database Reference for your installed build, to identify the table that holds report item text before writing a query against it.

Method 1 — Bulk Translation Query (No Scripting)

The fastest path for translators, reviewers, and one-off audits is the Bulk Translation tool built into COMOS.

  1. Open the COMOS project and navigate to the base object, folder, or document scope you want to search.
  2. From the main menu, select Extra → Bulk Translation Query.
  3. In the resulting dialog, set the Query Scope:
    • Current project — every report in the open project (slowest).
    • Current unit — every report in the current unit/folder.
    • Current document — single report.
  4. Apply a filter to limit the result to free text. The exact filter name varies by build; look for Text type = Free text or Source = Manual.
  5. Run the query. The result grid shows source text, target text, the host document, and the language.

Advantages: No scripting, no risk of corrupting objects, native translation workflow columns included.

Limitations:

  • Cannot be saved as a reusable COMOS query; you re-run it manually each time.
  • Filtering by text string is not exposed in the dialog — you can only filter by language, status, or document.
  • Read-only — no programmatic export to CSV or another system.

Method 2 — Scripted Report.Open Walk with ITEXT Filter

For automated, repeatable, and content-filtered searches, COMOS provides a script path. The approach recommended in the source thread is to open each report, iterate over Reportdocument.Item(i), and filter on TypeName == "ITEXT".

Reference implementation

' =========================================================
' COMOS VBScript query — Find free text matching a pattern
' Tested against COMOS 10.2 / 10.3 (Object Debugger values
' can differ — verify constants for your build)
' =========================================================
Option Explicit

' --- Configuration ---
Const SEARCH_STRING  = "REVIEW"          ' substring (case-insensitive)
Const OUTPUT_FILE    = "C:\Temp\FreeTextReport.csv"
Const SAVE_REPORT    = False              ' True to persist report changes
Const MAX_REPORTS    = 0                  ' 0 = no limit
Const ITEM_TYPE_NAME = "ITEXT"            ' verify in Object Debugger

Dim fso, ts
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts  = fso.CreateTextFile(OUTPUT_FILE, True)
ts.WriteLine "DocumentFullName" & vbTab & "ItemIndex" & vbTab & "TextContent"

Dim reportCount, matchCount
reportCount = 0
matchCount  = 0

Dim doc
For Each doc In ThisProject.Documents
    ProcessReport doc
    If MAX_REPORTS > 0 And reportCount >= MAX_REPORTS Then Exit For
Next

ts.Close
MsgBox "Processed " & reportCount & " reports. " & _
       "Matched " & matchCount & " free-text items."

' ---------------------------------------------------------
Sub ProcessReport(doc)
    On Error Resume Next
    Err.Clear

    If doc Is Nothing Then Exit Sub

    ' Restrict to P&ID documents to avoid hitting datasheets,
    ' loop diagrams, and other report types.
    If LCase(doc.Type) <> "p&id" And LCase(doc.Type) <> "pid" Then
        Exit Sub
    End If

    ' Skip documents open in another COMOS session — opening
    ' them can clobber the other session's unsaved changes.
    If doc.OpenInOtherSession = True Then
        Debug.Print "Skipped (open elsewhere): " & doc.FullName
        Exit Sub
    End If

    doc.Report.Open
    If Err.Number <> 0 Then
        Debug.Print "Open failed (" & Err.Number & ") for " & _
                    doc.FullName & ": " & Err.Description
        Err.Clear
        Exit Sub
    End If

    reportCount = reportCount + 1

    Dim i, item, txt
    Dim rdoc
    Set rdoc = doc.Report.Reportdocument

    For i = 1 To rdoc.ItemCount
        Err.Clear
        Set item = rdoc.Item(i)
        If Err.Number <> 0 Then
            Debug.Print "Item " & i & " in " & doc.FullName & _
                        " failed: " & Err.Description
            Err.Clear
        ElseIf TypeName(item) = ITEM_TYPE_NAME Then
            txt = item.Text
            ' Strip embedded newlines to keep the CSV clean
            txt = Replace(txt, vbCrLf, " ")
            txt = Replace(txt, vbLf,   " ")
            If InStr(1, txt, SEARCH_STRING, vbTextCompare) > 0 Then
                ts.WriteLine doc.FullName & vbTab & CStr(i) & vbTab & txt
                matchCount = matchCount + 1
            End If
        End If
    Next

    If SAVE_REPORT Then
        Err.Clear
        doc.Report.Save
        If Err.Number <> 0 Then
            Debug.Print "Save failed for " & doc.FullName & _
                        ": " & Err.Description
            Err.Clear
        End If
    End If

    On Error GoTo 0
End Sub

How to deploy the query

  1. Open the COMOS project in the COMOS desktop client.
  2. Navigate to a unit or folder where you have rights to create queries.
  3. Right-click → New → Query. Choose a Script-based query (German: Skriptbasierte Abfrage).
  4. Paste the script above into the editor.
  5. Adjust SEARCH_STRING, OUTPUT_FILE, and SAVE_REPORT for your scenario.
  6. Save and execute the query from the navigator context menu.
Test before scaling. Set MAX_REPORTS = 5 and SAVE_REPORT = False for the first run. Confirm the CSV looks correct, then scale up. A single corrupted report item can crash the COMOS shell if the error handlers are missing or mis-scoped.

Error Handling: The Two Failure Modes That Bite First

The field report documents two specific failure modes that surface only when the script is run against a real project. Both must be engineered around before the script is safe to schedule.

1. Save conflicts when documents are open elsewhere

If a report is currently open in another COMOS session (e.g., a colleague editing the same drawing), the script's call to doc.Report.Save will either silently fail or overwrite the other session's unsaved changes. The mitigation is to check doc.OpenInOtherSession before any save, and to default to read-only scans unless persistence is explicitly required.

' Guarded save pattern
If doc.OpenInOtherSession = False And doc.Locked = False Then
    doc.Report.Save
End If

If you do not need to persist changes (which is the case for any read-only query), comment out the doc.Report.Save line entirely:

' a.Report.Save   '<-- intentionally commented for read-only scan

2. Session-killing faults in report items

When a report contains a corrupted, partially migrated, or version-mismatched object, opening it from script can raise a COM error that propagates to the COMOS shell. The documented behavior is that the entire COMOS session terminates. In some COMOS 10.3+ builds, the error surfaces as a modal dialog that must be clicked away — fatal for an unattended batch run over several hundred reports.

The mitigation is a tight On Error Resume Next envelope around both doc.Report.Open and the per-item access loop, with an explicit skip-and-log path on error:

Sub ProcessReport(doc)
    On Error Resume Next
    Err.Clear
    doc.Report.Open
    If Err.Number <> 0 Then
        Debug.Print "Skip (open error " & Err.Number & _
                    "): " & doc.FullName
        Err.Clear
        Exit Sub
    End If

    Dim i, item
    For i = 1 To doc.Report.Reportdocument.ItemCount
        Err.Clear
        Set item = doc.Report.Reportdocument.Item(i)
        If Err.Number <> 0 Then
            Debug.Print "Item " & i & " in " & doc.FullName & _
                        " failed: " & Err.Description
            Err.Clear
        ElseIf TypeName(item) = "ITEXT" Then
            ' process match
        End If
    Next
    On Error GoTo 0
End Sub

3. Suppressing modal error dialogs at the COMOS level

For unattended runs, COMOS has a global switch that suppresses interactive error dialogs. The path differs slightly by build:

  • COMOS 10.2 / 10.3: Options → System → Error Handling → Suppress runtime errors in queries (checkbox). In the German build the path is Extras → Optionen → System → Fehlerbehandlung.
  • COMOS 10.4+: The same path, but in some builds the toggle sits under Tools → Options → Workflow → Queries.

Verify the option is enabled with a single-report test before scheduling a batch run against a production project. When this option is off, the modal dialog defeats the entire purpose of the On Error Resume Next envelope.

Method 3 — Database-Level Search with SQL FREETEXT

For projects with more than ~2,000 reports, the script-based approach is slow because each doc.Report.Open call performs a database round-trip. A faster path is to query the underlying database directly, using the SQL Server FREETEXT predicate.

From the Microsoft Learn — FREETEXT (Transact-SQL) reference, the predicate is used in a WHERE clause against a full-text indexed column. Conceptual example (table and column names are placeholders — verify against your schema):

-- Conceptual query; table/column names depend on COMOS version.
SELECT TOP 1000
    DocumentName,
    ItemIndex,
    TextContent
FROM dbo.ComosReportItem WITH (NOLOCK)
WHERE FREETEXT(TextContent, 'pump discharge');

Required preconditions:

  1. A full-text index must exist on the text column. If it does not, create it:
    CREATE FULLTEXT INDEX ON dbo.ComosReportItem (TextContent)
        KEY INDEX PK_ComosReportItem;
  2. The user running the query must have SELECT rights on the table. COMOS administrators typically grant read-only DB accounts for analytics workloads.
  3. The result will include both object-bound and free text unless your schema exposes a discriminator. If the table has an ItemType column, add AND ItemType = 'ITEXT' to the predicate.

For Oracle-based COMOS deployments, the equivalent is delivered through Oracle Text indexes (CTXSYS / CREATE INDEX ... INDEXTYPE IS CTXSYS.CONTEXT). The high-level free-text search pattern is documented at Oracle Help Center — Free Text Search.

For a general treatment of full-text search semantics — tokenization, stemming, ranking, recall vs. precision — see the Google Cloud — Full-Text Search Explained overview.

Performance and Batch Sizing

Observed run-time figures, which vary by hardware, network latency to the COMOS database, and COMOS build:

Reports scanned Method Approx. duration Notes
100 COMOS script (local DB) 30–90 s Negligible for ad-hoc use
500 COMOS script (local DB) 3–7 min Watch the error-handling envelope
1,000 COMOS script (networked DB) 10–20 min Round-trip dominates
10,000+ SQL FREETEXT Seconds Requires schema knowledge and DB access

For script-based runs, batch in chunks of 200–500 reports with a query restart between batches. This limits the blast radius if a single corrupted report kills the session, and lets you resume from a known checkpoint rather than re-scanning.

Verification and Result Validation

  1. Cross-check with Bulk Translation. Re-run the same search using Extra → Bulk Translation Query. The order of magnitude of matches should align. The Bulk Translation tool may include some object-bound translatable text that the ITEXT filter excludes; a discrepancy of 5–15% is normal.
  2. Spot-check three random reports. For each, open the report manually, locate the matched text item, and confirm the content matches the CSV row.
  3. Validate the CSV file.
    • Row count matches the script's reported match count.
    • No rows have an empty TextContent (would indicate a filter failure).
    • No DocumentFullName values are truncated (would indicate an unhandled error path).
  4. Run a small batch first. Always execute the script with MAX_REPORTS = 5 and SAVE_REPORT = False on a test project or a test folder before scaling. The session-kill failure mode hides until the loop reaches the offending document.

Method Comparison

Criterion Bulk Translation Query COMOS Script (ITEXT) SQL FREETEXT
Setup effort None Medium (script + test) High (schema + index)
Run time (1,000 reports) 1–2 min 10–20 min Seconds
Free text only Partial (needs filter) Yes (ITEXT cast) Needs ItemType filter
Modifies project No Optional (SAVE flag) No
Handles corrupted reports Tolerates Needs error handling Tolerates
Output format COMOS grid Scriptable (CSV, DB) Native SQL result
Required permissions Standard user Standard user DBA or read-only DB user
Reusable as saved query No Yes (saved as a query) No (ad-hoc SQL)

Recommendation by use case:

  • One-off audit or translation review: Bulk Translation Query.
  • Scheduled audit, CSV export, or repeated runs: ITEXT script, saved as a COMOS query.
  • Very large projects (10,000+ reports) or analytics workloads: SQL FREETEXT with a full-text index.

Troubleshooting Matrix

Symptom Likely cause Fix
COMOS session terminates mid-run Unhandled error in Report.Open on a corrupted report Wrap doc.Report.Open in On Error Resume Next; skip on Err.Number <> 0
Modal error dialog per report Suppression flag off Enable Suppress runtime errors in queries in COMOS options
TypeName(item) returns "Empty" or "Nothing" Unsupported item type on the report Guard with If TypeName(item) = "Empty" Then
Save overwrites another session's changes Document open in a second COMOS session Check doc.OpenInOtherSession before Report.Save; default to read-only
ITEXT not visible in Object Debugger Wrong COMOS build or restricted permission Verify COMOS version; ITEXT is exposed in standard iDB installations
Free text not detected on certain reports Older layout format not migrated Re-save the report once in the current COMOS version; items become accessible via ITEXT
CSV output truncated or broken Embedded newline in item.Text Replace vbCrLf / vbLf with a space before writing
SQL FREETEXT returns zero rows Column has no full-text index Create the index: CREATE FULLTEXT INDEX ON <Table> (TextContent) KEY INDEX <PK>
SQL query returns attribute text, not free text No ItemType filter Add AND ItemType = 'ITEXT' if the column exists in your schema
Query runs but writes 0 matches TypeName string mismatch in this COMOS build Open the report in Object Debugger, inspect an item, copy the exact class name
First report opens, then script silently stops Unhandled error leaves the loop in a bad state Reset Err after every iteration; place the On Error Resume Next inside the subroutine only

Frequently Asked Questions

How do I find free text on a COMOS P&ID without writing any script?

Use the built-in Bulk Translation Query under Extra → Bulk Translation Query. It iterates over the project and lists translatable text, including free text, without requiring any code. The dialog does not support substring filtering on the text itself, so for content-based searches you need the ITEXT script approach.

What is the ITEXT class in COMOS?

ITEXT is the base COMOS class for text items on a report. It is exposed in the COMOS Object Debugger and is the discriminator for free text when iterating over Reportdocument.Item(i). Object-bound text typically resolves to a longer subclass name (e.g., ITextAttributeObject), so a TypeName(item) = "ITEXT" exact-match test isolates free text from attribute labels.

Why does my COMOS session terminate when I run a script that opens reports?

An unhandled error during doc.Report.Open — usually caused by a corrupted or partially migrated report item — propagates to the COMOS shell and terminates the session. Wrap the open call and the per-item loop in On Error Resume Next, check Err.Number after each call, and skip the document or item on error. Also enable the Suppress runtime errors in queries option in COMOS to prevent modal dialogs from blocking unattended runs.

Can I search free text directly in the COMOS database?

Yes. On SQL Server, use the FREETEXT predicate (documented on Microsoft Learn) against the table that stores report item text. A full-text index on the text column is required. On Oracle, the equivalent is delivered by Oracle Text indexes. The result will include both object-bound and free text unless your schema exposes a discriminator column — add an ItemType = 'ITEXT' filter if available.

How do I prevent my script from overwriting another user's unsaved changes?

Test doc.OpenInOtherSession before calling doc.Report.Save. If the document is open elsewhere, log the skip and either continue with a read-only scan or exit the batch. For pure query use cases, comment out the Report.Save line entirely; persistence is never required for a search.

How should I size a batch run for very large projects?

Cap each run at 200–500 reports with a query restart between batches, and always run a 5-report smoke test first. For projects above ~2,000 reports, prefer the SQL FREETEXT path because the script's per-report Report.Open round-trip dominates the runtime. The general approach to full-text search — including tokenization, indexing, and ranking — is summarized at Google Cloud: Full-Text Search Explained.

Back to blog