Database
Values a factory system keeps in a database table (SQL Server, PostgreSQL, MySQL and MariaDB, SQLite, or any database through ODBC) read as tags, and written back where a tag is told to: the Database and Sign-in cards, a tag that reads a cell by its table, column and row or runs a query of its own, the two ways a tag writes, the scan that offers a tag per column, four worked examples and what the driver does not do.
The Database driver reads the values a factory system keeps in a database table: the production order the MES holds, the recipe or the setpoint the ERP keeps, the result another test system recorded. Each tag reads one value of one table, and its values land where every other tag's do: in Logic, on dashboards, in the runs of a Process test bench. Where a tag is told to, the driver also writes back: the cell the tag reads, or a command of the tag's own.
SQL Server, PostgreSQL, MySQL and MariaDB, and SQLite are reached with nothing installed on the computer. Any other database (Oracle, Access, Firebird and others) is reached through its own ODBC driver, which has to be installed on the computer in its 64-bit version.
Reading is the main use, and its path is short: a device says where its database is and how the station signs in, the scan offers one tag per column of its tables, and every tag is born read only. What belongs to writing appears on a tag only once its access lets the station write it.
A device of this driver is one database: two databases of the same server are two devices. The devices sit under the driver and may be filed in folders, Driver → Folder → Device → Tag, as under any driver without a serial line or a broker.
The driver's page
The line under the header reads "Each device reads one database. Add a device, enter where its database is and how the station signs in, then scan it to add its columns as tags." For Configure connector, the page holds the driver's own Scan scope card, with the device whose database the scan reads (see Discovery). Under it stands the Devices table of any driver (see The device table), grown by Add device at the right of its title; empty, it reads "No devices yet." The driver's bar carries Discover, greyed until the Scan scope card is complete. The driver is listed under Files and databases, beside the File driver.
Device
A device of this driver has no Connection card: the Database card stands in its place, followed by the Sign-in card on every database but SQLite, which has no sign-in. The Poll interval (ms) of the Device card, 1000 by default, says how often the tags read the database, each tag able to override it as on any driver.
A new device is a SQL Server one with no server: it reads "Server not entered yet", its page says "The station does not reach this device until it says where its database is, so nothing is read from it yet and there is no error to show. Enter it in the Database card below (the server and the database name, the file or the data source) and the station connects to it."
and nothing is read until it does. The Base URI the header shows is the runtime address, which never
holds the user or the password: database://sqlserver?server=mes-sql&instance=SQLEXPRESS&database=MES
for a SQL Server instance, database://sqlite?file=C%3A%5CData%5Crecipes.db for a SQLite file,
database://odbc?source=ERP for an ODBC data source.
The Database card
| Field | Shown | Meaning | Default |
|---|---|---|---|
| Database type | always | SQL Server, PostgreSQL, MySQL / MariaDB, SQLite or Other (ODBC), which reads "Uses the 64-bit ODBC driver installed on this computer for that database (Oracle, Access, Firebird and others)." | SQL Server |
| Server | SQL Server, PostgreSQL, MySQL / MariaDB | On SQL Server: "A host name or an IP address. SERVER\INSTANCE and SERVER,PORT are read apart into their boxes." On the other two: "A host name or an IP address. A port written after a colon goes to the Port box." | empty |
| Port | the same | Empty for the database's own port, which the empty box shows: 1433, 5432 or 3306. With a SQL Server instance and no port, the box shows nothing and the server's SQL Server Browser says the port. | empty |
| Instance name | SQL Server | "Empty for the default instance. A named instance without a port is found through the SQL Server Browser." Up to 16 letters, digits, _ and $, starting with a letter or _. |
empty |
| Database name | SQL Server, PostgreSQL, MySQL / MariaDB | The database on the server that holds the tables, up to 128 characters. | empty |
| Database file | SQLite | "The full path of the SQLite file, reached with the Windows access of the account the station runs under. It is opened read only unless a tag writes." The box shows C:\Data\recipes.db as a hint. The file is never created. |
empty |
| Data source or connection text | Other (ODBC) | "The name of a data source in Windows' ODBC Data Sources (64-bit), or a connection text such as Driver=;Dbq=C:\Data\plant.accdb. The password goes in the Password box, never in the text." | empty |
A field the type picked does not read is not drawn, and keeps its value for when it does. Picking another type empties a port left at the old database's own port, so the new database is reached on its own. The Server box reads apart what database tools write together:
| Typed in Server | Becomes |
|---|---|
mes-sql\SQLEXPRESS (SQL Server) |
Server mes-sql, Instance name SQLEXPRESS |
mes-sql,1433 (SQL Server) |
Server mes-sql, Port 1433 |
10.0.0.5:5433 |
Server 10.0.0.5, Port 5433 |
While the card does not say where the database is, the device is saved as it is and waits, its dot grey, nothing read and no error shown:
| Database type | Waits for | The device reads |
|---|---|---|
| SQL Server, PostgreSQL, MySQL / MariaDB | The server, then the database name | "Server not entered yet", then "Database name not entered yet" |
| SQLite | The file | "Database file not entered yet" |
| Other (ODBC) | The data source or the connection text | "Data source not entered yet" |
A setting the card cannot take is said under the cards, and the device is not saved until it is corrected:
| You enter | The card says |
|---|---|
A server with a scheme, a path or a space, such as http://mes-sql |
"The server is a host name or an IP address alone: no scheme, no path and no space. A SQL Server instance and a port written with it go to their own boxes." |
An instance name with a space or a sign other than _ and $ |
"The instance name is up to 16 letters, digits, underscores and dollar signs." |
| A database name longer than 128 characters | "The database name is at most 128 characters, without control characters." |
A file that is not a full path, such as recipes.db |
"The database file is a full path: a drive, a folder and the file (C:\Data\recipes.db), or a network share (\server\data\recipes.db)." |
A folder, or a path holding *, ?, <, > or a quote |
"Enter the path of the database file itself, not of a folder, without * ? | < > or quotes." |
A data source name holding a bracket, a brace, a parenthesis, a comma, a semicolon or one of ? * ! @ \ |
The card asks for the name the source has in ODBC Data Sources, or a connection text. |
A connection text that is not key=value pairs, such as a brace left open |
"A connection text is key=value pairs separated by semicolons; a value holding a semicolon goes in braces." |
A connection text holding PWD= or Password= |
"Take the password out of the connection text and enter it in the Password box: the text is shown and written in the journal, and the Password box keeps it protected." |
The save holds the same rules, and the feed says so when it refuses one: "Device 'MES' has a database setting its driver cannot use. Open it and correct the field its panel marks."
The Sign-in card
Every database but SQLite carries the Sign-in card, with the user the station signs in with.
| Field | Shown | Meaning | Default |
|---|---|---|---|
| Sign in with the station's Windows account | SQL Server | On: "SQL Server is signed in to with the Windows account the station runs under; no user or password is stored." Off: "SQL Server is signed in to with a database user and its password." | off |
| Username | a server signed in to with a user, and ODBC, where it is optional | The database user. | empty |
| Password | the same | The user's password, stored protected like every credential of a driver: it is never shown again, never written in the address or the journal, and never answered to an agent. | empty |
| Encryption | SQL Server | Encrypted, certificate checked: "The connection is encrypted and the server's certificate is checked against the certificates this computer trusts." Encrypted, any certificate accepted: "The connection is encrypted and any certificate is accepted, as a factory server with its own certificate needs. The server's identity is not checked." Not encrypted: "The values and the commands travel in the clear. Only for an old server that offers no encryption." | Encrypted, certificate checked |
PostgreSQL and MySQL have no Encryption field: their connection is encrypted whenever the server offers it. A SQL Server whose certificate is its own, as a factory server's often is, refuses the connection with the database's words about a certificate chain issued by an authority that is not trusted: Encrypted, any certificate accepted is the choice that server asks for.
Under its fields the card says what user to ask for: "Ask the database's administrator for a user with only the permissions the station needs: reading, and writing only to the tables its tags change." The station reads and writes another system's data with whatever its user may do, so that user is the real limit of what the station can change. Every write is written in the journal, as on every driver.
A server signed in to with a user and no user entered yet says instead "Enter the user the station signs in with. Until then the station does not connect this device." That is not a refusal: the device is saved, and its error says no database user is entered yet until the user is there.
Online, waiting and offline
| Situation | What the device and its tags do |
|---|---|
| The Database card does not say where the database is | The device waits, grey dot, nothing read and no error (see above). |
| A server signed in to with a user, and none entered | The station does not connect the device; its error says no database user is entered yet. |
| The server does not answer, refuses the sign-in, or the SQLite file does not exist | The device is offline with the database's own cause, and the station connects it as soon as it can. A connection is waited for at most 10 s. |
| The connection is lost (the server restarted, the network cut) | The device goes offline and connects again. |
| A statement the database refuses, or one still running after 10 s | That tag's failed read, with the database's own words; the device keeps reading its other tags. |
| A tag reads the most recent row of a table that has no row yet | That tag waits, without an error, and its device's health leaves it out until the first row is written: the device's other tags say whether it is online. A table emptied after the tag has read from it is not that wait: the tag keeps its last reading, which counts as a failed read once it is older than its poll interval plus 10 s, as on every driver. |
Each device holds one connection of its own, opened when it connects and never shared or kept in a pool, so a connection a server dropped is never used again.
Prepare the server
The three network databases come closed to another computer in common installations. Each of these settings is made on the server, by whoever administers it; the station changes none of them.
| Database | What keeps the station out | Where it is changed |
|---|---|---|
| SQL Server | TCP/IP switched off (SQL Server Express and Developer come so) | SQL Server Configuration Manager > SQL Server Network Configuration > Protocols for the instance: enable TCP/IP, then restart SQL Server (the instance) under SQL Server Services |
| SQL Server | A named instance listens on a port of its own choosing | TCP/IP > IP Addresses > IPAll: empty TCP Dynamic Ports and type the port in TCP Port, then restart; or leave the device's Port empty and give the instance name |
| SQL Server | A named instance without a port is located by the SQL Server Browser, which is stopped or blocked (error 26) | SQL Server Services: SQL Server Browser started, Start Mode Automatic; UDP 1434 allowed in the server's firewall |
| PostgreSQL | listen_addresses is localhost, its default | postgresql.conf: listen_addresses = '*', then restart PostgreSQL |
| PostgreSQL | No line of pg_hba.conf lets this station's address in (SQLSTATE 28000) | pg_hba.conf: a host line for the database, the user and this station's address, with scram-sha-256 (md5 for a password stored with MD5), then SELECT pg_reload_conf(); |
| MySQL, MariaDB | bind-address is 127.0.0.1, as many packages set it, or skip-networking is on | The [mysqld] section of the configuration file: bind-address = 0.0.0.0, skip-networking removed, then restart |
| MySQL, MariaDB | No account for this station's address (error 1130) | CREATE USER for the user at this station's address, and GRANT what the tags need |
Every one of them also needs the database's port allowed in the firewall of the server's computer. When the server answers one of these ways, the device's page says which setting it is, with these steps and the values of this device (the port, the instance, this station's address as the server saw it, the pg_hba.conf line and the MySQL account, each with a copy button), in place of the database's English error. The notice goes away by itself once the device connects, or when the server answers another way. The journal and the agent read the same steps.
Tag addressing
How a tag reads
A tag of this driver has no address box of its own: its Source card asks how it reads.
| Reads | What the tag shows | Its fields |
|---|---|---|
| Table and column | A cell: the value column of one row of a table. | Table, Value column, Row to read and the fields of the row |
| Own query | The first column of the first row a SELECT of its own returns. | Query text |
A new tag reads Table and column, by its key, as a Double. The types offered are Boolean, Int32, Int64, Float, Double, String and DateTime. Reading a cell, a whole-number tag refuses a value with a fraction rather than rounding it (writing is the other way, see Writing), and a text reads as a number only when it is one. Every tag is born Read only; what writing adds is under Writing.
Table and column
| Field | Shown | Meaning | Default |
|---|---|---|---|
| Table | Table and column | "A name, or a schema and a name (dbo.Orders). A name with spaces or capitals goes in quotes or brackets, as in [Order Lines]." | empty |
| Value column | Table and column | The column whose cell is the tag's value. | empty |
| Row to read | Table and column | By its key: "The row whose key column holds the key value. Tags of the same table and row are read together in one query." Most recent: "The row with the highest value of the date column: a date and time, or a number that only grows. Tags of the same table and row are read together in one query." | By its key |
| Key column | By its key | The column that picks the row, such as OrderNo. |
empty |
| Key value | By its key | What the key column holds in the row to read, such as 4711, typed as text: the database reads it as it reads a value of that column. |
empty |
| Date column | Most recent | The column whose highest value is the most recent row, such as updated_at. |
empty |
A name is read the way the database reads it:
| Written | Read as |
|---|---|
Orders |
A plain name, read as the database reads any plain name: PostgreSQL in lower case, Oracle in capitals. |
"Order Lines", [Order Lines] |
The name exactly, whichever quotes the database itself takes. |
dbo.Orders |
A schema and a table: a dot outside quotes separates them. |
The driver puts every part of a name in the quotes its database takes, so a name is never pasted into a statement as text. A tag whose fields cannot work is not saved, and its page says what it lacks:
| You leave or enter | The tag's page says |
|---|---|
| No table | "Enter the table the value is in." |
| A table of three parts, or a quote not closed | "The table is a name, or a schema and a name (dbo.Orders); put a name with spaces in quotes or brackets. Each part is at most 128 characters." |
| No value column | "Enter the column of the value." |
| A value column of two parts | "The value column is one name; put a name with spaces in quotes or brackets." |
| By its key, with no key column | "Enter the key column that picks the row." |
| By its key, with no key value | "Enter the key value: what the key column holds in the row to read." |
| Most recent, with no date column | "Enter the date column whose highest value is the most recent row." |
The read-only Source address (wire) line shows what the driver receives:
row?table=dbo.ProductionOrders&column=Quantity&key=OrderNo&equals=4711 for a row by its key,
newest?table=recipe_setpoints&column=oven_temperature&by=updated_at for the most recent row.
Own query
| Field | Meaning | Default |
|---|---|---|
| Query text | "One SELECT that only reads; the value is the first column of the first row. @now is the station's date and time." A query that starts with WITH and only reads is taken as well. | empty |
The query is read the way the database reads it: what stands inside a quoted text, a quoted name or a comment is not a word of the statement. A query that does more than read is refused where it is typed:
| You enter | The tag's page says |
|---|---|
| Nothing | "Enter the query: one SELECT whose first column of the first row is the value." |
A statement that is not a SELECT, such as UPDATE or DELETE |
"The query starts with SELECT or WITH. To write, let the tag's access write and use a write command." |
A SELECT that changes the database: SELECT ... INTO, FOR UPDATE, or one holding INSERT, UPDATE, EXEC |
"The query would change the database (INSERT, UPDATE, SELECT INTO, FOR UPDATE, EXEC and the like). A query only reads." |
| Two statements | "The query holds more than one statement. Keep one SELECT." |
| A quote, a bracket or a comment not closed | "A quote, a bracket or a comment of the query is not closed." |
A value other than @now, such as @order |
"A query takes only @now, the station's date and time. Write any other value into the text." |
The wire address of a query tag is query?sql= followed by the query, percent-encoded.
Reading
| A tag reading | How it is read |
|---|---|
| By its key | Its column, in the row whose key column equals the key value; the key value is handed to the database as a parameter. |
| The most recent row | Its column, in the row whose date column holds that column's highest value (WHERE ... = (SELECT MAX(...) FROM ...)), a form every database and ODBC read alike; when two rows tie, the first is read. |
| Several tags of the same table and row | One query per pass for all their columns, so the factory's database is not asked once per tag. Should the database refuse that query (a column the table lacks), the tag's own column is read alone and that row is read column by column from then on: a wrong column costs its own tag only. |
| Its own query | The query as written, @now handed over as a parameter. |
| The database answers | The tag |
|---|---|
| A value of a type the tag reads | Reads it. |
| An empty cell (NULL) | Fails its read. |
| No row holding the key value, or more than one | Fails its read: a tag reads one row. |
| The most recent row of a table that has no row yet | Waits, without an error. |
| A query that returns no row | Fails its read. |
| A value the tag's type does not read (a text in an Int32 tag, a fraction in a whole-number tag) | Fails its read, with the reason. |
A failed read keeps the tag's last reading, which counts as failed once it is older than its poll interval plus 10 s, as on every driver. The database is asked at every read: a change another program makes is seen at the next read, never the instant it is made.
Writing
A tag writes only once its Access is Read and write or Write only. Its Source card then adds what a write does:
| Field | Shown | Meaning | Default |
|---|---|---|---|
| A write | the tag writes | Changes the cell it reads: "Changes the cell this tag reads, in one row only. A newer value still waiting replaces an older one." Runs its write command: "Runs the write command below. Every write counts: none still waiting is dropped for a newer one." A tag reading its own query has no cell to change, and is offered Runs its write command alone. | Changes the cell it reads |
| Write command | Runs its write command | "An UPDATE with its WHERE, an INSERT, or a stored procedure call. @value is the value written and @now the station's date and time; the value is always a parameter, never pasted into the text." The empty box shows INSERT INTO results (result, recorded_at) VALUES (@value, @now) as a hint. |
empty |
A Write only tag that runs its write command reads nothing, so its Source card holds the write alone.
| A write | How it goes |
|---|---|
| Changes the cell it reads | One UPDATE that sets the value column to @value in the tag's row, inside a transaction that is undone unless exactly one row changed: a key value no row holds, or one two rows hold, writes nothing and says so. A newer value still waiting replaces an older one, as for any setpoint. |
| Runs its write command | The command runs once per write, with the value as @value and the station's date and time as @now. Every write counts: two INSERTs are two rows, and a write still waiting is never dropped for a newer one. A stored procedure is called with EXEC, CALL or ODBC's {call ...}. |
| A value with a fraction, in a whole-number tag | Rounded, not refused: a value with a fraction written to a whole-number tag (Int32 or Int64) with no Scale or Calibration is rounded to the nearest whole number before it reaches the database, halves away from zero (2.5 writes 3, -2.5 writes -3). Refusing a fraction is how a cell is read, not how a value is written. |
| Answer | Done, or refused with the database's own words: a permission the user lacks, a constraint the row breaks, a value the column does not take. |
A command the driver cannot run is refused on the tag's page:
| You enter | The tag's page says |
|---|---|
| Nothing | "Enter the write command: an UPDATE, an INSERT or a stored procedure call holding @value." |
A command that starts with another word, such as DELETE |
"The write command starts with UPDATE, INSERT, EXEC or CALL." |
| Two statements | "The write command holds more than one statement. Keep one, or call a stored procedure." |
| A quote, a bracket or a comment not closed | "A quote, a bracket or a comment of the write command is not closed." |
No @value |
"Put @value where the value written goes: it is always a parameter, never pasted into the text." |
A value other than @value and @now, such as @line |
"A write command takes only @value, the value written, and @now, the station's date and time." |
| An UPDATE without WHERE | "An UPDATE without WHERE changes every row of the table. Add the WHERE that picks the row." |
@@ names, the functions of SQL Server, and the argument names of an EXEC (@speed = @value) are
not values and are left as written. The save holds the same rules, and the feed says so when it
refuses a tag:
"Tag 'Order quantity' does not say where its value is in the database, or has a query or a write command its driver refuses. Open it and correct the field the tag panel marks."
The wire address adds the write: row?table=recipes&column=setpoint&key=code&equals=R-100&write=cell
for a cell, none?write=command&command= followed by the command for a Write only tag that runs
its command.
Discovery
The Scan scope card
For Configure connector, the driver's page carries its Scan scope card, under the line "Signs in as the device does and offers a tag for each column of its tables, at the most recent row or at the row of the smallest key."
| Field | Meaning | Default |
|---|---|---|
| Device to scan | A device of the driver, by its name. A database is scanned only through a device, which holds its sign-in; an edit of the device still waiting to be saved is saved first. | the first device by name |
| Tables | "Empty for every table, or a name or a pattern where * stands for any characters, such as Recipe*." | empty |
A driver with no device holds only "A database is scanned through a device, which holds its sign-in. Add a device of this driver and say where its database is." What the scope still lacks is said in red under the card, and Discover stays greyed until it is complete:
| The scope | The card says |
|---|---|
| A device that does not say where its database is, or has a setting its driver cannot use | "Device 'Recipes' does not say yet where its database is, or has a setting its driver cannot use. Complete its Database card first." |
A pattern with a schema, a quote, a bracket or a semicolon, such as dbo.Recipe* |
"'dbo.Recipe*' is not a table name or pattern. Write a name, or a pattern where * stands for any characters, without a schema or quotes." |
| A device that no longer exists | "The device picked to scan no longer exists. Pick another device to scan." |
When the device to scan has an edit that cannot be saved, the scan does not start: "Discovery was not started because the edit of the device to scan could not be saved."
What the scan offers
The scan signs in as the device does, reads the database's own list of its tables and views (the system ones left out) and their columns, and says which table it reads, such as "Reading the columns of recipes…". It offers one candidate, the device itself, marked Already configured: its card lists the columns no tag of the device reads yet, ticked, and Add tags, before Open, adds the ticked ones to the device, read only.
| The table | Its candidate tags |
|---|---|
| Has a date and time column | One per column, reading the most recent row by the first such column. |
| Has none | One per column but its key, reading the row of the smallest value of its primary key (or of its first column, in a table without one): change the tag's Key value to read another row. |
| Has none, and no row | Left out. |
| A column no tag type reads (binary data, a geometry) | Left out, and counted in the line that closes the scan. |
The tags are named after their table and column (recipes.oven_temperature), typed by the column's
type, and every one is Read only. A scan reads at most 100 tables and 500 values; one cut there
says "The scan of Recipes stopped early. A scan reads at most 100 tables and 500 values: give a table name or a pattern to see the others."
The rest of the scan's behaviour is on Discovery.
A device's own page does the same without its driver's page: Discover tags, on the head of its Tags card, signs in as the device does, scans its database as it is saved and offers only the columns it has no tag for yet (see Discovering a device's tags).
Example: a production order from SQL Server
The MES keeps its production orders in SQL Server, in the table dbo.ProductionOrders of the database
MES, one row per order number:
- On the driver's page, Add device; name it
MES. On the Database card keep SQL Server, enter Servermes-sql(ormes-sql\SQLEXPRESSfor a named instance), leave Port empty and enter Database nameMES. - On the Sign-in card enter Username
station_readerand its Password, or turn on Sign in with the station's Windows account. For a factory server whose certificate is its own, pick Encrypted, any certificate accepted. - Add tag
Order quantity, Int32: Tabledbo.ProductionOrders, Value columnQuantity, Row to read By its key, Key columnOrderNo, Key value4711. Its wire address isrow?table=dbo.ProductionOrders&column=Quantity&key=OrderNo&equals=4711. - Add tag
Product, String, on the same table and row, Value columnProductCode: both tags are read in one query.
With the tools:
device_upsert name=MES driver=Database databaseKind=SqlServer host="mes-sql\SQLEXPRESS" databaseName=MES username=station_reader password=<password> databaseEncryption=TrustServerCertificate
tag_upsert device=MES name="Order quantity" opcUaType=Int32 databaseTable=dbo.ProductionOrders address=Quantity databaseRow=Key databaseKeyColumn=OrderNo databaseKeyValue=4711
tag_upsert device=MES name=Product opcUaType=String databaseTable=dbo.ProductionOrders address=ProductCode databaseRow=Key databaseKeyColumn=OrderNo databaseKeyValue=4711
Example: a recipe setpoint from PostgreSQL
The recipe system adds a row to recipe_setpoints every time a setpoint changes, dated in its
updated_at column:
- Add device; name it
Recipes, Database type PostgreSQL, Serverrecipes-db, Port empty (PostgreSQL's 5432), Database namerecipes, then Username and Password on the Sign-in card. - Add tag
Oven setpoint, Double: Tablerecipe_setpoints, Value columnoven_temperature, Row to read Most recent, Date columnupdated_at.
Each new row is read at the tag's next read. PostgreSQL reads a plain name in lower case, so a
column created with capitals, such as OvenTemp, is written in quotes: "OvenTemp". With the tools:
device_upsert name=Recipes driver=Database databaseKind=PostgreSql host=recipes-db databaseName=recipes username=station password=<password>
tag_upsert device=Recipes name="Oven setpoint" opcUaType=Double databaseTable=recipe_setpoints address=oven_temperature databaseRow=Newest databaseDateColumn=updated_at
Example: a result line written as an INSERT
The quality system wants one row per measured part in its table test_results:
- On the device of that database, Add tag
Result, Double, Access Write only. - A write Runs its write command, Write command
INSERT INTO test_results (result, recorded_at) VALUES (@value, @now).
Each value the Logic writes to Result becomes a row of its own, with the station's date and time
beside it; writes that follow each other quickly are all kept, in order, none dropped for a newer one.
A Read and write tag reading a cell would instead change its one row with every write. With the
tools:
tag_upsert device=Quality name=Result opcUaType=Double accessType=WriteOnly databaseWriteMode=Command databaseCommand="INSERT INTO test_results (result, recorded_at) VALUES (@value, @now)"
Example: Access and Oracle through ODBC
| Database | On this computer | On the device |
|---|---|---|
| Microsoft Access | Microsoft's Access Database Engine, 64-bit | Database type Other (ODBC), Data source or connection text Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=C:\Data\plant.accdb, no user |
| Oracle | Oracle's 64-bit ODBC driver, and a data source ERP created for it in ODBC Data Sources (64-bit) |
Database type Other (ODBC), Data source or connection text ERP, Username and Password on the Sign-in card |
When the data source or the driver a device names exists only for 32-bit programs (an Access of a
32-bit Office, a data source made in ODBC Data Sources (32-bit)), or not on this computer at all, the
device's panel says which of the two it is, with the name the device gave, and gives the whole
instruction while the device is on and not connecting. The device's error says the same in English,
and so does driver_capabilities, under the Database driver's prerequisite (perDevice true):
| Part | What it says |
|---|---|
| What is missing | A 64-bit ODBC driver for that data source or driver: Ganter Lab is a 64-bit program and sees only the 64-bit ODBC drivers and the data sources made with them, and it cannot include another maker's driver |
| Where to get it | From the maker of the database; for Access, Microsoft's page "Download and install Microsoft 365 Access Runtime", whose runtime carries the Access Database Engine |
| Which one | The 64-bit version (for Access, the 64 Bit Download button of your language), never the 32-bit one |
| How to install it | As administrator; then, for a device that names a data source, create it in ODBC Data Sources (64-bit) with the same name and the same database |
| Known stumble | For Access on a computer with Office: Microsoft's page says the Access Runtime installed matches the Office already there and is not compatible with an Office installed with Windows Installer, and Microsoft's page on choosing between the 64-bit and 32-bit version of Office says one version is uninstalled before the other is installed |
| Afterwards | At its next connection attempt the device connects with the configuration it has, without restarting Ganter Lab |
The notice ends with the 64-bit ODBC drivers this computer has, by the name Driver={...} takes. A data
source or driver the 64-bit side has, and that still fails, shows the driver manager's own error.
Through ODBC a plain name reads as the database reads it (in capitals on Oracle) and a name in quotes exactly; dates and times are sent to the whole second, the finest every ODBC driver takes. With the tools:
device_upsert name="Plant book" driver=Database databaseKind=Odbc databaseOdbc="Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=C:\Data\plant.accdb"
device_upsert name=ERP driver=Database databaseKind=Odbc databaseOdbc=ERP username=STATION password=<password>
Agent tools
driver_capabilities describes this driver under database: the simple path, each database with
its fields and its own port, the encryption choices, the two ways a tag reads and the two ways it
writes, the rule that a value enters a statement only as @value or @now, the types, the timeouts,
the advice on the database user, discovery and four worked examples. device_upsert driver=Database
takes databaseKind (SqlServer, the default, PostgreSql, MySql, Sqlite or Odbc), and for a
server host (a SQL Server server\INSTANCE or server,port is read apart), port, databaseName,
and on SQL Server databaseInstance, databaseWindowsSignIn and databaseEncryption (Verified,
TrustServerCertificate or Off); databaseFile for SQLite, databaseOdbc for ODBC; username
and password, which is never answered back. A device it returns carries database, with the
address and whether the device still waits for its user. tag_upsert takes the value column as
address, databaseSource (Fields or Query), databaseTable, databaseRow (Key or
Newest), databaseKeyColumn, databaseKeyValue, databaseDateColumn, databaseQuery, and once
accessType writes, databaseWriteMode (Cell or Command) and databaseCommand; a new tag is read
only and a Double unless opcUaType says otherwise. device_discover driver=Database takes
databaseDevice, the name of a configured device of the driver, and optionally databaseTables, a
table name or a pattern with *; the tags the device lacks are added with tag_upsert.
connector_browse returns each device's databaseKind. The other tools are on
Agent tools.
Limits worth knowing
- The driver reads and writes the values of its tags, one value per tag. It does not record the station's runs in a database: a row per run with its serial number, verdict and measures is not something this driver writes.
- No ODBC driver ships with the product. Oracle, Access, Firebird and every database but the four reached directly need their own 64-bit ODBC driver installed on the computer; a 32-bit one is not seen.
- The device stores no Windows password: the Windows sign-in to SQL Server, and a SQLite file on a network share, use the account the station runs under, so the database or the share has to let that account in.
- A query only reads. Whatever changes the database is a write, and a write happens only on a tag whose access writes.
- A value never enters the text of a statement: the value written is always the
@valueparameter, the station's date and time@now, and a key value a parameter as well. A statement that names any other value is refused. - A cell write changes exactly one row; an UPDATE command needs its WHERE.
- The database is asked at each read: a change another program makes is seen at the next read, and a database that holds many tags of one row is asked once per pass for all of them.
- A binary column is not read.