Files
wwtools/grdb/queries/attributes.sql
T
Joseph Doherty 32f26272ae Initial commit: Wonderware / System Platform tools and reference
Five tools under one repo, all docs organized per DOCS-GUIDE.md:

- aalogcli: .NET 4.8 / x86 CliFx CLI for reading System Platform binary
  logs (*.aaLGX) for LLM debugging, built on aaOpenSource/aaLog. Commands:
  last, tail, range, unread, fields. Stable JSON envelope under --llm-json.
  Build template under lib/build/ for rebuilding aaLogReader.dll.

- aot: ArchestrA Object Toolkit 2014 v4.0 reference material. Dev guide
  (Markdown converted from CHM), API reference for the ArchestrA.Toolkit
  namespace, and the Monitor / Watchdog VS sample solutions.

- graccesscli: .NET 4.8 / x86 CliFx CLI that automates Galaxy
  configuration via the ArchestrA GRAccess COM interop. Includes session
  daemon, IPC protocol, and llm-json envelope contract.

- grdb: SQL/DDL exploration of the Galaxy Repository database. DDL
  captures, reusable queries, hierarchy / contained-name <-> tag-name
  translation notes.

- histdb: LLM-oriented reference for AVEVA Historian retrieval. INSQL
  linked-server, extension tables, every wwXxx time-domain extension,
  every retrieval mode, alarm/event SQL recipes, REST API. Distilled
  from the 243-page Historian Retrieval Guide.

Root contains:
- CLAUDE.md: thin index pointing into each tool's README.
- DOCS-GUIDE.md: doctrine for organizing docs for LLM consumption.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:22:20 -04:00

124 lines
4.8 KiB
SQL

-- Galaxy Object User-Defined Attributes/Tags for OPC UA Server
-- Returns user-defined (dynamic) attributes for deployed automation objects.
-- These are the attributes defined on templates and inherited by instances
-- via the deployed package derivation chain (e.g., MachineID, MoveInFlag).
--
-- Use full_tag_reference for read/write operations against the runtime.
-- Join with hierarchy.sql results on gobject_id to place attributes in the OPC UA browse tree.
--
-- For system/primitive attributes as well, see attributes_extended.sql.
--
-- Only attributes that existed at deploy time are included. The CTE walks
-- package.derived_from_package_id starting from each instance's deployed_package_id,
-- then joins dynamic_attribute on package_id to filter out post-deploy additions.
-- When the same attribute appears at multiple levels, only the shallowest
-- (most-derived) version is kept.
--
-- Historization detection: an attribute is historized when a primitive_instance
-- with a matching name exists in the deployed package chain and its primitive_definition
-- has primitive_name = 'HistoryExtension'.
--
-- Array dimensions are extracted from the mx_value hex string on the template's
-- dynamic_attribute row (bytes 5-6, little-endian uint16 at hex positions 13-16).
--
-- Data types (mx_data_type):
-- 1 = Boolean, 2 = Integer (Int32), 3 = Float (Single), 4 = Double,
-- 5 = String, 6 = Time (DateTime), 7 = ElapsedTime (TimeSpan),
-- 8 = (reference), 13 = (enumeration), 14 = (custom), 15 = InternationalizedString, 16 = (custom)
;WITH deployed_package_chain AS (
-- Start from each deployed instance's deployed package
SELECT
g.gobject_id,
p.package_id,
p.derived_from_package_id,
0 AS depth
FROM gobject g
INNER JOIN package p
ON p.package_id = g.deployed_package_id
WHERE g.is_template = 0
AND g.deployed_package_id <> 0
UNION ALL
-- Walk up the package derivation chain
SELECT
dpc.gobject_id,
p.package_id,
p.derived_from_package_id,
dpc.depth + 1
FROM deployed_package_chain dpc
INNER JOIN package p
ON p.package_id = dpc.derived_from_package_id
WHERE dpc.derived_from_package_id <> 0 AND dpc.depth < 10
)
SELECT
gobject_id,
tag_name,
attribute_name,
full_tag_reference,
mx_data_type,
data_type_name,
is_array,
array_dimension,
mx_attribute_category,
security_classification,
is_historized,
is_alarm
FROM (
SELECT
dpc.gobject_id,
g.tag_name,
da.attribute_name,
g.tag_name + '.' + da.attribute_name
+ CASE WHEN da.is_array = 1 THEN '[]' ELSE '' END
AS full_tag_reference,
da.mx_data_type,
dt.description AS data_type_name,
da.is_array,
CASE WHEN da.is_array = 1
THEN CONVERT(int, CONVERT(varbinary(2),
SUBSTRING(da.mx_value, 15, 2) + SUBSTRING(da.mx_value, 13, 2), 2))
ELSE NULL
END AS array_dimension,
da.mx_attribute_category,
da.security_classification,
CASE WHEN EXISTS (
SELECT 1 FROM deployed_package_chain dpc2
INNER JOIN primitive_instance pi
ON pi.package_id = dpc2.package_id
AND pi.primitive_name = da.attribute_name
INNER JOIN primitive_definition pd
ON pd.primitive_definition_id = pi.primitive_definition_id
AND pd.primitive_name = 'HistoryExtension'
WHERE dpc2.gobject_id = dpc.gobject_id
) THEN 1 ELSE 0 END AS is_historized,
CASE WHEN EXISTS (
SELECT 1 FROM deployed_package_chain dpc2
INNER JOIN primitive_instance pi
ON pi.package_id = dpc2.package_id
AND pi.primitive_name = da.attribute_name
INNER JOIN primitive_definition pd
ON pd.primitive_definition_id = pi.primitive_definition_id
AND pd.primitive_name = 'AlarmExtension'
WHERE dpc2.gobject_id = dpc.gobject_id
) THEN 1 ELSE 0 END AS is_alarm,
ROW_NUMBER() OVER (
PARTITION BY dpc.gobject_id, da.attribute_name
ORDER BY dpc.depth
) AS rn
FROM deployed_package_chain dpc
INNER JOIN dynamic_attribute da
ON da.package_id = dpc.package_id
INNER JOIN gobject g
ON g.gobject_id = dpc.gobject_id
INNER JOIN template_definition td
ON td.template_definition_id = g.template_definition_id
LEFT JOIN data_type dt
ON dt.mx_data_type = da.mx_data_type
WHERE td.category_id IN (1, 3, 4, 10, 11, 13, 17, 24, 26)
AND da.attribute_name NOT LIKE '[_]%'
AND da.attribute_name NOT LIKE '%.Description'
AND da.mx_attribute_category IN (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 24)
) ranked
WHERE rn = 1
ORDER BY tag_name, attribute_name;