# Machbase DBMS Manual — Full Text > Markdown corpus of the current published English DBMS 8.7.0 pages in navigation order. - language: `en` - document_count: `242` - document_index: https://docs.machbase.com/llms-chunks.json --- title: "Machbase DBMS Manual" url: https://docs.machbase.com/dbms/ language: en kind: section --- # Machbase DBMS Manual This manual covers installation, table-type usage, application development, operations, security, and reference information for Machbase 8.7.0. If you are new to Machbase, work through the SQL exercises in Chapter 1, then learn data models and storage and operational principles in Chapter 2. For system design, review table selection in Chapter 4 before moving to the relevant table chapter. For exact syntax or feature support, use Chapter 16. ## Manual Structure | Chapter | Title | Scope | |----|------|------| | 1 | [Getting Started](./getting-started/) | Overview, connection checks, quick start, basic commands | | 2 | [Core Concepts](./core-concepts/) | Table types, time model, ROLLUP, and retention policies | | 3 | [Installation, Deployment, and Upgrade](./installation-deployment-upgrade/) | Preparation, Standard Edition, Cluster Edition, upgrade | | 4 | [Table Type Selection and Schema Design](./data-modeling-table-design/) | Type decisions, schema, mutation policy, and patterns | | 5 | [TAG Table Usage](./tag-table-usage/) | TAG structure, metadata, input, query, correction, operations | | 6 | [ROLLUP for TAG Tables](./tag-rollup-usage/) | ROLLUP design, creation, query, rebuild, operations, performance tuning | | 7 | [LOG Table Usage](./log-table-usage/) | LOG structure, input, and text search | | 8 | [TRANSACTION Table Usage](./rdb-table-usage/) | TRANSACTION schema, DML, transactions, JOIN, backup and recovery | | 9 | [LOOKUP Table Usage](./lookup-table-usage/) | Reference data, primary keys, JSON, predicate DML, and joins | | 10 | [VOLATILE Table Usage](./volatile-table-usage/) | Memory tables, UPSERT, state cache, restart and data loss | | 11 | [Development and Application Integration](./development-tools-integration/) | Integration methods, common concepts, and language-specific SDKs/APIs | | 12 | [Performance Tuning](./performance-tuning/) | Query, ingestion, and cache tuning | | 13 | [Operations, Configuration, and Recovery](./operations-configuration-recovery/) | Server operations, backup, and Cluster operations | | 14 | [Accounts, Privileges, and Access Control](./security-access-control/) | Accounts, privileges, AUTH KEY, and access control | | 15 | [Troubleshooting](./troubleshooting/) | Diagnostics and resolution guides | | 16 | [Reference](./reference/) | SQL, functions, configuration, and system catalog reference | --- title: "1. Getting Started" url: https://docs.machbase.com/dbms/getting-started/ language: en kind: section --- # 1. Getting Started This chapter is a starting point for readers new to databases and for developers coming from another DBMS. It introduces how Machbase DBMS 8.7.0 stores data, then walks through the basic SQL workflow by inserting and querying one event. You can read the overview before installing a database. To run the example, you need a running DBMS server and its SQL client, `machsql`. The prerequisites in [10-Minute Quick Start](./quick-start/) explain how to prepare the server and connection. ## What You Will Learn 1. Understand the roles of tables, rows, columns, and SQL. 2. Distinguish historical records from current state. 3. Identify Machbase table types for measurements, events, and reference data. 4. Connect to the server, create a LOG table, and insert and query data. 5. Compare event time with server arrival time and choose your next learning path. ## Reading Order | Section | What you can do afterward | |---|---| | [Machbase DBMS Overview](./overview/) | Explain the purpose of a time-series database and the roles of its table types. | | [10-Minute Quick Start](./quick-start/) | Connect, insert and query data, and clean up the practice table. | | [Basic Command Cheatsheet](./command-cheatsheet/) | Distinguish shell commands from SQL and find common commands. | | [Choose the Next Document](./choose-next-doc/) | Find the documents relevant to your data, development tasks, and operations. | The example uses a small SQL `INSERT` so you can inspect the result directly. For continuous, high-volume ingestion and error handling, continue with [Data Input and Export](/dbms/development-tools-integration/data-input-load-export/). --- title: "1.1 Machbase DBMS Overview" url: https://docs.machbase.com/dbms/getting-started/overview/ language: en kind: page --- # 1.1 Machbase DBMS Overview Machbase DBMS is a time-series database for storing and analyzing data that accumulates over time, such as sensor measurements, equipment events, and application logs. You choose tables to match the structure of your data and how you update and query it, and manage historical records together with the reference data needed to interpret them. ## Introduction to Machbase DBMS ### What a Database and SQL Do A database stores application data in a defined structure so that different tasks can reuse it. A database management system, or DBMS, is the software that manages requests to read and write that data, user permissions, and storage space. A table groups records with the same structure. A row can represent one event or measurement. Columns hold individual attributes, such as a timestamp, equipment name, or measured value. Each column has a data type, such as a number, string, or date and time. This defined structure is called a schema. For example, a temperature history might look like this. The times and values below are illustrative. | Measurement target | Measurement time | Temperature | |---|---|---:| | Equipment A temperature sensor | 09:00:00 | 23.1 | | Equipment A temperature sensor | 09:00:01 | 23.5 | | Equipment B temperature sensor | 09:00:01 | 18.0 | SQL is the language used to work with this data. `CREATE` creates a table, `INSERT` adds rows, and `SELECT` reads the rows and columns you need. `WHERE` specifies selection conditions, `GROUP BY` defines aggregation groups, and `ORDER BY` controls result ordering. Although the SQL language is shared, supported changes and storage behavior depend on the table type. ### Current State and Historical Records “What is the current temperature of equipment A?” and “How did its temperature change over the past hour?” are different questions. Repeatedly overwriting one current value loses the history. Storing each measurement as a new row with a timestamp lets you analyze trends, maximum values, and when an abnormal condition occurred. These histories keep growing in a time-series system. In addition to ingestion speed, you must decide which targets and time ranges you will query and how long you need to keep raw data. Measurements do not necessarily arrive at regular intervals. Network delays, equipment outages, and retransmission can produce late or missing readings. ### Measurements, Events, and Reference Data A measurement describes the value of a particular target at a particular time. An event records something that happened, such as an alarm, an equipment stop, or a service starting. Equipment names, installation locations, and units of measurement are reference data used to interpret those records. A system often needs all three. Investigating an abnormal temperature may require the temperature history, alarms from the same period, and the sensor's installation location. SQL joins (`JOIN`) connect historical records with reference data through a shared value, such as an equipment identifier. ## Problems Machbase Solves Machbase's time-series features can be used together for the following tasks. | Task | Example | Related features | |---|---|---| | Collect raw history | Continuously store sensor readings and equipment events | TAG and LOG tables, SQL input, and SDK Append | | Query a relevant range | Inspect equipment A's temperature changes over the past hour | Tag and time conditions, indexes, and execution plans | | Query recurring statistics | Compare minute or hourly trends over long periods | TAG ROLLUP | | Interpret data | Associate sensor codes with equipment names and locations | Reference data and JOIN | | Manage retention periods | Remove raw records past their retention period | Retention Policy on supported tables | | Protect data against failures | Verify backup and recovery procedures | Edition-specific backup and recovery features | ROLLUP computes statistics over ranges of raw data. Compression reduces the space needed to store data, while a Retention Policy deletes old records. These features serve different purposes; having aggregates does not by itself mean that it is appropriate to delete the raw data. Performance requirements depend on data types, ingestion volume, concurrent queries, retention periods, and server resources. Learn the workflow with a small example, then measure throughput and latency using actual data and query conditions. [Core Concepts](../../core-concepts/) explains the roles of these features in more detail. ## Choosing a Table for Your Data | Table | Main use | What to check when choosing | |---|---|---| | TAG | Measurement histories organized by tag name and a time or distance axis | Whether queries focus on ranges and aggregates for specific tags. | | LOG | Event and log histories with multiple attributes | Whether you continuously add records and read them using time or search conditions. | | LOOKUP | Persistent reference data, such as equipment codes and mappings | The size and update pattern of the reference data loaded into memory. | | TRANSACTION | Business data requiring row-level changes and transactions | Whether you need relational DML and transactions in Standard Edition. | | VOLATILE | Shared state that can be recreated after a restart | Whether you can rebuild the data when it is lost at server shutdown. | In Machbase DBMS 8.7.0, explicitly use `CREATE LOG TABLE` to create a LOG table. A bare `CREATE TABLE` creates a TRANSACTION table, which is supported in Standard Edition. An industry label alone does not determine the table type. For the final choice, including update, join, and retention requirements, see [Table Type Selection](/dbms/data-modeling-table-design/table-types-selection-type/). Next, store one event and read it back in [10-Minute Quick Start](../quick-start/). --- title: "1.2 10-Minute Quick Start" url: https://docs.machbase.com/dbms/getting-started/quick-start/ language: en kind: page --- # 1.2 10-Minute Quick Start Connect to a running server, store one service-start event, and read it back. This example uses a LOG table for append-oriented event data and explains the SQL results and the two time columns. The estimated time does not include installing the server. ## Prerequisites - Machbase DBMS is running on `127.0.0.1:5656`. - The `machsql` command is available. - You can connect with a practice account that can create, insert into, query, and drop tables. - The commands below use the initial practice account `SYS` and password `MANAGER`. If the password has been changed, substitute its current value. - You can save a SQL file under `/tmp`, and the practice table name `DBMS_GS_QUICK` is available. Use a practice environment where this name does not conflict with a business table. The final `DROP TABLE` deletes the practice table and the data inserted into it. If the server is not ready yet, start with [Installation, Deployment, and Upgrade](/dbms/installation-deployment-upgrade/) and [Linux Standard Edition Installation](/dbms/installation-deployment-upgrade/standard-edition/#linux). ## Representative Sample This sample records one service-start event in a LOG table. Explicitly create it with `CREATE LOG TABLE`; the `_arrival_time` column is added automatically. Save the SQL file and run it with the following commands. ```bash cat > /tmp/dbms_gs_quick.sql <<'SQL' CREATE LOG TABLE DBMS_GS_QUICK ( EVENT_ID INTEGER, EVENT_TIME DATETIME, LEVEL VARCHAR(10), MESSAGE VARCHAR(40) ); INSERT INTO DBMS_GS_QUICK (EVENT_ID, EVENT_TIME, LEVEL, MESSAGE) VALUES ( 1, TO_DATE('2026-07-02 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'INFO', 'service started' ); SELECT _arrival_time, EVENT_ID, EVENT_TIME, LEVEL, MESSAGE FROM DBMS_GS_QUICK ORDER BY EVENT_ID; DROP TABLE DBMS_GS_QUICK; SQL machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER -f /tmp/dbms_gs_quick.sql ``` ### Check the Results Check each SQL step for errors. The SELECT result should contain one row with `EVENT_ID` equal to `1`, `LEVEL` equal to `INFO`, and `MESSAGE` equal to `service started`. `EVENT_TIME` is the event timestamp supplied by the application. In this example, `_arrival_time` is the server arrival timestamp recorded automatically by the DBMS. Its value therefore changes each time you run the example and need not equal `EVENT_TIME`. `CREATE LOG TABLE` defines the structure, and `INSERT` adds one row. `SELECT` specifies the columns to read, while `ORDER BY EVENT_ID` specifies result ordering. If the final `DROP TABLE` succeeds, the practice table is removed. To inspect the data further, omit the final DROP statement before running the script, then remove only that practice table when you finish. If a rerun fails because `DBMS_GS_QUICK` already exists, a previous run may not have reached the `DROP TABLE` step. Inspect it with `DESC DBMS_GS_QUICK;`. Only if it is the table from your previous practice run should you execute `DROP TABLE DBMS_GS_QUICK;` and retry. For a connection error, first check the server address, port, running state, and account details. ## What This Sample Checks | Item | What it verifies | |---|---| | Server connection | `machsql` connects to `127.0.0.1:5656`. | | Table creation | `CREATE LOG TABLE` explicitly creates a LOG table. | | Data input | `INSERT` and `TO_DATE` store event data. | | Data query | `SELECT` and `ORDER BY` verify the inserted row. | | Automatic column | The server automatically records the LOG table's `_arrival_time`. | | Cleanup | `DROP TABLE` removes the practice table. | --- title: "1.3 Basic Command Cheatsheet" url: https://docs.machbase.com/dbms/getting-started/command-cheatsheet/ language: en kind: page --- # 1.3 Basic Command Cheatsheet Run connection commands in your operating system's terminal and SQL in a connected `machsql` session. Adjust the server address, port, and account for your environment. `MANAGER` in these examples is the initial practice password used in the quick start. If it has been changed, use the account's current password. ## Commands to Run in the Terminal | Task | Command | |---|---| | Connect interactively | `machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER` | | Run a SQL file | `machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER -f file.sql` | ## SQL to Run in machsql | Task | Command | |---|---| | List tables | `SHOW TABLES;` | | Inspect columns and types | `DESC table_name;` | | Create a TRANSACTION table | `CREATE TRANSACTION TABLE table_name (...);` | | Create a LOG table | `CREATE LOG TABLE table_name (...);` | | Insert data | `INSERT INTO table_name VALUES (...);` | | Query matching data | `SELECT ... FROM table_name WHERE ...;` | | Sort query results | `SELECT ... FROM table_name ORDER BY ...;` | | Delete a table and its data | `DROP TABLE table_name;` | `table_name` and `...` are placeholders that must be replaced with actual names and definitions. For runnable SQL, use [Quick Start](../quick-start/). `DROP TABLE` also deletes the table's data, so first confirm that it is the practice table you intend to remove. In Machbase DBMS 8.7.0, `CREATE TABLE` without a table type creates a TRANSACTION table. TRANSACTION tables are supported in Standard Edition. Specifying the type makes the intent of an example clear. For the complete command reference, see [machsql](../../reference/command-line-tools/machsql/). --- title: "1.4 Choose the Next Document" url: https://docs.machbase.com/dbms/getting-started/choose-next-doc/ language: en kind: page --- # 1.4 Choose the Next Document The quick start stored and queried one row. When building a system, you also need to decide how data changes, which timestamp matters, how it will be queried, and how long to retain it. ## Questions to Answer Before Designing - Do you accumulate values over time for the same target, or overwrite its current state? - Do queries use measurement or event time, or the time the server received the data? - Which operations are most common: ranges for a specific tag, searches across columns, key lookups, or joins? - How will you handle late arrivals, duplicates, and incorrect values? - How long do you need raw data and aggregates, and which data must survive a restart? - Which Edition supports the features you need? ## Next Paths | What you need to do | Next document | |---|---| | Understand history, storage, and querying | [Core Concepts](../../core-concepts/) | | Choose table types and update policies | [Table Type Selection and Schema Design](../../data-modeling-table-design/) | | Store sensor and measurement histories | [TAG Tables](../../tag-table-usage/) | | Collect and search events and logs | [LOG Tables](../../log-table-usage/) | | Query tag statistics over long periods | [ROLLUP for TAG Tables](../../tag-rollup-usage/) | | Manage reference and business data | [LOOKUP](../../lookup-table-usage/), [TRANSACTION](../../rdb-table-usage/) | | Manage state that can be recreated | [VOLATILE Tables](../../volatile-table-usage/) | | Insert and query data from applications | [Development and Application Integration](../../development-tools-integration/) | | Check SQL syntax and data types | [SQL Reference](../../reference/sql/) | | Configure operations, backups, and permissions | [Operations, Configuration, and Recovery](../../operations-configuration-recovery/), [Accounts and Permissions](../../security-access-control/) | Start on a small scale with representative data and common queries. Measure ingestion speed, query latency, and storage use before adjusting ingestion methods, indexes, aggregates, and retention policies. --- title: "2. Core Concepts" url: https://docs.machbase.com/dbms/core-concepts/ language: en kind: section --- # 2. Core Concepts Chapter 1 introduced the SQL workflow for storing and reading data. This chapter explains that workflow from a design and operations perspective. The appropriate table and storage strategy depend on the meaning of time, how data changes, and which ranges you query. For example, keeping a device's current temperature requires a different number of records from keeping its temperature history for the past month. Calculating a monthly average and detecting brief anomalies require different levels of detail. Understanding these differences helps you choose tables, indexes, ROLLUP, and retention policies for their intended purposes. ## Contents | Section | Questions it addresses | |---|---| | [Data Model Concepts](concepts/) | What does one row represent, and how should time, NULL, duplicates, and changes be interpreted? | | [Storage and Execution Architecture](storage-execution-architecture/) | How is relevant data found, and which costs do storage, indexes, and caches reduce? | | [Feature Concepts and Distinctions](features-concepts/) | What are the separate purposes of raw data, aggregates, retention, and backups? | | [Edition Concepts](concepts-edition/) | When should you choose a single server or a distributed deployment, and which feature differences matter? | The examples use small data sets to explain concepts. Follow the links in each section for feature-specific SQL, support limits, and operational procedures. Then apply the concepts to your own data in [Table Type Selection and Schema Design](../data-modeling-table-design/). --- title: "2.1 Data Model Concepts" url: https://docs.machbase.com/dbms/core-concepts/concepts/ language: en kind: page --- # 2.1 Data Model Concepts A data model defines what one record represents, how records are identified, and how they are changed and queried. A time-series model also defines the meaning of the measurement target, timestamp, and value. Establishing these rules before choosing column names helps keep ingestion and analysis consistent. ## Understanding Time-Series Data Time-series data records observations or events over time. Examples include temperature measurements, trade histories, and service errors. Records may be collected at fixed intervals or only when events occur. Storage order is not guaranteed to match event order. ### What One Row Represents and How It Is Identified If one temperature-history row means “the value measured by one sensor at a particular time,” you need a sensor identifier, measurement timestamp, and value. The identifier tells you where the data came from, while the timestamp provides a basis for interpreting changes over time. Multiple sensors can report at the same time, so a timestamp alone cannot uniquely identify a row. Retransmission can also repeat a reading for the same sensor and timestamp. Decide whether to allow duplicates, remove them, or introduce a separate event identifier. A TAG `PRIMARY KEY` identifies a tag; it does not require every measurement row to have a unique name as a relational row key would. See [TAG Table Operations](../../tag-table-usage/operations-lifecycle/) for duplicate handling. ### Values, Units, and Quality A number alone does not explain its unit or meaning. The same `23.5` could represent temperature, pressure, or voltage. Manage units and measurement locations in tag definitions or reference data, and keep the meaning of values consistent within a series. Also distinguish `NULL` from `0`. Measuring zero is different from failing to obtain a value. Record quality or status in another column when needed. A period with no collection may have no rows at all, which is different from rows containing NULL. Common aggregates such as `AVG` operate on non-NULL values. Filling all missing values with zero or aggregating values with different units changes the result. For the exact NULL behavior of supported aggregates, see the [Function Reference](../../reference/sql/functions/functions-full/). ### Time-Series Workload Characteristics Many time-series systems continuously add rows and query time ranges for particular targets. They may combine monitoring of current values with analysis over long periods. These patterns motivate append-oriented ingestion, range queries, and ROLLUP. Historical data is not necessarily immutable, however. Incorrect equipment clocks, sensor calibration, or duplicate collection may require corrections. Some workloads read older data more often than recent data. Design around measured ingestion, query, and correction patterns. ### Table-Type Roles | Table type | Conceptual role | |---|---| | TAG | Measurement histories organized by name and a time or distance axis | | LOG | Events and logs that continuously accumulate new records | | TRANSACTION | Business data requiring transactions and row-level changes | | LOOKUP | Persistent reference data loaded into memory | | VOLATILE | Shared in-memory state that can be recreated after a restart | Separating history from reference data reduces repetition of equipment names or locations in every measurement row. However, joining historical records to current reference data also shows current names or locations. If you need information as it was when an event occurred, store it with the event or design a separate history of reference-data changes. ### Relational Business Models and Time-Series Models Relational and time-series models are not mutually exclusive. A relational DBMS can store time series and use indexes, partitions, and aggregates. Machbase also provides tables, SQL, joins, and relational changes. Compare the main workload rather than the product names. | Perspective | Relational business-data example | Time-series history example | |---|---|---| | Meaning of a row | The current state of an order | One sensor measurement or event | | Change pattern | Update or delete a row found by key | Add records and correct or remove relevant ranges | | Query pattern | Key lookups, condition searches, and joins of business tables | Target and time-range queries, trends, and interval statistics | | Consistency requirements | Commit or cancel several changes together | Manage missing, duplicate, or delayed input and when it becomes queryable | | Retention design | Business lifecycle and change history | Raw-data resolution, aggregation intervals, and retention periods | Do not apply the storage and ingestion characteristics of LOG and TAG unchanged to TRANSACTION, LOOKUP, or VOLATILE. For the final choice, see [Table Type Selection](../../data-modeling-table-design/table-types-selection-type/) and [Data Mutation Policy](../../data-modeling-table-design/alter-data-mutation-policy/). ## Write-Oriented Workloads and the Append-Only Model Appending adds a new row instead of overwriting an existing value. For example, recording a new event when equipment changes from `RUNNING` to `STOPPED` preserves both the previous state and the transition time. You can also maintain separate tables for direct access to current state and for its history of changes. ### Table Types and Change Models LOG is an append-oriented history table and does not support general row `UPDATE`. TAG adds measurement history and can correct DATA values within supported conditions and Edition limits. This differs from a general row update that can arbitrarily change tag names or the time axis. TRANSACTION provides relational DML and explicit transactions. LOOKUP and VOLATILE support reference-data or state changes. Check [Data Mutation Policy](../../data-modeling-table-design/alter-data-mutation-policy/) rather than assuming that every table type supports the same operations. Append-oriented design can help reduce contention between repeated input and arbitrary updates to historical rows. It does not eliminate all internal synchronization or recovery work. A storage structure alone does not guarantee lock-free execution or a particular throughput. ### SQL Input and SDK Append SQL `INSERT` submits values through a SQL statement and reports its execution result. SDK Append is an ingestion API for sending multiple rows during continuous collection. Follow the SDK's contract for buffering, transmission, error checks, and closing resources. Putting data into an application buffer, having the server process it, and reaching a point from which it can be recovered after a failure are different events. Append operations on LOG and TAG are not rolled back by `ROLLBACK` in an explicit TRANSACTION-table transaction. For Append into TRANSACTION tables, check your SDK's transaction participation and error-handling contract. See [Data Input and Export](../../development-tools-integration/data-input-load-export/) for completion checks and retries. ### Corrections, Schema Changes, and Retention One way to preserve a correction to an incorrect LOG event is to append a correction event. Before deleting and reinserting data, check the time-based deletion ranges and input ordering allowed for LOG. Do not assume that any individual row can be deleted independently. For TAG values, follow [TAG Data Correction Design](../../tag-table-usage/tag-data-update-correction/#design-correction-tag). Adding or dropping columns and changing types are separate capabilities. Schema changes are not universally prohibited for LOG or TAG; support depends on the table type and DATA or METADATA area. Check [DDL Syntax](../../reference/sql/syntax/ddl-syntax/) before applying changes. Continuously appending raw records increases storage use. Define raw-data retention separately from the purpose of ROLLUP statistics. Creating aggregates does not by itself delete raw data. ## Time Models and _arrival_time ### Event Time and Arrival Time Event time is when a device made a measurement or an event occurred. Arrival time is when the DBMS received the record. If a reading measured at 09:00 arrives at 09:05 after network recovery, the difference is five minutes. Measurement trends require event time; collection-delay analysis requires comparing the two timestamps. Also distinguish precision, time zone, and clock accuracy. Being able to represent nanoseconds does not mean a sensor clock is accurate to a nanosecond. For the time zone used when parsing or displaying DATETIME strings, see [Time Zone Configuration](../../reference/configuration/configuration-timezone/). ### The LOG Table's `_arrival_time` LOG automatically includes a DATETIME column named `_arrival_time`. With ordinary input that omits its value, the server records the arrival timestamp. Define a separate DATETIME column if you also need event time. ```sql CREATE LOG TABLE device_events ( device_id VARCHAR(20), event_time DATETIME, status VARCHAR(20) ); ``` Some input paths explicitly supply `_arrival_time`, so it cannot always be treated as the actual time of receipt. For ordering and restrictions on explicit values, see [The LOG Time Model](../../log-table-usage/arrival-time-model/). ```sql SELECT device_id, event_time, status FROM device_events WHERE _arrival_time >= TO_DATE('2026-07-03 09:00:00', 'YYYY-MM-DD HH24:MI:SS') AND _arrival_time < TO_DATE('2026-07-03 10:00:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY _arrival_time; ``` A half-open interval `[start, end)` includes the start and excludes the end, helping avoid counting shared boundaries twice when combining adjacent intervals. `BETWEEN` includes both boundaries; choose the form that matches your purpose. LOG `DURATION` restricts a range using `_arrival_time`. ### The TAG Table's BASETIME Column In a time-axis TAG table, the application supplies timestamps in a DATETIME column declared with `BASETIME`. TAG does not use LOG's automatic `_arrival_time` column. ```sql CREATE TAG TABLE sensor_values ( name VARCHAR(128) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ); INSERT INTO sensor_values VALUES ('temp_sensor_01', TO_DATE('2026-07-03 08:55:00', 'YYYY-MM-DD HH24:MI:SS'), 23.1); ``` Here, `name` identifies the sensor, `time` is the measurement timestamp, and `value` is the measured value. `SUMMARIZED` designates a representative numeric column for related statistics features such as ROLLUP. Creating the table alone does not create aggregates for every interval you might need. TAG also has a BASE DISTANCE model with a numeric axis instead of time. Consider it for measurements along a distance or position axis, but do not apply time-axis-only functions and policies unchanged. [TAG Schema](../../tag-table-usage/table-structure-schema/) explains the rules for each axis. ### Comparing the Two Time Models | Item | LOG | Time-axis TAG | |---|---|---| | Special time column | Automatically created `_arrival_time` | Declared `BASETIME` column | | Meaning of the input timestamp | Server time by default, or an explicitly supplied value | Time specified by the application | | Separate event time | Can be stored in an ordinary DATETIME column | BASETIME can represent event time | | Main design question | Which events and fields will be searched? | Which range of which tag will be analyzed? | Needing event time does not by itself rule out LOG. Choose a table based on tag structure, searches, aggregates, and update and deletion conditions, as well as the meaning of time. DATETIME columns in LOOKUP, VOLATILE, and TRANSACTION are ordinary columns; they do not automatically acquire the special time-axis behavior of LOG or TAG. Distinguish storage order from display order, too. Specify `ORDER BY` when result ordering matters, and add a tie-breaker when rows with identical timestamps must be ordered. --- title: "2.2 Storage and Execution Architecture" url: https://docs.machbase.com/dbms/core-concepts/storage-execution-architecture/ language: en kind: page --- # 2.2 Storage and Execution Architecture Query time is not determined by the length of the SQL statement alone. It also depends on how much data is read, how effectively conditions narrow that data, and the work required for sorting, joins, and aggregation. This section explains which costs storage, indexes, and caches reduce. ## Machbase Architecture Overview Users send write and query requests through `machsql` or an SDK. The server checks SQL syntax, objects, and permissions, chooses an execution method, accesses stored data, and returns the results. Storage and execution behavior depend on the table type and Edition. ### Standard Edition Architecture Standard Edition handles SQL processing and storage in a single database server. Time-series ingestion into LOG and TAG, relational changes in TRANSACTION, and reference data or state in LOOKUP and VOLATILE each use a path suited to the table's characteristics. ```text Client: machsql or SDK | Write and query requests v Machbase DBMS server SQL analysis and execution plans Table-specific storage and index access Memory buffers and background processing | v Stored data organized by table type ``` This is a conceptual diagram of the roles involved. It does not mean that every request uses the same storage path or that an API call immediately writes a disk file. ### Cluster Edition Architecture Cluster Edition divides work among several node roles. Ordinary application SQL connections use a Broker, while Warehouses store time-series data and execute queries. Coordinators manage cluster metadata and node state, Lookup nodes process reference data, and Deployers handle deployment and node management. Distributing data across groups shares processing and storage load. Replication within a group prepares for failures. These are different goals: adding nodes does not make every query faster by the same factor or automatically recover from every failure. For feature differences, see [Edition Concepts](../concepts-edition/). Deployment and recovery procedures are covered in [Cluster Installation](../../installation-deployment-upgrade/cluster-edition/) and [Cluster Operations](../../operations-configuration-recovery/cluster/). ### Write and Query Flows A write can be understood as checking the target table and columns, converting and validating values, and transferring and storing data. SQL and Append APIs report processing results differently, so applications must follow the error-handling and completion rules of their chosen path. A query involves SQL analysis and planning, data access, condition evaluation, aggregation, joins, sorting, and result delivery. Not every query processes data in exactly that order; the actual execution plan determines the access order. ## Columnar Storage and Compression ### Row-Oriented and Column-Oriented Storage Row-oriented storage groups values belonging to one row. Column-oriented storage groups values from the same column. The following illustration compares the ideas; it is not a literal diagram of the on-disk files. ```text Logical rows: (time1, sensorA, 23.1) (time2, sensorA, 23.5) (time3, sensorB, 18.0) Row-oriented: [time1, sensorA, 23.1] [time2, sensorA, 23.5] ... Column-oriented: [time1, time2, time3] [sensorA, sensorA, sensorB] [23.1, 23.5, 18.0] ``` Machbase's LOG and TAG time-series storage uses column-level access and compression. This can reduce the amount of data read when an analysis needs only a few columns across many rows. However, even a temperature average may also need sensor and timestamp data to evaluate its conditions. Row-oriented systems can also use indexes or partitions to read only relevant ranges. Compare the number of rows and columns read and the access path, rather than assuming that row-oriented storage always reads every row or that column-oriented storage is always faster. The relational storage of TRANSACTION and the memory characteristics of LOOKUP and VOLATILE should not be interpreted as identical to LOG and TAG storage. ### When Compression Helps Values in a column share a type, and sensor values or timestamps may exhibit repeated or similar patterns. These characteristics can help compression. Noisy values, irregular strings, and mixed input ordering can produce different results. Time-series timestamps are not necessarily monotonically increasing. Late measurements and input from multiple sources may be interleaved. Measure compression and processing performance with the actual types, value distributions, input order, and settings, rather than assuming a particular algorithm or compression ratio. ### Partitions and Read Ranges A partition divides data into manageable portions. Using query conditions and stored range information to skip unrelated portions reduces reads. This is called partition pruning. LOG and TAG storage units do not necessarily correspond to a user-defined day or month. The actual access range depends on tag and axis conditions, data distribution, and each table's storage structure. A time condition alone does not establish that only the necessary data is read; check execution plans and measurements. ## Indexing Principles An index is an access path for finding data that matches a condition. It can help when the target is a small fraction of the data, but another path may be better for an aggregate that reads most rows. Indexes also require storage and maintenance during writes and updates. | Table type | Basis for considering access paths | |---|---| | TAG | Tag name and ranges on the time or distance axis | | LOG | `_arrival_time` conditions and supported search indexes | | TRANSACTION | PRIMARY KEY, UNIQUE, and general indexes | | LOOKUP and VOLATILE | Memory-resident keys and supported secondary indexes | “The monthly average for all sensors” and “the last minute of values for sensor A” read different proportions of the data. Even on the same table, their performance can differ substantially. For joins, the input row counts and join conditions also matter. See [Schema Object Definitions](../../data-modeling-table-design/schema-objects-definition/) for supported indexes and restrictions, and [Index Tuning](../../performance-tuning/index-tuning/) for measurement and adjustment. ## Caches and Execution Plans ### SQL Execution The server checks SQL syntax, types, and objects, identifies executable access paths using conditions and indexes, and processes the actual data. An execution plan describes that method. The cost of building a plan differs from the cost of reading data according to the plan. ### Plan Reuse and PVO Cache The PVO Statement Cache reuses parsing, validation, optimization results, and execution plans for reusable SQL, reducing repeated preparation work. It does not cache result rows: reusing a plan still requires reading data and evaluating conditions. Caches such as Min-Max Cache use stored range information to reduce the data that needs to be read. Distinguish execution-plan caching from caches used for data access. Decide which cache to enlarge after examining hit rates and memory use. ### Inspecting a Plan with EXPLAIN The following example uses the `sensor_values` table created in [Data Model Concepts](../concepts/#time-model-arrival-time). ```sql EXPLAIN SELECT AVG(value) FROM sensor_values WHERE name = 'temp_sensor_01' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD') AND time < TO_DATE('2026-07-03', 'YYYY-MM-DD'); ``` Use the plan to inspect data access and condition evaluation. A plan alone does not show the actual response time or amount of disk I/O, so also measure execution with representative data. Distinguishing a first run with empty caches from a run that reuses cached information makes the results easier to interpret. Check PVO cache hit and eviction statistics in `V$PVO_CACHE_STAT` and cached SQL in `V$PVO_CACHE_LIST`. For configuration and diagnosis, see [Cache and Memory Tuning](../../performance-tuning/cache-tuning-memory/#pvo-cache). --- title: "2.3 Feature Concepts and Distinctions" url: https://docs.machbase.com/dbms/core-concepts/features-concepts/ language: en kind: page --- # 2.3 Feature Concepts and Distinctions This section explains the roles and selection criteria of ROLLUP, Retention Policy, Backup, Restore, and Mount for long-term data management in Machbase DBMS. Their detailed documents provide creation syntax and operational procedures. Raw data lets you reexamine individual events or measurements. Aggregates summarize many raw records for recurring queries. Retention policies determine what to delete and when, while backups provide material for recovery after a failure. Distinguishing these purposes helps avoid deleting necessary raw data merely because aggregates exist, or omitting backups because replication is configured. - **[The Role of ROLLUP Statistics](#role-statistics-rollup)** — Reduce the cost of recurring aggregate queries. - **[The Role of Retention Policy](#role-retention-policy)** — Automatically remove data based on its age. - **[Backup, Restore, and Mount](#concepts-backup-restore-mount)** — Distinguish data protection, recovery, and inspection. ## The Role of ROLLUP Statistics Repeatedly aggregating long TAG histories from raw rows becomes more expensive as the query range grows. ROLLUP aggregates specified numeric columns and other supported values from time-axis TAG data into intervals for recurring queries. Its definition determines the columns and aggregation methods. Default ROLLUP creates second (SEC), minute (MIN), and hour (HOUR) levels. Specify `WITH ROLLUP` when creating a table, or use ordinary `CREATE ROLLUP` to select intervals and conditions. Manage these objects through the public ROLLUP SQL rather than depending on generated object names or internal storage structures. ### Selection Criteria | Query pattern | Starting point | |---|---| | Repeated minute or hourly statistics over long periods | Consider default ROLLUP | | Explicit aggregation intervals or filter conditions | Consider ordinary ROLLUP with the required interval and conditions | | Store the results of your own aggregate SELECT in a separate TAG table | Consider Custom ROLLUP in Standard Edition | | First or last values are needed | Consider extended ROLLUP | | Most queries read raw values, or aggregates are rarely queried | Start without ROLLUP and measure execution time | ROLLUP is not a retention policy that replaces raw data. Design raw-data retention separately using Retention Policy, and check whether the relevant ROLLUP range must be rebuilt after correcting TAG data. ### Interpreting Aggregates Aggregation reduces detail. Keeping only a one-minute average cannot recover a brief anomaly or the order of individual measurements within that minute. Keeping minima and maxima also preserves the range, but still does not preserve every detail of the raw data. Averaging averages from several intervals can differ from the overall average. For example, if two observations average 10 and eight observations average 20, the overall average is `(2 × 10 + 8 × 20) / 10 = 18`, not the unweighted average of 15. Use the necessary statistics, such as sums and valid counts, when aggregating again, and follow the supported ROLLUP query functions. ROLLUP processing takes place separately from raw-data ingestion, so the newest raw rows and their aggregates may become available at different times. For late arrivals or corrected values, check the raw range, aggregation progress, and whether rebuilding is necessary. See [TAG ROLLUP](/dbms/tag-rollup-usage/) for detailed creation syntax, query functions, and rebuilding procedures. ## The Role of Retention Policy Retention Policy periodically removes LOG or TAG data past its retention period. It manages storage for continuously growing tables without requiring operators to repeat deletion commands manually. | Requirement | Method | |---|---| | Continuously remove data older than a defined period | Retention Policy | | Immediately remove a specific range of incorrect input | `DELETE`, within the table type's supported conditions | | Empty all data from a supported table | `TRUNCATE TABLE` | Attaching a retention policy does not mean all old data disappears immediately. Check the execution interval, supported table types, and actual deletion state. Manage the lifecycle of LOOKUP, VOLATILE, and TRANSACTION data using the explicit DML supported by those tables. Retention and ingestion volume together determine storage needs. Multiplying rows per second by the retention period in seconds estimates the raw row count, but actual disk use also depends on data types, compression, indexes, replication, and backups. Before deleting raw data, check aggregate coverage and retention, and the detail needed for auditing or reanalysis. Creating ROLLUP does not automatically change raw-data retention. See [Data Retention Policy](/dbms/operations-configuration-recovery/policy-data-retention/) for creation, attachment, detachment, and operational checks. ## Backup, Restore, and Mount All three work with backup data, but their outcomes differ. | Feature | Purpose | Production server | Result | |---|---|---|---| | Backup | Create a copy for recovery | Can run while the server is running | A backup in a separate location | | Instance Restore | Recover an instance from a backup | Requires an offline procedure | The production database is recovered | | Mount | Inspect a backup read-only | Can run while the server is running | The backup is queryable under a separate name | Separately, `RESTORE DATABASE` SQL restores a logical database on a running server. Distinguish its target and procedure from offline instance restoration. A successful Backup does not by itself validate the recovery procedure. On a supporting Edition, inspect the contents with Mount or test Restore in an isolated environment. Also manage backup-path permissions and retention. Mount does not restore data into the production database, and mounted data cannot be written. Restore and Mount are Standard Edition features; in Cluster, follow that Edition's backup and failure-recovery procedures. Define a recovery point objective (RPO), the acceptable window of data loss, and a recovery time objective (RTO), the time allowed to restore service. RPO guides review of backup and replication intervals; RTO guides review of the data to recover and the measured restoration time. An Edition or backup schedule alone does not guarantee either objective. An incorrect deletion can also reach replicas, so distinguish replication from backups. See [Backup, Restore, and Mount](/dbms/operations-configuration-recovery/backup-restore-mount/) for commands, permissions, Edition support, and recovery sequences. If you operate several logical databases, also see [Multi-Database Operations](/dbms/operations-configuration-recovery/multi-database/). ## Comparing Input Paths Consider `INSERT` for small SQL exercises, a supported SDK's Append API for continuous application ingestion, and tools such as `machloader` for file loading. Supported tables, input formats, and failure checks differ by tool, so similar names do not make them interchangeable. For selection criteria covering SQL, SDKs, and file-loading tools, see [Data Input and Export](/dbms/development-tools-integration/data-input-load-export/#machloader-vs-csvimport-csvexport-tagmetaimport). --- title: "2.4 Edition Concepts" url: https://docs.machbase.com/dbms/core-concepts/concepts-edition/ language: en kind: page --- # 2.4 Edition Concepts The Edition determines the deployment architecture and supported features. Standard starts with one server; Cluster divides storage and processing among several nodes. Choose based on the required SQL features, growth rate, failure recovery, and operational capacity, as well as the current data size. ## Differences Between Standard and Cluster Editions ### Standard Edition A single DBMS server handles SQL processing and data storage. You do not need to manage deployment and communication across distributed nodes, making it suitable for development and single-server operations. Check whether you need Standard-only features such as TRANSACTION tables, Restore, or Mount. Starting with one server does not necessarily mean the data set must be small. Measure whether the ingestion volume, query workload, and retention period fit within that server's CPU, memory, and storage capacity. ### Cluster Edition Coordinator, Deployer, Broker, Warehouse, and Lookup nodes have different roles. | Node type | Role | |---|---| | Coordinator | Manage cluster metadata and node state | | Deployer | Deploy packages and manage nodes | | Broker | Accept application SQL connections and distribute queries | | Warehouse | Store time-series data and execute queries | | Lookup | Process cluster reference data | Ordinary SQL applications connect to a Broker. Management tools use role-specific endpoints and ports, so distinguish SQL connection addresses from management addresses. Distributing data across Warehouse groups and replicating data within a group serve different purposes. Distribution expands capacity and throughput; replication helps with failure recovery. Design node counts, replication state, client reconnection, and recovery procedures together. ### Feature Support Differences | Item to check | Standard Edition | Cluster Edition | |---|---|---| | Main deployment structure | One DBMS server | Multiple nodes with separate roles | | TRANSACTION tables | Supported | Not supported | | Restore and Mount | Supported | Not supported | | Capacity and processing expansion | Expand server resources and storage configuration | Expand distributed groups and node configuration | | Failure recovery design | Backups, recovery procedures, and server operations | Node and group replication, state, connection handling, and recovery procedures | Shared features such as LOG, TAG, LOOKUP, VOLATILE, ROLLUP, and Retention do not necessarily have identical DML, DDL, or operational restrictions. For complete support information, see [Edition Support](../../reference/support-scope-constraints/edition/) and [Table Type Support](../../reference/support-scope-constraints/table-types-type/). ### Selection Criteria 1. Identify required features. If you need TRANSACTION tables, Restore, or Mount, first review Standard Edition support. 2. Run representative ingestion and queries. Use realistic data types, concurrent connections, query ranges, and retention periods to measure available capacity on one server. 3. Account for data growth and failure requirements. If you need distribution beyond one server, also consider Cluster's network, replication, and node-management costs. 4. Test failure scenarios. Monitoring nodes does not by itself guarantee uninterrupted recovery. Measure recovery time and verify application reconnection and retry behavior. Changing Editions in production involves more than increasing the server count. First verify compatibility for your SQL and SDKs, data migration, backups, and recovery methods. ## Related Documentation - [Storage and Execution Architecture](../storage-execution-architecture/) explains the processing flow. - [Installation, Deployment, and Upgrade](../../installation-deployment-upgrade/) describes deployment procedures. - [Versions and Compatibility](../../reference/support-scope-constraints/compatibility-version/) lists version-specific support. - [Relational Business Models and Time-Series Models](../concepts/#differences-rdbms) explains data-model selection criteria. --- title: "3. Installation, Deployment, and Upgrade" url: https://docs.machbase.com/dbms/installation-deployment-upgrade/ language: en kind: section --- # 3. Installation, Deployment, and Upgrade This chapter prepares Machbase DBMS 8.7.0 for use and checks that it can accept and query data. Installing a new server and upgrading a server that already contains data have different starting points. First decide which features and deployment environment you need, then choose the matching procedure. The data models and Edition differences introduced in Chapter 2 also affect deployment. Check Standard Edition support if you need TRANSACTION tables, Restore, or Mount. If you need distributed storage and replication, plan Cluster node roles, networking, and recovery together. ## Choose an Installation Path | Edition | Deployment structure | What to check | |---|---|---| | Standard Edition | One DBMS server handles SQL processing and storage | Required features and whether server resources can support ingestion, queries, and retention | | Cluster Edition | Separate Coordinator, Deployer, Lookup, Broker, and Warehouse roles | Distribution groups, replication, communication paths, and node operations | A single server is not limited to small data sets. Measure the required storage and performance using representative data. Similarly, adding Cluster nodes does not make every query proportionally faster. See [Edition Differences](/dbms/core-concepts/concepts-edition/#differences-standard-edition-cluster). ### Distinguish the Installation Components | Component | Meaning | Examples to check | |---|---|---| | Distribution package | Executables, libraries, and sample configuration | Version, Edition, OS, and CPU architecture | | Installation home | Executable and configuration location for a server or node | `MACHBASE_HOME`, `conf/machbase.conf` | | Data storage path | Location where the DBMS reads and writes data | `DBS_PATH`, free space, and access permissions | | Server instance or node | DBMS process running with that configuration | Process status, logs, and connection ports | | Logical database | SQL object namespace selected by a connection | Current database, users, privileges, and tables | Extracting a package, creating a new instance's database, starting the server, and creating tables are separate steps. Do not run new-instance initialization against a home containing existing data. The installation home and actual data path can also differ; check both before backup or upgrade. A logical database selected through SQL is distinct from an installation home. See [Multi-Database Operations](/dbms/operations-configuration-recovery/multi-database/) for selecting, creating, and granting access to multiple databases. ## Installation Sequence ### Standard Edition 1. Use [Pre-Installation Preparation](./pre-install-preparation/) to check the package, server account, resources, and ports. 2. Prepare a dedicated home and environment following the procedure for your operating system. - [Linux — Tarball](./standard-edition/#linux-tarball) - [Linux — Docker](./standard-edition/#linux-docker) - [Windows — Package](./standard-edition/#windows-package) 3. Check configuration and data paths. If using a separate license, follow [License Installation](./pre-install-preparation/#license) before the first startup. 4. Create the new database and start the server as described in the selected installation procedure. 5. Use the [Validation Checklist](./validation-checklist/) to check the process, port, connection, version, license, and a small insert/query workflow. A container deployment still needs the correct package version, a data volume, and write access for the server account. The relationship between container startup and DBMS initialization depends on the image, so follow its installation procedure. ### Cluster Edition 1. Review [Pre-Installation Preparation](./pre-install-preparation/) and [Cluster Environment Preparation](./cluster-edition/#preparation-environment-cluster-edition). 2. Decide each node's host, home, SQL/management/inter-node ports, and Warehouse replication group. 3. Prepare packages and licenses, then choose a deployment method. - [machclusterctl](./cluster-edition/#machclusterctl): configuration-based deployment and plan review - [Manual Installation](./cluster-edition/#manual-machcoordinatoradmin): stepwise registration and startup 4. Check role-specific node states and replication configuration, then connect to a Broker with SQL. 5. Use the [Validation Checklist](./validation-checklist/) to check ingestion/query behavior separately from replication state within a group. A successful SQL connection does not establish that every replica is healthy. Different Warehouse groups need not contain identical data. Continue with [Cluster Operations](/dbms/operations-configuration-recovery/cluster/) for failure handling. ## Upgrade For an existing system, follow [Upgrade](./upgrade/). Check compatibility of data files, SQL and SDKs, configuration, licenses, and backup/recovery paths as well as the new executables. Do not replace production settings with package samples or treat binary replacement alone as a completed upgrade. Keep baseline measurements and a backup from before the upgrade, and measure recovery time in an isolated environment. Returning to an earlier version requires data and configuration that the earlier version can read, not just its executables. ## Next Steps Installation validation begins operational preparation. Use the [Quick Start](/dbms/getting-started/quick-start/) to learn the SQL workflow, then model your data in [Table Type Selection and Schema Design](../data-modeling-table-design/). Before production use, prepare dedicated accounts, ingestion error handling, retention and backup, representative load tests, and monitoring. See [Observability and Diagnosis](/dbms/operations-configuration-recovery/diagnosis-observability/) and [Performance Tuning Approach](/dbms/performance-tuning/performance-approach/) for that process. --- title: "3.1 Pre-Installation Preparation" url: https://docs.machbase.com/dbms/installation-deployment-upgrade/pre-install-preparation/ language: en kind: page --- # 3.1 Pre-Installation Preparation Preparation establishes not only where to copy the software, but also where data will remain, which account will run the server, and how clients will connect. Check package and operating system compatibility, then prepare storage, networking, and licensing. Use the supplied release information and support policy to determine supported configurations. ## Deployment Information to Decide First | Item | Decision | Why it matters | |---|---|---| | Edition and version | Standard or Cluster, server and SDK versions | Select supported SQL features and deployment methods | | OS account | Server account and file owner | Align access to configuration, data, and log directories | | Installation home | Absolute path containing executables and configuration | Identify the instance controlled by administration commands | | Data path | Actual `DBS_PATH`, file system, and free space | Identify data to preserve across restarts and upgrades | | Connection details | Server address, SQL and management ports, allowed clients | Prevent port conflicts and connections to the wrong instance | | Recovery and licensing | Backup storage, restoration procedure, and license | Establish recovery and operating limits | The OS account `machbase` and database user `SYS` are different identities. The former controls processes and file access; the latter controls SQL connections and database permissions. A server can start successfully while loading or backup still fails because of file or SQL permissions. | Topic | Contents | |---|---| | [Requirements](#pre-install-requirements) | OS compatibility, resources, and network ports | | [Package Layout](#package) | Package naming, directories, and executables | | [License Installation](#license) | Installing license.dat and checking its state | ## Pre-Installation Requirements ### Operating System and Package Match the operating system and CPU architecture to the package. Supported OS releases and minimum versions can change between releases; check the release information supplied with the package instead of relying on a fixed version list. ### System Resources CPU, memory, disk, and network requirements depend on ingestion rate, retention, indexes, and ROLLUP. Include raw data, backups, and operational headroom as well as installation space, and validate capacity and throughput with representative workloads. Estimate raw row counts from the ingestion rate and retention period, then load representative data to measure row size, compression, and index costs. Include replica storage for Cluster. Separate directories on the same disk are neither independent failure domains nor independent I/O devices. ### Default Port | Port | Purpose | |---|---| | **5656** | SQL client connections over native TCP | Set `PORT_NO` in `$MACHBASE_HOME/conf/machbase.conf` to change the SQL port. The `MACHBASE_PORT_NO` environment variable is also used, so inspect the environment of the shell or service that starts the server. Specify the new port in clients too. A changed environment variable does not retroactively modify a running server. Allow the required incoming connections through the firewall. Cluster also requires ports for Coordinator links and administration, Brokers, Warehouses, and Deployers. ### Linux Kernel and Process Settings Check the following before installation. #### File Descriptor Limit A low file descriptor limit can constrain workloads that open many files. Defaults depend on the OS and account configuration; check the account that will run the server. ```bash # Check the current limit ulimit -Sn ``` This example uses 65535. If the current limit is lower, update `/etc/security/limits.conf` and verify the result in a new login session. ``` * hard nofile 65535 * soft nofile 65535 ``` Log in again as the server account. If a service manager starts the server, also check the limit configured for that service. ```bash ulimit -Sn # Expected output: 65535 ``` #### Port Reservation Reserve Machbase service ports so the OS does not select them automatically as ephemeral ports. This does not prevent another process from explicitly binding the same port. ```bash current=$(cat /proc/sys/net/ipv4/ip_local_reserved_ports) ports=5656 sudo sysctl -w net.ipv4.ip_local_reserved_ports="${current:+$current,}$ports" ``` Merge existing reserved ports rather than overwriting them. For persistence, merge the required values into `net.ipv4.ip_local_reserved_ports` in `/etc/sysctl.conf`. ``` net.ipv4.ip_local_reserved_ports = 5656 ``` ### Time Synchronization Use NTP or `chrony` to synchronize system clocks. Accurate time matters for time-series data, and clocks across Cluster nodes must be synchronized. ```bash # Check the time zone ls -l /etc/localtime date ``` ## Package Layout ### Package Naming Package names follow this pattern, with Edition-specific values. ``` machbase-EDITION-VERSION-OS-CPU-BIT-MODE.EXT ``` | Field | Meaning | Example | |---|---|---| | EDITION | Edition identifier | `SDK`, `cluster` | | VERSION | Major.Minor.Fix.AUX | `8.7.0.official` | | OS | Operating system | `LINUX`, `WINDOWS` | | CPU | CPU architecture | `X86` | | BIT | Architecture bit width | `64` | | MODE | Build mode | `release` | | EXT | File extension | `tgz` for Linux; `zip` or an installer for Windows | The Standard Edition Linux archive uses the name `machbase-SDK-...tgz`. - Standard: `machbase-SDK-8.7.0.official-LINUX-X86-64-release.tgz` - Cluster: `machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz` Different minor versions may differ in DB file or protocol compatibility. Check the destination release's compatibility guidance and the [Upgrade Procedure](../upgrade/) for supported paths, including fix-version changes. ### Installation Directories Extracting the archive creates the following layout under `$MACHBASE_HOME`. ```text $MACHBASE_HOME/ ├── bin/ Executables ├── conf/ Configuration, including machbase.conf ├── dbs/ Data storage ├── doc/ License documents ├── include/ C/C++ headers ├── install/ Makefile include files ├── lib/ Shared libraries ├── package/ Additional Cluster packages ├── sample/ Examples ├── trc/ Server trace logs ├── tutorials/ Tutorials ├── utility/ Utilities └── 3rd-party/ Grafana plugins and other integrations ``` ### Main Executables | Executable | Purpose | |---|---| | `machbased` | Server daemon | | `machadmin` | Server start, stop, and database creation | | `machsql` | SQL command-line client | | `machloader` | Bulk file loading and export | | `csvimport` | CSV import | | `csvexport` | CSV export | | `tagmetaimport` | Bulk TAG metadata registration | Cluster packages also contain administration tools such as `machcoordinatoradmin` and `machdeployeradmin`. `machclusterctl` is available in packages built to include it. ### Configuration Files Edition-specific sample files are under `$MACHBASE_HOME/conf/`. ```bash ls $MACHBASE_HOME/conf/ # machbase.conf # machbase.conf.sample.standard # machbase.conf.sample.edge # machloader.conf.sample ``` The active configuration file is `machbase.conf`. The full Standard package includes a copy of `machbase.conf.sample.standard` as `machbase.conf`. If your package does not include the active file, copy the sample for the appropriate Edition and configure it. Standard/Edge samples include `TRANSACTION_BUSY_TIMEOUT_MS`, `TRANSACTION_SYNCHRONOUS`, and `TRANSACTION_JOURNAL_MODE` for TRANSACTION write contention and durability. Start with the defaults, then evaluate concurrent writes and durability requirements before changing them. ## License Installation Without a license file, the server uses the default `COMMUNITY` license information. Before installation, confirm that its limits fit the planned features and capacity. If you need a separate license, prepare it before the first startup. Successful startup alone does not establish that the license meets production requirements. ### Check License State Use `VIOLATE_STATUS` and `VIOLATE_MSG` in `V$LICENSE_INFO` to inspect the installed license and any limit violations. Do not edit the license file's contents. ### Installation Methods #### Method 1: Copy the File Before Startup Copy `license.dat` to `$MACHBASE_HOME/conf/`. The server reads it when starting. ```bash cp license.dat $MACHBASE_HOME/conf/license.dat ``` #### Method 2: Use machadmin `machadmin` validates and installs the file. If the server is running, it also requests a license reload. ```bash machadmin -t /path/to/license.dat ``` #### Method 3: Use SQL on a Running Server Run the following in `machsql`. The server process must be able to read the specified file. ```sql ALTER SYSTEM INSTALL LICENSE = '/path/to/license.dat'; ``` ### Verify Installation #### machadmin ```bash machadmin -f ``` #### V$LICENSE_INFO ```sql SELECT ID, ISSUE_DATE, TYPE, CUSTOMER, VIOLATE_STATUS, VIOLATE_MSG FROM V$LICENSE_INFO; ``` Check that `VIOLATE_STATUS` is zero. You can also inspect license information in `machsql`: ```sql SHOW LICENSE; ``` --- title: "3.2 Standard Edition Installation" url: https://docs.machbase.com/dbms/installation-deployment-upgrade/standard-edition/ language: en kind: page --- # 3.2 Standard Edition Installation Standard Edition handles SQL and storage on one server. Install in this order: prepare the package, configure the execution environment, create the database, check the license, start the server, and verify SQL. A single server is not limited to small data sets; measure whether its resources meet your throughput and retention requirements. ## Installation Paths | OS | Method | Procedure | |---|---|---| | Linux | Tarball (.tgz) | [Tarball Installation](#linux-tarball) | | Linux | Docker container | [Docker Installation](#linux-docker) | | Windows | ZIP or installer | [Windows Package Installation](#windows-package) | First complete [Linux Preparation](#linux-preparation-environment-linux) or [Windows Preparation](#windows-preparation-environment-windows). ## Linux Installation | Method | Suitable situations | |---|---| | [Tarball](#linux-tarball) | Server deployments where you manage installation and data directories | | [Docker](#linux-docker) | Development and test environments using containers | Complete [Pre-Installation Preparation](../pre-install-preparation/) before tarball installation. For Docker, prepare Docker Engine and the necessary volume and port permissions. ### Linux Preparation File descriptor limits, clock synchronization, port reservation, and firewall configuration are shared preparation tasks. Configure them for the server account and operating environment using [Pre-Installation Preparation](../pre-install-preparation/). ### Tarball Installation The following procedure extracts a Linux tarball to install Standard Edition. #### 1. Create an OS User Create the dedicated server account: ```bash sudo useradd -m -d /home/machbase machbase sudo passwd machbase ``` Log in as `machbase` for the remaining steps. #### 2. Download and Extract the Package The example assumes that the package is under `/home/machbase/packages/`. Substitute the actual package name and extract it into a new installation directory without an existing instance. For an existing installation, follow [Upgrade](../upgrade/). ```bash machbase_package=/home/machbase/packages/machbase-SDK-8.7.0.official-LINUX-X86-64-release.tgz test -r "$machbase_package" && mkdir /home/machbase/machbase_home && tar zxf "$machbase_package" -C /home/machbase/machbase_home && cd /home/machbase/machbase_home ``` Check the extracted layout: ```bash ls -l # bin/ conf/ dbs/ doc/ include/ lib/ trc/ ... ``` #### 3. Set Environment Variables Add these variables to `~/.bashrc`: ```bash export MACHBASE_HOME=/home/machbase/machbase_home export PATH="$MACHBASE_HOME/bin:$PATH" export LD_LIBRARY_PATH="$MACHBASE_HOME/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" ``` Apply them to the current shell: ```bash source ~/.bashrc ``` #### 4. Create the Database `machadmin -c` creates the physical instance's database files. It is different from SQL `CREATE DATABASE`, which adds a logical database. First verify `MACHBASE_HOME`, `conf/machbase.conf`, and the actual `DBS_PATH`. If a database already exists, inspect the target path instead of deleting and recreating it. ```bash machadmin -c # Database created successfully. ``` #### Check Configuration and Licensing Before Startup Check `PORT_NO` and `DBS_PATH` in `conf/machbase.conf`. If you use a separate license, install it by copying the file or using `machadmin -t`, then check it with `machadmin -f` before starting. See [License Installation](../pre-install-preparation/#license). #### 5. Start the Server ```bash machadmin -u # Machbase server started successfully. ``` Check server state: ```bash machadmin -e ``` #### 6. Test the Connection Connect with `machsql`. The initial administrator credentials are `SYS` / `MANAGER`; use the current password if it has been changed. ```bash machsql # Machbase server address (Default:127.0.0.1) : # Machbase user ID (Default:SYS) # Machbase User Password : # MACHBASE_CONNECT_MODE=INET, PORT=5656 EDITION=STANDARD # Mach> ``` Run the basic SQL test: ```sql CREATE LOG TABLE install_check (id INTEGER, val DOUBLE); INSERT INTO install_check (id, val) VALUES (1, 3.14); SELECT id, val FROM install_check; DROP TABLE install_check; ``` Verify one row with `id=1` and `val=3.14`, followed by a successful DROP. If `install_check` already exists, choose an unused practice name instead of deleting it. #### Stop the Server Run this only if you need to stop the server after verification. ```bash machadmin -s # Machbase server shut down successfully. ``` #### Change the Port Change `PORT_NO` in `$MACHBASE_HOME/conf/machbase.conf` or set the environment variable: ```bash export MACHBASE_PORT_NO=7878 ``` Apply the setting while the server is stopped and start it again. This variable affects the current shell; a service needs the same environment configured separately. Specify the changed port when connecting, for example `machsql -s 127.0.0.1 -P 7878 -u SYS`. ### Docker Installation Docker packages the server and its execution environment in a container. Even for development and testing, prepare Docker Engine, storage volumes, ports, and file descriptor limits on the host. The deployment example uses `machbase/machbase`. If you build your own image, replace it with the local image name, such as `machbase:latest`. #### Check the Image ```bash docker pull machbase/machbase docker image ls machbase/machbase ``` #### Create the Container ```bash docker create \ --name machbase \ --ulimit nofile=65535 \ -p 5656:5656 \ -v /data/machbase:/home/machbase/machbase/dbs \ machbase/machbase ``` | Option | Meaning | |---|---| | `-p 5656:5656` | Host SQL port mapped to container SQL port | | `--ulimit nofile=65535` | File descriptor limit available to the server | | `-v /data/machbase:...` | Preserve the data directory on the host | Data stored only in a container's writable layer is removed with the container. Confirm that the actual data path is mounted on the volume, and also keep backups against volume deletion or disk failure. `docker create` does not start the server yet. The container's server account must be able to write `/data/machbase`. If it contains existing DB files, verify their version and instance. Check the image's actual version and `MACHBASE_HOME`, then pin a validated tag or digest for production. Do not assume the untagged public image always contains 8.7.0. If you use a separate license, copy it before starting: ```bash docker cp /path/to/license.dat machbase:/home/machbase/machbase/conf/license.dat ``` Start the prepared container: ```bash docker start machbase ``` #### Check Container State ```bash docker ps docker logs machbase ``` #### Test the Connection ##### machsql Inside the Container ```bash docker exec -it machbase machsql # Mach> ``` ##### From the Host If `machsql` is installed on the host: ```bash machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER ``` #### Stop and Restart the Container ```bash docker stop machbase docker start machbase ``` #### Update the License Copy the replacement file into the running container and install it with the license command. Configuration and licensing are separate from the data volume; retain their originals so that they can be reapplied when recreating a container. ```bash docker cp /path/to/license.dat machbase:/tmp/license.dat docker exec machbase machadmin -t /tmp/license.dat docker exec machbase machadmin -f ``` ## Windows Installation ### Before You Start - Check supported Windows versions in the supplied package's release information. - Match package bit width and CPU architecture to the operating system. Complete [Windows Preparation](#windows-preparation-environment-windows) first. ### Installation Methods | Method | Description | |---|---| | [Windows Package Installation](#windows-package) | Installation wizard; creates environment variables and shortcuts | ### Windows Preparation Check firewall configuration before installation. #### Allow the SQL Port | Port | Protocol | Purpose | |---|---|---| | 5656 | TCP | SQL client connections | ##### Configure Through the UI 1. Open **Control Panel → Windows Defender Firewall → Advanced settings**. 2. Select **Inbound Rules**, then **New Rule**. 3. Choose **Port**, then **Next**. 4. Choose **TCP**, enter `5656` in **Specific local ports**, then **Next**. 5. Choose **Allow the connection**, then **Next**. 6. Select only the network profiles where access is needed: **Domain**, **Private**, or **Public**. 7. Name the rule, for example `Machbase`, and select **Finish**. Restrict the rule's remote-address scope to the actual clients. If remote access is unnecessary, you do not need an inbound allow rule. ##### Configure with Administrator PowerShell The following creates an inbound rule; apply the same profile and address restrictions. ```powershell New-NetFirewallRule -DisplayName "Machbase SQL" -Direction Inbound -Protocol TCP -LocalPort 5656 -Action Allow ``` #### Visual C++ Redistributable The runtime requires Visual C++ Redistributable. The installer may handle this dependency. If it is missing, obtain the appropriate runtime from Microsoft's official site. ### Windows Package Installation A ZIP contains `bin\`, `conf\`, `dbs\`, and `trc\` at its root. The installer creates `machbase_home\` below the installation directory and configures environment variables and shortcuts. #### Installation Procedure 1. Download the Windows package. 2. For a ZIP, extract it into the desired installation directory. ```cmd mkdir C:\machbase tar -xf machbase-SDK-8.7.0.official-WINDOWS-X86-64-release.zip -C C:\machbase ``` 3. If using an installer instead, run it and select **Next**. 4. Select the installation directory. Its default follows the form `C:\machbase-\`. Change it if needed, then select **Next**. 5. After installation, select **Next → Close**. #### Initialize a ZIP Installation In Command Prompt, set the extracted directory as the installation home. This example uses a new installation at `C:\machbase`. Check the active configuration and license first. Run `-c` only for a new instance without existing DB files. ```cmd set "MACHBASE_HOME=C:\machbase" set "PATH=%MACHBASE_HOME%\bin;%PATH%" machadmin.exe -c machadmin.exe -f machadmin.exe -u machadmin.exe -e ``` These `set` commands affect the current window. Use the same installation home and executable path in later windows or services. If an installer already created the database, do not repeat the ZIP creation command. #### Start and Stop the Server An installer provides these desktop or Start-menu shortcuts: - **start Machbase** runs `machadmin.exe -u`. - **stop Machbase** runs `machadmin.exe -s`. - **machsql** opens the SQL console. #### Connect from Command Prompt For an installer, `\machbase_home\bin` is added to `PATH`. For a ZIP, add its `bin\` directory yourself or run the executable by its full path. ```cmd machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER ``` The initial credentials are `SYS` / `MANAGER`. #### Installation Layout A ZIP places `bin\`, `conf\`, `dbs\`, and `trc\` directly below the extraction directory. An installer places the same layout under `machbase_home\`. See [Package Layout](../pre-install-preparation/#package). --- title: "3.3 Cluster Edition Installation and Deployment" url: https://docs.machbase.com/dbms/installation-deployment-upgrade/cluster-edition/ language: en kind: page --- # 3.3 Cluster Edition Installation and Deployment Cluster Edition separates SQL connections, storage, replication, and node management into different roles. Before installation, assign each role to a host and choose its ports and storage paths. Ordinary SQL connections go to Brokers; administration commands go to the appropriate management node. ## Node Roles | Node | Role | |---|---| | Coordinator | Manage cluster metadata and monitor node state | | Deployer | Deploy packages and initialize nodes | | Lookup | Process reference data and related requests | | Broker | Accept client SQL, parse it, and distribute queries | | Warehouse | Store data and execute queries | The YAML example below uses three hosts with two Coordinators, three Deployers, two Lookup nodes (one master and one monitor), two Brokers, and two Warehouses in one replication group. Choose actual node counts and placement according to availability, throughput, and the capacity that must remain after a failure. ## Deployment Methods | Method | Description | When to use it | |---|---|---| | [machclusterctl](#machclusterctl) | Automated deployment from `cluster.yaml` | Recommended starting point for new installations | | [Manual administration](#manual-machcoordinatoradmin) | Register and deploy nodes through Coordinator commands | When individual steps require direct control | ## Installation Order 1. Understand the [Cluster Configuration](#overview). 2. Complete [Environment Preparation](#preparation-environment-cluster-edition), including SSH, kernel settings, and clock synchronization. 3. Prepare packages, paths, and the [License](../pre-install-preparation/#license) installation method. 4. Deploy, start, and verify licensing using the chosen method. 5. Complete [Installation Validation](../validation-checklist/). ## Cluster Configuration Overview Coordinator, Deployer, Lookup, Broker, and Warehouse have separate responsibilities. Understand their relationships before planning deployment. ### Node Roles in Detail #### Coordinator The Coordinator manages metadata, node registration, and monitoring. Consider Primary/Secondary redundancy. Although management and running data-processing paths are separate, Coordinator failure alone does not establish whether all SQL will continue. Check other nodes and client impact and follow a tested recovery procedure. - Configuration: `$MACHBASE_COORDINATOR_HOME/conf/machbase.conf` - Tool: `machcoordinatoradmin` - Main ports: `CLUSTER_LINK_PORT_NO`, `HTTP_ADMIN_PORT` The defaults are `CLUSTER_LINK_PORT_NO=3868` and `HTTP_ADMIN_PORT=5779`. This chapter explicitly uses `5101` and `5102` for the Coordinator link and management ports to avoid conflicts. #### Deployer The Deployer carries out package deployment and initialization requested by the Coordinator. Place one on each node host or operate it on a separate deployment server. - Tool: `machdeployeradmin` #### Lookup Lookup nodes process reference data. Their configured roles are `master`, `monitor`, or `slave`. #### Broker Brokers accept and parse client SQL and distribute work to Warehouses. Ordinary applications connect to Broker addresses. Direct Warehouse connections are for management diagnostics, such as comparing replicas, and are separate from application connection paths. Redundant Brokers are recommended. - Default client connection port: 5656 #### Warehouse Warehouses store data and execute queries. Members of the same group replicate data for availability. At least two members per group are recommended. ### Configuration Illustration ``` [Client] │ (SQL, 5656) ▼ [Broker ×2] ────────────────────────────────────────── │ (Query distribution) ├─► [Warehouse group1-node1] ◄──Replication──► [Warehouse group1-node2] └─► [Warehouse group2-node1] ◄──Replication──► [Warehouse group2-node2] [Coordinator Primary] ◄──HA──► [Coordinator Secondary] │ (Metadata and node monitoring) [Deployer] │ [Lookup master / monitor] ``` ### Edition Comparison See [Standard and Cluster Differences](../../core-concepts/concepts-edition/#differences-standard-edition-cluster). ## Prepare the Cluster Environment Prepare the following on the relevant hosts before deployment. ### File Descriptor Limit Edit the limit configuration on each node host: ```bash sudo vi /etc/security/limits.conf ``` ``` * hard nofile 65535 * soft nofile 65535 ``` Check the result in a new login session as the server account. If a service manager starts the process, also check that service's file descriptor limit. ```bash ulimit -Sn # 65535 ``` ### Create OS Users Create the `machbase` account on each host: ```bash sudo useradd -m machbase --home-dir /home/machbase sudo passwd machbase ``` ### SSH Key Authentication For `machclusterctl`, the deployment host must be able to connect to all target hosts using noninteractive key-based SSH. ```bash # Create a key on the deployment host; skip if one already exists ssh-keygen -t rsa -b 4096 # Register the public key on each target host ssh-copy-id machbase@192.168.1.11 ``` The address is an example; repeat registration and verification for every target host. Check that the connection works without a password: ```bash ssh machbase@192.168.1.11 'hostname' ``` ### Network Kernel Parameters These are tuning examples, not required values for every server. First measure current kernel settings, memory use, and network bottlenecks. Compare memory and latency as well as throughput after changes, and persist only changes that have been validated. ```bash sudo sysctl -w net.core.rmem_default=33554432 sudo sysctl -w net.core.wmem_default=33554432 sudo sysctl -w net.core.rmem_max=268435456 sudo sysctl -w net.core.wmem_max=268435456 sudo sysctl -w 'net.ipv4.tcp_rmem=262144 33554432 268435456' sudo sysctl -w 'net.ipv4.tcp_wmem=262144 33554432 268435456' sudo sysctl -w 'net.ipv4.tcp_mem=8388608 8388608 8388608' ``` To make validated settings persistent, add them to `/etc/sysctl.conf`. ### Time Synchronization Synchronize all node clocks with NTP or `chrony`. ```bash # Example with chrony sudo systemctl enable chronyd sudo systemctl start chronyd chronyc tracking ``` An isolated installation environment without a time server can set its initial clock manually. Replace this illustrative timestamp with the actual current time. A manual setting does not continuously correct clock drift; establish clock synchronization before production. ```bash sudo date -s "2025-01-02 12:34:56" ``` ### Reserve Ports Reserve the ports used by Machbase on each host. ```bash current=$(cat /proc/sys/net/ipv4/ip_local_reserved_ports) ports=5101-5110,5201-5202,5301-5302,5401,5500-5503,5656 sudo sysctl -w net.ipv4.ip_local_reserved_ports="${current:+$current,}$ports" ``` Merge existing reservations rather than overwriting them. Adjust the ranges for the actual configuration, including cluster links, Coordinator/Deployer management, service ports, and Warehouse replication-manager ports. ## Deploy with machclusterctl `machclusterctl` deploys and manages a cluster from `cluster.yaml`. It uses SSH to deploy packages, initialize nodes, and coordinate startup and shutdown. ### Prerequisites - Run commands on the host that will contain the Primary Coordinator. The package and SSH private key must be readable there. - Configure key-based SSH from that host to every target host. - Ensure permission to create and write the parent directories of each node's `home_path` and `dbs_path`. - If a separate license is required, prepare the package and licensing procedure before automatic startup. Do not invent a license property in the YAML. - Complete [Cluster Environment Preparation](#preparation-environment-cluster-edition). ### Workflow | Step | Document | |---|---| | 1. Write cluster.yaml | [YAML Configuration](#machclusterctl-cluster-yaml) | | 2. Validate it | [YAML Validation](#machclusterctl-validation-yaml) | | 3. Install and start | [Initial Installation](#machclusterctl-initial) | | 4. Inspect state | [Status Checks](#machclusterctl-status-check-state) | | 5. Make later configuration changes | [Cluster Operations](../../operations-configuration-recovery/cluster/) | | 6. Diagnose a failure | [Cluster Troubleshooting](../../troubleshooting/cluster/) | ### Write cluster.yaml `cluster.yaml` declares the nodes and their paths. Replace the example addresses with actual hosts. `origin_path` is the archive read on the Primary Coordinator host where the command runs. `home_path` and `dbs_path` belong to the node's host. `deployer` references the Deployer that will deploy and control that node. #### Example File ```yaml version: "1" cluster: name: mc-prod hosts: node1: address: machbase@192.168.1.10 node2: address: machbase@192.168.1.11 node3: address: machbase@192.168.1.12 package: name: machbase origin_path: /home/machbase/packages/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz ssh: key_file: /home/machbase/.ssh/id_rsa defaults: coordinator: home_path: /home/machbase/coordinator cluster_link_port: 5101 http_admin_port: 5102 deployer: home_path: /home/machbase/deployer cluster_link_port: 5201 http_admin_port: 5202 lookup: home_path: /home/machbase/lookup cluster_link_port: 5301 broker: home_path: /home/machbase/broker cluster_link_port: 5401 service_port: 5656 warehouse: home_path: /home/machbase/warehouse cluster_link_port: 5501 service_port: 5500 coordinators: - alias: coord-primary-1 host: node1 role: primary - alias: coord-secondary-1 host: node2 role: secondary deployers: - alias: deployer-1 host: node1 - alias: deployer-2 host: node2 - alias: deployer-3 host: node3 lookup: - alias: lookup-master-1 host: node1 deployer: deployer-1 type: master - alias: lookup-monitor-1 host: node2 deployer: deployer-2 type: monitor brokers: - alias: broker-1 host: node1 deployer: deployer-1 dbs_path: /data/machbase/broker-1/dbs - alias: broker-2 host: node2 deployer: deployer-2 warehouse_groups: - name: group1 nodes: - alias: warehouse-group1-1 host: node2 deployer: deployer-2 dbs_path: /data/machbase/warehouse-group1-1/dbs - alias: warehouse-group1-2 host: node3 deployer: deployer-3 dbs_path: /data/machbase/warehouse-group1-2/dbs ``` #### Field Reference | Field | Meaning | |---|---| | `version` | YAML schema version; currently `"1"` | | `cluster.name` | Cluster identifier, also used for `destroy` confirmation | | `cluster.hosts` | Host aliases and SSH `address` values in `user@host` form | | `cluster.package.name` | Package name registered with the Coordinator | | `cluster.package.origin_path` | Input archive for `install`, `apply`, and `upgrade` | | `cluster.package.registered_path` | Observed Coordinator package-store path recorded by `export`; not an input archive | | `cluster.ssh.key_file` | SSH private-key path; no password field is used | | `cluster.defaults` | Role-specific `home_path`, `cluster_link_port`, and `service_port` defaults | | `cluster.coordinators` | Coordinator nodes; `role` is `primary` or `secondary` | | `cluster.deployers` | Deployer nodes | | `cluster.lookup` | Lookup nodes; `type` is `master`, `monitor`, or `slave` | | `cluster.brokers` | Broker nodes; clients connect to `service_port` | | `cluster.warehouse_groups` | Warehouse groups and their members | #### Redundancy and Placement Recommended configuration: - Two Coordinators: Primary and Secondary for high availability. - One or more Deployers. - One Lookup `master` and at least one `monitor`. - Two or more Brokers for load balancing. - Two Warehouses per group for replication and high availability. If several nodes of the same type share one host, explicitly give the additional nodes different `home_path` values and ports. Coordinator and Deployer management use `http_admin_port`. Broker and Warehouse nodes can specify `dbs_path`; it is a path on the node's host. If omitted, the normal `DBS_PATH` behavior of `machcoordinatoradmin --add-node` applies. The legacy `cluster.package.path` remains a compatibility input, but new YAML should use `origin_path`. Only Coordinator and Deployer use `http_admin_port`; do not configure HTTP ports for Broker, Lookup, or Warehouse. Validate the file after editing. ### Validate the YAML `validate` statically checks syntax, required values, aliases, port conflicts, and topology. #### Validation Command ```bash machclusterctl validate -f cluster.yaml ``` #### Checks | Item | Validation | |---|---| | YAML syntax | Parsing errors | | Environment substitution | `${VAR}` and `${VAR:-default}` expressions | | Required fields | Cluster, hosts, package, and required node values | | Aliases | Duplicate node aliases | | Ports | Declared conflicts on the same host | | Topology | Primary Coordinator, Lookup master/monitor, and Deployer references | #### Example Output ```text Validation passed. ``` Correct reported errors and validate again. #### Inspect the Installation Plan Use `install --dry-run --verbose` to inspect SSH access, package availability, remote directory permissions, and the proposed actions. ```bash machclusterctl install -f cluster.yaml --dry-run --verbose ``` After installation, `apply --dry-run` compares current state with the YAML and displays the change plan without applying remote changes. ```bash machclusterctl apply -f cluster.yaml --dry-run --verbose ``` #### Common Errors | Error | Cause | Correction | |---|---|---| | `field ... not found` | Unsupported YAML key | Use a supported `cluster.*` field | | `required field ...` | Missing value | Add the reported field | | `duplicate alias` | Reused alias | Assign unique node aliases | | `port conflict` | Same port on the same host | Change the conflicting port; changing only the home path does not resolve it | | `deployer ... not found` | Unknown Deployer reference | Set `deployer` to a configured Deployer alias or host:port | ### Initial Installation After preparing and validating the YAML, inspect the plan before installing. #### 1. Install the Cluster ```bash machclusterctl install -f cluster.yaml --dry-run --verbose ``` If the checks pass, perform the installation: ```bash machclusterctl install -f cluster.yaml --yes --verbose ``` The command automatically performs these steps: 1. Copies and extracts packages on each node. 2. Generates each node's `machbase.conf` and configures ports. 3. Initializes the Coordinator database. 4. Registers each node with the Coordinator. #### 2. Start the Cluster `install` prepares and starts the Coordinator, Deployers, Lookup, Brokers, and Warehouses. Use the following only when you need to start the installed cluster again: ```bash machclusterctl start ``` #### 3. Check State ```bash export MACHBASE_COORDINATOR_HOME=/home/machbase/coordinator machclusterctl status ``` To explicitly select a Coordinator home when several are managed from one host: ```bash machclusterctl status --coordinator /home/machbase/coordinator ``` Output follows `machcoordinatoradmin --cluster-status-full --verbose`. The following is a partial illustration of the columns, not the complete node list from the YAML. Coordinator and Broker can show role states such as `primary` or `leader`. Compare registered node counts and role-specific desired and actual states, rather than requiring every row to say `normal`. ``` +-------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------+-----------------+----------+ | Node Type | Node Name | Group Name | Group State | Desired & Actual State | RP State | Disk(%) (00/00) | Ping(μs) | +-------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------+-----------------+----------+ | coordinator | coord-1(192.168.1.10:5101) | Coordinator | normal | primary | primary | ----------- | --------------- | 214 | | deployer | deployer-1(192.168.1.10:5201) | Deployer | normal | running | running | ----------- | --------------- | 100 | | broker | broker-1(192.168.1.11:5401) | Broker | normal | leader | leader | ----------- | --------------- | 100 | | warehouse | wh-g1-1(192.168.1.13:5501) | group1 | normal | normal | normal | running | 26.9 | 100 | +-------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------+-----------------+----------+ ``` #### 4. Test Client Connections Connect to a Broker IP and its SQL port: ```bash machsql -s 192.168.1.11 -P 5656 -u SYS -p MANAGER # Mach> ``` #### Stop the Cluster ```bash machclusterctl stop ``` ### After Installation For topology changes, node addition/removal, and recovery, follow [Cluster Operations](../../operations-configuration-recovery/cluster/). For failure classification and recovery decisions, see [Cluster Troubleshooting](../../troubleshooting/cluster/). ## Deploy Manually with machcoordinatoradmin If `machclusterctl` is unavailable, prepare Coordinator and Deployer processes directly, then register packages and nodes. Do not repeat creation commands in an already deployed cluster. The manual example is separate from the YAML example above. Run each command on the host for its corresponding role. | Host | Roles | |---|---| | `192.168.1.10` | Primary Coordinator, Deployer, Lookup master | | `192.168.1.11` | Deployer, Lookup monitor, Broker | | `192.168.1.13` | Deployer, first Warehouse in group1 | | `192.168.1.14` | Deployer, replica Warehouse in group1 | | `192.168.1.20` | Optional Secondary Coordinator | Separate homes and ports for roles on the same host. Prepare a Deployer on each host containing data-processing nodes and match the node's `--deployer` address to that host. ### Manual Deployment Order 1. Read [Package Preparation](#manual-machcoordinatoradmin-package) and prepare full and lightweight packages. 2. Install and start [Coordinator and Deployers](#manual-machcoordinatoradmin-coordinator-deployer). 3. [Register the lightweight package](#manual-machcoordinatoradmin-package) with the running Coordinator. 4. Register and start [Lookup, Broker, and Warehouse](#manual-machcoordinatoradmin-lookup-broker-warehouse). 5. [Check overall state](#manual-machcoordinatoradmin-lookup-broker-warehouse) after registration and startup. ### Comparison with machclusterctl | Item | machclusterctl | Manual deployment | |---|---|---| | Configuration | One `cluster.yaml` | Edit each node's `machbase.conf` | | Package deployment | Automated remote copy | Direct Coordinator/Deployer installation; Deployer installs data-processing nodes | | Node registration | Automatic | `machcoordinatoradmin --add-node` | | Start and stop | `machclusterctl start/stop` | Individual node commands | Manual deployment offers direct control but requires tracking every host and role. For new installations, start with `machclusterctl` when available. ### Package Preparation and Registration Install the full package on Coordinator and Deployer hosts. Register the lightweight package used for Broker and Warehouse deployment only after the Coordinator is running. #### Package Types | Package | Target | Contents | |---|---|---| | Full | Coordinator and Deployer | All executables | | Lightweight | Broker and Warehouse | Only data-processing files; smaller package | Example filenames: - Full: `machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz` - Lightweight: `machbase-cluster-8.7.0.official-LINUX-X86-64-release-lightweight.tgz` #### Install Full Packages ##### Coordinator Host ```bash # Run on the Coordinator host mkdir -p /home/machbase/coordinator scp machbase@package-host:/path/to/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz /home/machbase/ tar zxf /home/machbase/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz -C /home/machbase/coordinator ``` ##### Each Deployer Host ```bash mkdir -p /home/machbase/deployer scp machbase@package-host:/path/to/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz /home/machbase/ tar zxf /home/machbase/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz -C /home/machbase/deployer ``` Do not manually extract the lightweight package into Broker or Warehouse homes here. After it is registered, the Deployer selected by `--add-node` deploys it to `--home-path`. #### Register the Package with the Coordinator Install Coordinator and Deployer first, then register the package with the running Coordinator: ```bash $MACHBASE_COORDINATOR_HOME/bin/machcoordinatoradmin --add-package=machbase \ --file-name="/home/machbase/machbase-cluster-8.7.0.official-LINUX-X86-64-release-lightweight.tgz" ``` Broker and Warehouse registration later references it as `--package-name=machbase`. #### Set Role-Specific Environments Replace `package-host` and `/path/to/` with the actual package location. Use separate management shells for Coordinator and Deployer even when they share a host. Apply these settings to the appropriate shell and use the same values for services or login initialization files. ```bash # Coordinator management shell export MACHBASE_COORDINATOR_HOME=/home/machbase/coordinator export MACHBASE_HOME=$MACHBASE_COORDINATOR_HOME export PATH=$MACHBASE_HOME/bin:$PATH export LD_LIBRARY_PATH=$MACHBASE_HOME/lib:$LD_LIBRARY_PATH ``` ```bash # Separate Deployer management shell export MACHBASE_DEPLOYER_HOME=/home/machbase/deployer export MACHBASE_HOME=$MACHBASE_DEPLOYER_HOME export PATH="$MACHBASE_HOME/bin:$PATH" export LD_LIBRARY_PATH="$MACHBASE_HOME/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" ``` ### Install Coordinator and Deployers Prepare the packages first, then start the Coordinator before registering Deployers. #### Coordinator ##### 1. Configure machbase.conf Edit `$MACHBASE_COORDINATOR_HOME/conf/machbase.conf`: ```bash vi $MACHBASE_COORDINATOR_HOME/conf/machbase.conf ``` Use this host's address and the planned ports: ``` CLUSTER_LINK_HOST = 192.168.1.10 # This host's IP CLUSTER_LINK_PORT_NO = 5101 HTTP_ADMIN_PORT = 5102 ``` ##### 2. Create Metadata and Start ```bash machcoordinatoradmin -c machcoordinatoradmin -u ``` ##### 3. Register the Coordinator Itself ```bash machcoordinatoradmin --add-node="192.168.1.10:5101" \ --node-type=coordinator \ --http-admin-port=5102 ``` ##### 4. Verify Registration ```bash machcoordinatoradmin --cluster-status ``` #### Optional Secondary Coordinator For redundancy, prepare the Secondary package and configuration on its own host. Register it from the **Primary Coordinator first**, then start it on the Secondary host. ```bash # Register from the Primary first machcoordinatoradmin --add-node="192.168.1.20:5101" \ --node-type=coordinator \ --http-admin-port=5102 # Then start on the Secondary host, specifying the Primary machcoordinatoradmin -u --primary=192.168.1.10:5101 ``` Complete Primary registration before starting the Secondary. #### Deployer Perform these steps on every Deployer host in the manual layout. Replace `CLUSTER_LINK_HOST` with that host's own IP. Copying another host's address would make the communication address inconsistent with the actual process location. ##### 1. Configure machbase.conf ``` CLUSTER_LINK_HOST = 192.168.1.10 # Deployer host IP CLUSTER_LINK_PORT_NO = 5201 HTTP_ADMIN_PORT = 5202 ``` ##### 2. Start the Deployer ```bash machdeployeradmin -c machdeployeradmin -u ``` ##### 3. Register Deployers with the Coordinator After all Deployers are running, use the Primary Coordinator's management shell: ```bash machcoordinatoradmin --add-node="192.168.1.10:5201" \ --node-type=deployer \ --http-admin-port=5202 machcoordinatoradmin --add-node="192.168.1.11:5201" \ --node-type=deployer --http-admin-port=5202 machcoordinatoradmin --add-node="192.168.1.13:5201" \ --node-type=deployer --http-admin-port=5202 machcoordinatoradmin --add-node="192.168.1.14:5201" \ --node-type=deployer --http-admin-port=5202 ``` ### Install Lookup, Broker, and Warehouse Prepare Coordinator and Deployers first. Register the lightweight package with the Coordinator with `--add-package` before adding Broker or Warehouse nodes. #### Lookup Nodes Register and start the master and monitor. This example places them on the Primary and Broker hosts, using the local Deployer on each. Confirm that the homes are not used by existing Lookup nodes. ```bash machcoordinatoradmin --add-node="192.168.1.10:5301" \ --node-type=lookup \ --lookup-type=master \ --deployer="192.168.1.10:5201" \ --home-path="/home/machbase/lookup" machcoordinatoradmin --add-node="192.168.1.11:5301" \ --node-type=lookup \ --lookup-type=monitor \ --deployer="192.168.1.11:5201" \ --home-path="/home/machbase/lookup" machcoordinatoradmin --startup-node="192.168.1.10:5301" machcoordinatoradmin --startup-node="192.168.1.11:5301" ``` #### Broker ##### 1. Check Registration Settings The node configuration is generated during `--add-node` and deployed through the Deployer. Choose the cluster link and SQL service ports before registration. Do not configure an HTTP management port for Broker. ``` CLUSTER_LINK_HOST = 192.168.1.11 # Broker host IP CLUSTER_LINK_PORT_NO = 5401 PORT_NO = 5656 # Client SQL port ``` ##### 2. Register from the Coordinator ```bash machcoordinatoradmin --add-node="192.168.1.11:5401" \ --node-type=broker \ --deployer="192.168.1.11:5201" \ --package-name=machbase \ --home-path="/home/machbase/broker" \ --dbs-path="/data/machbase/broker_dbs" \ --port-no=5656 ``` | Parameter | Meaning | |---|---| | `--add-node` | Node IP:CLUSTER_LINK_PORT_NO | | `--node-type` | `broker`, `warehouse`, or `lookup` | | `--deployer` | IP:CLUSTER_LINK_PORT_NO of the Deployer that installs and controls the node | | `--package-name` | Registered package name | | `--home-path` | Node installation home | | `--dbs-path` | Broker/Warehouse data path; otherwise uses the default `DBS_PATH` | | `--port-no` | SQL or node service port | | `--replication` | Warehouse replication-manager address in `host:port` form | ##### 3. Start the Node From the Coordinator: ```bash machcoordinatoradmin --startup-node="192.168.1.11:5401" ``` #### Warehouses Warehouse nodes belong to groups. Nodes in the same group replicate data. ##### 1. Check Registration Settings The configuration is generated during registration and deployed through the Deployer. Establish the cluster link, service port, and replication-manager address beforehand. ``` CLUSTER_LINK_HOST = 192.168.1.13 CLUSTER_LINK_PORT_NO = 5501 PORT_NO = 5500 ``` ##### 2. Register the Nodes ```bash machcoordinatoradmin --add-node="192.168.1.13:5501" \ --node-type=warehouse \ --deployer="192.168.1.13:5201" \ --package-name=machbase \ --home-path="/home/machbase/warehouse_g1_1" \ --dbs-path="/data/machbase/warehouse_g1_1_dbs" \ --port-no=5500 \ --replication=192.168.1.13:5502 \ --group=group1 \ --no-replicate machcoordinatoradmin --add-node="192.168.1.14:5501" \ --node-type=warehouse \ --deployer="192.168.1.14:5201" \ --package-name=machbase \ --home-path="/home/machbase/warehouse_g1_2" \ --dbs-path="/data/machbase/warehouse_g1_2_dbs" \ --port-no=5500 \ --replication=192.168.1.14:5502 \ --group=group1 ``` There is no separate `--add-group` step. Specify the Warehouse group with `--group` when registering each node. ##### 3. Start the Nodes ```bash machcoordinatoradmin --startup-node="192.168.1.13:5501" machcoordinatoradmin --startup-node="192.168.1.14:5501" ``` #### Check All Nodes ```bash machcoordinatoradmin --cluster-status ``` Compare role-specific states: Coordinator may be `primary`, Broker `leader`, and Warehouses `normal`, `sync-active`, or `sync-standby`. Verify the configured node list rather than one universal state string. #### Verify the First Connection Connect to the Broker SQL port and run `SELECT CURRENT_DATABASE();` and a representative query. For subsequent node control and recovery, use [Cluster Operations](../../operations-configuration-recovery/cluster/) and [Cluster Troubleshooting](../../troubleshooting/cluster/). --- title: "3.4 Upgrade" url: https://docs.machbase.com/dbms/installation-deployment-upgrade/upgrade/ language: en kind: page --- # 3.4 Upgrade An upgrade is more than replacing executables: it verifies that existing data, configuration, and applications retain their intended behavior on the new version. First confirm a supported version transition, prepare a restorable backup, and define service-resumption criteria. Adjust the example 8.7.0 package names and paths to the distribution you received. ## Before upgrading - Check compatibility between the current and target versions. A minor-version change can involve a different database file format. - Take a backup before upgrading. See [backup procedures](/dbms/operations-configuration-recovery/backup-restore-mount/#backup). - Identify clients with ongoing INSERT or Append work. ### Machbase 8.7.0 pre-upgrade check When upgrading from 8.5 to 8.7.0, identify the following dependencies and migrate them to supported alternatives before replacing binaries. 1. Locate removed properties `HTTP_AUTH`, `HTTP_ENABLE`, `HTTP_MAX_MEM`, `HTTP_PORT_NO`, `RS_CACHE_*`, `STREAM_THREAD_COUNT`, and `STREAM_WAIT_MS` in the current configuration and compare them with the supported list. Remove obsolete properties and preserve supported ones. In particular, Cluster `HTTP_ADMIN_PORT` remains a management port; do not remove it simply because it matches `HTTP_*`. 2. Migrate applications calling `/machbase` or `/machiot` to a backend using a supported SDK. 3. Update SQL or operational scripts that invoke `STREAM_*` procedures or `FLUSH RESULT_CACHE`. 4. Migrate C/C++ applications using `machcli.h` and `MachCLI*()` to Machbase SQLCLI or ODBC. SQLCLI and ODBC are separate API sets. 5. Replace operational workflows and dashboards that depend on WebAdmin/MWA with command-line tools or separate applications. See [version compatibility](/dbms/reference/support-scope-constraints/compatibility-version/#removed-features-870) for the complete list of removed and retained features. ## Upgrade paths | Edition | Method | Procedure | |---------|--------|-----------| | Standard Edition | Stop the server and replace the package | [Standard upgrade](#standard-edition) | | Cluster Edition | Restart Brokers and Warehouses sequentially | [Online upgrade](#cluster-edition-online) | | Cluster Edition | Stop the entire cluster | [Full-stop upgrade](#cluster-edition-full-stop) | For Cluster Edition, choose online or full-stop upgrade according to availability requirements. --- ## Standard Edition upgrade Stop the server, replace the package, and restart. Apply this procedure only to supported version transitions that can open the existing physical database files. If the transition requires data conversion or export/import, follow the release-specific migration procedure first. ### Preparation 1. **Take and validate a backup.** Use a supported BACKUP command and verify restoration in a separate environment. Simply copying a live data directory does not establish a recoverable backup. 2. **Finish client activity.** Complete ongoing Append and INSERT operations and close connections. 3. **Record the current version:** ```bash machbased -v ``` ### Procedure #### 1. Stop the server ```bash machadmin -s # Machbase server shut down successfully. ``` #### 2. Preserve the existing package and configuration Retain the current configuration and license as well as executables and libraries in a separate location. Check that the destinations below do not already contain an earlier backup. ```bash cp -a "$MACHBASE_HOME/bin" "$MACHBASE_HOME/bin.bak" cp -a "$MACHBASE_HOME/lib" "$MACHBASE_HOME/lib.bak" cp -a "$MACHBASE_HOME/conf" "$MACHBASE_HOME/conf.bak" ``` Preserve `dbs/` and data under any separately configured `DBS_PATH`. These copies preserve executables and configuration; they do not replace a database backup. Once the new version has modified data, do not assume that restoring old binaries alone can recover the instance. Use the backup restoration path you have validated. #### 3. Extract and apply the new package Extract the new package into a separate working directory and inspect its contents and configuration changes first. ```bash upgrade_stage=$(mktemp -d) tar zxf machbase-SDK-8.7.0.official-LINUX-X86-64-release.tgz -C "$upgrade_stage" ``` Extraction alone does not replace executables in the existing installation. The following example applies executables, libraries, and headers from a Standard tarball containing `bin/`, `lib/`, and `include/`. Confirm that the server is stopped first. If any command fails, do not proceed to server startup. ```bash ( set -e test -n "$MACHBASE_HOME" test -x "$upgrade_stage/bin/machbased" test -d "$upgrade_stage/lib" test -d "$upgrade_stage/include" test -d "$MACHBASE_HOME/bin" test -d "$MACHBASE_HOME/lib" test -d "$MACHBASE_HOME/include" cp -a "$upgrade_stage/bin/." "$MACHBASE_HOME/bin/" cp -a "$upgrade_stage/lib/." "$MACHBASE_HOME/lib/" cp -a "$upgrade_stage/include/." "$MACHBASE_HOME/include/" "$MACHBASE_HOME/bin/machbased" -v ) ``` Preserve the existing `conf/machbase.conf`, license, and data at the actual `DBS_PATH`, and merge new configuration entries into the existing configuration. Copying replaces distribution files with matching names but does not automatically remove files present only in the old version. Select SDK and plugin files explicitly for the new version, and consult the release instructions for additional replacements and removals. Start the server only after checking the reported binary version and reviewing the configuration. #### 4. Start the server ```bash machadmin -u # Machbase server started successfully. ``` #### 5. Check the version ```bash machbased -v # Connect to the server. machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER ``` ```sql SELECT EDITION, BINARY_DB_MAJOR_VERSION, BINARY_DB_MINOR_VERSION FROM V$VERSION; ``` ### Important constraints - Do not delete `dbs/` or initialize it with `machadmin -d`. - Minor-version upgrades may require database file migration. Read the release notes. - On Windows, stop the Machbase service before applying the new package or installer. --- ## Cluster Edition upgrade Choose a method according to the required service interruption. | Method | Service impact | Suitable situation | |--------|----------------|--------------------| | [Online upgrade](#cluster-edition-online) | Sequential Broker/Warehouse restarts | Replacing only Brokers and Warehouses | | [Full-stop upgrade](#cluster-edition-full-stop) | Cluster outage | A maintenance window is available, or a major-version transition is required | ### Common precautions - Do not run DDL or DELETE during the upgrade. - Do not concurrently add, start, stop, or remove nodes. - Online upgrade targets Brokers and Warehouses. Use full-stop upgrade to replace Coordinators, Deployers, or Lookups as well. - Take a backup before upgrading. --- ### Online upgrade Upgrade Brokers and Warehouses sequentially while the cluster is running. If all binaries, including Coordinator, Deployer, and Lookup, must be replaced, use [full-stop upgrade](#cluster-edition-full-stop). #### Procedure ##### 1. Change the package in cluster.yaml Set `cluster.package.name` and `cluster.package.origin_path` to the new package. When package contents change, assign distinct names to both the package and archive file. ```yaml cluster: package: name: machbase-v8.7.0 origin_path: /home/machbase/packages/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz ``` `registered_path` is the Coordinator package-repository path recorded by `machclusterctl export`. Use `origin_path` to specify the upgrade archive. ##### 2. Inspect the execution plan ```bash machclusterctl upgrade -f cluster.yaml --online --dry-run --verbose ``` ##### 3. Run the online upgrade ```bash machclusterctl upgrade -f cluster.yaml --online --yes --verbose ``` Omitting `--online` also selects online mode, but specifying it makes the operational procedure explicit. ##### 4. Check overall status ```bash machclusterctl status ``` #### Manual upgrade reference When calling `machcoordinatoradmin --upgrade-node` directly, specify both the target node and the package name. ```bash machcoordinatoradmin --upgrade-node=192.168.1.11:5401 --package-name=machbase-v8.7.0 ``` Limit online targets to Brokers and Warehouses. If only one Broker remains, upgrading it can interrupt client connections for that period. Online mode avoids stopping the entire cluster; it is not an HA-aware rolling upgrade that guarantees uninterrupted service. Warehouse groups may temporarily become read-only, so validate application reconnection, retry handling, and write delays. Use full-stop mode if protocol compatibility changes or binaries for every role must be aligned. Check the role-specific states and versions of all target nodes, then validate representative queries, input, and replication. --- ### Full-stop upgrade Stop the entire cluster and upgrade all nodes. Use this method when all binaries, including Coordinator, Deployer, and Lookup, must be replaced or when the database file format changes. #### Procedure ##### 1. Finish client activity Verify that all INSERT, Append, and SELECT work has completed. ##### 2. Change the package in cluster.yaml Set `cluster.package.name` and `cluster.package.origin_path` to the new package. There must be no pending topology changes, such as node additions, removals, or port changes. Apply topology changes with `apply` before running the upgrade. `machclusterctl upgrade --full-stop` replaces the package in every node home, including Coordinator and Deployer. Set `origin_path` to a complete Cluster package containing `machcoordinatoradmin` and `machdeployeradmin`. ##### 3. Inspect the execution plan ```bash machclusterctl upgrade -f cluster.yaml --full-stop --dry-run --verbose ``` ##### 4. Run the full-stop upgrade ```bash machclusterctl upgrade -f cluster.yaml --full-stop --yes --verbose ``` With the entire cluster stopped, `machclusterctl` extracts the package into a temporary staging location and applies it to the node homes. #### Manual deployment reference For manual deployment, register the new package with the Coordinator. ```bash machcoordinatoradmin --add-package=machbase-v8.7.0 \ --file-name=/home/machbase/packages/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz ``` Stop nodes in this order: Warehouse → Broker → Lookup → Deployer → Coordinator. ```bash machcoordinatoradmin --shutdown-node=192.168.1.13:5501 machcoordinatoradmin --shutdown-node=192.168.1.14:5501 machcoordinatoradmin --shutdown-node=192.168.1.11:5401 machcoordinatoradmin --shutdown-node=192.168.1.10:5301 machdeployeradmin --shutdown machcoordinatoradmin --shutdown ``` When replacing packages in node homes, preserve `conf/machbase.conf` and the `dbs/`, `meta/`, and `package/` directories. Extract the package in a separate working location, then replace files while excluding the paths that must be retained. Start nodes in this order: Coordinator → Deployer → Lookup → Broker → Warehouse. ```bash machcoordinatoradmin --startup machdeployeradmin --startup machcoordinatoradmin --startup-node=192.168.1.10:5301 machcoordinatoradmin --startup-node=192.168.1.11:5401 machcoordinatoradmin --startup-node=192.168.1.13:5501 machcoordinatoradmin --startup-node=192.168.1.14:5501 ``` After restarting, synchronize Broker and Warehouse package metadata with the new package name. ```bash machcoordinatoradmin --upgrade-node=192.168.1.11:5401 --package-name=machbase-v8.7.0 machcoordinatoradmin --upgrade-node=192.168.1.13:5501 --package-name=machbase-v8.7.0 machcoordinatoradmin --upgrade-node=192.168.1.14:5501 --package-name=machbase-v8.7.0 ``` ##### 5. Check status ```bash machclusterctl status ``` Before resuming service, verify Broker connections, representative reads and writes, replication, license, and configuration as well as node status. Compare [installation validation](../validation-checklist/) with the pre-upgrade record. Retain the previous package, configuration, and backup until verification is complete. #### Important constraints - A major-version upgrade may change the database file format. Read the release notes and take a backup before upgrading. - Do not delete or initialize `conf/machbase.conf`, `dbs/`, `meta/`, or `package/`. --- title: "3.5 Installation Validation Checklist" url: https://docs.machbase.com/dbms/installation-deployment-upgrade/validation-checklist/ language: en kind: page --- # 3.5 Installation Validation Checklist Validation goes beyond checking that a process is running. Actual clients must connect to the intended server version and configuration, then write and read data within their permissions. Work through server status, connectivity, version and license, SQL, and Cluster replication in order. Record the execution host, installation home, connection address and port, time, and any errors for each result. For an upgrade, compare these with the pre-upgrade record. `SYS`/`MANAGER` are initial exercise credentials; substitute the actual account. Check that exercise table names do not collide with existing business objects. ## Standard Edition checklist ### 1. Check the server process ```bash machadmin -e # Machbase server is running with PID(). ``` You can also inspect processes directly, but distinguish the target server from servers running under other installation homes. Verify that `MACHBASE_HOME` identifies the instance being checked. ```bash ps -ef | grep machbased | grep -v grep ``` ### 2. Check the listening port ```bash ss -tlnp | grep 5656 # LISTEN 0 128 0.0.0.0:5656 ... ``` Use a port-inspection tool appropriate for the operating system. Replace `5656` with the actual SQL port and check that the listener uses the intended interface. A listening socket and a successful remote client connection are separate checks; test connectivity from the application host too. ### 3. Test a machsql connection ```bash machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER # MACHBASE_CONNECT_MODE=INET, PORT=5656 EDITION=STANDARD # Mach> ``` If local connections succeed but remote connections fail, check the address, port, listener, and firewall. For authentication errors, check the username, authentication method, and expiry status. If connection succeeds but object access fails, check the current database and SQL permissions separately. ### 4. Check the version ```sql SELECT * FROM V$VERSION; SELECT CURRENT_DATABASE(); ``` ### 5. Check the license ```sql SELECT ID, ISSUE_DATE, TYPE, VIOLATE_STATUS FROM V$LICENSE_INFO; ``` Check that `VIOLATE_STATUS` is 0 and that the installed license type and validity period match the operating plan. If a violation is reported, inspect `VIOLATE_MSG` and the server logs for its cause. ### 6. Test basic SQL ```sql CREATE LOG TABLE check_test (id INTEGER, ts DATETIME); INSERT INTO check_test (id, ts) VALUES (1, NOW); SELECT id, ts FROM check_test; DROP TABLE check_test; ``` Verify that one row with `id=1` and a timestamp is returned and that DROP succeeds. This checks only basic LOG input. If the service uses TAG, TRANSACTION, Append, or other paths, also test representative writes and queries using those tables and the actual SDK. ## Additional Cluster Edition checks ### 7. Check cluster node status ```bash machcoordinatoradmin --cluster-status # Compare node count and role-specific states with the deployment record. ``` ### 8. Test a Broker connection ```bash machsql -s 192.168.1.11 -P 5656 -u SYS -p MANAGER ``` ```sql SELECT * FROM V$NODE_STATUS; ``` Healthy state names differ by role: for example, Coordinator `primary`, Broker `leader`, and Warehouse replication states. Do not compare every node against one status string. Check the desired and actual states, group membership, and addresses against the deployment record. ### 9. Check data replication First verify input and queries through a Broker, then inspect replication within Warehouse groups. Reading a row through a Broker does not by itself prove that every replica has synchronized. ```sql -- Insert through a Broker. CREATE LOG TABLE cluster_check_test (id INTEGER, ts DATETIME); INSERT INTO cluster_check_test (id, ts) VALUES (1, NOW); -- Verify the input through the Broker. SELECT COUNT(*) FROM cluster_check_test; ``` Direct SQL connections to Warehouses are an administrative replication diagnostic, not the normal application path. Use `machcoordinatoradmin --cluster-status` to identify active and standby peers in the same replication group. When needed, connect to each peer's native port with an administrative account and compare the same query results. Do not assume nodes in different Warehouse groups all contain the same rows. After validation, remove the exercise table through the Broker connection. ```sql DROP TABLE cluster_check_test; ``` --- ## Acceptance criteria and troubleshooting Proceed with service acceptance once server, connection, permission, representative SQL, and required replication checks pass. To validate persistence, retain test data in a separate validation environment and compare results before and after a normal restart. Do not reinitialize a server containing business data merely to check installation. If a check fails, preserve the first error and relevant logs, then investigate the failed stage. - Server log: `$MACHBASE_HOME/trc/machbase.trc` - See [operations and diagnostics](/dbms/operations-configuration-recovery/diagnosis-observability/). --- title: "4. Table Types and Schema Design" url: https://docs.machbase.com/dbms/data-modeling-table-design/ language: en kind: section --- # 4. Table Types and Schema Design This chapter translates the meaning of your data and its mutation/query requirements into Machbase DBMS tables and columns. Once the database is running, decide what one row represents. Choosing a familiar table type first and forcing all data into it can create conflicting requirements for history, updates, and retention. If table roles are new to you, first read [Data Model Concepts](/dbms/core-concepts/concepts/). This chapter connects those concepts to concrete schemas and designs you can validate. ## Start with the Data Before choosing a table name, describe one row in a sentence. “One measurement from one sensor,” “one equipment state-change event,” and “the current installation information for one device” describe different units of data. Records from the same equipment can still have different storage roles. | Design question | Decision to make | |---|---| | What does one row represent? | A measurement, event, current state, or reference record | | How is its subject identified? | Tag names, business keys, and duplicate-ingestion identifiers | | What does the time or axis mean? | Measurement time, receipt time, or distance/position | | How are values interpreted? | Units, type ranges, precision, NULL, and missing observations | | Which mutations are needed? | Appends, historical corrections, key changes, and deletion boundaries | | Which queries recur? | Tag/time ranges, predicate searches, key lookups, aggregates, and joins | | What must be retained? | Raw data, aggregates, reference history, and state recoverable after restart | | What can be undone after failure? | Table/API transaction scope, retries, and reconstruction | Data size or input frequency alone does not determine the table type. Check that values grouped in a row describe the same observation or event, and design common identifiers for records that must be joined. Having a join key does not mean the DBMS automatically enforces every business relationship. Check the constraints supported by the selected table type. ## Contents | Order | Section | Design outcome | |-----:|---|---| | 4.1 | [Choose a Table Type](./table-types-selection-type/) | A type matching mutation, query, persistence, and Edition requirements | | 4.2 | [Schema Objects](./schema-objects-definition/) | Columns and types, identifiers, defaults/constraints, indexes, and views | | 4.3 | [Data Mutation Policy](./alter-data-mutation-policy/) | Correction/deletion boundaries and failure handling | | 4.4 | [Anti-Patterns](./table-types-patterns-type-anti/) | Reasons to revise choices that do not match requirements | | 4.5 | [Modeling Patterns](./patterns-modeling/) | Concrete combinations of history, state, and reference data | Choose a type in 4.1 and define structure and mutation rules in 4.2–4.3. Check the anti-patterns in 4.4, then adapt the patterns in 4.5 to your data. Comparison tables are starting points; follow the linked table guides and references for exact SQL and supported conditions. ## An Equipment-Monitoring Example Temperature, alarms, equipment definitions, and display state need not use the same storage model. | Data | Meaning of one row | Storage role to consider | |---|---|---| | Temperature history | One sensor reading at a particular time | TAG for tag/time-range queries and aggregation | | Alarm history | One alarm event at a particular time | LOG for append-oriented events | | Equipment reference data | One device's name, location, and thresholds | LOOKUP, or TRANSACTION when multiple changes must share a transaction | | Current display state | Recent state that can be recalculated | VOLATILE when authoritative data and a rebuild path exist | This is an example, not a fixed prescription. A record containing several measurements, or different mutation and retention requirements, may call for another design. Check Standard Edition support when considering TRANSACTION. Joining temperature history to current equipment definitions interprets that history using today's names and locations. If you need the location or threshold at measurement time, retain it with the history or model changes to the reference data. When maintaining a current-state cache, do not assume the history insert and cache update form one transaction. Prepare a way to rebuild the cache after failure. ## Validate with a Small Data Set Before scaling up, use representative records and common queries to check the design. 1. Insert normal values together with NULLs, missing observations, boundary values, and duplicate or late-arriving records. 2. Check that raw queries and aggregates use the same time basis, units, and NULL policy. 3. Compare results after corrections, deletion, and reingestion, including effects on related rows and aggregates. 4. Distinguish data that must survive restart from state that must be recreated, and verify the recovery sequence. 5. Increase ingestion rate, query range, and concurrency while measuring throughput, latency, and storage. Design for input failures, applications using old schemas, and restart recovery alongside the normal workflow. Before evolving a schema, inspect existing data and dependencies in views, ROLLUPs, and clients. When needed, migrate to a new table, validate it, and then switch over. Continue with the [Table Usage Chapters](/dbms/) and [Development and Application Integration](/dbms/development-tools-integration/) for implementation, and [Performance Tuning](/dbms/performance-tuning/) for measurement. --- title: "4.1 Choose a Table Type" url: https://docs.machbase.com/dbms/data-modeling-table-design/table-types-selection-type/ language: en kind: page --- # 4.1 Choose a Table Type Choose a table type that matches the data early in design. An unsuitable type can reduce performance and limit required functionality. - **[Selection Guide](/dbms/data-modeling-table-design/table-types-selection-type/#selection-decision)** - **[Type Comparison](/dbms/data-modeling-table-design/table-types-selection-type/#comparison-tag-log-rdb-volatile-lookup)** - **[TRANSACTION vs LOOKUP](/dbms/data-modeling-table-design/table-types-selection-type/#comparison-rdb-vs-lookup)** For table roles and storage concepts, see [Data Model Concepts](../../core-concepts/concepts/#time-series). The same data can need different types depending on whether you accumulate history or update current state. Review mutation, query, and persistence requirements together. ### Describe the data before selecting a type Before naming a table, describe the fact represented by one row in a sentence. Even for the same equipment, one temperature reading, one current operating state, and one maintenance job have different row semantics, keys, and update patterns. | Design question | Equipment monitoring decision | |---|---| | What does one row represent? | One sensor reading or an equipment's current state | | How is it found? | Sensor name and event time, equipment ID, or maintenance job number | | How do values change? | Append history, correct errors, or overwrite current rows | | Must changes commit together? | Whether job registration and part quantity changes share a transaction | | How long is it retained? | Raw and aggregate retention periods; whether state is rebuildable after restart | | What is the scale? | Tag count, rows/s, row size, memory used by reference data and indexes | For example, consider TAG for temperature history, LOG for alarms, and LOOKUP for equipment code tables. If inventory changes and job registration must commit together, consider TRANSACTION in Standard Edition. A current-state cache can use VOLATILE if it is rebuildable from source data. Align row semantics and failure recovery before combining these records in one table. ## Selection guide Use the following flow to narrow candidates, then verify DML, transactions, memory usage, and edition support in the comparison tables. Even reference data may need TRANSACTION instead of LOOKUP when multiple changes must share one transaction. ### Decision flow ```text Is the data sensor/device measurements? ├── YES → Time axis? YES → TAG TABLE (BASETIME) │ Distance axis? YES → TAG TABLE (BASEDISTANCE) └── NO ↓ Is the data events/logs/packets? (append-only) ├── YES → LOG TABLE └── NO ↓ Is the data a code table/reference data? (repeated reads and updates) ├── YES → LOOKUP TABLE └── NO ↓ Is the data in-memory state/cache that can be discarded on server restart? ├── YES → VOLATILE TABLE └── NO ↓ General relational business data (UPDATE/DELETE/SELECT/INSERT all required) └── TRANSACTION TABLE ``` ### Key criteria | Question | Type | |------|------| | Time- or distance-based measurements? | TAG | | Append raw events and remove only older ranges? | LOG | | Reference data requiring a PRIMARY KEY and repeated reads/updates? | LOOKUP | | Can the data be lost on server restart? | VOLATILE | | General relational work (INSERT/UPDATE/DELETE/SELECT)? | TRANSACTION | ### Considerations - Using a unique tag name for every event causes continuing growth in tags and metadata. Consider LOG for events without recurring measurement targets. - LOG cannot UPDATE or DELETE with general predicates, so it is unsuitable for mutable data. Use retention-oriented `BEFORE`, `OLDEST`, or `EXCEPT` DELETE. - TRANSACTION is Standard Edition only. In Cluster Edition, consider LOOKUP for small datasets or an external RDBMS. - VOLATILE data is lost on server restart. ## Type comparison ### Feature comparison | Item | TAG | LOG | TRANSACTION | VOLATILE | LOOKUP | |------|-----|-----|-----|----------|--------| | DDL | `CREATE TAG TABLE` | `CREATE LOG TABLE` | `CREATE TABLE` / `CREATE TRANSACTION TABLE` / `CREATE TXN TABLE` | `CREATE VOLATILE TABLE` | `CREATE LOOKUP TABLE` | | Main use | Sensors and measurements | Events and logs | Relational business data | Temporary aggregates | Codes and reference data | | INSERT | Yes | Yes | Yes | Yes | Yes | | UPDATE | Yes (Standard, tag/BASETIME predicates) | No | Yes | Yes | Yes | | DELETE | Yes (BEFORE/predicates/all) | Yes (BEFORE/OLDEST/EXCEPT/all) | Yes | Yes (PK equality/all) | Yes (general predicates/all) | | PRIMARY KEY | Required | No | Optional | Optional | Required | | BASETIME | Required (time axis) | No | No | No | No | | _arrival_time | No | Added automatically | No | No | No | | Indexes | Tag/axis access, supported secondary indexes | BITMAP/KEYWORD/LSM | BTREE PK + secondary indexes | Key and secondary indexes | Key and secondary indexes | | Persistence | Yes | Yes | Yes | No (memory) | Yes | | Cluster Edition | Yes | Yes | No | Yes | Yes | Append API support depends on the SDK and ingestion path as well as the table type. Check your driver/table combination in the [SDK Append Matrix](../../development-tools-integration/sdk-support-scope/#append-table-type-matrix). ### Storage characteristics | Item | TAG | LOG | TRANSACTION | VOLATILE | LOOKUP | |------|-----|-----|-----|----------|--------| | Storage | Columnar | Columnar | Row-oriented (relational) | In memory | Persistent storage + all rows resident in memory | | Capacity criteria | Tags, raw data, ROLLUP, retention | Raw data, search indexes, retention | Rows, indexes, transaction load | Memory for all rows and indexes | Memory for all rows and indexes; reload time after restart | Small in-memory tables do not have a fixed row-count definition. Measure actual memory including row width, variable-length values, and secondary indexes. Compression ratios and server specifications alone cannot guarantee disk-table throughput either; run representative ingestion and queries together. ### TRANSACTION table restrictions TRANSACTION tables have these restrictions: - **No Cluster Edition support:** Standard Edition only. - **Minimum columns:** At least one. ## TRANSACTION vs LOOKUP TRANSACTION and LOOKUP both store relational data, but differ in target scale and features. ### Comparison | Item | TRANSACTION | LOOKUP | |------|-----------|--------------| | DDL | `CREATE TRANSACTION TABLE` | `CREATE LOOKUP TABLE` | | PRIMARY KEY | Optional | Required | | INSERT | Yes | Yes | | UPDATE (with WHERE) | Yes | Yes | | UPDATE (without WHERE) | Yes (all rows) | No | | DELETE | Yes | Yes | | Explicit transactions | Control multiple statements with COMMIT/ROLLBACK | Does not participate; changes are per statement | | Indexes | BTREE PK + secondary indexes | In-memory key and secondary indexes | | Data scale | Validate disk capacity and transaction load | Validate reference-data read/update load | | JOIN target | Yes | Yes | | Cluster Edition | No | Yes | ### Selection criteria **Choose TRANSACTION for:** - Data requiring explicit transactions and relational DML - General relational workloads requiring UPDATE, DELETE, INSERT, and SELECT - Queries on varied column combinations without a PRIMARY KEY - Standard Edition environments **Choose LOOKUP for:** - Code tables and reference data - PRIMARY KEY lookups and single-row UPDATE/DELETE - Use in Cluster Edition - Real-time reference-data updates ### Example ```sql -- LOOKUP: country codes (PK lookup and predicate-based UPDATE) CREATE LOOKUP TABLE country_code ( code VARCHAR(4) PRIMARY KEY, name VARCHAR(64) ); INSERT INTO country_code VALUES ('KR', 'Republic of Korea'); UPDATE country_code SET name = 'Korea' WHERE code = 'KR'; SELECT code, name FROM country_code WHERE code = 'KR'; -- TRANSACTION: order history (large scale, general UPDATE/DELETE) CREATE TRANSACTION TABLE order_history ( order_id LONG PRIMARY KEY, item_id INTEGER, qty INTEGER, amount DECIMAL(18,2) ); INSERT INTO order_history VALUES (12345, 501, 1, 12000.00); UPDATE order_history SET qty = 10 WHERE order_id = 12345; SELECT order_id, qty, amount FROM order_history WHERE order_id = 12345; DELETE FROM order_history WHERE order_id = 12345; SELECT COUNT(*) FROM order_history WHERE order_id = 12345; ``` The first SELECT returns the updated country name; the order SELECT returns quantity `10`. The final COUNT is `0`. Here, `amount` is an illustrative value maintained separately from quantity and is not recalculated automatically. In an actual order model, define the relationship among unit price, quantity, and total, and which columns change together. When finished, use `DROP TABLE` to remove only the tables created in this example. --- title: "4.2 Schema Object Definitions" url: https://docs.machbase.com/dbms/data-modeling-table-design/schema-objects-definition/ language: en kind: page --- # 4.2 Schema Object Definitions This page covers decisions for designing tables, columns, indexes, and views. Use the [SQL Syntax Reference](/dbms/reference/sql/syntax/) as the authoritative source for syntax and options rather than duplicating them here. - **[Create and drop tables](#create-delete)** - **[Alter tables](#alter)** - **[Choose columns and data types](#selection-type-column-data-types)** - **[Constraints and defaults](#constraints-defaults-condition)** - **[Index design](#index-create-delete)** - **[View design](#create-view)** ## Create and drop tables First complete [Table Type Selection](../table-types-selection-type/). Then define table names, columns, keys, constraints, indexes, and views for the selected type. ### Row granularity and column roles Keep row granularity consistent within a table. Mixing daily equipment summaries and second-level raw data as equivalent rows makes `COUNT` and `AVG` hard to interpret. Define clear row granularity and query names for raw data and aggregates separately. | Column role | Example | Design principle | |---|---|---| | Target identity | `sensor_id`, `equipment_id` | Use stable values separate from display names | | Event timing | `measured_at`, `event_time` | Specify whether this is event time or arrival time | | Measurement | `temperature_c`, `pressure_kpa` | Define units, valid ranges, and correction methods | | Quality | `quality_code` | Distinguish missing values, measurement failures, and valid zero | | Reference attributes | Location, equipment type | Decide between tag metadata and a separate reference table | An existing business identifier, such as an external equipment code, is a natural key; a separately assigned number is a surrogate key. If codes can change or be reused by different sources, define their identity scope or consider a surrogate key. An auto-increment number provides generation order; it does not automatically guarantee event time or duplicate-free ingestion. A TAG name identifies a tag, not an individual measurement row. Use table names that begin with a letter and contain letters, digits, and underscores. Avoid reserved words and names that resemble system objects. Before dropping a table, check dependent views, indexes, ROLLUPs, and retention policies. For creation examples by type, see: - [Create TAG Tables](/dbms/tag-table-usage/create-alter-drop/) - [Create LOG Tables](/dbms/log-table-usage/create-alter-drop/) - [TRANSACTION Tables](/dbms/rdb-table-usage/) - [LOOKUP Tables](/dbms/lookup-table-usage/) - [VOLATILE Tables](/dbms/volatile-table-usage/) ## Alter tables Support for adding, dropping, renaming, and changing column types depends on the table type and whether data exists. Before changing a production table, proceed in this order: 1. Check that the edition and table type support the intended `ALTER TABLE` operation. 2. Check dependencies on existing data, indexes, views, and application column order. 3. Measure execution time and locking effects with production-equivalent schemas and data volume. 4. If rollback is difficult, create a new table, validate it, and then switch over. After adding a column, query both existing and newly inserted rows to check NULL and DEFAULT behavior. Not all table types backfill existing rows with DEFAULT. Existing VOLATILE rows and automatically registered TAG metadata rows, for example, have separate rules. Check the actual type's DDL contract, including [ARRAY DEFAULT Rules](/dbms/reference/sql/types/array/#default와-기존-row). Also define application deployment and schema change order. Specify column lists where the ingestion path supports them, and compare positional Append and binding code with the new schema. For migration to a new table, compare per-key counts, time ranges, NULL rates, and representative aggregates as well as total rows. Define how to prevent missing or duplicate rows arriving during the switch. For exact support and syntax, see the [ALTER TABLE Reference](/dbms/reference/sql/syntax/) and [Support by Table Type](/dbms/reference/support-scope-constraints/table-types-type/). ## Choose columns and data types Choose the smallest suitable type based on actual value ranges and operations. Distinguish display formats from storage types. | Data | Types to consider | Considerations | | --- | --- | --- | | Integer measurements and codes | `SHORT`, `INTEGER`, `LONG` families | Check reserved NULL values and ranges | | Floating-point measurements | `FLOAT`, `DOUBLE` | Check precision, aggregate error, and reserved NULL values | | Values requiring exact decimal arithmetic | `DECIMAL` | Define precision, scale, and rounding rules first | | Timestamps | `DATETIME` | Design representable ranges and time zones with client/session policies | | Short strings | `VARCHAR` | Check maximum length and encoding | | Long text | `TEXT` | Check table support, sorting/aggregation restrictions, and index cost | | Network addresses | `IPV4`, `IPV6` | Consider address types instead of strings | | Structured documents | `JSON` | Check size limits, column promotion criteria, and table support | | Binary data | `BINARY` | Variable or fixed length depends on table type | | Fixed-size numeric collections | Numeric `ARRAY` | Distinguish element type/length, element NULLs, and whole-array NULL | `VARCHAR(n)` measures bytes, which may differ from character counts for Korean text or emoji. Integer types reserve some boundary values for NULL, so do not assume general-purpose programming-language integer ranges. FLOAT and DOUBLE also recognize their positive maximum values as NULL. Valid ranges and operation semantics take priority over choosing a small type. ### Exact decimal values: DECIMAL Use `DECIMAL` when decimal accuracy matters, such as monetary amounts, tax rates, and settlement values. Use `FLOAT` or `DOUBLE` for measurements that tolerate approximation and need a wide exponent range. The distinction is semantic, not just storage size: choose DECIMAL when rounded results directly drive business rules. Define the following first: | Decision | Rule | |---|---| | precision | Total significant digits, 1–65 | | scale | Fractional digits, 0–30; cannot exceed precision | | Omitted parameters | `DECIMAL` means `DECIMAL(10,0)`; `DECIMAL(M)` means `DECIMAL(M,0)` | Input with more fractional digits than scale is rounded to the nearest value, with ties away from zero. Rounding is final at storage time, so verify that it matches business rules. Values exceeding precision produce an error rather than being truncated or converted to floating point. Allow sufficient digits. `SUM`, `AVG`, `MIN`, `MAX`, `GROUP BY`, `ORDER BY`, and `DISTINCT` use exact processing. Operations without an exact DECIMAL path, such as percentiles or advanced statistics, convert to DOUBLE and return approximate results. Distinguish exact aggregates from informational statistics. Passing a value through floating point in the application loses accuracy regardless of the storage type. Use decimal representations or strings: JDBC `BigDecimal`, Python `decimal.Decimal`, or ODBC `SQL_NUMERIC`. For declarations, indexes, and client mappings, see [DECIMAL and NUMERIC Fixed-Point Types](/dbms/reference/sql/types/decimal-numeric-fixed-point/). ### Structured documents: JSON Use `JSON` for supplementary attributes whose keys vary by source or grow over time; fields can be added without schema changes. Promote values frequently used in `WHERE` or `GROUP BY` to separate columns. JSON columns cannot be primary keys, and LOOKUP does not support JSON path indexes. Account for size limits: a document is at most 32,768 bytes, and a JSON path is at most 512 bytes. Use JSON for attributes needed by queries rather than entire raw payloads. | Table type | JSON column | Considerations | |---|:---:|---| | TAG, LOG, TRANSACTION | Yes | JSON functions and path queries supported | | LOOKUP | Yes | Supported as an ordinary column; JSON path indexes unsupported | | VOLATILE | No | JSON columns cannot be created | Use `->` and `JSON_EXTRACT_*` for queries, and the `JSON_SET` family for changes. Mutation functions are useful only when the table type supports `UPDATE`; for tables without row updates, such as LOG or TAG, construct the document at ingestion time. For function support, see [JSON Support by Table Type](/dbms/reference/sql/types/table-types-type-support-scope-json/). ### Restrictions to check before choosing a type | Type | Design considerations | |---|---| | `TEXT` | Supported only in LOG and Standard Edition TRANSACTION. LOG TEXT columns cannot be used in `ORDER BY` or `GROUP BY`, or converted to VARCHAR with `MODIFY COLUMN`. Store sortable or aggregatable values separately as VARCHAR or numeric columns. | | `BINARY` | LOG supports variable-length values up to 64MB; TAG uses fixed-length `BINARY(n)` of 1–32,767 bytes. LOOKUP and VOLATILE do not support it. | | `DATETIME` | Represents 1970-01-01 through 2262-04-11 with nanosecond precision. Do not use arbitrary far-future dates to mean expiration or no expiration. | | `ARRAY` | Fixed-length, one-dimensional numeric arrays with cardinality 1–1024. Distinguish whole-array NULL from element NULL. | For complete ranges and table support, use the [Data Type Reference](/dbms/reference/sql/types/). ## Constraints and defaults `PRIMARY KEY`, `NOT NULL`, and `DEFAULT` support differs by table type. A TAG `PRIMARY KEY` identifies a tag; LOOKUP, VOLATILE, and TRANSACTION `PRIMARY KEY` columns determine row identity and update access paths. NULL represents an unknown or absent value, unlike zero or an empty time range. Replacing measurement failures with DEFAULT 0 can distort averages and validity checks. `COUNT(*)` counts rows; `COUNT(value)` counts rows where that column is non-NULL. Distinguish them when reporting sample counts. Defaults define behavior for omitted inputs; they do not replace validation. Validate constraints unsupported by a table in ingestion or business applications. Do not assume support for constraints such as foreign keys merely because another DBMS provides them. Check [TRANSACTION Support](/dbms/reference/support-scope-constraints/rdb/). Do not use system columns such as `_ARRIVAL_TIME` or `_RID` as application business keys. Reference them only for documented query semantics, without depending on their storage structure or generation mechanism. ## Index design Indexes reduce query costs but add ingestion and storage costs. First list representative queries and check predicate selectivity, the proportion of matching rows. A monthly average across all equipment differs from a specific order lookup for one device. Instead of indexing every filter or join column, compare `EXPLAIN` and actual execution times, then retain useful indexes. - Do not start with extra indexes when tag and time-range access is sufficient for TAG queries. - For frequently filtered LOG columns, measure plans and selectivity before adding indexes. - Design LOOKUP, VOLATILE, and TRANSACTION indexes around key lookups and joins. - For word searches in long text, consider `KEYWORD` indexes supported by the table type. For creation/deletion syntax and supported types, see the [Index SQL Reference](/dbms/reference/sql/syntax/). ## View design A view names a reusable query but does not store its results. Avoid unintended fixed time ranges or unnecessary all-column reads in view definitions. Check dependent views before changing base tables or columns. Views can consistently expose frequently used columns and unit conversions. Creating a view alone does not copy data or reduce query cost. A view joining historical events to current reference data can change historical results when the reference data changes. For attributes as they were at event time, use versioned reference data or attributes recorded with the original event. For view creation, querying, deletion, and restrictions, see the [VIEW SQL Reference](/dbms/reference/sql/syntax/). --- title: "4.3 Data Mutation Policy" url: https://docs.machbase.com/dbms/data-modeling-table-design/alter-data-mutation-policy/ language: en kind: page --- # 4.3 Data Mutation Policy Support for `UPDATE`, `DELETE`, and `TRUNCATE` differs by table type. This page summarizes policies relevant to data model selection. Use the linked SQL references for exact syntax and restrictions. A mutation policy defines who may change which data and what can be rolled back on failure, not just whether a value is editable. Treat current-state updates, raw measurement corrections, schema changes, and retention-based deletion as separate operations. ## Data mutation support by table type | Table type | UPDATE | DELETE | TRUNCATE | |------------|--------|--------|----------| | TAG | DATA correction in Standard: requires tag selection and BASETIME predicates | `BEFORE`, tag/axis predicates, or all rows | No | | LOG | No | `BEFORE`, `OLDEST`, `EXCEPT`, or all rows | Yes | | TRANSACTION | Yes | Yes | Yes | | VOLATILE | Primary-key predicate | Primary-key predicate or all rows | No | | LOOKUP | General predicates; cannot change the PK | General predicates or all rows | No | LOG tables are designed to preserve ingested events without updating them. Store frequently modified state or configuration in VOLATILE, LOOKUP, or TRANSACTION tables. ## Mutation units and failure handling | Operation | Design decision | |---|---| | Update current settings | Key, allowed values, and concurrent-writer handling | | Correct inaccurate measurements | Tag/time range, reason, and ROLLUP recalculation | | Correct a LOG event | Whether to retain the original and link a correction event | | Replace a reference key | Reference migration order and intermediate failure handling | | Delete a period | Retention cutoff, deletion scope, and required backups | Multiple TRANSACTION DML statements can share an explicit transaction. Do not assume LOOKUP or VOLATILE changes or LOG or TAG ingestion participate in that transaction. For example, TAG history may remain after a subsequent VOLATILE cache update fails. Prepare cache rebuilding or retry procedures. Append transaction participation depends on the API and target type; check [SDK Support Scope](/dbms/development-tools-integration/sdk-support-scope/). Before changing multiple rows, query the count and representative rows with the same predicates. This precheck does not lock rows or fix the later mutation scope. With concurrent ingestion or updates, also control the operation window and target range. Verify the affected row count and resulting values afterward. ## UPDATE policy ### TRANSACTION, VOLATILE, LOOKUP - TRANSACTION supports general relational `UPDATE` and transactions. - VOLATILE selects targets through primary-key equality predicates. - LOOKUP supports general predicates, but its primary-key column cannot be changed. LOOKUP UPDATE requires a WHERE clause. Changing a LOOKUP or VOLATILE primary key requires separate delete and insert statements. First define how to preserve the original and switch references. If both statements must be rolled back together, consider TRANSACTION. For supported LOOKUP predicates and expressions, see [LOOKUP Predicate UPDATE](/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-update-syntax/). ### TAG data UPDATE TAG time-series data and metadata use different update syntax. | Target | Syntax | Key restriction | |------|------|-----------| | Time-series data | `UPDATE tag_table SET ... WHERE ...` | Requires both tag selection and BASETIME predicates | | Metadata | `UPDATE tag_table METADATA SET ...` | Uses TAG-specific metadata syntax | TAG data UPDATE is supported on logical TAG tables in Standard Edition. Tag names, BASETIME, and metadata columns cannot be SET targets. If materialized rollups cover the changed range, regenerate them with `ROLLUP_REBUILD`. The right-hand side of TAG DATA `SET` cannot reference existing row columns. Do not apply corrections with expressions such as `SET value = value + 1`. Pass calculated values as constants or parameters and limit the affected range. If correction history is required, store before/after values and reasons separately rather than only overwriting the current value. The following references define syntax and allowed expressions: - [TAG Data UPDATE](/dbms/reference/sql/syntax/dml-syntax/tag-data-update-syntax/) - [TAG Data UPDATE WHERE/SET Constraints](/dbms/reference/sql/syntax/dml-syntax/tag-data-update-where-set-constraints/) - [TAG Metadata](/dbms/tag-table-usage/tag-metadata/) LOG tables do not support `UPDATE`. ## DELETE policy ### TRANSACTION, VOLATILE, LOOKUP - TRANSACTION supports deletion with general `WHERE` predicates. - VOLATILE supports primary-key deletion or deletion of all rows without a predicate. - LOOKUP supports general predicates or deletion of all rows without `WHERE`. For supported LOOKUP predicates, see [LOOKUP Predicate DELETE](/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-delete-syntax/). ### LOG LOG uses retention-oriented deletion syntax instead of arbitrary `WHERE` predicates. Choose `OLDEST`, `EXCEPT`, `BEFORE`, or deletion of all rows according to the purpose. For exact syntax and examples, see [LOG Data Lifecycle](/dbms/log-table-usage/operations-lifecycle/). ### TAG/KV TAG/KV can remove old data with `BEFORE` or select targets through tag names and axis predicates. The `BEFORE` timestamp must be earlier than the current time. For syntax, see [TAG Data Mutation](/dbms/tag-table-usage/data-input-mutation/). For recurring retention-based deletion, use a [Retention Policy](/dbms/operations-configuration-recovery/policy-data-retention/). ### TAG metadata Delete TAG metadata with `DELETE FROM table_name METADATA`. If any selected tag still has actual data, the entire statement fails. For detailed conditions, see [TAG Metadata](/dbms/tag-table-usage/tag-metadata/). ## TRUNCATE policy `TRUNCATE TABLE` is supported only for LOG and TRANSACTION. It removes all rows while retaining the schema and index definitions. | Item | TRUNCATE | DELETE | |------|----------|--------| | Target | Entire table | All rows or selected rows, depending on type | | `WHERE` | Not allowed | Allowed within the supported scope | | TRANSACTION rollback | Possible in an explicit transaction | Possible in an explicit transaction | Before deletion, check backups and reingestion paths. For TAG, use supported `BEFORE` or tag/axis predicates. To clear VOLATILE or LOOKUP, use `DELETE` without predicates. Do not apply TRANSACTION rollback guarantees to LOG deletion. Later ROLLBACK cannot undo committed changes. Logical deletion and physical disk reclamation may occur at different times; check storage usage and the table's reclamation state. --- title: "4.4 Anti-Patterns" url: https://docs.machbase.com/dbms/data-modeling-table-design/table-types-patterns-type-anti/ language: en kind: page --- # 4.4 Anti-Patterns An anti-pattern is a use that conflicts with data semantics and requirements, not simply the choice of a particular table type. Check whether each example's assumptions apply to your workload before choosing an alternative. The same schema may suit current state but not history. - **[Unbounded History in LOOKUP](/dbms/data-modeling-table-design/table-types-patterns-type-anti/#high-frequency-lookup)** - **[One Table per Sensor](/dbms/data-modeling-table-design/table-types-patterns-type-anti/#per-sensor-create)** - **[Incorrect Table Type](/dbms/data-modeling-table-design/table-types-patterns-type-anti/#table-types-selection-type-wrong)** - **[VOLATILE as Persistent Storage](/dbms/data-modeling-table-design/table-types-patterns-type-anti/#storage-persistent-volatile)** - **[Misusing TRANSACTION for Time Series](/dbms/data-modeling-table-design/table-types-patterns-type-anti/#time-series-storage-misuse-rdb)** ## Unbounded history in LOOKUP ### Problem The issue is not query frequency itself, but storing continuously growing measurement history in LOOKUP. LOOKUP keeps all rows and indexes in memory, so long-term history increases memory pressure. It suits repeated key lookups on small reference datasets. ### Anti-pattern example ```sql -- Incorrect design: sensor measurements in LOOKUP CREATE LOOKUP TABLE sensor_data_wrong ( sensor_id VARCHAR(64) PRIMARY KEY, value DOUBLE, ts DATETIME ); -- sensor_id is the PK, so this schema holds only one current row per sensor -- Appending history with the same PK causes a conflict INSERT INTO sensor_data_wrong VALUES ('TEMP-01', 25.3, NOW); INSERT INTO sensor_data_wrong VALUES ('TEMP-01', 25.5, NOW); -- Duplicate PK error ``` ### Correct pattern Consider TAG when collection and querying focus on per-tag measurement history. LOOKUP can assign a distinct key to each measurement, but all history still resides in memory. Add a VOLATILE latest-value cache only when performance requires it and it is rebuildable from raw data. If TAG latest-value queries meet the requirement, no separate cache is needed. ```sql -- Correct design: history in TAG CREATE TAG TABLE sensor_data ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); -- Latest-value cache in VOLATILE CREATE VOLATILE TABLE sensor_latest ( sensor_id VARCHAR(64) PRIMARY KEY, value DOUBLE, updated_at DATETIME ); ``` ### Result | | Anti-pattern (LOOKUP) | Correct design (TAG) | |-|-----------------|-----------------| | History under the same sensor key | No (the sample sensor key identifies a row) | Yes (multiple measurements under a tag name) | | Continuous ingestion path | Row-identifier based | Time-series Append API available | | Time-range queries | General predicates | Tag/time-axis queries | ## One table per sensor ### Problem Creating a separate table for each sensor or tag increases DDL, privileges, and query targets as sensor counts grow, raising operational costs. ### Anti-pattern example ```sql -- Incorrect design: one table per sensor CREATE TAG TABLE sensor_temp_01 ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); CREATE TAG TABLE sensor_temp_02 ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); CREATE TAG TABLE sensor_temp_03 ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); -- ... 10,000 sensors require 10,000 tables ``` ### Consequences | Problem | Description | |------|------| | Management complexity | DDL management for every table | | Query complexity | Combining tables for cross-sensor aggregates | | Metadata growth | Increased system catalog load | | Adding a sensor | DDL required each time | ### Correct pattern Store all sensor data in one TAG table with sensor names as the PRIMARY KEY. This applies to sensors sharing column structure, privileges, and retention policies. Separate tables may be appropriate when units, schemas, access privileges, or retention periods require independent management. Sensor count alone should not determine table separation. ```sql -- Correct design: all temperature sensors in one table CREATE TAG TABLE temperature_sensor ( name VARCHAR(128) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); -- Insert all sensor data into one table INSERT INTO temperature_sensor VALUES ('TEMP-01', NOW, 23.5); INSERT INTO temperature_sensor VALUES ('TEMP-02', NOW, 24.1); INSERT INTO temperature_sensor VALUES ('TEMP-10000', NOW, 22.9); ``` ### Benefits - No DDL for new sensors; INSERT with a new tag name is sufficient. - Simpler cross-sensor aggregation. - Fewer objects to operate and manage. ## Incorrect table type The following common anti-patterns select table types that do not match data characteristics. ### Anti-pattern 1: Event logs in TAG ```sql -- Incorrect: event logs in TAG CREATE TAG TABLE error_log_wrong ( name VARCHAR(256) PRIMARY KEY, -- Event content becomes the tag name time DATETIME BASETIME, level SHORT ); -- Problem: a unique name per event causes unbounded tag growth ``` **Correct design:** Use a LOG table. ```sql CREATE LOG TABLE error_log ( level SHORT, msg VARCHAR(512), src VARCHAR(128) ); ``` ### Anti-pattern 2: Sensor values in LOG Storing sensor values in LOG is not inherently wrong. The problem below is omitting actual measurement time when queries require per-tag measurement-time aggregates, leaving only arrival time. LOG can suit searches on multi-field equipment events. ```sql -- Insufficient schema when measurement time is required CREATE LOG TABLE sensor_wrong ( sensor_id VARCHAR(64), value DOUBLE -- No measurement time; only server arrival time is recorded automatically ); ``` **Correct design:** Use a TAG table. ```sql CREATE TAG TABLE sensor_measurements ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); ``` ### Anti-pattern 3: Large histories in LOOKUP ```sql -- Incorrect: order history requiring relational transactions in LOOKUP CREATE LOOKUP TABLE order_history_wrong ( order_id LONG PRIMARY KEY, customer VARCHAR(64) -- Check memory for all rows/indexes and explicit transaction requirements ); ``` **Correct design:** Use a TRANSACTION table. ```sql CREATE TRANSACTION TABLE order_history ( order_id LONG, customer VARCHAR(64), item_id INTEGER, amount DOUBLE, status VARCHAR(16) ); -- UPDATE/DELETE/SELECT are all supported UPDATE order_history SET status = 'SHIPPED' WHERE order_id = 1001; ``` ### Anti-pattern 4: Time-series data in TRANSACTION TRANSACTION supports time columns and an Append API, but not TAG-specific time-axis storage or ROLLUP. Consider TAG when measurement collection and aggregation matter more than relational changes. See [Misusing TRANSACTION for Time Series](/dbms/data-modeling-table-design/table-types-patterns-type-anti/#time-series-storage-misuse-rdb). ## VOLATILE as persistent storage ### Problem This pattern stores data requiring permanent retention in VOLATILE. ### Anti-pattern example ```sql -- Incorrect: critical configuration in VOLATILE CREATE VOLATILE TABLE critical_config ( key_name VARCHAR(64) PRIMARY KEY, value VARCHAR(256) ); INSERT INTO critical_config VALUES ('license_key', 'XXXX-XXXX-XXXX'); INSERT INTO critical_config VALUES ('max_connections', '1000'); -- All settings disappear on server restart! ``` ### Consequences - The table and data disappear when the server stops or restarts. - A failure that terminates the server process also prevents recovery of in-memory data. Keeping the only source in VOLATILE therefore risks data loss. ### Correct pattern Store data requiring permanent retention in LOOKUP or TRANSACTION. ```sql -- Correct: configuration in LOOKUP CREATE LOOKUP TABLE app_config ( key_name VARCHAR(64) PRIMARY KEY, value VARCHAR(256) ); INSERT INTO app_config VALUES ('max_connections', '1000'); -- Data remains after server restart ``` ### Appropriate VOLATILE uses Use VOLATILE for data that can be recreated or discarded after restart. This includes task state with a defined lifetime as well as query caches. Do not keep required business results only in memory. | Suitable | Unsuitable | |------|--------| | Latest sensor value cache | Source transaction data | | Real-time aggregate results | Critical configuration | | Temporary session state | Audit logs | | Dashboard cache | User information | ## Misusing TRANSACTION for time series ### Problem This pattern stores continuous time-series data, such as sensor or IoT measurements, in TRANSACTION. If relational updates are unnecessary, the lack of TAG/time-axis access and ROLLUP may conflict with query and operational requirements. Conversely, TRANSACTION is justified when measurement registration must share a transaction with other business changes. ### Anti-pattern example ```sql -- Incorrect: sensor time series in TRANSACTION CREATE TRANSACTION TABLE sensor_timeseries ( sensor_id VARCHAR(64), ts DATETIME, value DOUBLE, unit VARCHAR(16) ); ``` ### Consequences | Problem | Description | |------|------| | Ingestion semantics mismatch | Relational writes for values that do not require relational transactions | | No TAG time axis | Cannot use TAG's BASETIME-based query structure | | Different aggregation features | Cannot use TAG-specific ROLLUP | ### Correct pattern Store sensor measurements in a TAG table. ```sql -- Correct: use TAG CREATE TAG TABLE sensor_history ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, unit VARCHAR(16) ); -- Bulk ingestion through high-speed Append API buffers -- Time-based aggregation and TAG-specific optimizations available SELECT name, DATE_TRUNC('hour', time, 1) AS hour, AVG(value), MAX(value) FROM sensor_history WHERE time >= NOW - 86400000000000 GROUP BY name, hour; ``` ### When TRANSACTION is appropriate Use TRANSACTION for relational business data such as orders, inventory, and equipment history. Even with time columns, business history requiring UPDATE/DELETE suits TRANSACTION; high-frequency measurements that accumulate without updates suit TAG. ## Aggregating values with different meanings Identical schemas do not make values with different units or row semantics directly aggregatable. Average cumulative energy (kWh) is not power consumption (kW), and an unweighted average of interval averages may differ from the overall sample average. Replacing NULL with zero turns measurement failures into valid zeros. Record units, sample counts, and quality rules alongside type selection. When reaggregating interval statistics, retain required components such as sums and valid counts. Before deleting raw data, check the resolution needed for future analysis. --- title: "4.5 Modeling Patterns" url: https://docs.machbase.com/dbms/data-modeling-table-design/patterns-modeling/ language: en kind: page --- # 4.5 Modeling Patterns This page covers data modeling patterns commonly used in production. Each section's SQL demonstrates a different model. Choose the relevant section and run it in a separate practice environment after checking for existing tables with the same names. Creating schemas does not automatically run collection, aggregation, or cache updates. Also design the work performed by ingestion applications or schedulers and its failure handling. - **[Time-Axis Modeling](/dbms/data-modeling-table-design/patterns-modeling/#time-axis-modeling)** - **[Distance-Axis Modeling](/dbms/data-modeling-table-design/patterns-modeling/#distance-axis-modeling)** - **[State and Cache Modeling](/dbms/data-modeling-table-design/patterns-modeling/#state-cache-status-modeling)** - **[Event and Log Modeling](/dbms/data-modeling-table-design/patterns-modeling/#event-log-modeling-logs)** - **[Reference and Master Data](/dbms/data-modeling-table-design/patterns-modeling/#reference-master-modeling)** - **[Persistent and Temporary Data](/dbms/data-modeling-table-design/patterns-modeling/#persistent-temporary)** - **[INSERT and UPDATE Patterns](/dbms/data-modeling-table-design/patterns-modeling/#insert-update)** - **[JOIN and Metadata Design](/dbms/data-modeling-table-design/patterns-modeling/#join-metadata-design)** - **[Combined Table Types](/dbms/data-modeling-table-design/patterns-modeling/#table-types-patterns-combined-type)** ## Time-axis modeling This pattern uses time as the primary axis and suits sensor measurements, energy monitoring, and environmental data. One row represents one observation from one meter. Define `time` as measurement time, not arrival time, and document whether `kwh` is a cumulative reading or interval consumption. The following schema assumes voltage and current belong to the same observation. If their measurement intervals or timestamps differ, store separate series or define missing-value rules instead of forcing them into one row. ### Basic pattern: TAG table ```sql CREATE TAG TABLE power_meter ( meter_id VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, kwh DOUBLE, voltage DOUBLE, current DOUBLE ) METADATA ( location VARCHAR(64), phase SHORT, rating_kw DOUBLE ); ``` ### Time-range aggregation ```sql -- Hourly average and maximum meter readings (last 24 hours) SELECT meter_id, DATE_TRUNC('hour', time, 1) AS hour, AVG(kwh) AS avg_kwh, MAX(kwh) AS peak_kwh FROM power_meter WHERE time >= NOW - 86400000000000 GROUP BY meter_id, hour ORDER BY meter_id, hour; ``` If `kwh` is cumulative energy, this average is the mean meter reading, not hourly consumption. Calculate interval consumption from the difference between start and end readings, accounting for meter resets, replacement, and rollover. Also distinguish power (kW) from energy (kWh) in column names and units. ### Multiple-resolution storage Store high-resolution raw data and lower-resolution aggregates in separate tables. ```sql -- Raw data (second-level resolution) CREATE TAG TABLE power_raw ( meter_id VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, kwh DOUBLE ); -- One-minute aggregates (cached in VOLATILE or a separate TAG table) CREATE VOLATILE TABLE power_1min ( key_id VARCHAR(80) PRIMARY KEY, meter_id VARCHAR(32), ts DATETIME, avg_kwh DOUBLE, max_kwh DOUBLE ); ``` This DDL creates storage only. The application must assign `key_id` values in `power_1min` that uniquely identify each meter and interval, then populate aggregates. VOLATILE results disappear on restart, so do not use it for long-term aggregate retention. Keep statistics needed after raw-data deletion in persistent TAG tables or supported ROLLUPs, and check each retention policy. ### Time zone handling DATETIME represents an instant; connection time zones affect string input and output. To display Korean time, configure the client's time zone. Adding nine hours to a stored timestamp changes the instant itself rather than displaying the same instant in another time zone. ```sql -- Check the client time zone, then query the original timestamp SELECT meter_id, time, kwh FROM power_meter WHERE meter_id = 'MTR-001' AND time >= '2024-01-01 00:00:00'; ``` If input and connection time zones differ, align them before ingestion. For a JDBC `TIMEZONE` example, see [JDBC Connections](/dbms/development-tools-integration/jdbc/). ## Distance-axis modeling This pattern uses distance or position as the primary axis and suits pipeline inspection, road sensors, and laser scans. A distance axis is not another display format for time. Time-axis ROLLUP and retention rules cannot be applied unchanged. For repeated inspections of a pipe, define an inspection-run identifier or table separation rule so `pipe_id` does not mix runs. This example assumes one inspection of one pipe, with distance in m and thickness in mm. ### Basic pattern ```sql CREATE TAG TABLE pipeline_thickness ( pipe_id VARCHAR(32) PRIMARY KEY, distance DOUBLE BASEDISTANCE, -- Unit: meters thickness DOUBLE, temp DOUBLE ); ``` ### Query a range ```sql -- Query the 0–50 m range for a pipe SELECT pipe_id, distance, thickness FROM pipeline_thickness WHERE pipe_id = 'PIPE-A' AND distance BETWEEN 0.0 AND 50.0 ORDER BY distance; -- Query locations below the threshold SELECT pipe_id, distance, thickness FROM pipeline_thickness WHERE pipe_id = 'PIPE-A' AND thickness < 8.0 -- Thickness below 8 mm ORDER BY distance; ``` ### Distance-based aggregation ```sql -- Average thickness for each 10 m segment SELECT pipe_id, FLOOR(distance / 10.0) * 10 AS segment_start, AVG(thickness) AS avg_thickness, MIN(thickness) AS min_thickness FROM pipeline_thickness WHERE pipe_id = 'PIPE-A' GROUP BY pipe_id, FLOOR(distance / 10.0) * 10 ORDER BY segment_start; ``` ### Combine time and distance To manage inspection time and position together, add a distance column to a time-axis TAG table. ```sql -- Store a time axis with position information CREATE TAG TABLE inspection_data ( inspector VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, distance DOUBLE, -- Position column, not an axis thickness DOUBLE, defect SHORT ); -- Query a specific date and distance range SELECT inspector, time, distance, thickness FROM inspection_data WHERE inspector = 'INSPECTOR-01' AND time BETWEEN '2024-01-01' AND '2024-01-02' AND distance BETWEEN 100.0 AND 200.0 ORDER BY time; ``` ## State and cache modeling This cache pattern supports real-time queries of current device or sensor state. ### Latest-state cache Cache each device's current state in a VOLATILE table. ```sql -- State cache (VOLATILE) CREATE VOLATILE TABLE device_status ( device_id VARCHAR(64) PRIMARY KEY, status VARCHAR(16), value DOUBLE, updated_at DATETIME ); -- State history (TAG or LOG) CREATE TAG TABLE device_status_history ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, status VARCHAR(16) ); ``` ### State update flow The following SQL updates history and cache separately. The two writes are not one transaction, and their separately evaluated `NOW` values need not match. In actual ingestion, choose the measurement timestamp once and pass it to both paths. Define event ordering and concurrent update handling in the application so late historical values do not overwrite the latest cache. ```sql -- On receiving a new measurement: -- 1. Store history in TAG INSERT INTO device_status_history VALUES ('DEV-01', NOW, 78.5, 'WARNING'); -- 2. Update the VOLATILE cache (ON DUPLICATE KEY UPDATE) INSERT INTO device_status VALUES ('DEV-01', 'WARNING', 78.5, NOW) ON DUPLICATE KEY UPDATE SET status = 'WARNING', value = 78.5, updated_at = NOW; ``` ### Dashboard queries ```sql -- All devices currently in an alarm state SELECT device_id, status, value, updated_at FROM device_status WHERE status IN ('ALARM', 'WARNING') ORDER BY updated_at DESC; -- Latest state of a specific device SELECT device_id, status, value, updated_at FROM device_status WHERE device_id = 'DEV-01'; ``` ### State definition reference Manage the meaning of state codes in LOOKUP. ```sql CREATE LOOKUP TABLE status_definition ( code VARCHAR(16) PRIMARY KEY, label VARCHAR(64), color VARCHAR(16), severity SHORT ); INSERT INTO status_definition VALUES ('NORMAL', 'Normal', 'green', 0); INSERT INTO status_definition VALUES ('WARNING', 'Warning', 'yellow', 1); INSERT INTO status_definition VALUES ('ALARM', 'Alarm', 'red', 2); -- Query with JOIN SELECT d.device_id, s.label, s.color, d.value FROM device_status d JOIN status_definition s ON d.status = s.code ORDER BY s.severity DESC; ``` ## Event and log modeling Use LOG tables to model system events, alarms, and audit logs. ### Hierarchical event model ```sql -- Alarm event LOG table CREATE LOG TABLE alarm_event ( severity SHORT, -- 1=INFO, 2=WARN, 3=ERROR, 4=CRITICAL category VARCHAR(32), -- Category source VARCHAR(64), -- Event source message VARCHAR(512), src_ip IPV4 -- Source IP, if available ); -- System audit LOG table CREATE LOG TABLE audit_log ( user_id VARCHAR(64), action VARCHAR(32), -- INSERT, UPDATE, DELETE, LOGIN, etc. target VARCHAR(128), -- Target table/resource detail TEXT, -- Details for full-text search result VARCHAR(8) -- SUCCESS, FAILURE ); CREATE INDEX idx_audit_detail ON audit_log(detail) INDEX_TYPE KEYWORD; ``` ### Alarm aggregation ```sql -- Alarm counts by severity over the last hour SELECT severity, COUNT(*) AS cnt FROM alarm_event WHERE _arrival_time >= NOW - 3600000000000 GROUP BY severity ORDER BY severity DESC; -- Alarm summary by source over the last 24 hours SELECT source, COUNT(*) AS total, SUM(CASE WHEN severity = 4 THEN 1 ELSE 0 END) AS critical_cnt FROM alarm_event WHERE _arrival_time >= NOW - 86400000000000 GROUP BY source ORDER BY total DESC; ``` ### Log level filtering ```sql -- ERROR or higher over the last 10 minutes SELECT _arrival_time, source, message FROM alarm_event WHERE severity >= 3 AND _arrival_time >= NOW - 600000000000 ORDER BY _arrival_time DESC LIMIT 100; ``` ### Full-text search ```sql -- Audit logs containing a keyword SELECT _arrival_time, user_id, action, target FROM audit_log WHERE detail SEARCH 'password' AND _arrival_time >= NOW - 86400000000000; ``` ## Reference and master data modeling Use LOOKUP for reference data such as code tables, equipment master data, and user information. Storing only identifiers in history avoids repeating names and locations. However, changing a location in current master data also changes joined historical results. If the production line at event time matters, model separate change history with validity periods or record those attributes in the original row. The following hierarchy does not automatically enforce references through foreign keys; applications must reject nonexistent factory and line codes. ### Hierarchical code system ```sql -- Main category codes CREATE LOOKUP TABLE category_main ( code VARCHAR(8) PRIMARY KEY, label VARCHAR(64) ); -- Subcategory codes (reference main category) CREATE LOOKUP TABLE category_sub ( code VARCHAR(16) PRIMARY KEY, main_code VARCHAR(8), label VARCHAR(64) ); CREATE INDEX idx_sub_main ON category_sub(main_code); ``` ### Equipment master hierarchy ```sql -- Factory master CREATE LOOKUP TABLE factory ( factory_id VARCHAR(16) PRIMARY KEY, name VARCHAR(64), location VARCHAR(128) ); -- Production line master (references factory) CREATE LOOKUP TABLE production_line ( line_id VARCHAR(16) PRIMARY KEY, factory_id VARCHAR(16), name VARCHAR(64) ); -- Equipment master (references production line) CREATE LOOKUP TABLE equipment ( equip_id VARCHAR(32) PRIMARY KEY, line_id VARCHAR(16), equip_name VARCHAR(128), equip_type VARCHAR(32), install_dt DATETIME ); CREATE INDEX idx_equip_line ON equipment(line_id); CREATE INDEX idx_equip_type ON equipment(equip_type); ``` ### Master data joins Store equipment identifiers in the measurement table and attributes such as factory, line, and equipment names once in LOOKUP tables. First restrict the measurement time range, then join LOOKUP tables by equipment identifier. For join syntax and plan inspection, see [JOIN and Subqueries](/dbms/tag-table-usage/query-analysis/). ## Combine persistent and temporary data Keep authoritative data in persistent tables (TAG, LOG, TRANSACTION, LOOKUP) and query caches in VOLATILE. Do not assume the two writes share one transaction. Design for cache lag and reconstruction after failure. ### Raw data and aggregate cache Store raw data in a persistent table and aggregate results in VOLATILE. ```sql -- Raw data (persistent TAG) CREATE TAG TABLE sensor_data ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); -- Aggregate cache (temporary VOLATILE) CREATE VOLATILE TABLE sensor_recent_avg ( key_id VARCHAR(64) PRIMARY KEY, sensor_id VARCHAR(64), base_ts DATETIME, avg_val DOUBLE, max_val DOUBLE, cnt LONG ); ``` ### Cache refresh One cache row holds a sensor's last two hours of statistics. `base_ts` is the latest included measurement timestamp, not the aggregation window boundary. Use the same range definition each time. For results at an identical instant, choose one reference timestamp per execution. The example excludes future measurements. When comparing results, replace each SQL's `NOW` with the same fixed reference timestamp to calculate both lower and upper bounds. ```sql -- Periodic aggregate refresh (run hourly) DELETE FROM sensor_recent_avg; INSERT INTO sensor_recent_avg SELECT name AS key_id, name, MAX(time) AS base_ts, AVG(value), MAX(value), COUNT(*) FROM sensor_data WHERE time >= NOW - 3600000000000 * 2 -- Recalculate the last two hours AND time <= NOW GROUP BY name; ``` Do not append `ON DUPLICATE KEY UPDATE` to `INSERT ... SELECT`. Rebuild the cache by deleting its contents and loading it again. Between deletion and reload, other queries may see an empty or partially populated cache. Define application behavior during refresh, retries after failure, and fallback to raw-data queries. If a consistently complete result is required, consider a separate switchover or transaction model that provides it. ### Optimize dashboard queries ```sql -- Query the stored cache (the application handles fallback to raw data) SELECT sensor_id, base_ts, avg_val, max_val FROM sensor_recent_avg WHERE base_ts >= NOW - 3600000000000 * 2 AND base_ts <= NOW ORDER BY sensor_id, base_ts; ``` This predicate displays cache rows whose latest measurement is within the last two hours. It does not recalculate stored averages relative to query time. Manage aggregate freshness through the refresh interval. ### Failure recovery If a server restart removes the VOLATILE table and cache, first recreate the table, then recalculate the same last-two-hour statistics from TAG. Run the following CREATE only after a restart in which the table disappeared. The source retention period must still include the data needed for recalculation. ```sql -- Rebuild the cache after server restart CREATE VOLATILE TABLE sensor_recent_avg ( key_id VARCHAR(64) PRIMARY KEY, sensor_id VARCHAR(64), base_ts DATETIME, avg_val DOUBLE, max_val DOUBLE, cnt LONG ); INSERT INTO sensor_recent_avg SELECT name, name, MAX(time), AVG(value), MAX(value), COUNT(*) FROM sensor_data WHERE time >= NOW - 3600000000000 * 2 -- Same last-two-hour range as normal refresh AND time <= NOW GROUP BY name; ``` After recovery, compare per-sensor counts, averages, and latest timestamps with raw-data aggregates at the same reference time. `cnt` includes rows with NULL measurements. Store `COUNT(value)` separately if the sample count used for the average is needed. ## INSERT and UPDATE patterns The model must decide which data can change. This page does not redefine the DML support matrix. Use [Data Mutation Policy](../alter-data-mutation-policy/) for table-specific conditions and [Data Input and Export](/dbms/development-tools-integration/data-input-load-export/) to choose INSERT, Append, or file ingestion. ## JOIN and metadata design Apply these principles when combining table types. First define join cardinality. Check whether each sensor code has exactly one master row or is reused across factories. If one source row matches several reference rows, result counts and aggregates such as SUM can be duplicated. Match identity scope and types, not just code names. 1. Review join order using filtered row counts and execution plans, not only raw row counts. 2. Match JOIN column types and check supported index usage. 3. Reduce joined rows with explicit time ranges and business predicates in WHERE. 4. For queries that include TAG attributes, consider METADATA instead of separate LOOKUP tables. For reproducible join examples, see [TAG Queries and Analysis](/dbms/tag-table-usage/query-analysis/) and [LOOKUP Queries and Analysis](/dbms/lookup-table-usage/query-analysis/). ## Combined table types These common designs combine multiple table types in production systems. ### Manufacturing equipment monitoring ```text ┌───────────────────────────────────────────────────────────────┐ │ Equipment monitoring system │ ├───────────────────┬───────────────────┬───────────────────────┤ │ TAG │ LOG │ LOOKUP │ │ sensor_data │ alarm_event │ equipment_master │ │ Measurement │ Alarm events │ Equipment reference │ │ history │ │ data │ ├───────────────────┴───────────────────┴───────────────────────┤ │ VOLATILE │ │ sensor_latest (latest-value cache) │ └───────────────────────────────────────────────────────────────┘ ``` ### Logistics and order management (Standard Edition) ```text ┌───────────────────────────────────────────────────────────────┐ │ Logistics management system │ ├───────────────────┬───────────────────┬───────────────────────┤ │ TRANSACTION │ LOG │ LOOKUP │ │ orders │ delivery_log │ product_master │ │ Order management │ Delivery events │ Product reference │ │ UPDATE/DELETE │ │ data │ ├───────────────────┴───────────────────┴───────────────────────┤ │ VOLATILE │ │ order_status_cache (current-state cache) │ └───────────────────────────────────────────────────────────────┘ ``` ### Pattern summary | Role | Recommended type | Reason | |------|---------|------| | High-frequency measurement history | TAG | High-speed Append API buffers, time-series optimization | | Event and alarm logs | LOG | Append-only, automatic arrival time | | Relational business data (UPDATE/DELETE) | TRANSACTION | SELECT/INSERT/UPDATE/DELETE all supported | | Reference and code data | LOOKUP | PK identity, general-predicate UPDATE/DELETE, persistence | | Real-time state cache | VOLATILE | In-memory speed, UPSERT | --- Read next: - [SELECT GROUP BY and Aggregation](/dbms/reference/sql/syntax/select-syntax/) - [Operations and Configuration](/dbms/operations-configuration-recovery/) --- title: "5. Using TAG Tables" url: https://docs.machbase.com/dbms/tag-table-usage/ language: en kind: section --- # 5. Using TAG Tables TAG tables store measurement histories by repeatedly observed entity name and a time or distance axis. This chapter covers Machbase DBMS 8.7.0 TAG structure, ingestion, queries, metadata, correction, and operations. It validates the deployment and data-model choices from Chapters 3 and 4 through practical SQL. A tag is an observed entity; a DATA row is one observation. METADATA holds one attribute row per tag, not separate attributes per historical observation. Distinguish original measurements, current attributes, interval aggregates, and ingestion times to interpret results and correction scope consistently. ## Chapter Contents | Section | Content | |---|---| | [Overview and Selection Criteria](./overview-use-criteria/) | Tag identifiers, observation rows, time/distance axes | | [Table Structure and Schema](./table-structure-schema/) | Column order/types, LSL/USL, BINARY, storage design | | [Create, Alter, and Drop](./create-alter-drop/) | Basic DDL, METADATA expansion, object cleanup | | [Data Ingestion and Changes](./data-input-mutation/) | Automatic registration, SQL/Append/file input | | [Queries and Analysis](./query-analysis/) | Range/latest-value/STAT queries and interpretation | | [Indexes and Performance](./index-performance/) | Validate access paths with actual data | | [Operations and Data Lifecycle](./operations-lifecycle/) | Deletion, retention, deduplication completion | | [Constraints, Errors, and Troubleshooting](./constraints-errors-troubleshooting/) | Valid conditions and intentional failure examples | | [Usage Patterns and Scenarios](./patterns-scenarios/) | Observation granularity, units, missing-data models | | [TAG Metadata](./tag-metadata/) | Registration, queries, changes, deletion, JSON, ARRAY | | [TAG Data UPDATE and Correction](./tag-data-update-correction/) | Direct correction, NULL correction, audit history | | [tagmetaimport and Bulk Metadata Registration](./tagmetaimport/) | CSV setup, input targets, rerun errors | ## Exercises and Support Scope Each page is an independent exercise. If a setup table exists, determine whether it belongs to another workload; do not delete it arbitrarily. Run success examples separately from intentional failures. Apply cleanup SQL only to objects created for that exercise. TAG DATA UPDATE is Standard Edition only. Check Edition-specific scope for duplicate-check intervals, METADATA ALTER, and individual LSL/USL operations. SQL INSERT, Append responses, storage-buffer flush, and index/statistics completion are different events. [Chapter 6](../tag-rollup-usage/) covers full ROLLUP creation, query, and rebuild procedures. This chapter addresses only how TAG corrections and deletions relate to aggregates. --- title: "5.1 Overview and Selection Criteria" url: https://docs.machbase.com/dbms/tag-table-usage/overview-use-criteria/ language: en kind: page --- # 5.1 Overview and Selection Criteria Consider TAG for histories of repeated observations of sensors, equipment, or similar entities. Start by distinguishing one tag from one row. Multiple rows at different times can share a name; a shared name alone does not remove duplicate rows. ## TAG Table Characteristics `PRIMARY KEY` identifies the tag name, unlike a relational per-row unique key. One table has either a time axis or a distance axis. ```sql -- Time-axis TAG for observations over time. CREATE TAG TABLE ch5_overview_time ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ); -- Distance-axis TAG for observations over distance or position. -- Distance-axis TAG does not support ROLLUP. CREATE TAG TABLE ch5_overview_distance ( name VARCHAR(64) PRIMARY KEY, distance DOUBLE BASEDISTANCE, value DOUBLE ); ``` In both examples, the name is first and the axis second. Time axes use `DATETIME BASETIME`; distance axes use `DOUBLE`, `LONG`, or `ULONG` with `BASEDISTANCE`. Optional `SUMMARIZED` belongs on the third column. See [Create, Alter, and Drop](../create-alter-drop/) for column order/types and [Table Structure and Schema](../table-structure-schema/) for design choices. `SUMMARIZED` marks a representative statistics/aggregation column. It does not automatically create a ROLLUP object. The following lists data scopes to distinguish, not columns of the sample table. DATA consists of user-supplied observations; METADATA and STAT are separate scopes for per-tag attributes and statistics. | Scope | Meaning | |---|---| | Tag name | First column identifying a sensor or repeatedly observed entity | | DATA | User-supplied observation rows: axis values and DATA columns | | METADATA | Current per-tag attributes such as location, units, and settings; separate from ordinary DATA | | STAT | Per-tag ingestion statistics from `V$_STAT`, not direct sample-table columns | ## When TAG Fits - Continuously append histories of multiple entities using one schema. - Frequently query time/distance ranges for specific tags. - Select tags by current attributes and analyze their histories. - Store and query repeated interval statistics on a time axis. See [TAG ROLLUP](../../tag-rollup-usage/) for aggregation design. A single-value model uses a tag per measurement; a multi-value model groups temperature, pressure, and other simultaneous measurements in one row. Do not force readings from different times into one row; define missing-data and quality policies. Equal timestamps may reflect duplicate collection, so define duplicate handling for name, time, and values separately. ## When to Consider Other Tables | Requirement | Alternative | |---|---| | Event searches centered on events rather than observed entities | LOG | | General predicates and changes on persistent reference data | LOOKUP | | Explicit multi-DML transactions and relational changes | TRANSACTION (Standard Edition only) | | Shared state cache rebuildable from a source | VOLATILE | TAG also supports JOIN and limited value correction. Do not assume that JOIN requirements rule out TAG or that every measurement must use TAG. DATA UPDATE is Standard Edition only. Cluster supports only METADATA UPDATE; plan reingestion and reaggregation when measurement correction is required. ## Design Sequence 1. Define whether a tag identifies a sensor, equipment item, or inspection run. 2. Define the meaning and units of measurement time or distance/position. 3. Define value types, NULL/quality indicators, and observation frequency. 4. Separate per-observation attributes from current METADATA. 5. Compare range-query, aggregation, correction, and retention needs with Edition support. Verify and remove the example tables as follows: ```sql -- Inspect the example schemas. DESC ch5_overview_time; DESC ch5_overview_distance; -- Clean up to avoid name conflicts with later examples. DROP TABLE ch5_overview_distance; DROP TABLE ch5_overview_time; ``` Continue with [Schema Design](../table-structure-schema/) and [Ingestion and Query Exercises](../data-input-mutation/). --- title: "5.2 Table Structure and Schema" url: https://docs.machbase.com/dbms/tag-table-usage/table-structure-schema/ language: en kind: page --- # 5.2 Table Structure and Schema ## Design a TAG Table TAG table design determines what constitutes one tag and where each value belongs, not just how many columns to create. See [Create, Alter, and Drop](../create-alter-drop/#original-85-creating-tag-tables) for positional column roles, axis types, and prohibited types. This page covers decisions within those rules. The DDL on this page contains independent model examples. Sections explain required creation order for exercises. Use different names if objects already exist. Review the following when designing a schema: - [Use Cases](#tag-schema-use-case-summary) - [Tag Name Column](#tag-name-column-design) - [Choose a Time or Distance Axis](#time-axis-design-tag) - [Value Columns](#tag-table-design-design-column) - [METADATA Columns](#metadata-column-design-summary) - [JSON METADATA Columns](#json-metadata-column-design-summary) - [Binary Columns](#tag-table-design-design-column-binary) - [VARCHAR Storage Optimization](#tag-table-design-storage-varchar) - [Storage Strategy](#tag-table-design-strategy) - [LSL/USL](#tag-table-design-lsl-usl) - [Correction and Duplicate Policies](#correction-duplication-policy-summary) - [Constraints and Support](#tag-schema-limitations-summary) ### Use Cases TAG suits repeated observations with a shared structure across many subjects. Identify the observed entity, such as a sensor, equipment item, vehicle, or inspection run, then check whether its history can be queried along time or distance. Decide here whether to model it as TAG or split it into other table types. See [Use Cases](../patterns-scenarios/#use-cases-tag) for business models. ### Tag Name Column Decide whether a tag represents a sensor, equipment item, or inspection run. Finer granularity increases tag counts and metadata/index overhead; coarser granularity mixes histories of different entities within one tag. Naming conventions are also covered in [VARCHAR Storage Optimization](#tag-table-design-storage-varchar). ### Choose a Time or Distance Axis Choose the axis according to the query range: measurement timestamps require a time axis; cumulative positions along a route require a distance axis. One TAG table cannot have both. Changing the axis later requires recreating the table. ```sql -- Time-axis TAG with ranges based on measurement timestamps. CREATE TAG TABLE time_sensor ( name VARCHAR(40) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ); ``` ```sql -- Distance-axis TAG with ranges based on distance or position. CREATE TAG TABLE rail_sensor ( name VARCHAR(40) PRIMARY KEY, distance DOUBLE BASEDISTANCE, value DOUBLE ); ``` `DURATION`, ROLLUP, and time functions apply only to BASETIME. Use ordinary comparisons and `BETWEEN` for distance ranges. See [Queries and Analysis](../query-analysis/) for examples. ### Value Columns Value columns are ordinary data columns other than the tag name and axis columns. They store values that change per measurement row, such as readings, status, and quality codes. #### Supported Types Common types are listed below. See the [Data Type Reference](/dbms/reference/sql/types/) for full support, including JSON, BINARY, DECIMAL, and numeric ARRAY. | Type | Description | Storage size | |------|------|---------| | `DOUBLE` | 64-bit floating point | 8 bytes | | `FLOAT` | 32-bit floating point | 4 bytes | | `LONG` | 64-bit integer | 8 bytes | | `INTEGER` (`INT`) | 32-bit integer | 4 bytes | | `SHORT` | 16-bit integer | 2 bytes | | `VARCHAR(n)` | Variable-length string | Up to n bytes | #### Recommended Types | Data | Recommended type | |--------|---------| | Analog values: temperature, humidity, pressure | `DOUBLE` | | Counters, status codes | `INTEGER` | | Flags, binary states | `SHORT` | | Cumulative energy or flow | `DOUBLE` or `LONG` | | Tag string values | `VARCHAR(n)` | #### Multiple Value Columns Storing multiple measurements in one table may introduce NULLs. This model suits measurements collected at the same time. ```sql CREATE TAG TABLE weather_station ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, temperature DOUBLE, -- Always collected humidity DOUBLE, -- Always collected wind_speed DOUBLE, -- Optional rainfall DOUBLE -- Optional ); ``` #### Allow NULL Values TAG value columns allow NULL by default. If a tag collects only some measurements, insert NULL into the remaining columns. ```sql -- Without wind_speed and rainfall INSERT INTO weather_station VALUES ('WS-01', NOW, 22.5, 65.0, NULL, NULL); ``` ### METADATA Columns Use METADATA for current per-tag attributes, not values repeated in every DATA row. Examples include installation location, units, equipment settings, and management status. Separating DATA and METADATA preserves observation history while allowing independent queries and changes to current tag attributes. Decide which attributes belong in METADATA and which remain DATA: values that change per observation belong in DATA; mostly fixed attributes over a tag lifetime belong in METADATA. See [Use METADATA](../tag-metadata/#original-85-tag-metadata) for input, query, and update examples. ### JSON METADATA Columns Consider JSON METADATA for hierarchical or frequently changing attribute sets. For example, store equipment location, manufacturer details, and installation options in one JSON document and query selected paths. Choose separate columns for fixed attributes used frequently in predicates, or JSON when attributes vary by tag. Consider indexes for frequently filtered paths. See [JSON METADATA](../tag-metadata/#metadata-design-json) for syntax and examples. ### Binary Columns Use `BINARY(n)` in TAG tables for sensor frames of 1–32767 bytes. See [Binary Columns](#original-85-binary-columns) for input literals, length limits, and driver behavior. For large images or waveforms, also consider external storage with only a reference key in the table. ### VARCHAR Storage Optimization Declare `VARCHAR` according to the actual maximum length. See the [DDL Reference](/dbms/reference/sql/syntax/ddl-syntax/) for storage-option syntax. Combine site, equipment, and sensor identifiers with consistent separators in tag names to support range queries. ### Storage Strategy Data is stored in column storage separated by tag. Choose a strategy based on volume and query patterns. #### One Table or Multiple Tables ##### One TAG Table (Recommended) Group sensors of the same kind in one TAG table. ```sql -- Recommended: all temperature sensors in one table CREATE TAG TABLE temperature_sensor ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); ``` **Benefits** - Fewer objects to manage - Easier cross-tag aggregation - Simpler operations ##### Multiple TAG Tables Consider separate tables for different column layouts, retention periods, privileges, or operational cycles. Do not create one table per sensor merely because sensor counts increase. ```sql -- Temperature/humidity sensors (DOUBLE values) CREATE TAG TABLE thermo_sensor ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, temp DOUBLE, humid DOUBLE ); -- Vibration sensors (DOUBLE + BINARY waveform) CREATE TAG TABLE vibration_sensor ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, rms DOUBLE, waveform BINARY(4096) ); ``` #### Manage Tag Counts - Measure tag-index and metadata memory growth with production-scale data. - Encode sensor hierarchies in tag names. - Avoid designs where every record has a unique tag name (an antipattern). #### Partition Strategy Limit time-axis TAG queries by `BASETIME`. Do not depend on internal storage objects or partition names. Manage retention through [Data Retention Policies](/dbms/operations-configuration-recovery/policy-data-retention/). ### LSL and USL LSL (Lower Specification Limit) and USL (Upper Specification Limit) define acceptable value bounds. Setting per-tag bounds in METADATA can reject out-of-range DATA input, allowing different ingestion quality rules for each tag. This feature rejects input; it does not correct values. Log and reprocess rejected input according to the ingestion error policy. #### Constraints The following constraints apply: * LSL/USL is not entirely unsupported in Cluster. Limit definitions at table creation, metadata values, and DATA INSERT/Append limit checks use common paths. The exercise below that adds limit columns to existing METADATA with ALTER is for Standard Edition. * The third TAG column, __Value__, must be __SUMMARIZED__ to configure LSL/USL. * LSL must be less than or equal to USL. Input __Value__ must be within the inclusive bounds: __(LSL <= Value <= USL)__. * Data inserted before limits are configured is not validated. * NULL LSL/USL columns disable the corresponding input validation. * Limits can be used independently; configure only USL for an upper bound. * USL alone checks only upper-bound violations; LSL alone checks only lower-bound violations. #### Supported Data Types Limit columns must have the same type as the target __Value__ column. The following covers bounds for basic numeric types. SUMMARIZED itself also supports JSON, so SUMMARIZED eligibility and numeric limit configuration are separate requirements. | Type | Description | Range | Significant digits | |----|------|-----|----| | short | Signed 16-bit integer | -32767 ~ 32767 | - | | ushort | Unsigned 16-bit integer | 0 ~ 65534 | - | | integer | Signed 32-bit integer | -2147483647 ~ 2147483647 | - | | uinteger | Unsigned 32-bit integer | 0 ~ 4294967294 | - | | long | Signed 64-bit integer | -9223372036854775807 ~ 9223372036854775807 | - | | ulong | Unsigned 64-bit integer | 0~18446744073709551614 | - | | float | 32-bit floating point | - | 6[^1] | | double | 64-bit floating point | - | 15[^1] | #### Configure and Use LSL/USL The CREATE examples show independent alternatives. Only the base `example` table is used in subsequent INSERT/UPDATE exercises; create alternatives separately. Specify `LOWER LIMIT` (LSL) or `UPPER LIMIT` (USL) on tag metadata columns, either when creating the TAG table or adding metadata columns. ##### CREATE ```sql CREATE TAG TABLE example ( tag_id VARCHAR(50) PRIMARY KEY, time DATETIME BASETIME, value INTEGER SUMMARIZED) METADATA ( lsl INTEGER LOWER LIMIT, usl INTEGER UPPER LIMIT ); ``` Use both limit columns or only one. LSL alone checks `Value >= LSL` without an upper bound, equivalent to a NULL USL value. ```sql CREATE TAG TABLE example_lower_only ( tag_id VARCHAR(50) PRIMARY KEY, time DATETIME BASETIME, value INTEGER SUMMARIZED) METADATA ( lsl INTEGER LOWER LIMIT ); ``` ##### ADD COLUMN When added with `ADD COLUMN` after data already exists, the default is __NULL__. ```sql CREATE TAG TABLE example_alter_limits ( tag_id VARCHAR(50) PRIMARY KEY, time DATETIME BASETIME, value INTEGER SUMMARIZED ); ALTER TABLE example_alter_limits METADATA ADD COLUMN (lsl INTEGER LOWER LIMIT); ALTER TABLE example_alter_limits METADATA ADD COLUMN (usl INTEGER UPPER LIMIT); ``` As with [CREATE](#create), you can add only one limit attribute. ```sql CREATE TAG TABLE example_alter_upper ( tag_id VARCHAR(50) PRIMARY KEY, time DATETIME BASETIME, value INTEGER SUMMARIZED ); ALTER TABLE example_alter_upper METADATA ADD COLUMN (usl INTEGER UPPER LIMIT); ``` ##### INSERT Set LSL/USL values for a specific TAG ID. ```sql INSERT INTO example metadata VALUES ('TAG_01', 100, 200); ``` Subsequent tag data input behaves as follows: ```sql INSERT INTO example VALUES ('TAG_01', NOW, 95); -- Failure ``` ```text [ERR-02342: SUMMARIZED value is less than LOWER LIMIT.] ``` ```sql INSERT INTO example VALUES ('TAG_01', NOW, 100); -- Success (Inclusive) ``` ```text 1 row(s) inserted. Elapsed time: 0.000 ``` ```sql INSERT INTO example VALUES ('TAG_01', NOW, 150); -- Success ``` ```text 1 row(s) inserted. Elapsed time: 0.000 ``` ```sql INSERT INTO example VALUES ('TAG_01', NOW, 200); -- Success (Inclusive) ``` ```text 1 row(s) inserted. Elapsed time: 0.000 ``` ```sql INSERT INTO example VALUES ('TAG_01', NOW, 205); -- Failure ``` ```text [ERR-02341: SUMMARIZED value is greater than UPPER LIMIT.] ``` Querying the TAG table shows that only values within the specification range were inserted. ```sql SELECT * FROM example; ``` ```text TAG_ID TIME VALUE LSL USL ------------------------------------------------------------------------------------------------------------------------------ TAG_01 2023-09-12 09:31:27 923:289:631 100 100 200 TAG_01 2023-09-12 09:31:27 929:013:232 150 100 200 TAG_01 2023-09-12 09:31:27 939:209:248 200 100 200 [3] row(s) selected. Elapsed time: 0.001 ``` ##### UPDATE Update LSL/USL column values. These changes do not apply retroactively to existing data. ```sql UPDATE example metadata SET lsl = 10, usl = 100 WHERE tag_id = 'TAG_01'; ``` ```text 1 row(s) updated. Elapsed time: 0.001 ``` ```sql SELECT tag_id, lsl, usl FROM example METADATA; ``` ```text TAG_ID LSL USL ---------------------------------------------------------------------------------------- TAG_01 10 100 [1] row(s) selected. Elapsed time: 0.001 ``` ##### DELETE Disable LSL/USL constraints by setting their values to NULL, not by using `DROP COLUMN`. ```sql UPDATE EXAMPLE METADATA SET lsl = NULL, usl = NULL WHERE tag_id = 'TAG_01'; ``` ```text 1 row(s) updated. Elapsed time: 0.001 ``` ```sql SELECT tag_id, lsl, usl FROM example METADATA; ``` ```text TAG_ID LSL USL ---------------------------------------------------------------------------------------- TAG_01 NULL NULL [1] row(s) selected. Elapsed time: 0.001 ``` #### Check LSL/USL Violations in TRACE Logs - Location: `$MACHBASE_HOME/trc/machbase.trc` - Quick filter: ```bash grep LIMIT_DROP $MACHBASE_HOME/trc/machbase.trc | tail -n 20 ``` - Log format: `LIMIT_DROP (TYPE=) TABLE= TAG= ` - TYPE=LOWER/UPPER identifies the violated bound. - DATETIME uses `YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn`. - Actual examples: ``` [2025-11-29 13:50:34 P-151395 T-126343511537344][QP-INFO] LIMIT_DROP (TYPE=LOWER) TABLE=TAG3 TAG=tag-1 TIME=2020-01-01 00:00:00 000:000:000 VALUE=5.55 [2025-11-29 13:50:34 P-151395 T-126343511537344][QP-INFO] LIMIT_DROP (TYPE=UPPER) TABLE=TAG3 TAG=tag-1 TIME=2020-01-01 00:00:04 000:000:000 VALUE=30.55 [2025-11-29 13:50:35 P-151395 T-126344475694784][QP-INFO] LIMIT_DROP (TYPE=LOWER) TABLE=TAG3 TAG=tag-2 TIME=1998-12-24 09:00:00 000:000:000 VALUE=0 [2025-11-29 13:50:35 P-151395 T-126344475694784][QP-INFO] LIMIT_DROP (TYPE=UPPER) TABLE=TAG3 TAG=tag-2 TIME=1998-12-24 09:00:00 000:000:008 VALUE=45 ``` - Usage - Identify LOWER/UPPER violation times and values by tag. - Filter further by TAG/table name with grep to trace specific targets. - Caution: Lines are limited to about 4KB and may truncate with many columns. Immediately after startup, before the metadata cache is ready, table names may appear as IDs. [^1]: [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) ### Correction and Duplicate Policies Value correction and deduplication require decisions beyond column definitions, but should be planned during schema design. Decide which value columns can change, whether to preserve originals in separate columns or tables, and how to rebuild ROLLUP after correction. DATA UPDATE is Standard Edition only; in Cluster, design reingestion and reaggregation procedures. See [Data Correction](../tag-data-update-correction/#design-correction-tag). If the same tag/axis value can be inserted repeatedly, decide whether to allow duplicates, remove them during collection, or use Machbase automatic deduplication. See [Automatic Deduplication](../operations-lifecycle/#original-85-duplication-removal) for configuration and operational validation. ### Constraints and Support TAG tables are designed for repeated observations and do not support every SQL feature of ordinary relational tables. Check axis, METADATA, correction, ROLLUP, and Edition support before implementation. Verify that the design fits the supported scope and revisit affected decisions if needed. See [Constraints and Precautions](../constraints-errors-troubleshooting/#limitations-tag) for unsupported features and common errors. ## Binary Columns `BINARY(n)` stores fixed-length sensor-frame binary values in TAG tables. TAG `BINARY` without a length uses 32767 bytes. Specify the required frame size to make storage and transmission size clear. The length-qualified `BINARY(n)` form cannot be declared in other table types. Valid lengths are 1–32K-1 (1–32767) bytes. Binary columns cannot be indexed. Insert `BINARY` values with explicit binary literals. ### DDL Rules ```sql CREATE TAG TABLE t1( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, frame BINARY(4) ); ``` - Valid length: `1 <= n <= 32767` (32K-1). - Out-of-range lengths, such as `BINARY(0)`, fail at creation. - `DESC` and table metadata show declared byte length, not hexadecimal width. SQL `LENGTH(binary_col)` returns the displayed value length excluding trailing zero padding added to short input. ### Supported Input Formats ```sql X'hex_digits' x'hex_digits' B'bit_digits' b'bit_digits' O'octal_digits' o'octal_digits' ``` | Format | Meaning | Unit | | --- | --- | --- | | `X'...'`, `x'...'` | Hexadecimal literal | 2 hexadecimal digits = 1 byte | | `B'...'`, `b'...'` | Binary literal | 8 bits = 1 byte | | `O'...'`, `o'...'` | Octal literal | 3 octal digits = 1 byte | Prefixes are case-insensitive. ```sql CREATE TAG TABLE t_bin ( name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value BINARY(4) ); INSERT INTO t_bin VALUES('hex1', '2024-01-01 00:00:00', X'0A'); INSERT INTO t_bin VALUES('hex2', '2024-01-01 00:00:01', x'00010203'); INSERT INTO t_bin VALUES('bit1', '2024-01-01 00:00:02', B'00001010'); INSERT INTO t_bin VALUES('oct1', '2024-01-01 00:00:03', O'012'); ``` `X'0A'`, `B'00001010'`, and `O'012'` all represent the one-byte value `0x0A`. ### Binary Literal Rules #### Hexadecimal Literals `X'...'` and `x'...'` accept `0-9`, `A-F`, and `a-f`. ```sql X'00' X'0AFF' x'abcdef' ``` Hexadecimal literals require an even number of digits; two digits represent one byte. #### Binary Literals `B'...'` and `b'...'` accept only `0` and `1`. ```sql B'00000000' -- 0x00 B'00001010' -- 0x0A b'11111111' -- 0xFF ``` The bit count must be a multiple of 8; eight bits represent one byte. #### Octal Literals `O'...'` and `o'...'` accept only `0-7`. ```sql O'000' -- 0x00 O'012' -- 0x0A o'377' -- 0xFF ``` Octal digits must occur in groups of three. Each group must be in the one-byte range `000` through `377`. #### Empty Values Empty single quotes represent a zero-length binary value. ```sql X'' B'' O'' ``` ### Length Limits A `BINARY(n)` column accepts at most `n` bytes. ```sql CREATE TAG TABLE t_limit ( name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value BINARY(2) ); INSERT INTO t_limit VALUES('ok_hex', '2024-01-01 00:00:00', X'0AFF'); INSERT INTO t_limit VALUES('ok_bit', '2024-01-01 00:00:01', B'0000101011111111'); INSERT INTO t_limit VALUES('ok_oct', '2024-01-01 00:00:02', O'012377'); INSERT INTO t_limit VALUES('bad_hex', '2024-01-01 00:00:03', X'000102'); -- Fails: 3 bytes ``` Input fails whenever the final binary value exceeds the target `BINARY(n)` length, regardless of source. This applies to binary literals, ordinary strings, legacy `'0x...'` string input, and copying other `BINARY` columns through `INSERT ... SELECT`. ```sql CREATE TAG TABLE t_src ( name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value BINARY(8) ); CREATE TAG TABLE t_dst ( name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value BINARY(4) ); INSERT INTO t_src VALUES('k1', '2024-01-01 00:00:00', X'0102030405060708'); INSERT INTO t_dst SELECT name, time, value FROM t_src; -- Fails: 8-byte value into BINARY(4) ``` The same length check applies to values produced inside SQL expressions, including `CASE`, `INSERT ... SELECT`, and views. ### Invalid Input The following inputs are invalid: ```sql X'0' -- Odd number of hexadecimal digits X'0G' -- G is not a hexadecimal digit B'0101' -- Bit count is not a multiple of 8 B'00000002' -- 2 is not a binary digit O'12' -- Octal digits are not in groups of three O'400' -- Exceeds one-byte range X'0102 -- Missing closing single quote ``` Invalid values or excessive lengths fail with this error: ```text [ERR-02233: Error occurred at column (n): (Invalid insert value.)] ``` ### Differences from Legacy String Input String input in the form `'0x...'` remains available for compatibility. It converts a string to `BINARY`; `X'...'`, `B'...'`, and `O'...'` explicitly identify binary values as SQL binary literals. Ordinary strings can also be inserted into `BINARY(n)`, but fail if their byte length exceeds `n`. Prefer explicit binary literals in new SQL for clarity. `'0b...'`, `'0o...'`, and unquoted `0x...`, `0b...`, `0o...` are not supported as binary literals. ### Output and Tools - machsql displays uppercase hexadecimal without `0x`. Trailing zero padding added to short input is omitted from text output. - machloader: Declare `BINARY(n)` in the schema; invalid or oversized values fail. - Machbase SQLCLI, ODBC, Java, C#, and Node.js drivers send/receive fixed-length buffers; metadata `LENGTH` is in bytes. ## Clean Up Examples Drop only tables actually created on this page. If you did not execute an alternative DDL statement, do not run its DROP statement. ```sql DROP TABLE time_sensor; DROP TABLE rail_sensor; DROP TABLE weather_station; DROP TABLE temperature_sensor; DROP TABLE thermo_sensor; DROP TABLE vibration_sensor; DROP TABLE example; DROP TABLE example_lower_only; DROP TABLE example_alter_limits; DROP TABLE example_alter_upper; DROP TABLE t1; DROP TABLE t_bin; DROP TABLE t_limit; DROP TABLE t_dst; DROP TABLE t_src; ``` --- title: "5.3 Create, Alter, and Drop" url: https://docs.machbase.com/dbms/tag-table-usage/create-alter-drop/ language: en kind: page --- # 5.3 Create, Alter, and Drop TAG tables require a tag identifier and one axis column. This page provides runnable basic examples and links to the SQL reference for complete options. ## Create a TAG Table The first two columns have fixed roles. The name and axis columns are required; changing their order or placing them elsewhere causes creation to fail. | Position | Purpose and properties | | --- | --- | | First | Tag name: `VARCHAR` with `PRIMARY KEY`; no other type is allowed. Identifies a repeatedly observed entity such as a sensor, equipment item, or inspection run. Multiple DATA rows can share a tag name, unlike a relational per-row unique key. | | Second | Orders and queries observations by time or distance/position. Use `DATETIME BASETIME` for time or `DOUBLE`, `LONG`, or `ULONG` with `BASEDISTANCE` for distance. A TAG table has only one of these axes. | | Third and later | DATA columns that vary per observation, such as temperature, pressure, status, or quality code. Support numeric types, `VARCHAR`, `DATETIME`, JSON, numeric ARRAY, and BINARY. Choose one representative value for per-tag statistics and automatic ROLLUP by marking it `SUMMARIZED`. This is optional and allowed only on the third column. | ARRAY is allowed only in other DATA columns, not the name, axis, or `SUMMARIZED` column. Unlike LOG, TAG DATA does not support `TEXT`, `CLOB`, or `BLOB`; use `VARCHAR` for long strings and `BINARY` for binary data. See the [Data Type Reference](/dbms/reference/sql/types/) for syntax and ranges. Declare attributes stored once per tag separately in `METADATA`, outside those column positions. `location` in the time-axis example is one such attribute. The two tables below are independent exercises. Check for existing objects, then execute in order. Choose an axis matching the data meaning. Distance-axis TAG tables do not support ROLLUP. ### Time-Axis TAG ```sql CREATE TAG TABLE ch5_tag_ddl ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ) METADATA ( location VARCHAR(64) ); ``` `SUMMARIZED` has two effects. First, per-tag STAT views collect value statistics such as `MIN_VALUE` and `MAX_VALUE` for this column. Without it, STAT retains only row counts and axis ranges. Second, automatic `WITH ROLLUP` creation and whole-JSON-document ROLLUP use this column. Ordinary numeric ROLLUP specifies a column explicitly in `CREATE ROLLUP ... ON table(column)`, so it does not require `SUMMARIZED`. Omit it if value statistics are unnecessary and you plan to create ROLLUP manually. Supported types are the supported numeric types and JSON. See [Chapter 6](../../tag-rollup-usage/) for ROLLUP creation requirements. Store per-tag attributes such as location and units in `METADATA`; define values that change per measurement as ordinary DATA columns. ### Distance-Axis TAG ```sql CREATE TAG TABLE ch5_distance_ddl ( name VARCHAR(32) PRIMARY KEY, distance DOUBLE BASEDISTANCE, value DOUBLE ); ``` Use `DOUBLE` for fractional distances, or `LONG`/`ULONG` for integer axes according to range. ## Alter a TAG Table The METADATA ADD/DROP exercise requires Standard Edition. Arbitrary TAG DATA column changes are restricted. Consider migrating to a new table for schema expansion. Metadata columns can be added or dropped with supported syntax. ```sql ALTER TABLE ch5_tag_ddl METADATA ADD COLUMN (team VARCHAR(32)); ALTER TABLE ch5_tag_ddl METADATA ADD COLUMN (limits DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]); ALTER TABLE ch5_tag_ddl METADATA DROP COLUMN (team); ALTER TABLE ch5_tag_ddl METADATA DROP COLUMN (limits); ``` Standard Edition can add fixed-length numeric ARRAY columns to TAG METADATA. Existing metadata rows receive the specified ARRAY DEFAULT. Rows automatically registered by TAG DATA input after ALTER do not reapply that DEFAULT; the new ARRAY column is whole NULL. Ordinary TAG DATA ARRAY columns can be declared at `CREATE TABLE` but not added with ALTER. TAG METADATA ARRAY columns have no automatic indexes and do not support explicit indexes. See [TAG Metadata](../tag-metadata/) and [Numeric ARRAY Types](/dbms/reference/sql/types/array/) for details. Before changing a populated production table, check dependent queries, SDK column order, and reingestion paths. After ALTER, verify with `DESC ch5_tag_ddl;` and METADATA queries. ## Drop a TAG Table `DROP TABLE` removes raw data and metadata together. Remove dependent objects such as ROLLUP in dependency order first. TAG `DROP TABLE ... CASCADE` can also remove associated ROLLUPs, so do not use it as a routine cleanup default. Check additional dependency restrictions on custom ROLLUP target tables. ```sql DROP TABLE ch5_distance_ddl; DROP TABLE ch5_tag_ddl; ``` See the [DDL Syntax Reference](/dbms/reference/sql/syntax/ddl-syntax/) for exact properties, supported scope, and DDL. Read next: - [TAG Table Structure and Schema](../table-structure-schema/) - [TAG Data Ingestion and Changes](../data-input-mutation/) - [TAG Metadata](../tag-metadata/) --- title: "5.4 Data Ingestion and Changes" url: https://docs.machbase.com/dbms/tag-table-usage/data-input-mutation/ language: en kind: page --- # 5.4 Data Ingestion and Changes Ingest TAG data with SQL `INSERT`, Append APIs, or file-loading tools. Use SQL examples to check features and load small amounts; consider Append APIs first for continuous collection. ## SQL INSERT This example creates time-axis and distance-axis TAG tables, verifies data, and cleans up. Ensure exercise names do not conflict with existing tables. Time-axis names identify sensors; distance-axis names identify inspection subjects or runs. ```sql CREATE TAG TABLE ch5_input_time ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); INSERT INTO ch5_input_time VALUES ('TEMP_001', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 25.5); INSERT INTO ch5_input_time VALUES ('TEMP_001', TO_DATE('2026-01-01 10:01:00', 'YYYY-MM-DD HH24:MI:SS'), 25.7); CREATE TAG TABLE ch5_input_distance ( name VARCHAR(32) PRIMARY KEY, distance DOUBLE BASEDISTANCE, value DOUBLE, quality INTEGER ); INSERT INTO ch5_input_distance VALUES ('PIPE_A', 0.0, 10.1, 100); INSERT INTO ch5_input_distance VALUES ('PIPE_A', 500.5, 11.2, 100); EXEC TABLE_FLUSH(ch5_input_time); EXEC TABLE_FLUSH(ch5_input_distance); SELECT name, time, value FROM ch5_input_time ORDER BY time; SELECT name, distance, value, quality FROM ch5_input_distance ORDER BY distance; SELECT COUNT(*) FROM ch5_input_time; SELECT COUNT(*) FROM ch5_input_distance; DROP TABLE ch5_input_distance; DROP TABLE ch5_input_time; ``` Each table returns two rows. Time-axis values are 25.5 and 25.7; distance-axis positions are 0.0 and 500.5. Tags were not preregistered, so the first DATA input registers each name automatically. The application manages actual event times and retransmission status. Use `TABLE_FLUSH` in validation or operational procedures that explicitly need to flush pending storage/input buffers. It is not a transaction commit or a query-visibility guarantee. Do not execute it per row in ordinary collection loops. See the [EXEC Procedure Reference](/dbms/reference/sql/syntax/execute-procedure-syntax/#table-flush) for arguments and errors. ## Ingest with Metadata A TAG table with user metadata can automatically register new tags through DATA-only input. If attributes such as location and units must be set first, register with `INSERT ... METADATA` before DATA input. Supported syntax can also send DATA and metadata together. Do not assume ordinary DATA input updates existing attributes every time. Omit system-managed columns from input lists. See [TAG Metadata](../tag-metadata/) for metadata registration, updates, and deletion. ## Choose an Input Path | Path | Suitable for | Checks | | --- | --- | --- | | SQL `INSERT` | Feature checks, low-frequency input | Per-statement parsing and round-trip cost | | SDK Append | Continuous high-throughput input | Batch size, flush, error handling | | `csvimport` / `machloader` | Bulk client-file loads | Column order, date format, bad files | | `LOAD DATA INFILE` | Server-accessible files | Server paths/permissions, error policy | See [Development Integration](/dbms/development-tools-integration/) for SDK connections and Append examples, and [Data Ingestion and Export](/dbms/development-tools-integration/data-input-load-export/) for file formats and commands. ## Correct Data TAG data UPDATE in Standard Edition requires both tag selection and BASETIME ranges. Tag names, axes, and metadata columns are not ordinary data UPDATE targets. Existing ROLLUP results do not change automatically after correction; rebuild the affected range explicitly. See [ROLLUP_REBUILD](../../tag-rollup-usage/rollup-rebuild/). Check success responses, failure counts, and retry policies in the selected API. Distinguish SQL NULL, SDK NULL representations, and numeric 0, and define a duplicate policy for retransmitting observations. For numeric ARRAY and sparse input, use the [ARRAY Append Examples](../../development-tools-integration/data-input-load-export/array-append/). See [TAG Data Correction](../tag-data-update-correction/) for detailed procedures. --- title: "5.5 Queries and Analysis" url: https://docs.machbase.com/dbms/tag-table-usage/query-analysis/ language: en kind: page --- # 5.5 Queries and Analysis This page covers common TAG time-series query patterns: time and distance ranges, multiple tags, and statistics views. ## Query Tag Data ### Sample Schema (Time Axis) This example registers two tags and inserts 10 rows per tag. `TAG_0001` has data from January 1–10, 2018; `TAG_0002` has data from February 1–10. ```sql create tag table TAG (name varchar(20) primary key, time datetime basetime, value double summarized); insert into tag metadata values ('TAG_0001'); insert into tag metadata values ('TAG_0002'); insert into tag values('TAG_0001', '2018-01-01 01:00:00 000:000:000', 1); insert into tag values('TAG_0001', '2018-01-02 02:00:00 000:000:000', 2); insert into tag values('TAG_0001', '2018-01-03 03:00:00 000:000:000', 3); insert into tag values('TAG_0001', '2018-01-04 04:00:00 000:000:000', 4); insert into tag values('TAG_0001', '2018-01-05 05:00:00 000:000:000', 5); insert into tag values('TAG_0001', '2018-01-06 06:00:00 000:000:000', 6); insert into tag values('TAG_0001', '2018-01-07 07:00:00 000:000:000', 7); insert into tag values('TAG_0001', '2018-01-08 08:00:00 000:000:000', 8); insert into tag values('TAG_0001', '2018-01-09 09:00:00 000:000:000', 9); insert into tag values('TAG_0001', '2018-01-10 10:00:00 000:000:000', 10); insert into tag values('TAG_0002', '2018-02-01 01:00:00 000:000:000', 11); insert into tag values('TAG_0002', '2018-02-02 02:00:00 000:000:000', 12); insert into tag values('TAG_0002', '2018-02-03 03:00:00 000:000:000', 13); insert into tag values('TAG_0002', '2018-02-04 04:00:00 000:000:000', 14); insert into tag values('TAG_0002', '2018-02-05 05:00:00 000:000:000', 15); insert into tag values('TAG_0002', '2018-02-06 06:00:00 000:000:000', 16); insert into tag values('TAG_0002', '2018-02-07 07:00:00 000:000:000', 17); insert into tag values('TAG_0002', '2018-02-08 08:00:00 000:000:000', 18); insert into tag values('TAG_0002', '2018-02-09 09:00:00 000:000:000', 19); insert into tag values('TAG_0002', '2018-02-10 10:00:00 000:000:000', 20); exec table_flush(tag); ``` The final `TABLE_FLUSH` explicitly processes storage buffers. Do not interpret it as a transaction commit or a guarantee of query visibility. See [TABLE_FLUSH](/dbms/reference/sql/syntax/execute-procedure-syntax/#table-flush) for details. ### Retrieve All TAG Data ```sql select * from tag ORDER BY name, time; ``` ```text NAME TIME VALUE -------------------------------------------------------------------------------------- TAG_0001 2018-01-01 01:00:00 000:000:000 1 TAG_0001 2018-01-02 02:00:00 000:000:000 2 TAG_0001 2018-01-03 03:00:00 000:000:000 3 TAG_0001 2018-01-04 04:00:00 000:000:000 4 TAG_0001 2018-01-05 05:00:00 000:000:000 5 TAG_0001 2018-01-06 06:00:00 000:000:000 6 TAG_0001 2018-01-07 07:00:00 000:000:000 7 TAG_0001 2018-01-08 08:00:00 000:000:000 8 TAG_0001 2018-01-09 09:00:00 000:000:000 9 TAG_0001 2018-01-10 10:00:00 000:000:000 10 TAG_0002 2018-02-01 01:00:00 000:000:000 11 TAG_0002 2018-02-02 02:00:00 000:000:000 12 TAG_0002 2018-02-03 03:00:00 000:000:000 13 TAG_0002 2018-02-04 04:00:00 000:000:000 14 TAG_0002 2018-02-05 05:00:00 000:000:000 15 TAG_0002 2018-02-06 06:00:00 000:000:000 16 TAG_0002 2018-02-07 07:00:00 000:000:000 17 TAG_0002 2018-02-08 08:00:00 000:000:000 18 TAG_0002 2018-02-09 09:00:00 000:000:000 19 TAG_0002 2018-02-10 10:00:00 000:000:000 20 [20] row(s) selected. ``` The output is one execution result. Specify `ORDER BY name, time` when ordering must be guaranteed. Unfiltered output order may depend on the execution plan and scan direction. ### Retrieve Data by Tag Name This example retrieves data for TAG_0002. ```sql select * from tag where name='TAG_0002' ORDER BY name, time; ``` ```text NAME TIME VALUE -------------------------------------------------------------------------------------- TAG_0002 2018-02-01 01:00:00 000:000:000 11 TAG_0002 2018-02-02 02:00:00 000:000:000 12 TAG_0002 2018-02-03 03:00:00 000:000:000 13 TAG_0002 2018-02-04 04:00:00 000:000:000 14 TAG_0002 2018-02-05 05:00:00 000:000:000 15 TAG_0002 2018-02-06 06:00:00 000:000:000 16 TAG_0002 2018-02-07 07:00:00 000:000:000 17 TAG_0002 2018-02-08 08:00:00 000:000:000 18 TAG_0002 2018-02-09 09:00:00 000:000:000 19 TAG_0002 2018-02-10 10:00:00 000:000:000 20 [10] row(s) selected. ``` ### Query a Time Range This example applies a time range to TAG_0002. > `BETWEEN` includes both boundaries, equivalent to `>=` together with `<=`. > The examples return the same results with `>` and `<` because there are no rows > at the boundary timestamps. To avoid reading boundary rows twice in adjacent > intervals, use `time >= start AND time < end`. ```sql select * from tag where name = 'TAG_0002' and time between to_date('2018-02-01') and to_date('2018-02-05') ORDER BY name, time; ``` ```text NAME TIME VALUE -------------------------------------------------------------------------------------- TAG_0002 2018-02-01 01:00:00 000:000:000 11 TAG_0002 2018-02-02 02:00:00 000:000:000 12 TAG_0002 2018-02-03 03:00:00 000:000:000 13 TAG_0002 2018-02-04 04:00:00 000:000:000 14 [4] row(s) selected. ``` ```sql select * from tag where name = 'TAG_0002' and time > to_date('2018-02-01') and time < to_date('2018-02-05') ORDER BY name, time; ``` ```text NAME TIME VALUE -------------------------------------------------------------------------------------- TAG_0002 2018-02-01 01:00:00 000:000:000 11 TAG_0002 2018-02-02 02:00:00 000:000:000 12 TAG_0002 2018-02-03 03:00:00 000:000:000 13 TAG_0002 2018-02-04 04:00:00 000:000:000 14 [4] row(s) selected. ``` ### Distance-Axis Sample Schema This example uses a distance-axis (`BASE DISTANCE`) TAG table. ```sql CREATE TAG TABLE trip_tag ( name VARCHAR(20) PRIMARY KEY, distance_m DOUBLE BASE DISTANCE, value DOUBLE, quality INTEGER ); INSERT INTO trip_tag VALUES('ODO_A', 0, 10.1, 100); INSERT INTO trip_tag VALUES('ODO_A', 500, 11.2, 101); INSERT INTO trip_tag VALUES('ODO_A', 1000, 12.3, 102); INSERT INTO trip_tag VALUES('ODO_B', 1000.1, 21.5, 100); INSERT INTO trip_tag VALUES('ODO_B', 1500, 22.1, 101); INSERT INTO trip_tag VALUES('ODO_B', 2000, 22.9, 102); EXEC TABLE_FLUSH(trip_tag); ``` ### Query a Distance Range ```sql SELECT name, distance_m, value, quality FROM trip_tag WHERE name = 'ODO_A' AND distance_m BETWEEN 0 AND 1000 ORDER BY distance_m; ``` As with a time axis, narrowing the axis range is the basic query pattern. ### Fractional Boundaries on a DOUBLE Distance Axis ```sql SELECT name, distance_m, value, quality FROM trip_tag WHERE name = 'ODO_B' AND distance_m BETWEEN 1000.1 AND 2000 ORDER BY distance_m; ``` Numeric comparison excludes `1000` and includes `1500` and `2000`. ### Check Distance-Axis Execution Plans For large distance-range queries, use `EXPLAIN` to check whether distance predicates become key ranges. ```sql EXPLAIN SELECT name, distance_m, value FROM trip_tag WHERE name = 'ODO_B' AND distance_m BETWEEN 1000.1 AND 2000 ORDER BY distance_m; ``` Check for: - `KEYVALUE INDEX SCAN` or a similar index scan - A `distance_m between ...` condition under `KEY RANGE` ### Aggregate into Distance Buckets This example groups nonnegative distances into intervals of 500. TRUNC truncates toward zero. For negative coordinates, choose the desired boundary rule separately, such as FLOOR. ```sql SELECT TRUNC(distance_m / 500, 0) * 500 AS dist_bucket, COUNT(*) AS sample_count, MIN(value) AS min_v, MAX(value) AS max_v, AVG(value) AS avg_v FROM trip_tag WHERE name = 'ODO_B' GROUP BY TRUNC(distance_m / 500, 0) * 500 ORDER BY dist_bucket; ``` For example, `1750` belongs to bucket `1500`. ### Query a Time Range Across Multiple Tags Apply the same time range to two or more tags. Use `IN` when the target name list is known. For many tags, measure performance with both list size and time-range width. ```sql select * from tag where name in ('TAG_0002', 'TAG_0001') and time between to_date('2018-01-05') and to_date('2018-02-05') ORDER BY name, time; ``` ```text NAME TIME VALUE -------------------------------------------------------------------------------------- TAG_0001 2018-01-05 05:00:00 000:000:000 5 TAG_0001 2018-01-06 06:00:00 000:000:000 6 TAG_0001 2018-01-07 07:00:00 000:000:000 7 TAG_0001 2018-01-08 08:00:00 000:000:000 8 TAG_0001 2018-01-09 09:00:00 000:000:000 9 TAG_0001 2018-01-10 10:00:00 000:000:000 10 TAG_0002 2018-02-01 01:00:00 000:000:000 11 TAG_0002 2018-02-02 02:00:00 000:000:000 12 TAG_0002 2018-02-03 03:00:00 000:000:000 13 TAG_0002 2018-02-04 04:00:00 000:000:000 14 [10] row(s) selected. ``` ### Filter by Values You can also filter tag values. This example selects TAG_0002 values greater than 12 and less than 15. ```sql select * from tag where name = 'TAG_0002' and value > 12 and value < 15 and time between to_date('2018-02-01') and to_date('2018-02-05') ORDER BY name, time; ``` ```text NAME TIME VALUE -------------------------------------------------------------------------------------- TAG_0002 2018-02-03 03:00:00 000:000:000 13 TAG_0002 2018-02-04 04:00:00 000:000:000 14 [2] row(s) selected. ``` ### Per-Tag Statistics View `V$
_STAT` Creating a TAG table automatically creates a virtual table aggregating statistics per tag ID, named v${tag table name}_stat. Distinguish tag-name/axis statistics from value statistics for the third SUMMARIZED column. STAT reflects background index/statistics processing, so verify recent input with source SELECT queries as well. Exercises needing immediate statistics use TABLE_FLUSH followed by INDEX_FLUSH to wait for processing. Axis-specific BASE DISTANCE STAT schemas are supported since Machbase 8.7.0 Axis-related column names and types depend on the TAG axis. | TAG axis | Minimum/maximum axis | Axis of minimum/maximum value | Latest inserted row axis | Axis statistic type | |--------|--------------|----------------------|------------------|--------------| | `DATETIME BASE TIME` | `MIN_TIME`, `MAX_TIME` | `MIN_VALUE_TIME`, `MAX_VALUE_TIME` | `RECENT_ROW_TIME` | `DATETIME` | | `DOUBLE/LONG/ULONG BASE DISTANCE` | `MIN_DISTANCE`, `MAX_DISTANCE` | `MIN_VALUE_DISTANCE`, `MAX_VALUE_DISTANCE` | `RECENT_ROW_DISTANCE` | Original BASE DISTANCE type | Both Editions share `NAME`, `ROW_COUNT`, `MIN_VALUE`, and `MAX_VALUE`. Cluster Edition adds `HOSTNAME VARCHAR(64)` at the beginning of the schema. #### BASE TIME STAT Schema ```sql DESC v$tag_stat; ``` ```text [ COLUMN ] ---------------------------------------------------------------------------------------------------- NAME NULL? TYPE LENGTH ---------------------------------------------------------------------------------------------------- NAME varchar 100 ROW_COUNT ulong 20 MIN_TIME datetime 31 MAX_TIME datetime 31 MIN_VALUE double 17 MIN_VALUE_TIME datetime 31 MAX_VALUE double 17 MAX_VALUE_TIME datetime 31 RECENT_ROW_TIME datetime 31 ``` Without SUMMARIZED on the third column, VALUE statistics (MIN_VALUE, MAX_VALUE, MIN_VALUE_TIME, MAX_VALUE_TIME) are not stored. Collected statistics: | Column | Information | |--|--| | NAME | Tag ID name | | ROW_COUNT | Row count | | MIN_TIME | Minimum basetime for this tag ID | | MAX_TIME | Maximum basetime for this tag ID | | MIN_VALUE | Minimum summarized value for this tag ID | | MIN_VALUE_TIME | Basetime inserted with MIN_VALUE | | MAX_VALUE | Maximum summarized value for this tag ID | | MAX_VALUE_TIME | Basetime inserted with MAX_VALUE | | RECENT_ROW_TIME | Basetime of the most recently inserted row | The statistics exercise uses a separate table from the preceding 20-row query example. Only its two tags appear; TAG_0001 and TAG_0002 do not affect expected statistics. 1. With a SUMMARIZED column ```sql CREATE TAG TABLE ch5_stat_time (name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED); ``` ```sql INSERT INTO ch5_stat_time VALUES('tag-0', TO_DATE('2021-08-12'), 10); INSERT INTO ch5_stat_time VALUES('tag-0', TO_DATE('2021-08-13'), 10); INSERT INTO ch5_stat_time VALUES('tag-0', TO_DATE('2021-08-14'), 20); INSERT INTO ch5_stat_time VALUES('tag-0', TO_DATE('2021-08-11'), 5); INSERT INTO ch5_stat_time VALUES('tag-1', TO_DATE('2022-08-12'), 100); INSERT INTO ch5_stat_time VALUES('tag-1', TO_DATE('2022-08-11'), 200); INSERT INTO ch5_stat_time VALUES('tag-1', TO_DATE('2022-08-10'), 50); ``` ```sql EXEC TABLE_FLUSH(ch5_stat_time); EXEC INDEX_FLUSH(ch5_stat_time); SELECT * FROM v$ch5_stat_time_stat ORDER BY name; ``` ```text NAME ROW_COUNT MIN_TIME MAX_TIME MIN_VALUE --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MIN_VALUE_TIME MAX_VALUE MAX_VALUE_TIME RECENT_ROW_TIME --------------------------------------------------------------------------------------------------------------------------------- tag-0 4 2021-08-11 00:00:00 000:000:000 2021-08-14 00:00:00 000:000:000 5 2021-08-11 00:00:00 000:000:000 20 2021-08-14 00:00:00 000:000:000 2021-08-11 00:00:00 000:000:000 tag-1 3 2022-08-10 00:00:00 000:000:000 2022-08-12 00:00:00 000:000:000 50 2022-08-10 00:00:00 000:000:000 200 2022-08-11 00:00:00 000:000:000 2022-08-10 00:00:00 000:000:000 [2] row(s) selected. ``` 2. Without a SUMMARIZED column ```sql CREATE TAG TABLE other_tag (name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE); ``` ```text Executed successfully. ``` ```sql INSERT INTO other_tag VALUES('tag-0', TO_DATE('2021-08-12'), 10); INSERT INTO other_tag VALUES('tag-0', TO_DATE('2021-08-13'), 10); INSERT INTO other_tag VALUES('tag-0', TO_DATE('2021-08-14'), 20); INSERT INTO other_tag VALUES('tag-0', TO_DATE('2021-08-11'), 5); INSERT INTO other_tag VALUES('tag-1', TO_DATE('2022-08-12'), 100); INSERT INTO other_tag VALUES('tag-1', TO_DATE('2022-08-11'), 200); INSERT INTO other_tag VALUES('tag-1', TO_DATE('2022-08-10'), 50); ``` ```sql EXEC TABLE_FLUSH(other_tag); EXEC INDEX_FLUSH(other_tag); SELECT * FROM v$other_tag_stat ORDER BY name; ``` ```text NAME ROW_COUNT MIN_TIME MAX_TIME MIN_VALUE --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MIN_VALUE_TIME MAX_VALUE MAX_VALUE_TIME RECENT_ROW_TIME --------------------------------------------------------------------------------------------------------------------------------- tag-0 4 2021-08-11 00:00:00 000:000:000 2021-08-14 00:00:00 000:000:000 NULL NULL NULL NULL 2021-08-11 00:00:00 000:000:000 tag-1 3 2022-08-10 00:00:00 000:000:000 2022-08-12 00:00:00 000:000:000 NULL NULL NULL NULL 2022-08-10 00:00:00 000:000:000 [2] row(s) selected. ``` #### BASE DISTANCE STAT Schema Distance-axis TAG statistics views expose distance values as numeric types. ```sql CREATE TAG TABLE distance_sensor ( name VARCHAR(32) PRIMARY KEY, odometer_m DOUBLE BASE DISTANCE, value DOUBLE SUMMARIZED ); INSERT INTO distance_sensor VALUES('sensor', 20.5, 8); INSERT INTO distance_sensor VALUES('sensor', 10.25, 3); INSERT INTO distance_sensor VALUES('sensor', 30.75, 5); EXEC TABLE_FLUSH(distance_sensor); EXEC INDEX_FLUSH(distance_sensor); ``` In Standard Edition, a `DOUBLE BASE DISTANCE` table has this schema: ```sql DESC V$DISTANCE_SENSOR_STAT; ``` ```text [ COLUMN ] ---------------------------------------------------------------------------------------------------- NAME NULL? TYPE LENGTH ---------------------------------------------------------------------------------------------------- NAME varchar 100 ROW_COUNT ulong 20 MIN_DISTANCE double 17 MAX_DISTANCE double 17 MIN_VALUE double 17 MIN_VALUE_DISTANCE double 17 MAX_VALUE double 17 MAX_VALUE_DISTANCE double 17 RECENT_ROW_DISTANCE double 17 ``` The five distance statistic columns use the original BASE DISTANCE type. | BASE DISTANCE type | STAT column type | `DESC` length | |--------------------|----------------|-------------| | `DOUBLE` | `double` | 17 | | `LONG` | `long` | 20 | | `ULONG` | `ulong` | 20 | ```sql SELECT name, row_count, min_distance, max_distance, min_value, min_value_distance, max_value, max_value_distance, recent_row_distance FROM V$DISTANCE_SENSOR_STAT WHERE name = 'sensor'; ``` - `MIN_DISTANCE` and `MAX_DISTANCE` are the minimum and maximum distances for the statistics row. - `MIN_VALUE_DISTANCE` and `MAX_VALUE_DISTANCE` are the distances where the minimum and maximum summarized values occurred. - `RECENT_ROW_DISTANCE` is the most recently inserted row's distance, not the largest distance. - Without `SUMMARIZED`, `MIN_VALUE_DISTANCE` and `MAX_VALUE_DISTANCE` are `NULL`. ##### Query in Cluster Edition Cluster statistics views add `HOSTNAME` and may return rows per Warehouse. Inspect Warehouse-specific values first. ```sql SELECT hostname, name, row_count, min_distance, max_distance, min_value, min_value_distance, max_value, max_value_distance, recent_row_distance FROM V$DISTANCE_SENSOR_STAT ORDER BY hostname, name; ``` Row counts and distance boundaries can be safely aggregated by tag name. ```sql SELECT name, SUM(row_count) AS row_count, MIN(min_distance) AS min_distance, MAX(max_distance) AS max_distance FROM V$DISTANCE_SENSOR_STAT GROUP BY name; ``` {{< callout type="warning" >}} Keep `MIN_VALUE` paired with `MIN_VALUE_DISTANCE` and `MAX_VALUE` with `MAX_VALUE_DISTANCE` from the same Warehouse row. Independent `MIN` or `MAX` aggregations can combine values from different Warehouses. `RECENT_ROW_DISTANCE` is also per-Warehouse; do not interpret `MAX(RECENT_ROW_DISTANCE)` as the latest inserted row across the cluster. {{< /callout >}} ##### 8.7.0 Compatibility Old BASE DISTANCE statistics column names are not provided as aliases. Existing tables also use the new schema after the 8.7.0 server restarts. | Before 8.7.0 | 8.7.0 | |-----------------|------------| | `MIN_TIME` | `MIN_DISTANCE` | | `MAX_TIME` | `MAX_DISTANCE` | | `MIN_VALUE_TIME` | `MIN_VALUE_DISTANCE` | | `MAX_VALUE_TIME` | `MAX_VALUE_DISTANCE` | | `RECENT_ROW_TIME` | `RECENT_ROW_DISTANCE` | BASE TIME TAG tables retain the `*_TIME DATETIME` schema. ### Scan Direction Hints Distinguish axis traversal from result sorting. The latest value in a reverse-axis scan is the largest axis value; it may differ from STAT RECENT_ROW, which describes the last inserted row. Ordering multiple rows with the same axis value requires an additional application-defined criterion. ```sql SELECT * FROM tag WHERE name = 'TAG_0001' ORDER BY time LIMIT 10; SELECT /*+ SCAN_FORWARD(tag) */ name, time, value FROM tag WHERE name = 'TAG_0001' LIMIT 10; SELECT /*+ SCAN_BACKWARD(tag) */ name, time, value FROM tag WHERE name = 'TAG_0001' LIMIT 10; ``` See [TABLE_SCAN_DIRECTION](/dbms/reference/configuration/configuration/) for the default direction without a hint. ## Cleanup ```sql DROP TABLE ch5_stat_time; DROP TABLE distance_sensor; DROP TABLE trip_tag; DROP TABLE other_tag; DROP TABLE tag; ``` --- title: "5.6 Indexes and Performance" url: https://docs.machbase.com/dbms/tag-table-usage/index-performance/ language: en kind: page --- # 5.6 Indexes and Performance Start TAG queries by limiting tag names and axis ranges. Choose additional indexes only after measuring actual predicates and execution plans. ## Basic Query Paths TAG tables automatically manage structures for queries by `PRIMARY KEY` tag name and `BASETIME` or `BASEDISTANCE`. Applications should not depend on generated system-object names or storage stages. | Query condition | Tuning direction | | --- | --- | | Axis range for one tag | Specify both tag name and axis range | | Same time range for multiple tags | Limit time first and manage target tag count | | Metadata attributes | Define TAG `METADATA` columns | | Repeated time aggregation | Consider ROLLUP | | Value-driven queries | Validate secondary value indexes with execution plans | Broad queries without tag or axis limits read more data. Check `EXPLAIN` and execution time with actual volumes instead of assuming constant speed. ## METADATA Columns Use `METADATA` for attributes defined once per tag, such as location or device type. Ordinary scalar METADATA columns have automatic search indexes. Raw JSON columns do not; index required JSON paths explicitly. Numeric ARRAY metadata supports neither automatic nor explicit indexes. See [TAG Metadata](../tag-metadata/). Putting time-series values or frequently changing status in METADATA obscures update semantics. Depending on the value, consider TAG DATA columns, LOOKUP, VOLATILE, or TRANSACTION tables (Standard Edition only). ## Secondary Indexes on Value Columns For frequent value predicates, consider `INDEX_TYPE TAG` secondary indexes. They increase ingestion and storage costs; compare representative queries before and after creation. This example uses isolated names to create value and JSON path indexes, checks execution plans, and removes all objects. The small sample validates syntax and results, not performance benefits. Run in a separate environment without name conflicts. ```sql CREATE TAG TABLE ch5_index_tag ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, payload JSON ) METADATA ( location VARCHAR(64) ); INSERT INTO ch5_index_tag METADATA VALUES ('TEMP-01', 'LINE-A'); INSERT INTO ch5_index_tag METADATA VALUES ('TEMP-02', 'LINE-B'); INSERT INTO ch5_index_tag VALUES ('TEMP-01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, '{"state":"normal"}'); INSERT INTO ch5_index_tag VALUES ('TEMP-01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 90.0, '{"state":"alarm"}'); INSERT INTO ch5_index_tag VALUES ('TEMP-02', TO_DATE('2026-01-01 00:02:00', 'YYYY-MM-DD HH24:MI:SS'), 95.0, '{"state":"alarm"}'); CREATE INDEX idx_ch5_index_tag_value ON ch5_index_tag (value) INDEX_TYPE TAG; CREATE INDEX idx_ch5_index_tag_json ON ch5_index_tag (payload->'$.state'); EXPLAIN SELECT name, time, value FROM ch5_index_tag WHERE name = 'TEMP-01' AND time BETWEEN TO_DATE('2026-01-01', 'YYYY-MM-DD') AND TO_DATE('2026-01-02', 'YYYY-MM-DD') AND value > 80.0; SELECT name, value FROM ch5_index_tag WHERE location = 'LINE-A' AND value > 80.0 ORDER BY name, time; SELECT name, value FROM ch5_index_tag WHERE payload->'$.state' = 'alarm' ORDER BY name, time; DROP INDEX idx_ch5_index_tag_json; DROP INDEX idx_ch5_index_tag_value; DROP TABLE ch5_index_tag; ``` The first SELECT returns TEMP-01 with 90.0; the second returns TEMP-01 with 90.0 and TEMP-02 with 95.0. Verify identical results before and after indexing. With production-scale data, compare ingestion cost and index size as well as query time. Match JSON path result types to comparison value types, and use `EXPLAIN` to check whether the intended path uses an index. ## Avoid Inapplicable Tuning - Do not create separate indexes on TAG axis columns. - Do not apply the LOG `MINMAX_CACHE_SIZE` setting to TAG value columns. - Consider ROLLUP for repeated broad-period aggregation instead of relying only on secondary indexes. See the [SQL Syntax Reference](/dbms/reference/sql/syntax/) for index syntax and [Query Tuning](/dbms/performance-tuning/performance-query-tuning/) for measurement and tuning procedures. --- title: "5.7 Operations and Data Lifecycle" url: https://docs.machbase.com/dbms/tag-table-usage/operations-lifecycle/ language: en kind: page --- # 5.7 Operations and Data Lifecycle Manage TAG data through manual deletion, retention policies, and duplicate prevention. This page explains operational choices and links to complete SQL references. ## Delete TAG Data Limit deletion with tag identifiers and axis predicates. Common time-axis TAG choices are: | Purpose | Condition | | --- | --- | | Delete all data for one tag | Match tag `PRIMARY KEY` | | Delete one tag's time range | Tag match + BASETIME range | | Delete old data for all tags | BASETIME predicate or `BEFORE` | | Delete all table data | TAG `DELETE` without predicates | This example creates a separate test table, checks deletion scope, and cleans up. ```sql CREATE TAG TABLE ch5_lifecycle ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); INSERT INTO ch5_lifecycle VALUES ('TAG_0001', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1.0); INSERT INTO ch5_lifecycle VALUES ('TAG_0001', TO_DATE('2026-01-02 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 2.0); INSERT INTO ch5_lifecycle VALUES ('TAG_0002', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 3.0); DELETE FROM ch5_lifecycle WHERE name = 'TAG_0001' AND time < TO_DATE('2026-01-02 00:00:00', 'YYYY-MM-DD HH24:MI:SS'); SELECT name, time, value FROM ch5_lifecycle ORDER BY name, time; DELETE FROM ch5_lifecycle; SELECT COUNT(*) FROM ch5_lifecycle; DROP TABLE ch5_lifecycle; ``` After the first deletion, TAG_0001 retains value 2.0 at 2026-01-02, and TAG_0002 retains 3.0. After full deletion, COUNT is 0. DATA and METADATA deletion are separate. To remove tag registrations, also check [METADATA Deletion](../tag-metadata/) requirements. See [TAG DELETE Syntax](/dbms/reference/sql/syntax/dml-syntax/) for operators and Edition support. Use [Retention Policies](/dbms/operations-configuration-recovery/policy-data-retention/) when deletion must run periodically. ### Handle ROLLUP Data Deleting raw TAG data and handling existing ROLLUP are separate operations. If aggregates must reflect corrected or deleted source data, rebuild the affected ROLLUP range. Do not repeatedly execute ROLLUP deletion as a retention policy. - [Partial ROLLUP Deletion and Rebuild](/dbms/tag-rollup-usage/rollup-rebuild/) - [Rebuild ROLLUP After TAG Correction](../tag-data-update-correction/) ## Automatic Deduplication `TAG_DUPLICATE_CHECK_DURATION` sets the duplicate-check interval in minutes. Standard Edition accepts 0–43200; 0 disables it. Cluster accepts only 0, so the following enablement exercise is Standard Edition only. Within the interval measured against server time, rows with identical tags, axis values, and DATA values are duplicates. Detection occurs during index processing and duplicate cleanup, so an Append success count is not an already-deduplicated count. Late data outside the interval may not be deduplicated as expected. This does not replace business-key uniqueness constraints. ```sql CREATE TAG TABLE ch5_dedup ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ) TAG_DUPLICATE_CHECK_DURATION = 1440; INSERT INTO ch5_dedup VALUES ('TAG_0001', NOW, 1.0); INSERT INTO ch5_dedup SELECT name, time, value FROM ch5_dedup; EXEC TABLE_FLUSH(ch5_dedup); EXEC INDEX_FLUSH(ch5_dedup); SELECT name, time, value FROM ch5_dedup WHERE name = 'TAG_0001'; ALTER TABLE ch5_dedup SET TAG_DUPLICATE_CHECK_DURATION = 60; DROP TABLE ch5_dedup; ``` The second input copies the first row, including its exact axis timestamp. This exercise assumes no concurrent production ingestion. Wait for storage buffers and index processing, then verify that one row remains. Do not call both flush procedures per row in a normal collection loop. Check full properties and restrictions against the current [CREATE TAG TABLE Syntax](/dbms/reference/sql/syntax/ddl-syntax/). Data already deleted by retention is no longer available for duplicate comparison. ## Operational Checklist 1. Define raw and ROLLUP retention periods separately. 2. Measure maximum arrival delay to choose a duplicate-check interval. 3. Verify target tags and time ranges with SELECT before deleting or correcting. 4. Validate ROLLUP and representative queries after bulk changes. 5. Monitor input volume, disk use, and retention execution together. --- title: "5.8 Constraints, Errors, and Troubleshooting" url: https://docs.machbase.com/dbms/tag-table-usage/constraints-errors-troubleshooting/ language: en kind: page --- # 5.8 Constraints, Errors, and Troubleshooting The UPDATE exercises require Standard Edition. Create these tables first and run valid SQL separately from intentional failures. Do not include failure examples in a normal script. Do not delete existing objects with conflicting names. ```sql CREATE TAG TABLE ch5_error_time ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, status INTEGER ) METADATA (location VARCHAR(64)); INSERT INTO ch5_error_time METADATA VALUES ('sensor-01', 'zone-1'); INSERT INTO ch5_error_time METADATA VALUES ('sensor-02', 'zone-2'); INSERT INTO ch5_error_time VALUES ('sensor-01', TO_DATE('2026-07-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 0); INSERT INTO ch5_error_time VALUES ('sensor-02', TO_DATE('2026-07-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 0); CREATE TAG TABLE ch5_error_distance ( name VARCHAR(64) PRIMARY KEY, distance DOUBLE BASEDISTANCE, value DOUBLE SUMMARIZED ); ``` ## TAG Data UPDATE WHERE Errors WHERE must include both tag selection and BASETIME predicates. Ambiguous or unsupported conditions cause UPDATE to fail. {{< callout type="warning" >}} **Required Predicates** Specify both a tag predicate such as `WHERE name ...` and a BASETIME predicate such as `time ...`. Full UPDATE without conditions, tag-only UPDATE, and time-only UPDATE are not allowed. {{< /callout >}} ### Symptom The following UPDATE statements are rejected: ```sql -- No time predicate UPDATE ch5_error_time SET value = 99.9 WHERE name = 'sensor-01'; -- No tag predicate UPDATE ch5_error_time SET value = 99.9 WHERE time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); -- Uses OR UPDATE ch5_error_time SET value = 99.9 WHERE name = 'sensor-01' OR name = 'sensor-02'; ``` ### Cause Conditions that cannot clearly restrict target tags and the time range are rejected. | Predicate | Supported | |-----------|:--------:| | `name = 'sensor-01' AND time >= ...` | O | | `name IN ('sensor-01', 'sensor-02') AND time BETWEEN ...` | O | | `name LIKE 'sensor-%' AND time < ...` | O | | Only `value > 10` | X | | Only `name = 'sensor-01'` | X | | Only `time >= ...` | X | | `OR`, subqueries, aggregate predicates | X | ### Resolution Specify both tag and time predicates. ```sql UPDATE ch5_error_time SET value = 99.9 WHERE name = 'sensor-01' AND time = TO_DATE('2026-07-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'); UPDATE ch5_error_time SET status = 1 WHERE name IN ('sensor-01', 'sensor-02') AND time >= TO_DATE('2026-07-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND time < TO_DATE('2026-07-02 00:00:00', 'YYYY-MM-DD HH24:MI:SS'); ``` ### NAME or TIME Binding Rejected with `ERR-02190` Since Machbase 8.7.0, Standard Edition supports bind parameters for NAME and BASETIME predicate values as follows: ```sql UPDATE ch5_error_time SET value = ? WHERE name = ? AND time = ?; ``` If both required predicates are present but the statement fails with `ERR-02190: Invalid UPDATE/DELETE condition. Specify it as (primary key column) = (value)`, check the server version. Older servers do not support NAME/TIME binding for TAG data UPDATE. Upgrade to 8.7.0 or later. For named markers, also use an 8.7.0 SDK that supports the named API. The `?` example is SQL for SDK prepare/bind, not a statement to run unchanged without values in machsql. When reusing a prepared statement, rebind all SET, NAME, and TIME values. See [TAG Data UPDATE Binding](/dbms/reference/sql/syntax/dml-syntax/tag-data-update-syntax/#tag-data-update-predicate-bind) for marker rules. Before a large UPDATE, run `SELECT COUNT(*)` with the same WHERE condition to check the target row count. ## TAG Data UPDATE SET Target Errors SET can target only actual DATA columns. PRIMARY KEY, BASETIME, and metadata columns raise errors as SET targets. {{< callout type="warning" >}} **SET Targets** `value` and user DATA columns can be updated. `name`, `time`, and columns in the METADATA block cannot be SET targets in TAG data UPDATE. {{< /callout >}} ### Symptom ```sql -- Error: attempts to update PRIMARY KEY column (name) UPDATE ch5_error_time SET name = 'new-sensor' WHERE name = 'old-sensor' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); -- Error: attempts to update BASETIME column (time) UPDATE ch5_error_time SET time = NOW WHERE name = 'sensor-01' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); -- Error: changes metadata through data UPDATE UPDATE ch5_error_time SET location = 'zone-2' WHERE name = 'sensor-01' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); ``` ### UPDATE Support by Column Type | Column type | Description | Data UPDATE | |-----------|------|:-----------:| | PRIMARY KEY (`name`) | Unique tag identifier | X | | BASETIME (`time`) | Time-series timestamp | X | | DATA (`value`, auxiliary columns) | Actual row values | O | | `SUMMARIZED` DATA column | Column with statistics | O | | Metadata column | Tag attribute in METADATA | X | ### Resolution Use ordinary UPDATE for DATA values. ```sql UPDATE ch5_error_time SET value = 99.9, status = 1 WHERE name = 'sensor-01' AND time = TO_DATE('2026-07-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'); ``` Use separate syntax for metadata. ```sql UPDATE ch5_error_time METADATA SET location = 'zone-2' WHERE name = 'sensor-01'; ``` To change a tag name or time axis, insert data with the new `name`/`time`, then delete the original data according to operational policy. ## BASE DISTANCE TAG STAT Column Errors Machbase 8.7.0 exposes distance-named, numeric axis columns in BASE DISTANCE TAG `V$
_STAT` views. Pre-upgrade SQL referencing `MIN_TIME`, `MAX_TIME`, or `RECENT_ROW_TIME` may fail with column-not-found errors. ### Symptoms - Existing `*_TIME` columns cannot be queried in BASE DISTANCE statistics after upgrade. - Older servers may interpret distances as `DATETIME`, displaying meaningless dates. - Using Standard ordinal result mappings in Cluster may shift columns because `HOSTNAME` is added first. ### Diagnosis Check both the table axis and actual statistics-view schema. ```sql DESC ch5_error_distance; DESC V$CH5_ERROR_DISTANCE_STAT; ``` For BASE DISTANCE, `MIN_DISTANCE`, `MAX_DISTANCE`, `MIN_VALUE_DISTANCE`, `MAX_VALUE_DISTANCE`, and `RECENT_ROW_DISTANCE` should use the original distance type. Cluster adds `HOSTNAME VARCHAR(64)` as the first column. ### Resolution 1. Replace old `*_TIME` SQL names with corresponding `*_DISTANCE` names. 2. Change SDK mappings from `DATETIME` to the original `DOUBLE`, `LONG`, or `ULONG`. 3. Read Cluster results by name or recheck ordinals including `HOSTNAME`. 4. Retain existing `*_TIME DATETIME` mappings for BASE TIME TAG queries. See [Per-Tag Statistics Views](../query-analysis/#tag-stat-axis-schema) for the complete mapping and Cluster aggregation precautions. ## Constraints and Precautions ### Feature Support | Feature | Status | |------|------| | Time-series DATA UPDATE | Standard Edition; tag/BASETIME predicates required | | Metadata UPDATE | Supported (`UPDATE ... METADATA`) | | DELETE | Supported (`BEFORE`, tag/axis predicates, or full deletion) | | Multiple PRIMARY KEY columns | Unsupported; one column only | | BASETIME and BASEDISTANCE together | Unsupported | | TAG DATA ordinary-column ALTER ADD/DROP | Unsupported | | TAG METADATA ALTER ADD/DROP | Supported in Standard Edition | ### Tag Count Limits - System settings limit the number of tags per TAG table. - More tags increase tag-index and metadata memory use. Measure query and ingestion performance with production-scale data. - Do not make tag names unique per record (an antipattern; see [One Table per Sensor](/dbms/data-modeling-table-design/table-types-patterns-type-anti/#per-sensor-create)). ### Late-Arriving Data - BASETIME accepts arbitrary past timestamps. - Measure ingestion rates and query performance separately for workloads with substantial late-arriving data. ### Cluster Edition Support Cluster Edition supports TAG tables. However, TAG data UPDATE is Standard Edition only and is not supported in Cluster. ### Summary ``` TAG table = sensor name (PK) + time/distance axis + measurements - INSERT/APPEND: O - UPDATE: DATA requires Standard Edition tag/BASETIME predicates; METADATA uses separate SQL - DELETE: O (BEFORE or tag/axis predicates) - METADATA: O (separate attributes; UPDATE supported) ``` --- **Read Next** - [TRANSACTION Table Design](/dbms/rdb-table-usage/) ## Clean Up the Exercise Verify successful changes with SELECT, then remove only the exercise tables. ```sql SELECT name, time, value, status FROM ch5_error_time ORDER BY name, time; DROP TABLE ch5_error_time; DROP TABLE ch5_error_distance; ``` --- title: "5.9 Usage Patterns and Scenarios" url: https://docs.machbase.com/dbms/tag-table-usage/patterns-scenarios/ language: en kind: page --- # 5.9 Usage Patterns and Scenarios Each example is independent. Check for conflicting objects before creating tables. Define tag names, the meaning of one observation, value units, and missing-data policy before applying DDL. ## Use Cases ### IoT Sensor Data Manage sensor data from factories, buildings, and infrastructure in one TAG table. ```sql CREATE TAG TABLE factory_sensor ( name VARCHAR(128) PRIMARY KEY, time DATETIME BASETIME, temperature DOUBLE, vibration DOUBLE, current DOUBLE ); -- One row groups measurements from the same equipment observation. INSERT INTO factory_sensor VALUES ( 'F01/LINE-A/MOTOR-01', NOW, 75.3, 0.15, 2.4 ); ``` This model stores simultaneous measurements from one device in multiple columns. For per-measurement tags such as `.../TEMP` and `.../VIBRATION`, consider a single-value `name, time, value` model. Represent differences in measurement times with NULL and quality status. ### Energy Monitoring Collect electricity, gas, and water meter data over time. ```sql CREATE TAG TABLE energy_meter ( meter_id VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, kwh DOUBLE, voltage DOUBLE, current DOUBLE ); ``` If `kwh` is cumulative, AVG(kwh) is the average meter reading, not interval consumption. Calculate consumption from boundary differences with rules for resets, replacements, and missing values. Distinguish power kW from energy kWh and record units in metadata or the ingestion contract. ### Vehicle and Asset Tracking Record GPS coordinates and speed as time series. ```sql CREATE TAG TABLE vehicle_track ( vehicle_id VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, lat DOUBLE, lon DOUBLE, speed DOUBLE, heading DOUBLE ); ``` Specify coordinate reference systems and latitude, longitude, and speed units in the ingestion contract. Replacing missing positions with 0 makes them indistinguishable from real coordinates. Creating this table does not automatically provide spatial indexes or route matching. Query by vehicle/time range first, then perform the required analysis. ### Unsuitable Cases - A different tag name for every record (exploding tag counts) - Frequent full-data UPDATE without tag/time limits - Simple event logs (prefer LOG tables) ## Verify Results and Clean Up For the IoT example, verify that the following query returns the three measurements in one row. ```sql SELECT name, time, temperature, vibration, current FROM factory_sensor; DROP TABLE factory_sensor; DROP TABLE energy_meter; DROP TABLE vehicle_track; ``` Apply cleanup only to tables actually created on this page. --- title: "5.10 TAG Metadata" url: https://docs.machbase.com/dbms/tag-table-usage/tag-metadata/ language: en kind: page --- # 5.10 TAG Metadata ## Tag Metadata ### Overview METADATA stores one row of current attributes per tag. Ordinary TAG queries repeat those attributes with each DATA row. Changing a current attribute may also change what historical DATA queries display. Preserve event-time attributes in DATA or a separate attribute history when required. The basic, JSON, and complete examples below use separate tables. Use metadata for static tag attributes such as sensor location, equipment status, installation details, external identifiers, and JSON documents. Metadata-specific SQL supports the following operations. `TAG` in these examples is a table name; replace it with your actual TAG table name. - Query metadata only - `UPDATE` / `DELETE` using metadata predicates - Query the last modification time of a metadata row - ADD/DROP ARRAY metadata columns and set DEFAULT for existing rows - Declare `JSON` metadata columns - Query and index JSON paths - Update part of a JSON document Use `TAG METADATA` syntax without accessing internal storage tables directly. ### Define Metadata Columns Define metadata columns in the `METADATA (...)` clause of `CREATE TAG TABLE`. ```sql CREATE TAG TABLE ch5_meta ( name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ) METADATA ( location VARCHAR(100), status VARCHAR(20), srcip IPV4 ); ``` Metadata stores only one row per tag name. ### Add and Drop ARRAY Metadata Columns Standard Edition can add and drop fixed-length numeric ARRAY columns in the METADATA area of an existing TAG table. ```sql INSERT INTO ch5_meta (name, time, value) VALUES ('TEMP_OLD', TO_DATE('2026-09-05 00:00:00'), 10.0); ALTER TABLE ch5_meta METADATA ADD COLUMN (limits DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]); INSERT INTO ch5_meta (name, time, value) VALUES ('TEMP_NEW', TO_DATE('2026-09-05 00:00:01'), 20.0); SELECT name, limits FROM ch5_meta METADATA ORDER BY name; ``` The existing `TEMP_OLD` metadata row is backfilled with `[0.0000, NULL]`. The `TEMP_NEW` row automatically registered by TAG DATA input after ALTER does not reapply the ADD COLUMN DEFAULT; `limits` is whole NULL. Without a DEFAULT, pre-ALTER rows also receive whole NULL. Added ARRAY metadata columns appear in explicit projections and `SELECT *` in ordinary TAG queries. ARRAY metadata columns have no automatic indexes and do not support explicit indexes such as: ```sql -- Unsupported; raises an error. CREATE INDEX idx_sensor_limits ON ch5_meta METADATA(limits); ``` Specify `METADATA` when dropping a column as well. ```sql ALTER TABLE ch5_meta METADATA DROP COLUMN (limits); ``` Ordinary ARRAY columns in TAG DATA can be declared in `CREATE TAG TABLE`, but cannot be added with ALTER. See [Numeric ARRAY Types](/dbms/reference/sql/types/array/) for element types, cardinality, and DEFAULT rules. ### Insert Metadata Use `INSERT INTO ... METADATA` to insert metadata. ```sql INSERT INTO ch5_meta METADATA VALUES ( 'TEMP_001', 'Building-A/F1', 'READY', '192.168.0.11' ); ``` You can also specify a column list. ```sql INSERT INTO ch5_meta METADATA (name, status, srcip, location) VALUES ('TEMP_002', 'STOP', '192.168.0.12', 'Building-A/F2'); ``` Notes: - Without a column list, VALUES follow the tag name and metadata declaration order. - With a column list, values follow that list. - NULL/DEFAULT handling for omitted input follows the DDL and input-path rules. - The identifier is the TAG name column, declared as `name` in this example. - Creating a metadata row automatically records server time in `_LAST_UPDATE_TIME`. ### Query Metadata #### Query Metadata Only Use `FROM TAG METADATA` for metadata-only queries. ```sql SELECT name, location, status, srcip FROM ch5_meta METADATA ORDER BY name; ``` This returns one row per tag name. ```sql SELECT * FROM ch5_meta METADATA ORDER BY name; ``` `SELECT *` and `table_alias.*` return only `NAME` and metadata columns. System-managed columns such as `_LAST_UPDATE_TIME` do not appear in `SELECT *`. Specify their names explicitly when needed. #### Query the Last Modification Time TAG metadata has a system-managed `_LAST_UPDATE_TIME` column recording each metadata row's last modification time. `_LAST_UPDATE_TIME` records metadata row creation or an actual metadata value change, not the latest tag DATA insertion. ##### Query Methods Query `_LAST_UPDATE_TIME` explicitly by name. ```sql SELECT name, _last_update_time FROM ch5_meta METADATA; ``` It can be selected with other metadata columns or used in predicates. ```sql SELECT name, location, status, _last_update_time FROM ch5_meta METADATA WHERE name = 'TEMP_001'; ``` `SELECT *` and `table_alias.*` omit `_LAST_UPDATE_TIME`. ##### Automatic Recording and Update Rules Creating a metadata row records `_LAST_UPDATE_TIME` automatically. ```sql INSERT INTO ch5_meta METADATA(name, location, status) VALUES('TEMP_003', 'Building-A/F3', 'READY'); ``` An actual user metadata value change updates `_LAST_UPDATE_TIME`. ```sql UPDATE ch5_meta METADATA SET status = 'DONE' WHERE name = 'TEMP_003'; ``` Updating to the same value, or removing a missing JSON path without changing the stored result, is not an actual change. `_LAST_UPDATE_TIME` remains unchanged. ```sql UPDATE ch5_meta METADATA SET status = 'DONE' WHERE name = 'TEMP_003'; ``` Removing a nonexistent JSON path is also a no-op if the stored value does not change. Run the example after creating the JSON table below. ##### Restrictions on Direct Writes `_LAST_UPDATE_TIME` is system-managed. Users cannot insert or modify it directly. The following statements are not allowed: ```sql INSERT INTO ch5_meta METADATA(name, location, status, _last_update_time) VALUES('TEMP_004', 'Building-A/F4', 'READY', now); ``` ```sql UPDATE ch5_meta METADATA SET _last_update_time = now WHERE name = 'TEMP_003'; ``` `_LAST_UPDATE_TIME` is also prohibited as a TAG name column, TAG metadata column, or target of `ALTER TABLE ... METADATA ADD COLUMN`. It cannot be removed with `ALTER TABLE ... METADATA DROP COLUMN`. ```sql CREATE TAG TABLE invalid_sensor ( _last_update_time VARCHAR(128) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); ``` ```sql CREATE TAG TABLE invalid_sensor_meta ( name VARCHAR(128) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ) METADATA ( _last_update_time DATETIME ); ``` Names sharing only the prefix, such as `_LAST_UPDATE_TIME2`, are allowed as user columns. ##### Time Predicates and Automatic Index An index on `_LAST_UPDATE_TIME` is provided automatically for time predicates. ```sql SELECT name, location, _last_update_time FROM ch5_meta METADATA WHERE _last_update_time >= TO_DATE('2026-06-08 00:00:00') ORDER BY _last_update_time; ``` There is no need to create another index on the same column. ##### machloader / tagmetaimport Considerations When importing TAG metadata, include only `NAME` and user metadata columns in input/form files. Internal `_ID` and system-managed `_LAST_UPDATE_TIME` are not input targets. For metadata columns `location` and `status`, use this input form: ```text TEMP_001,Building-A/F1,READY TEMP_002,Building-A/F2,STOP ``` The server fills `_LAST_UPDATE_TIME` automatically during import. A user-defined `_LAST_UPDATE_TIME` in an ordinary LOG, LOOKUP, or VOLATILE table behaves as an ordinary column. Reserved behavior applies only to the TAG metadata system column. #### Query with Data Use ordinary `FROM TAG` to query time-series data using metadata predicates. ```sql SELECT name, status, time, value FROM ch5_meta WHERE status = 'READY' ORDER BY name, time; ``` Results are DATA-row based, so a tag's metadata values repeat with each DATA row. Notes: - `FROM TAG METADATA` cannot select DATA columns such as `TIME` or `VALUE`. - `FROM TAG` selects DATA mode; `FROM TAG METADATA` selects metadata mode. - Internal `_ID` and `_RID` columns are unavailable in `TAG METADATA`. ### Update Metadata Use `UPDATE TAG METADATA` to change metadata. ```sql UPDATE ch5_meta METADATA SET status = 'DONE', srcip = '10.0.0.20' WHERE name = 'TEMP_001'; ``` Metadata predicates can update multiple tags at once. ```sql UPDATE ch5_meta METADATA SET status = 'DONE' WHERE status = 'READY'; ``` Notes: - Update targets are `NAME` and metadata columns. - `UPDATE ... METADATA` cannot change DATA columns such as `TIME` or `VALUE`. - Internal columns cannot be changed. - `_LAST_UPDATE_TIME` changes only when metadata values actually change. ### Delete Metadata Use `DELETE FROM TAG METADATA` to delete metadata. To delete one tag's metadata, specify its name in `WHERE`. ```sql DELETE FROM ch5_meta METADATA WHERE name = 'TEMP_002'; ``` Metadata predicates can delete multiple tags at once. ```sql DELETE FROM ch5_meta METADATA WHERE status = 'STOP'; ``` Without `WHERE`, all metadata is targeted. The exercise still contains DATA for TEMP_OLD and TEMP_NEW, so the following full deletion intentionally fails. ```sql DELETE FROM ch5_meta METADATA; ``` Notes: - If any target has DATA rows, the entire statement fails. - Metadata for a tag in use cannot be deleted. - Full deletion also fails entirely if any tag is in use; it does not delete only unused tags. To delete metadata for a tag in use, delete its DATA rows first, then retry the metadata deletion. ```sql DELETE FROM ch5_meta WHERE name = 'TEMP_001'; DELETE FROM ch5_meta METADATA WHERE name = 'TEMP_001'; ``` ### JSON Metadata Columns Metadata can contain `JSON` columns. ```sql CREATE TAG TABLE ch5_meta_json ( name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ) METADATA ( status VARCHAR(20), info JSON ); ``` Example JSON metadata input: ```sql INSERT INTO ch5_meta_json METADATA VALUES ( 'SHIP_001', 'READY', '{"name":"alpha","ship":{"status":"READY"}}' ); ``` Notes: - Do not specify a length for `JSON` metadata columns. - Invalid JSON strings raise errors. - The raw JSON column itself is not indexed automatically. ### When a JSON Value Does Not Change ```sql SELECT name, _last_update_time FROM ch5_meta_json METADATA; UPDATE ch5_meta_json METADATA SET info = JSON_REMOVE(info, '$.missing') WHERE name = 'SHIP_001'; SELECT name, _last_update_time FROM ch5_meta_json METADATA; ``` If a missing path leaves the stored value unchanged, the modification time also remains unchanged. ### Query JSON Paths Query JSON metadata with the `->` operator. ```sql SELECT name, info->'$.name', info->'$.ship.status' FROM ch5_meta_json METADATA WHERE info->'$.ship.status' = 'READY' ORDER BY name; ``` Use the same syntax in DATA queries. ```sql SELECT name, time, value FROM ch5_meta_json WHERE info->'$.ship.status' = 'READY' ORDER BY name, time; ``` #### Path Notation Queries and partial updates use full JSONPath syntax. - Ordinary key: `$.name` - Nested key: `$.ship.status` - Use bracket notation for keys containing `.` or `-`. ```sql SELECT info->'$[''ship.owner'']' FROM ch5_meta_json METADATA; SELECT info->'$[''ship-owner'']' FROM ch5_meta_json METADATA; ``` ### JSON Path Indexes #### Declare Indexes at Table Creation Index frequently queried JSON paths in the metadata definition. ```sql CREATE TAG TABLE ch5_meta_json_indexed ( name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ) METADATA ( status VARCHAR(20), info JSON INDEX('name', 'ship.status') ); ``` Strings inside `INDEX(...)` are interpreted as follows: - `'name'` means `$.name`. - `'ship.status'` means `$.ship.status`. - Use full JSONPath for special-character keys or complex paths. ```sql INFO JSON INDEX('$[''ship.owner'']') ``` #### Add Indexes After Creation JSON path indexes can also be added after table creation. ```sql CREATE INDEX idx_ship_owner ON ch5_meta_json METADATA (info->'$.owner'); ``` #### Drop an Index Drop an index by its name. ```sql SHOW INDEX idx_ship_owner; DROP INDEX idx_ship_owner; ``` Manage explicitly created indexes by their declared names. Run `SHOW INDEX idx_ship_owner;` before DROP. After deletion, the same name refers to a nonexistent object. #### Index Considerations Current JSON path indexes primarily support string comparisons. ```sql SELECT name FROM ch5_meta_json METADATA WHERE info->'$.status' = 'READY'; ``` String-literal comparisons can use indexes. Numeric-literal comparisons may use a full scan. Examples: - `info->'$.num' = '10'`: May use an index - `info->'$.num' = 10`: May use a full scan ### Partial JSON Updates JSON functions return a new document value with the specified path changed. UPDATE stores that result in the column. This is a logical path-level update, not a performance guarantee of modifying only part of a storage file in place. #### JSON_SET Stores an SQL scalar as a JSON scalar. ```sql UPDATE ch5_meta_json METADATA SET info = JSON_SET(info, '$.ship.status', 'DONE') WHERE name = 'SHIP_001'; ``` #### JSON_SET_JSON Parses the input string as JSON and stores an object or array. ```sql UPDATE ch5_meta_json METADATA SET info = JSON_SET_JSON(info, '$.owner', '{"name":"machbase","team":"db"}') WHERE name = 'SHIP_001'; ``` #### JSON_REMOVE Removes a member or nested path. ```sql UPDATE ch5_meta_json METADATA SET info = JSON_REMOVE(info, '$.owner.team') WHERE name = 'SHIP_001'; ``` #### Partial Update Rules - `JSON_SET(..., path, NULL)` stores JSON `null`. - `JSON_SET_JSON(..., path, NULL)` returns SQL `NULL`. - A `NULL` JSON document argument returns SQL `NULL`. - A `NULL` or empty path raises an error. - `JSON_REMOVE` of a nonexistent path is a no-op, not an error. - `JSON_REMOVE(..., '$')` is not allowed. - Partial updates primarily support object paths. - Array-element path updates, such as `$.items[0]`, are unsupported. ### Complete Example ```sql CREATE TAG TABLE ch5_meta_complete ( name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ) METADATA ( status VARCHAR(20), srcip IPV4, info JSON INDEX('name', 'ship.status') ); INSERT INTO ch5_meta_complete METADATA VALUES ( 'SHIP_001', 'READY', '192.168.0.11', '{"name":"alpha","ship":{"status":"READY"}}' ); INSERT INTO ch5_meta_complete VALUES ('SHIP_001', '2026-04-01 00:00:00', 10.5); SELECT name, status, info FROM ch5_meta_complete METADATA; SELECT name, time, value FROM ch5_meta_complete WHERE info->'$.ship.status' = 'READY'; CREATE INDEX idx_ship_owner ON ch5_meta_complete METADATA (info->'$.owner'); UPDATE ch5_meta_complete METADATA SET info = JSON_SET(info, '$.ship.status', 'DONE') WHERE name = 'SHIP_001'; DROP INDEX idx_ship_owner; ``` ### Summary - Metadata-only queries: `FROM TAG METADATA` - DATA queries: `FROM TAG` - Metadata updates/deletions: `UPDATE/DELETE ... METADATA` - ARRAY metadata changes: `ALTER TABLE ... METADATA ADD/DROP COLUMN` - JSON metadata: `INFO JSON` - `_LAST_UPDATE_TIME` is the metadata row's last modification time and can be queried explicitly. - JSON path indexes: `INFO JSON INDEX(...)` or `CREATE INDEX ... ON TAG METADATA (...)` - Partial JSON updates: `JSON_SET`, `JSON_SET_JSON`, `JSON_REMOVE` - The server manages `_LAST_UPDATE_TIME` identically in Standard and Cluster environments. ## Clean Up the Exercise Unlike the full-deletion failure example, DROP removes the table, DATA, and METADATA. Verify that these names belong to objects created for this exercise before executing. ```sql DROP TABLE ch5_meta; DROP TABLE ch5_meta_json; DROP TABLE ch5_meta_json_indexed; DROP TABLE ch5_meta_complete; ``` --- title: "5.11 TAG Data UPDATE and Correction" url: https://docs.machbase.com/dbms/tag-table-usage/tag-data-update-correction/ language: en kind: page --- # 5.11 TAG Data UPDATE and Correction TAG DATA correction can directly replace original values or preserve originals and apply corrected values at query time. These approaches affect ROLLUP differently. UPDATE exercises require Machbase DBMS 8.7.0 Standard Edition. ## Correct Values Directly Specify both tag-name and BASETIME predicates. SET expressions cannot reference existing-row columns; pass a precomputed value or bind parameter instead of `SET value = value + 1`. Create the following table with a nonconflicting name. It includes default ROLLUP to verify aggregate correction. ```sql CREATE TAG TABLE ch5_correction ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED, status INTEGER ) WITH ROLLUP; INSERT INTO ch5_correction VALUES ('TEMP-01', TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 0); INSERT INTO ch5_correction VALUES ('TEMP-01', TO_DATE('2026-01-01 12:30:00', 'YYYY-MM-DD HH24:MI:SS'), 99.0, 0); INSERT INTO ch5_correction VALUES ('TEMP-02', TO_DATE('2026-01-01 12:30:00', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 0); ``` ### Check Scope, Update, and Query Again ```sql SELECT COUNT(*), MIN(value), MAX(value) FROM ch5_correction WHERE name = 'TEMP-01' AND time >= TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS') AND time < TO_DATE('2026-01-01 13:00:00', 'YYYY-MM-DD HH24:MI:SS'); UPDATE ch5_correction SET value = 25.0, status = 1 WHERE name = 'TEMP-01' AND time >= TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS') AND time < TO_DATE('2026-01-01 13:00:00', 'YYYY-MM-DD HH24:MI:SS'); SELECT name, time, value, status FROM ch5_correction ORDER BY name, time; ``` The first query returns 2 rows, minimum 10.0, and maximum 99.0. After UPDATE, both TEMP-01 rows have value=25.0 and status=1; TEMP-02 retains 20.0. A preceding COUNT does not lock targets. Control the cutoff and range separately when concurrent ingestion is possible. ### Multiple Tags and Error Handling Tag selection supports `=`, `IN`, and `LIKE`. Check target names and counts before broad patterns or long time ranges, and divide work into smaller ranges. Multiple tags may be processed sequentially; do not assume a failure atomically undoes the entire statement. Requery changed values and remaining targets before retrying. Use `>= start AND < end` for adjacent time intervals to avoid processing boundary rows twice. Ending a full day at `23:59:59` can miss fractional-second data after that time. See [TAG UPDATE](../../reference/sql/syntax/dml-syntax/tag-data-update-syntax/) for allowed predicates and binding. ### Rebuild ROLLUP Changing source data does not automatically update previously calculated ROLLUP. Rebuild the corrected interval as follows, then follow [ROLLUP Rebuild](../../tag-rollup-usage/rollup-rebuild/) for progress and query validation. ```sql EXEC ROLLUP_REBUILD(ch5_correction, 'TEMP-01', TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), TO_DATE('2026-01-01 13:00:00', 'YYYY-MM-DD HH24:MI:SS')); ``` ## Preserve Originals and Correct to NULL Store original and corrected values in separate columns to retain the initial value. A corrected value may itself be NULL, so use a flag instead of testing only `corrected_value IS NOT NULL`. ```sql CREATE TAG TABLE ch5_correction_overlay ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, raw_value DOUBLE, corrected_value DOUBLE, is_corrected SHORT ); INSERT INTO ch5_correction_overlay VALUES ('TEMP-01', TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 99.0, NULL, 0); UPDATE ch5_correction_overlay SET corrected_value = NULL, is_corrected = 1 WHERE name = 'TEMP-01' AND time = TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'); SELECT name, raw_value, is_corrected, CASE WHEN is_corrected = 1 THEN corrected_value ELSE raw_value END AS effective_value FROM ch5_correction_overlay; ``` raw_value is 99.0, is_corrected is 1, and effective_value is NULL. A flag of 0 selects the original. This approach chooses values in a query expression without changing raw_value. Do not assume default ROLLUP aggregates the CASE expression automatically or that rebuilding raw_value incorporates corrections. Define a separate query/aggregation model for effective values. ## Correction History and Validation Record separate history to retain reasons and operators for repeated changes. ```sql CREATE LOG TABLE ch5_correction_log ( sensor_name VARCHAR(64), target_time DATETIME, old_value DOUBLE, new_value DOUBLE, reason VARCHAR(256), corrected_by VARCHAR(64) ); ``` TAG updates and LOG history writes do not share one TRANSACTION transaction. Design ordering, partial-failure handling, and operation identifiers for retries in the application. Creating a history table does not automatically record audits. After correction, verify original/effective values, affected-row counts, interval statistics, and reports. Then remove only exercise objects. The CASCADE below also deletes the ROLLUPs of ch5_correction. ```sql DROP TABLE ch5_correction CASCADE; DROP TABLE ch5_correction_overlay; DROP TABLE ch5_correction_log; ``` --- title: "5.12 tagmetaimport and Bulk Metadata Registration" url: https://docs.machbase.com/dbms/tag-table-usage/tagmetaimport/ language: en kind: page --- # 5.12 tagmetaimport and Bulk Metadata Registration ## Register Metadata with tagmetaimport `tagmetaimport` imports tag names and user metadata from CSV. Distinguish the logical TAG name used in SQL from the `-t` input target. The current wrapper passes `-t` to machloader. For logical table `ch5_meta_import`, the metadata input target is `_CH5_META_IMPORT_META`. Do not assume `-t ch5_meta_import` automatically selects METADATA. Use that name only to specify the tool target. Use `ch5_meta_import METADATA` for SQL queries/changes; do not extend this into direct modification of internal storage objects. Specify `-t` instead of relying on a default. ## 1. Prepare the Table Run this SQL in an exercise database without conflicting objects. ```sql CREATE TAG TABLE ch5_meta_import ( name VARCHAR(40) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ) METADATA ( location VARCHAR(40), status VARCHAR(20) ); ``` ## 2. Prepare CSV Save the following as `ch5_metadata.csv` on the client. ```csv name,location,status TEMP_001,Building-A/F1,READY TEMP_002,Building-A/F2,STOP TEMP_003,Building-B/F3,READY ``` After the tag name, list values in METADATA declaration order. Omit DATA time/value and system columns `_ID`/`_LAST_UPDATE_TIME`. Use `-H` for a header; do not assume headers automatically map arbitrary column orders. ## 3. Import and Verify Adjust the address/account to the exercise server and run with the `MACHBASE_HOME` and library environment of the installed 8.7.0 package. ```bash tagmetaimport -s 127.0.0.1 -P 5656 -u SYS -p MANAGER \ -t _CH5_META_IMPORT_META -d ch5_metadata.csv -H \ -l ch5_import.log -b ch5_import.bad ``` Expect 3 successes and 0 failures on the first run. The METADATA query below returns three rows and DATA COUNT is 0. Registering metadata is separate from inserting measurements. ```sql SELECT name, location, status, _last_update_time FROM ch5_meta_import METADATA ORDER BY name; SELECT COUNT(*) FROM ch5_meta_import; ``` ## 4. Existing Tags and Reruns Reimporting the same file does not automatically update existing tags. This path uses ordinary METADATA INSERT, so duplicate tags count as failed rows. Expect 0 successes and 3 failures on the second run, with existing attributes unchanged. Check success/failure counts and bad/log files, not just exit status. Do not assume a file containing valid new rows and invalid rows forms one transaction. Check registered tags, correct failed rows, and reprocess only those rows. Change existing attributes with explicit UPDATE or supported UPSERT. ```sql UPDATE ch5_meta_import METADATA SET status = 'DONE' WHERE name = 'TEMP_001'; INSERT INTO ch5_meta_import METADATA VALUES ('TEMP_002', 'Building-C/F2', 'READY') ON DUPLICATE KEY UPDATE; SELECT name, location, status FROM ch5_meta_import METADATA ORDER BY name; ``` TEMP_001 changes to DONE; TEMP_002 changes to Building-C/F2 and READY. Actual value changes update modification time; same-value no-ops preserve it. Do not interpret this as an automatic UPSERT option in `tagmetaimport`. ## Cleanup and Related Documentation After checking results, run `DROP TABLE ch5_meta_import;` to remove only the exercise table. Remove CSV, log, and bad files after confirming they are no longer needed for reprocessing. See the [tagmetaimport Reference](../../reference/command-line-tools/tagmetaimport/) for options and [TAG Metadata](../tag-metadata/) for SQL registration and change rules. --- title: "6. ROLLUP for TAG Tables" url: https://docs.machbase.com/dbms/tag-rollup-usage/ language: en kind: section --- # 6. ROLLUP for TAG Tables ROLLUP preaggregates data from time-axis TAG tables and combines the stored statistics at query time to reduce repeated analysis cost. This chapter distinguishes basic, conditional, extension, JSON, and Custom ROLLUP in Machbase DBMS 8.7.0, covering creation, result validation, and rebuilding. ## Distinguish Three Intervals | Concept | Meaning | Example | |---|---|---| | Creation INTERVAL | Width of stored aggregation buckets | 1 MIN | | WAKEUP INTERVAL | How often the aggregation job wakes up | 10 SEC | | Query bucket | Result interval requested by a report | `rollup('min', 5, time)` | Multiple partial aggregates can be stored for the same bucket. Basic ROLLUP public query syntax merges the required statistics; for Custom target TAG tables, users write the final reaggregation query. Define source retention separately from ROLLUP retention and rebuild policies. ## Chapter Contents | Section | Topics | |---|---| | [Overview and Use Criteria](./overview-use-criteria/) | Basic exercise and source/aggregate comparison | | [Target TAG Design](./target-tag-table-design/) | ON/FROM, hierarchy constraints, and capacity estimates | | [Creation and Deletion](./create-delete-rollup/) | CREATE, WITH ROLLUP, IF NOT EXISTS, and dependencies | | [Query Syntax](./query-syntax-rollup/) | Candidate selection, time units, and origin | | [Conditional ROLLUP](./conditional-rollup/) | Source filters and explicit candidate selection | | [Custom ROLLUP](./custom-rollup/) | Reaggregating incremental results and OHLCV hierarchies | | [Extension ROLLUP](./extension-rollup/) | FIRST/LAST and OHLC validation | | [JSON ROLLUP](./json-summarized-rollup/) | Path/full-document aggregation and NULL | | [Control and Status](./ingestion-control-rollup/) | STOP/START/WAKEUP/FORCE, V$ROLLUP, and gaps | | [REBUILD](./rollup-rebuild/) | Supported targets, bucket boundaries, and corrections | | [Performance Tuning](./performance-tuning-rollup/) | Comparing costs for equivalent results | | [Usage Scenarios](./patterns-scenarios/) | Multiple tags and source/aggregate responsibilities | Each page is a standalone exercise with object names beginning with `ch6_`. Check for conflicts with existing business objects and keep intentional-error examples separate from success scripts. Query fixed-time data using the stated fixed ranges. Clean up only the exercise tables and ROLLUPs. Custom and REBUILD are Standard Edition only. Creating a ROLLUP or successfully ingesting data does not mean aggregation has finished. Exercises use a named FORCE call to catch up processing and then check results. Continue with [Support Scope](../reference/support-scope-constraints/rollup/) and [Troubleshooting](../troubleshooting/rollup/) for limitations and diagnosis. --- title: "6.1 ROLLUP Overview and Use Criteria" url: https://docs.machbase.com/dbms/tag-rollup-usage/overview-use-criteria/ language: en kind: page --- # 6.1 ROLLUP Overview and Use Criteria ROLLUP reduces the cost of repeatedly aggregating raw rows. It is neither a source-retention policy nor a cache for arbitrary query results, and it cannot reconstruct source information absent from the aggregates. ## Use Criteria | Requirement | Approach to consider | |---|---| | Repeated interval statistics for one numeric column | General ROLLUP | | Aggregate only samples meeting quality conditions | Conditional ROLLUP | | First and last values within an interval | EXTENSION ROLLUP | | Store multiple aggregate expressions in a separate TAG | Custom ROLLUP (Standard Edition only) | | Aggregate numeric values in JSON paths or documents | JSON path or full-document ROLLUP | | Distance-axis TAG | Ordinary numeric interval aggregation; ROLLUP unsupported | SUMMARIZED is not required when explicitly creating a ROLLUP on an ordinary numeric column. WITH ROLLUP automatic creation and full-document JSON aggregation have separate SUMMARIZED requirements. See [Creation Syntax](../create-delete-rollup/). ## Basic Exercise ### 1. Create and Insert ```sql CREATE TAG TABLE ch6_basic ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, quality INTEGER ); CREATE ROLLUP ch6_basic_ru ON ch6_basic(value) INTERVAL 1 MIN; INSERT INTO ch6_basic VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1); INSERT INTO ch6_basic VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1); INSERT INTO ch6_basic VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1); INSERT INTO ch6_basic VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1); ``` ### 2. Check the Completed Aggregation Range ```sql EXEC TABLE_FLUSH(ch6_basic); ALTER ROLLUP ch6_basic_ru FORCE; SHOW ROLLUPGAP; ``` SHOW ROLLUPGAP is a machsql command. SDKs should use supported SQL queries such as V$ROLLUP. TABLE_FLUSH processes storage buffers; FORCE catches up the named ROLLUP's processing range. It does not complete processing for future arrivals during continuous ingestion. ### 3. Compare with Source Data ```sql SELECT DATE_TRUNC('minute', time) AS bucket, COUNT(value), MIN(value), MAX(value), AVG(value) FROM ch6_basic WHERE name = 'TEMP_01' GROUP BY bucket ORDER BY bucket; SELECT rollup('min', 1, time) AS bucket, COUNT(value), MIN(value), MAX(value), AVG(value) FROM ch6_basic WHERE name = 'TEMP_01' GROUP BY bucket ORDER BY bucket; ``` | Bucket | COUNT(value) | MIN | MAX | AVG | |---|---:|---:|---:|---:| | 2026-01-01 00:00:00 | 2 | 10 | 20 | 15 | | 2026-01-01 00:01:00 | 1 | 30 | 30 | 30 | Both queries should return the same results. A DATE_TRUNC aggregation on source data does not automatically switch simply because a ROLLUP exists. Specify `rollup()` explicitly in ROLLUP queries. ### 4. Clean Up ```sql DROP ROLLUP ch6_basic_ru; DROP TABLE ch6_basic; ``` ## Before Adoption Define representative tag counts, ingestion volume, query frequency, and acceptable aggregation lag. Determine the finest required interval and source retention first, then continue to [Hierarchy Design](../target-tag-table-design/). Measure long-period performance with production-like data rather than extrapolating from this small sample. --- title: "6.2 Target TAG Table Design for ROLLUP" url: https://docs.machbase.com/dbms/tag-rollup-usage/target-tag-table-design/ language: en kind: page --- # 6.2 Target TAG Table Design for ROLLUP ## ON and FROM `ON source(column)` aggregates a column of a source time-axis TAG table. `FROM rollup_name` combines statistics from an existing general/extension ROLLUP into larger intervals. A Custom target is also a TAG table, but the next Custom stage uses INTO...AS with a SELECT from that target TAG. ## Hierarchy Exercise ```sql CREATE TAG TABLE ch6_design ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, quality INTEGER ); CREATE ROLLUP ch6_design_sec ON ch6_design(value) INTERVAL 1 SEC; CREATE ROLLUP ch6_design_min FROM ch6_design_sec INTERVAL 1 MIN; CREATE ROLLUP ch6_design_hour FROM ch6_design_min INTERVAL 1 HOUR; INSERT INTO ch6_design VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1); INSERT INTO ch6_design VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1); INSERT INTO ch6_design VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1); INSERT INTO ch6_design VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1); EXEC TABLE_FLUSH(ch6_design); ALTER ROLLUP ch6_design_sec FORCE; ALTER ROLLUP ch6_design_min FORCE; ALTER ROLLUP ch6_design_hour FORCE; SELECT name, rollup('hour', 1, time) AS bucket, SUM(value), COUNT(value), AVG(value) FROM ch6_design GROUP BY name, bucket ORDER BY name, bucket; ``` TEMP_01 has sum 60, count 3, and average 20; TEMP_02 has 100, 1, and 100. FORCE lower levels first so upper levels can process newly generated lower-level results. ### Hierarchy Constraints - The upper interval must be larger than the source interval and an integer multiple of it. Equal intervals are not allowed. - FROM cannot convert general ROLLUP to extension ROLLUP or vice versa. Keep EXTENSION consistent throughout the hierarchy. - JSON path/full-document modes must also match the source. - Coarse statistics cannot reconstruct source detail finer than the smallest supported query interval. Each creation example below intentionally fails. ```sql CREATE ROLLUP ch6_design_bad_same FROM ch6_design_min INTERVAL 1 MIN; CREATE ROLLUP ch6_design_bad_divisor FROM ch6_design_min INTERVAL 90 SEC; CREATE ROLLUP ch6_design_bad_ext FROM ch6_design_sec INTERVAL 1 MIN EXTENSION; ``` ## Choosing Intervals and Storage Capacity Assuming every tag has values in every interval, the approximate logical bucket count is `(retention time / bucket interval) × tag count`. Retaining 1-second buckets for 10,000 tags for 365 days gives about 315.4 billion buckets. Actual row counts depend on partial aggregates, empty intervals, and column counts. Measure disk usage including compression and storage overhead. If second-level observations are queried only by minute, assess whether every second-level hierarchy is needed. Creation intervals use SEC/MIN/HOUR; DAY/WEEK/MONTH/YEAR are query bucket units. In particular, do not assume a 24 HOUR storage interval works directly for daily queries; check [Candidate Selection Rules](../query-syntax-rollup/). A new ROLLUP initially aggregates existing data still present in its source. Check initial workload and gaps. FORCE does not rewind processing after source corrections. Follow [REBUILD Support Scope](../rollup-rebuild/). ## Clean Up ```sql DROP ROLLUP ch6_design_hour; DROP ROLLUP ch6_design_min; DROP ROLLUP ch6_design_sec; DROP TABLE ch6_design; ``` --- title: "6.3 Create and Delete ROLLUP" url: https://docs.machbase.com/dbms/tag-rollup-usage/create-delete-rollup/ language: en kind: page --- # 6.3 Create and Delete ROLLUP ## Creation Syntax ```text CREATE ROLLUP [IF NOT EXISTS] name ON source_tag [(column_or_json_path)] INTERVAL n (SEC|MIN|HOUR) [WAKEUP INTERVAL m (SEC|MIN|HOUR)] [EXTENSION] [WHERE predicate]; CREATE ROLLUP [IF NOT EXISTS] name FROM source_rollup INTERVAL n (SEC|MIN|HOUR) [WAKEUP INTERVAL m (SEC|MIN|HOUR)] [EXTENSION] [WHERE predicate]; ``` Do not specify a separate extension name after EXTENSION. CREATE accepts SEC/MIN/HOUR, unlike query-function units such as DAY/MONTH. The interval must be positive; the current validation maximum is equivalent to 365 days. Source, hierarchy, and aggregation-mode requirements must also be met. | Target | Requirement | |---|---| | Ordinary numeric column | Specify a supported numeric type; SUMMARIZED is not required | | JSON path | Specify the JSON column and a valid path | | Entire JSON document | Requires a JSON SUMMARIZED column | | WITH ROLLUP automatic creation | Requires the third column to be SUMMARIZED | | METADATA, distance-axis, or non-TAG | Not a general ROLLUP target | ## Creation, Duplicate-Name Checks, and Queries ```sql CREATE TAG TABLE ch6_create ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, quality INTEGER ); CREATE ROLLUP IF NOT EXISTS ch6_create_ru ON ch6_create(value) INTERVAL 1 MIN; CREATE ROLLUP IF NOT EXISTS ch6_create_ru ON ch6_create(value) INTERVAL 1 MIN; INSERT INTO ch6_create VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1); INSERT INTO ch6_create VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1); INSERT INTO ch6_create VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1); INSERT INTO ch6_create VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1); EXEC TABLE_FLUSH(ch6_create); ALTER ROLLUP ch6_create_ru FORCE; SELECT DISTINCT ROLLUP_NAME, COLUMN_NAME, INTERVAL_TIME, WAKEUP_INTERVAL FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CREATE_RU'; SELECT rollup('min', 1, time) AS bucket, AVG(value) FROM ch6_create WHERE name = 'TEMP_01' GROUP BY bucket ORDER BY bucket; ``` Recreating an existing name retains its definition. IF NOT EXISTS neither changes nor verifies the definition, and does not bypass all invalid-SQL or source validation. Both interval columns are 60000 ms. The query averages are 15 at 00:00 and 30 at 00:01. Creating the same name without IF NOT EXISTS causes an error. Check it separately from the successful exercise. ```sql CREATE ROLLUP ch6_create_ru ON ch6_create(value) INTERVAL 1 MIN; ``` ## Automatic Creation with WITH ROLLUP The following separate table automatically creates the default SEC→MIN→HOUR hierarchy. ```sql CREATE TAG TABLE ch6_auto ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ) WITH ROLLUP (SEC); SELECT DISTINCT ROLLUP_NAME, ROOT_TABLE, INTERVAL_TIME, EXT_TYPE FROM V$ROLLUP WHERE ROOT_TABLE = 'CH6_AUTO' ORDER BY INTERVAL_TIME; ``` The query returns three rows with INTERVAL_TIME values 1000, 60000, and 3600000. Automatic EXTENSION creation uses `WITH ROLLUP (SEC) EXTENSION`. Check actual generated names in V$ROLLUP; do not assume name conflicts are resolved automatically. The argument determines the hierarchy: `(SEC)` creates SEC, MIN, and HOUR; `(MIN)` creates MIN and HOUR; `(HOUR)` creates only HOUR. Omitting the argument is equivalent to `(SEC)`. Only the first stage reads the source TAG; each later stage reads the preceding ROLLUP. Only SEC/MIN/HOUR are accepted. Query-function units such as DAY cause an error. ## Deleting and Changing Definitions Remove upper-level dependents before a source referenced by another ROLLUP. A Custom target TAG cannot be dropped before its job. To change a definition, account for readers and reaggregation time, then switch to a new object or remove and recreate the existing definition. ```sql DROP ROLLUP ch6_create_ru; DROP TABLE ch6_create; DROP TABLE ch6_auto CASCADE; ``` The final CASCADE also removes this exercise's automatic ROLLUPs. Do not use it as the default for ordinary production cleanup. CASCADE on a Custom source can remove associated jobs, but does not automatically delete user target TAG tables. Conditional, extension, JSON, and Custom exercises are provided independently in their sections. For full syntax, see the [SQL Reference](../../reference/sql/syntax/rollup-syntax/). --- title: "6.4 ROLLUP Query Syntax" url: https://docs.machbase.com/dbms/tag-rollup-usage/query-syntax-rollup/ language: en kind: page --- # 6.4 ROLLUP Query Syntax ## Explicit ROLLUP Queries ```text rollup(time_unit, period, basetime_column [, origin]) ``` | Argument | Requirements | |---|---| | time_unit | SECOND/SEC, MINUTE/MIN, HOUR, DAY, WEEK, MONTH, YEAR; case-insensitive | | period | Positive integer literal; not a column or parameter placeholder | | basetime_column | BASETIME column of the source time-axis TAG | | origin | If omitted, uses the default reference point adjusted for the time-zone offset; explicit values have unit-specific restrictions | The result is a DATETIME bucket. Finer detail than the minimum stored aggregation interval cannot be reconstructed. If no applicable ROLLUP exists, the query fails instead of automatically falling back to a raw scan. Write a separate DATE_TRUNC/DATE_BIN + GROUP BY query for source aggregation. ## Preparation and Basic Queries ```sql CREATE TAG TABLE ch6_query ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, quality INTEGER ); CREATE ROLLUP ch6_query_sec ON ch6_query(value) INTERVAL 1 SEC; INSERT INTO ch6_query VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1); INSERT INTO ch6_query VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1); INSERT INTO ch6_query VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1); INSERT INTO ch6_query VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1); EXEC TABLE_FLUSH(ch6_query); ALTER ROLLUP ch6_query_sec FORCE; SELECT name, rollup('min', 1, time) AS bucket, COUNT(value), SUM(value), MIN(value), MAX(value), AVG(value) FROM ch6_query WHERE time >= TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND time < TO_DATE('2026-01-01 00:02:00', 'YYYY-MM-DD HH24:MI:SS') GROUP BY name, bucket ORDER BY name, bucket; ``` TEMP_01 at 00:00 has COUNT=2, SUM=30, AVG=15; at 00:01 it has 1, 30, 30. TEMP_02 at 00:00 has 1, 100, 100. If SELECT returns name, also include name in GROUP BY. Omitting name combines tags; do not mix sensors with different units. ## Candidate Selection and Hints 1. If a ROLLUP_TABLE hint is present, check the named candidate for compatibility. 2. Automatic selection finds candidates matching the aggregate column, JSON path, mode, and requested interval. 3. Search unconditional candidates first; if none exist, include conditional candidates. 4. Select the largest applicable interval. For equal intervals, retain the first registered candidate. Do not assume general ROLLUP always takes priority over extension ROLLUP. If only conditional ROLLUPs exist, filtered data can be selected automatically. Check which sample set the result represents. Specify a hint when a particular aggregate must be used. ```sql SELECT /*+ ROLLUP_TABLE(ch6_query_sec) */ rollup('min', 1, time) AS bucket, AVG(value) FROM ch6_query WHERE name = 'TEMP_01' GROUP BY bucket ORDER BY bucket; ``` ### Stored Candidate Intervals and Query Buckets Current candidate-interval validation calculates SEC requests as period seconds and MIN requests as period minutes. HOUR and DAY/WEEK/MONTH/YEAR requests are checked against period hours during candidate selection. Selected statistics are then merged into the requested calendar/time buckets. Do not assume a 24 HOUR ROLLUP automatically serves `rollup('day', 1, time)`. That request considers HOUR/MIN/SEC candidates compatible with a 1-hour basis. Distinguish creation INTERVAL from result buckets and inspect the actual execution plan. ## Aggregate Functions and Samples General numeric ROLLUP supports MIN, MAX, SUM, COUNT, AVG, and SUMSQ. FIRST/LAST in a ROLLUP query require EXTENSION. Custom results are stored in ordinary TAG tables; use the sum/count rules in [Custom Reaggregation](../custom-rollup/). COUNT for full-document JSON aggregation is covered separately in [JSON](../json-summarized-rollup/). ### SUMSQ, Variance, and Standard Deviation ROLLUP queries do not directly support STDDEV, STDDEV_POP, VARIANCE, or VAR_POP. Using them in a `rollup()` query causes `ERR-02816: Only rollup column with aggregate function can be referenced in ROLLUP SELECT query.` Variances and standard deviations cannot be added across intervals. Averaging two interval standard deviations does not give the standard deviation of the combined interval. Instead, ROLLUP stores SUMSQ, the sum of squared values, alongside COUNT and SUM. All three are additive and remain valid when merged into buckets larger than the storage interval. Variance and standard deviation can then be calculated at query time. SUMSQ is included in both general and EXTENSION ROLLUP. | Value | Formula | |---|---| | Population variance | `SUMSQ/N - (SUM/N)^2` | | Population standard deviation | Square root of population variance | | Sample variance | `(SUMSQ - SUM^2/N) / (N-1)` | | Sample standard deviation | Square root of sample variance | N is `COUNT(value)`, the number of valid, non-NULL values. Keep only supported aggregates in the ROLLUP query block, and calculate variance and standard deviation outside the inline view. This reads COUNT, SUM, and SUMSQ once and separates derived calculations, allowing formulas to change without changing the ROLLUP query. ```sql SELECT bucket, n, s, sq, sq/n - POWER(s/n, 2) AS var_pop, SQRT(sq/n - POWER(s/n, 2)) AS stddev_pop FROM ( SELECT rollup('min', 1, time) AS bucket, COUNT(value) AS n, SUM(value) AS s, SUMSQ(value) AS sq FROM ch6_query WHERE name = 'TEMP_01' GROUP BY bucket ) t ORDER BY bucket; ``` The 00:00 bucket contains 10 and 20, so n=2, s=30, sq=500, population variance=25, and population standard deviation=5. The 00:01 bucket has one value, so both population measures are 0. Sample variance divides by `N-1`, so handle single-value buckets first, also outside the inline view. Explicit `ELSE NULL` causes `ERR-02042`; omit ELSE. ```sql SELECT bucket, n, CASE WHEN n > 1 THEN (sq - POWER(s, 2)/n) / (n - 1) END AS var_samp FROM ( SELECT rollup('min', 1, time) AS bucket, COUNT(value) AS n, SUM(value) AS s, SUMSQ(value) AS sq FROM ch6_query WHERE name = 'TEMP_01' GROUP BY bucket ) t ORDER BY bucket; ``` The 00:00 sample variance is 50; the single-value 00:01 bucket returns NULL. To omit single-value intervals, use `WHERE n > 1` outside the inline view. Source-table `VARIANCE` and `STDDEV` return 0 rather than NULL for these intervals, so align display policies when combining results. For the example values, results match direct `VAR_POP`, `STDDEV_POP`, `VARIANCE`, and `STDDEV` on the source table. However, both formulas lose precision when the mean is large relative to the spread. For values near 100000 varying only in fractional digits, `SUMSQ/N` and `(SUM/N)^2` are nearly equal, reducing significant digits after subtraction. If floating-point error yields a small negative variance, SQRT is also invalid. When precision matters, compare with source-table STDDEV and VAR_POP to establish an acceptable range. ## Calendar Units and origin Use the same data to check monthly results and weeks starting on Monday. ```sql SELECT rollup('month', 1, time, '2000-01-01 00:00:00') AS bucket, SUM(value), COUNT(value), AVG(value) FROM ch6_query WHERE name = 'TEMP_01' GROUP BY bucket ORDER BY bucket; SELECT rollup('week', 1, time, '1970-01-05 00:00:00') AS bucket, AVG(value) FROM ch6_query WHERE name = 'TEMP_01' GROUP BY bucket ORDER BY bucket; ``` The monthly query returns SUM=60, COUNT=3, AVG=20 in the 2026-01-01 bucket. Monthly/yearly origin values must be on the first day of a month after time-zone interpretation, and results fall at midnight on the corresponding month boundary. This does not shift monthly business start times by arbitrary dates or time offsets. Distinguish fixed-interval origins, such as day/week, from month/year calendar calculations. Check string interpretation together with the connection time zone. Do not assume DST automatically matches the desired business calendar. Compare against source DATE_BIN aggregation around boundaries. Validate equivalence to source results for origins or query boundaries that would split stored aggregates. ## Clean Up ```sql DROP ROLLUP ch6_query_sec; DROP TABLE ch6_query; ``` --- title: "6.5 Conditional ROLLUP" url: https://docs.machbase.com/dbms/tag-rollup-usage/conditional-rollup/ language: en kind: page --- # 6.5 Conditional ROLLUP ## Filter Source Rows Before Aggregation Conditional ROLLUP maintains statistics for source rows meeting quality or state conditions. This differs from removing bad samples from an already computed average. The quality column used by the predicate is not itself retained in the aggregate result. ## 1. Prepare the Table and Two ROLLUPs ```sql CREATE TAG TABLE ch6_condition ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, quality INTEGER ); CREATE ROLLUP ch6_condition_all ON ch6_condition(value) INTERVAL 1 MIN EXTENSION; CREATE ROLLUP ch6_condition_good ON ch6_condition(value) INTERVAL 1 MIN EXTENSION WHERE quality = 1; INSERT INTO ch6_condition VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1); INSERT INTO ch6_condition VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1); INSERT INTO ch6_condition VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1); INSERT INTO ch6_condition VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1); INSERT INTO ch6_condition VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:50', 'YYYY-MM-DD HH24:MI:SS'), 90.0, 0); EXEC TABLE_FLUSH(ch6_condition); ALTER ROLLUP ch6_condition_all FORCE; ALTER ROLLUP ch6_condition_good FORCE; ``` ## 2. Compare the Source Predicate and ROLLUP ```sql SELECT DATE_TRUNC('minute', time) AS bucket, COUNT(value), AVG(value), MIN(value), MAX(value), FIRST(time, value), LAST(time, value) FROM ch6_condition WHERE name = 'TEMP_01' AND quality = 1 GROUP BY bucket ORDER BY bucket; SELECT /*+ ROLLUP_TABLE(ch6_condition_good) */ rollup('min', 1, time) AS bucket, COUNT(value), AVG(value), MIN(value), MAX(value), FIRST(time, value), LAST(time, value) FROM ch6_condition WHERE name = 'TEMP_01' GROUP BY bucket ORDER BY bucket; SELECT /*+ ROLLUP_TABLE(ch6_condition_all) */ rollup('min', 1, time) AS bucket, COUNT(value), AVG(value), MIN(value), MAX(value), FIRST(time, value), LAST(time, value) FROM ch6_condition WHERE name = 'TEMP_01' GROUP BY bucket ORDER BY bucket; ``` | Bucket and set | COUNT | AVG | MIN | MAX | FIRST | LAST | |---|---:|---:|---:|---:|---:|---:| | 00:00, all rows | 3 | 40 | 10 | 90 | 10 | 90 | | 00:00, quality=1 | 2 | 15 | 10 | 20 | 10 | 20 | | 00:01, both sets | 1 | 30 | 30 | 30 | 30 | 30 | The bad sample is last in its interval, so LAST also differs. FIRST/LAST return the selected value, not a timestamp/value pair. ## Explicit Candidate Selection This example uses hints to fix the result sets for all samples and valid samples. Automatic selection favors unconditional candidates, but can select filtered statistics when only conditional candidates exist. Do not interpret this as conditional ROLLUP always being ignored or EXTENSION always requiring a hint. ## Syntax and Constraints For general ROLLUP, place the filter in WHERE after INTERVAL and EXTENSION. Comparisons, BETWEEN, IN, LIKE, logical operations, and supported scalar functions are allowed. Subqueries, aggregate functions, and predicates on the tag-name PRIMARY KEY are unsupported. Custom uses WHERE inside SELECT; do not mix these syntax forms. ## Check Status and Clean Up ```sql SELECT DISTINCT ROLLUP_NAME, PREDICATE, ENABLED FROM V$ROLLUP WHERE ROOT_TABLE = 'CH6_CONDITION'; DROP ROLLUP ch6_condition_good; DROP ROLLUP ch6_condition_all; DROP TABLE ch6_condition; ``` When business quality criteria change, update both the predicate and reaggregation plan. Existing aggregates do not automatically adopt the new predicate. See [Control](../ingestion-control-rollup/) and [Rebuild Scope](../rollup-rebuild/). --- title: "6.6 Custom ROLLUP" url: https://docs.machbase.com/dbms/tag-rollup-usage/custom-rollup/ language: en kind: page --- # 6.6 Custom ROLLUP Standard Edition only ## Custom and General ROLLUP Custom ROLLUP appends incremental SELECT aggregation results to a precreated target TAG table. General ROLLUP reads internal statistics through `rollup()`; Custom instead requires querying the target TAG directly and merging partial aggregates again. It cannot be created in Cluster Edition. ```text CREATE ROLLUP [IF NOT EXISTS] name INTO (destination_tag) AS (SELECT ... FROM source_tag [WHERE ...] GROUP BY ...) INTERVAL n (SEC|MIN|HOUR) [WAKEUP INTERVAL m (SEC|MIN|HOUR)]; ``` The source must be one time-axis TAG table. JOIN and FROM subqueries are unsupported. The target must be a precreated TAG compatible with the SELECT column order and types. WHERE inside SELECT is allowed, but direct BASETIME predicates are not. Do not append an external WHERE after INTERVAL as in general ROLLUP. Match the creation interval to the time bucket calculated by SELECT. Because the job processes only new input, one bucket can contain several result rows. Do not interpret row count as bucket count. ## 1. Sum and Valid-Count Exercise ```sql CREATE TAG TABLE ch6_custom_src ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ); CREATE TAG TABLE ch6_custom_dst ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, sum_value DOUBLE, valid_count LONG, total_count LONG ); CREATE ROLLUP ch6_custom_ru INTO (ch6_custom_dst) AS ( SELECT name, DATE_TRUNC('minute', time) AS time, SUM(value), COUNT(value), COUNT(*) FROM ch6_custom_src GROUP BY name, time ) INTERVAL 1 MIN; INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10); INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:05', 'YYYY-MM-DD HH24:MI:SS'), 10); EXEC TABLE_FLUSH(ch6_custom_src); ALTER ROLLUP ch6_custom_ru FORCE; INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:10', 'YYYY-MM-DD HH24:MI:SS'), 20); INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:15', 'YYYY-MM-DD HH24:MI:SS'), 20); INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:20', 'YYYY-MM-DD HH24:MI:SS'), 20); INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:25', 'YYYY-MM-DD HH24:MI:SS'), 20); INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20); INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:35', 'YYYY-MM-DD HH24:MI:SS'), 20); INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:40', 'YYYY-MM-DD HH24:MI:SS'), 20); INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:45', 'YYYY-MM-DD HH24:MI:SS'), 20); INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:55', 'YYYY-MM-DD HH24:MI:SS'), NULL); EXEC TABLE_FLUSH(ch6_custom_src); ALTER ROLLUP ch6_custom_ru FORCE; SELECT name, DATE_TRUNC('minute', time) AS bucket, SUM(value), COUNT(value), COUNT(*), AVG(value) FROM ch6_custom_src GROUP BY name, bucket ORDER BY name, bucket; SELECT name, time, SUM(sum_value) AS sum_value, SUM(valid_count) AS valid_count, SUM(total_count) AS total_count, CASE WHEN SUM(valid_count) = 0 THEN NULL ELSE SUM(sum_value) / SUM(valid_count) END AS avg_value FROM ch6_custom_dst GROUP BY name, time ORDER BY name, time; ``` The bucket has sum 180, 10 valid values, 11 total rows, and average 18. This differs from 15, the simple average of partial averages 10 and 20. Use COUNT(value) so NULL is excluded from the average denominator, and retain COUNT(*) separately for total rows including NULL. Define a result policy that avoids division by zero for all-NULL buckets. ### Sample Ratio and Time-Based Availability Matching sample count divided by total sample count is a sample ratio. Interpreting it as time-based availability requires accounting for observation intervals, missing data, and state duration. Sum the numerator and denominator separately; do not average partial ratios. ## 2. OHLCV and a 1-Minute → 10-Minute Custom Hierarchy This is a separate exercise. Store the first and last source observation timestamps to support FIRST/LAST reaggregation. ```sql CREATE TAG TABLE ch6_ticks ( code VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, price DOUBLE, volume DOUBLE ); CREATE TAG TABLE ch6_candle_min ( code VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, open_price DOUBLE, high_price DOUBLE, low_price DOUBLE, close_price DOUBLE, volume DOUBLE, cnt LONG, firsttime DATETIME, lasttime DATETIME ); CREATE TAG TABLE ch6_candle_10m ( code VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, open_price DOUBLE, high_price DOUBLE, low_price DOUBLE, close_price DOUBLE, volume DOUBLE, cnt LONG, firsttime DATETIME, lasttime DATETIME ); CREATE ROLLUP ch6_candle_ru_min INTO (ch6_candle_min) AS ( SELECT code, DATE_TRUNC('minute', time) AS time, FIRST(time, price), MAX(price), MIN(price), LAST(time, price), SUM(volume), COUNT(*), MIN(time), MAX(time) FROM ch6_ticks GROUP BY code, time ) INTERVAL 1 MIN; CREATE ROLLUP ch6_candle_ru_10m INTO (ch6_candle_10m) AS ( SELECT code, DATE_BIN('min', 10, time, TO_DATE('2000-01-01 00:00:00')) AS time, FIRST(firsttime, open_price), MAX(high_price), MIN(low_price), LAST(lasttime, close_price), SUM(volume), SUM(cnt), MIN(firsttime), MAX(lasttime) FROM ch6_candle_min GROUP BY code, time ) INTERVAL 10 MIN; INSERT INTO ch6_ticks VALUES ('AAPL', TO_DATE('2026-01-01 09:00:00'), 100, 2); INSERT INTO ch6_ticks VALUES ('AAPL', TO_DATE('2026-01-01 09:00:30'), 105, 3); INSERT INTO ch6_ticks VALUES ('AAPL', TO_DATE('2026-01-01 09:01:00'), 103, 1); INSERT INTO ch6_ticks VALUES ('AAPL', TO_DATE('2026-01-01 09:01:30'), 99, 4); EXEC TABLE_FLUSH(ch6_ticks); ALTER ROLLUP ch6_candle_ru_min FORCE; EXEC TABLE_FLUSH(ch6_candle_min); ALTER ROLLUP ch6_candle_ru_10m FORCE; SELECT code, time, FIRST(firsttime, open_price), MAX(high_price), MIN(low_price), LAST(lasttime, close_price), SUM(volume), SUM(cnt) FROM ch6_candle_10m GROUP BY code, time ORDER BY code, time; ``` The 09:00 10-minute bucket has Open=100, High=105, Low=99, Close=99, volume=10, and cnt=4. NULL prices or volumes require separate rules and tests for choosing row timestamps and values. If multiple trades share a timestamp but have business ordering, design an additional identifier. This 10-minute Custom example demonstrates creation and querying. Do not assume its interval is supported by current Custom time-range REBUILD processing. Check [REBUILD Limitations](../rollup-rebuild/). ## Status and Cleanup Jobs start automatically after creation, so do not immediately repeat START. Call STOP/START and FORCE according to job state. Dropping a target TAG is blocked while its job exists. ```sql SELECT DISTINCT ROLLUP_NAME, ROLLUP_TABLE, ROOT_TABLE, EXT_TYPE, INTERVAL_TIME, WAKEUP_INTERVAL FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CUSTOM_RU'; DROP ROLLUP ch6_candle_ru_10m; DROP ROLLUP ch6_candle_ru_min; DROP TABLE ch6_candle_10m; DROP TABLE ch6_candle_min; DROP TABLE ch6_ticks; DROP ROLLUP ch6_custom_ru; DROP TABLE ch6_custom_dst; DROP TABLE ch6_custom_src; ``` EXT_TYPE=2 indicates Custom; PREDICATE records the SELECT body. Clean up only objects from the exercises you ran. For source corrections and retry/completion checks for upper-level reaggregation, follow [Control and Status](../ingestion-control-rollup/) and the REBUILD procedure. --- title: "6.7 Extension ROLLUP and FIRST/LAST" url: https://docs.machbase.com/dbms/tag-rollup-usage/extension-rollup/ language: en kind: page --- # 6.7 Extension ROLLUP and FIRST/LAST ## EXTENSION versus Source FIRST/LAST EXTENSION adds first/last values and associated timestamp information to ROLLUP. Using FIRST/LAST in an ordinary source GROUP BY differs from querying FIRST/LAST from stored ROLLUP statistics. The latter requires an applicable extension ROLLUP. EXTENSION adds only first/last values and timestamps. MIN, MAX, SUM, COUNT, and SUMSQ, the sum of squares, are also stored in general ROLLUP. For deriving variance and standard deviation from SUMSQ, see [SUMSQ, Variance, and Standard Deviation](../query-syntax-rollup/#query-sumsq-stddev-rollup). ## Preparation and Ingestion ```sql CREATE TAG TABLE ch6_ext ( code VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, price DOUBLE ); CREATE ROLLUP ch6_ext_first ON ch6_ext(price) INTERVAL 1 MIN EXTENSION; CREATE ROLLUP ch6_ext_plain ON ch6_ext(price) INTERVAL 1 MIN; INSERT INTO ch6_ext VALUES ('AAPL', TO_DATE('2026-01-01 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100); INSERT INTO ch6_ext VALUES ('AAPL', TO_DATE('2026-01-01 09:00:10', 'YYYY-MM-DD HH24:MI:SS'), 105); INSERT INTO ch6_ext VALUES ('AAPL', TO_DATE('2026-01-01 09:00:20', 'YYYY-MM-DD HH24:MI:SS'), 99); INSERT INTO ch6_ext VALUES ('AAPL', TO_DATE('2026-01-01 09:00:30', 'YYYY-MM-DD HH24:MI:SS'), 103); EXEC TABLE_FLUSH(ch6_ext); ALTER ROLLUP ch6_ext_first FORCE; ALTER ROLLUP ch6_ext_plain FORCE; ``` ## Comparing Source and OHLC Results ```sql SELECT DATE_TRUNC('minute', time) AS bucket, FIRST(time, price) AS open_price, MAX(price) AS high_price, MIN(price) AS low_price, LAST(time, price) AS close_price FROM ch6_ext WHERE code = 'AAPL' GROUP BY bucket ORDER BY bucket; SELECT /*+ ROLLUP_TABLE(ch6_ext_first) */ rollup('min', 1, time) AS bucket, FIRST(time, price) AS open_price, MAX(price) AS high_price, MIN(price) AS low_price, LAST(time, price) AS close_price FROM ch6_ext WHERE code = 'AAPL' GROUP BY bucket ORDER BY bucket; ``` Both queries return Open=100, High=105, Low=99, Close=103 in the 09:00 bucket. ROLLUP FIRST/LAST use BASETIME as the first argument and the aggregate column as the second. Design separately for equal-timestamp values when additional business ordering is required. ## General and Extension Candidates Together General ROLLUP does not always take priority over extension ROLLUP. Registration order affects candidates with the same conditions and interval. This example creates extension first, but explicitly selects it when results must depend on a particular candidate. Where only extension is applicable, it can be selected without a hint. The following query intentionally fails because it forces general ROLLUP. ```sql SELECT /*+ ROLLUP_TABLE(ch6_ext_plain) */ rollup('min', 1, time) AS bucket, FIRST(time, price) FROM ch6_ext WHERE code = 'AAPL' GROUP BY bucket; ``` For automatic extension hierarchies, use `WITH ROLLUP (SEC) EXTENSION` in a separate table's CREATE statement. Keep the extension attribute consistent when creating a hierarchy with FROM. For Custom OHLCV reaggregation, see [Custom Examples](../custom-rollup/). ## Clean Up ```sql DROP ROLLUP ch6_ext_plain; DROP ROLLUP ch6_ext_first; DROP TABLE ch6_ext; ``` --- title: "6.8 JSON SUMMARIZED ROLLUP" url: https://docs.machbase.com/dbms/tag-rollup-usage/json-summarized-rollup/ language: en kind: page --- # 6.8 JSON SUMMARIZED ROLLUP ## JSON Path and Full-Document Aggregation JSON path ROLLUP aggregates numeric values at a specified path. Full-document ROLLUP maintains statistics for numeric paths in a JSON SUMMARIZED column. Do not treat missing paths, JSON null, SQL NULL, and arrays as equivalent samples. ## Preparation ```sql CREATE TAG TABLE ch6_json ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value JSON SUMMARIZED ); CREATE ROLLUP ch6_json_metric ON ch6_json(value.metric) INTERVAL 1 MIN; CREATE ROLLUP ch6_json_whole ON ch6_json(value) INTERVAL 1 MIN; INSERT INTO ch6_json VALUES ('S1', TO_DATE('2026-01-01 00:00:00'), '{"metric":10,"nested":{"x":2},"status":"OK","items":[1,2]}'); INSERT INTO ch6_json VALUES ('S1', TO_DATE('2026-01-01 00:00:10'), '{"metric":20,"nested":{"x":4},"status":"WARN","items":[3,4]}'); INSERT INTO ch6_json VALUES ('S1', TO_DATE('2026-01-01 00:00:20'), '{"metric":null,"status":false}'); INSERT INTO ch6_json VALUES ('S1', TO_DATE('2026-01-01 00:00:30'), NULL); EXEC TABLE_FLUSH(ch6_json); ALTER ROLLUP ch6_json_metric FORCE; ALTER ROLLUP ch6_json_whole FORCE; ``` ## Comparing Path Aggregates ```sql SELECT DATE_TRUNC('minute', time) AS bucket, COUNT(JSON_EXTRACT_DOUBLE(value, '$.metric')), AVG(JSON_EXTRACT_DOUBLE(value, '$.metric')) FROM ch6_json WHERE name = 'S1' GROUP BY bucket ORDER BY bucket; SELECT /*+ ROLLUP_TABLE(ch6_json_metric) */ rollup('min', 1, time) AS bucket, COUNT(value.metric), AVG(value.metric) FROM ch6_json WHERE name = 'S1' GROUP BY bucket ORDER BY bucket; SELECT /*+ ROLLUP_TABLE(ch6_json_metric) */ rollup('min', 1, time) AS bucket, AVG(value->'$.metric') FROM ch6_json WHERE name = 'S1' GROUP BY bucket ORDER BY bucket; ``` metric has two valid numeric samples with average 15. Dot and arrow syntax express the same path. Specifying an array element in a path is different from full-document aggregation automatically expanding arrays. `value.items[0]."metric-id"` is an example path declaration, but first verify that the JSON structure and numeric samples actually exist. ## Full-Document Aggregation and COUNT ```sql SELECT COUNT(*) AS raw_rows, COUNT(value) AS raw_documents FROM ch6_json; SELECT /*+ ROLLUP_TABLE(ch6_json_whole) */ rollup('min', 1, time) AS bucket, COUNT(value), AVG(value), MIN(value), MAX(value), SUM(value) FROM ch6_json WHERE name = 'S1' GROUP BY bucket ORDER BY bucket; ``` Source COUNT(*) is 4 and COUNT(value) is 3. Full-document ROLLUP COUNT(value) sums stored document aggregate counts. Currently those counts are built from source COUNT(*), so this bucket containing both numeric-path documents and SQL NULL returns 4. Do not apply the ordinary source COUNT(value) NULL-exclusion rule unchanged. AVG returns metric=15 and nested.x=3, calculated from the valid numeric samples at each path. Strings, booleans, JSON null, and arrays are excluded from numeric aggregation; nonnumeric paths can appear as null or be omitted. Do not compare serialized JSON as fixed strings based on key order. Test separate samples for documents with no numeric paths and intervals containing only SQL NULL. JSON path and full-document aggregation use different candidate modes. Do not assume forcing a ROLLUP from another mode with a hint gives equivalent results. Invalid JSON causes an ingestion error. ## Clean Up ```sql DROP ROLLUP ch6_json_whole; DROP ROLLUP ch6_json_metric; DROP TABLE ch6_json; ``` --- title: "6.9 ROLLUP Control and State" url: https://docs.machbase.com/dbms/tag-rollup-usage/ingestion-control-rollup/ language: en kind: page --- # 6.9 ROLLUP Control and State ## Job State and Processing Completion ROLLUP starts automatically at creation. Repeating START immediately or stopping an already stopped job can cause a state error. This exercise separates states in the sequence create → STOP → insert → START → WAKEUP → FORCE. ```sql CREATE TAG TABLE ch6_control ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, quality INTEGER ); CREATE ROLLUP ch6_control_ru ON ch6_control(value) INTERVAL 1 MIN WAKEUP INTERVAL 10 SEC; ALTER ROLLUP ch6_control_ru STOP; INSERT INTO ch6_control VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1); INSERT INTO ch6_control VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1); INSERT INTO ch6_control VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1); INSERT INTO ch6_control VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1); EXEC TABLE_FLUSH(ch6_control); SELECT DISTINCT ROLLUP_NAME, ENABLED, INTERVAL_TIME, WAKEUP_INTERVAL FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CONTROL_RU'; ALTER ROLLUP ch6_control_ru START; ALTER ROLLUP ch6_control_ru WAKEUP; ALTER ROLLUP ch6_control_ru FORCE; SELECT rollup('min', 1, time) AS bucket, AVG(value) FROM ch6_control WHERE name = 'TEMP_01' GROUP BY bucket ORDER BY bucket; ``` While stopped, ENABLED is 0, INTERVAL_TIME is 60000 ms, and WAKEUP_INTERVAL is 10000 ms. The final query returns TEMP_01 averages of 15 at 00:00 and 30 at 00:01. | Command | Purpose | Completion meaning | |---|---|---| | STOP | Stop the job | Unprocessed input remains | | START | Resume a stopped job | Continue from the processing position | | WAKEUP | Wake the job | Does not wait for processing completion | | FORCE | Wait for the target source processing range to catch up | Does not recalculate historical corrections or complete future input | | ROLLUP_REBUILD | Recalculate historical buckets for supported targets | Rebuild aggregates after source corrections | Instead of SQL ALTER, you can use named `EXEC ROLLUP_START(name)`, `ROLLUP_STOP(name)`, and `ROLLUP_FORCE(name)` calls. Do not execute the same transition consecutively using both forms. Distinguish unnamed bulk control from control of a specific job. ## WAKEUP INTERVAL If omitted, WAKEUP INTERVAL equals the creation INTERVAL. It must be positive, no greater than the aggregation interval, and divide that interval exactly. More frequent wakeups can reduce lag but increase processing load. ```sql ALTER ROLLUP ch6_control_ru SET WAKEUP INTERVAL 5 SEC; SELECT DISTINCT ROLLUP_NAME, INTERVAL_TIME, WAKEUP_INTERVAL FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CONTROL_RU'; ``` WAKEUP_INTERVAL becomes 5000 ms. The next statement intentionally fails because its interval does not divide 60 seconds. ```sql ALTER ROLLUP ch6_control_ru SET WAKEUP INTERVAL 7 SEC; ``` ## Reading V$ROLLUP | Column | Meaning | |---|---| | ROLLUP_NAME | Job name used for control | | ROLLUP_TABLE | Aggregate target table; user target TAG for Custom | | SOURCE_TABLE, ROOT_TABLE | Direct source and root-source relationship | | COLUMN_NAME | Column aggregated in general/path mode | | INTERVAL_TIME, WAKEUP_INTERVAL | Creation and wakeup intervals in milliseconds | | LAST_WAKEUP_TIME, NEXT_WAKEUP_TIME | Previous wakeup and next scheduled wakeup | | EXT_TYPE | 0 general, 1 extension, 2 Custom | | PREDICATE | General predicate or Custom SELECT body | | ENABLED | Whether the job is enabled | | RUN_STATE | `I` initial, `S` waiting, `R` processing | | END_RID | Source processing position | | LAST_ELAPSED_MSEC | Previous processing time in ms | | DATABASE_NAME, USER_ID | Database and owner identifiers | ```sql SELECT ROLLUP_NAME, ROLLUP_TABLE, SOURCE_TABLE, ROOT_TABLE, INTERVAL_TIME, WAKEUP_INTERVAL, LAST_WAKEUP_TIME, NEXT_WAKEUP_TIME, ENABLED, RUN_STATE, LAST_ELAPSED_MSEC FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CONTROL_RU' ORDER BY ROLLUP_NAME; SHOW ROLLUPGAP; ``` SHOW ROLLUPGAP is a machsql-only client command; do not send it to an SDK's ordinary SQL API. GAP is the difference between source and ROLLUP processing RIDs, not elapsed time lag. Check it alongside all hierarchy levels and relevant nodes. gap=0 does not mean corrections to already aggregated source data are reflected. During continuous input it changes with observation time, so pause input for reproducible comparisons. If retention deletes source data while a job is stopped, START cannot restore it. Run FORCE from lower to upper levels. On failure, check the first error, state, and source accessibility. ## Clean Up ```sql DROP ROLLUP ch6_control_ru; DROP TABLE ch6_control; ``` For detailed command contracts, see the [EXEC Reference](../../reference/sql/syntax/execute-procedure-syntax/) and [ROLLUP Troubleshooting](../../troubleshooting/rollup/). --- title: "6.10 ROLLUP_REBUILD" url: https://docs.machbase.com/dbms/tag-rollup-usage/rollup-rebuild/ language: en kind: page --- # 6.10 ROLLUP_REBUILD ROLLUP_REBUILD recalculates aggregates after historical source-value corrections and is available only in Standard Edition. Unlike FORCE, it deletes and recreates affected buckets. It is not a general-purpose command for rebuilding arbitrary ROLLUP definitions. ## Check Supported Targets First | Target | Current support path | |---|---| | Complete SEC→MIN→HOUR hierarchy created with WITH ROLLUP | Basic numeric, extension, and full-document JSON modes | | Supported Custom tree linked to the source | Check 1 SEC/1 MIN/1 HOUR intervals and SELECT compatibility with rebuild boundaries | | Manually named general ROLLUP with arbitrary intervals | Do not assume the same support as automatic hierarchies | | Automatic MIN/HOUR-only hierarchy without SEC | Not considered a complete default hierarchy | | Custom with other intervals, such as 10 MIN | Unsupported by the current time-boundary generation path | | Cluster Edition | Unsupported | Custom SELECT buckets, INTERVAL, and reference time zone must align with rebuild boundaries. First inspect the tree for unsupported jobs. Creation support for a Custom expression or interval does not imply rebuild support. ## Time Arguments and Bucket Boundaries Specify timestamp strings or TO_DATE with constant strings. This path does not evaluate arbitrary DATETIME expressions; do not use NOW arithmetic or bound parameters in examples. The operation includes the buckets containing both endpoints and expands to entire buckets. At the 1-minute level, 00:00:30–00:01:00 recalculates the 00:00 and 00:01 buckets, namely [00:00:00, 00:02:00). Equal start/end values recalculate the containing bucket; start later than end is an error. Upper time levels expand to wider buckets. ## Default Hierarchy and Custom Correction Exercise ### 1. Preparation and Initial Aggregation ```sql CREATE TAG TABLE ch6_rebuild ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ) WITH ROLLUP (SEC); CREATE TAG TABLE ch6_rebuild_dst ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, sum_value DOUBLE, cnt LONG ); CREATE ROLLUP ch6_rebuild_custom INTO (ch6_rebuild_dst) AS ( SELECT name, DATE_TRUNC('minute', time) AS time, SUM(value), COUNT(value) FROM ch6_rebuild GROUP BY name, time ) INTERVAL 1 MIN; INSERT INTO ch6_rebuild VALUES ('S1', TO_DATE('2026-01-01 00:00:00'), 1); INSERT INTO ch6_rebuild VALUES ('S1', TO_DATE('2026-01-01 00:00:30'), 200); INSERT INTO ch6_rebuild VALUES ('S1', TO_DATE('2026-01-01 00:01:00'), 300); INSERT INTO ch6_rebuild VALUES ('S1', TO_DATE('2026-01-01 00:01:30'), 4); EXEC TABLE_FLUSH(ch6_rebuild); SELECT DISTINCT ROLLUP_NAME, INTERVAL_TIME FROM V$ROLLUP WHERE ROOT_TABLE = 'CH6_REBUILD' ORDER BY INTERVAL_TIME, ROLLUP_NAME; ALTER ROLLUP _CH6_REBUILD_ROLLUP_SEC FORCE; ALTER ROLLUP _CH6_REBUILD_ROLLUP_MIN FORCE; ALTER ROLLUP _CH6_REBUILD_ROLLUP_HOUR FORCE; ALTER ROLLUP ch6_rebuild_custom FORCE; SELECT rollup('min', 1, time) AS bucket, AVG(value) FROM ch6_rebuild WHERE name = 'S1' GROUP BY bucket ORDER BY bucket; ``` Verify that automatically generated names in control commands match V$ROLLUP above. Do not guess names of other objects. Initial minute averages are 100.5 and 152. ### 2. Correct Source Data and Rebuild ```sql UPDATE ch6_rebuild SET value = 20 WHERE name = 'S1' AND time = TO_DATE('2026-01-01 00:00:30'); UPDATE ch6_rebuild SET value = 30 WHERE name = 'S1' AND time = TO_DATE('2026-01-01 00:01:00'); EXEC ROLLUP_REBUILD(ch6_rebuild, 'S1', TO_DATE('2026-01-01 00:00:30'), TO_DATE('2026-01-01 00:01:00')); ``` ### 3. Compare Source, General, and Custom Results ```sql SELECT DATE_TRUNC('minute', time) AS bucket, SUM(value), COUNT(value), AVG(value) FROM ch6_rebuild WHERE name = 'S1' GROUP BY bucket ORDER BY bucket; SELECT rollup('min', 1, time) AS bucket, SUM(value), COUNT(value), AVG(value) FROM ch6_rebuild WHERE name = 'S1' GROUP BY bucket ORDER BY bucket; SELECT time, SUM(sum_value), SUM(cnt), SUM(sum_value) / SUM(cnt) FROM ch6_rebuild_dst WHERE name = 'S1' GROUP BY time ORDER BY time; SHOW ROLLUPGAP; ``` All three results have sum 21, count 2, average 10.5 at 00:00, and sum 34, count 2, average 17 at 00:01. The value 4 at 00:01:30, after the end argument, must also be included when its bucket is recalculated. ## Operational Impact and Failure Recovery Related jobs catch up, stop, recalculate, and restart. Internal processing also stabilizes source reads, so normal work does not simply continue unchanged during rebuilding. Measure acceptable query/ingestion delays and downtime in a validation environment first. Do not assume all stages roll back as one atomic transaction. State recovery after failure is best effort; check actual data and V$ROLLUP. Restoring the original stopped state is not guaranteed either. Before retrying, verify supported targets, remaining source data, and reaggregation scope. A nonexistent tag can be a no-op when a valid rebuild target is otherwise prepared. A successful response alone does not prove the intended tag was processed; compare actual results. Original statistics cannot be reconstructed after the source data has been deleted. ## Clean Up ```sql DROP ROLLUP ch6_rebuild_custom; DROP TABLE ch6_rebuild_dst; DROP TABLE ch6_rebuild CASCADE; ``` Remove Custom targets separately. If a general definition must change or the task is outside this procedure's scope, prepare a supported new definition and data migration procedure. Do not substitute arbitrary deletion of internal storage tables. For exact arguments, see the [REBUILD Reference](../../reference/sql/syntax/rollup-rebuild-syntax/). --- title: "6.11 ROLLUP Performance Tuning" url: https://docs.machbase.com/dbms/tag-rollup-usage/performance-tuning-rollup/ language: en kind: page --- # 6.11 ROLLUP Performance Tuning ## Compare Equivalent Results Before Costs ROLLUP reduces the number of raw rows read. First verify equivalent tags, time ranges, NULL handling, and aggregation criteria; then compare execution time, CPU, I/O, and memory. Small-example timings do not guarantee production performance. ## Comparison Exercise ```sql CREATE TAG TABLE ch6_perf ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE, quality INTEGER ); CREATE ROLLUP ch6_perf_ru ON ch6_perf(value) INTERVAL 1 MIN; INSERT INTO ch6_perf VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1); INSERT INTO ch6_perf VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1); INSERT INTO ch6_perf VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1); INSERT INTO ch6_perf VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1); EXEC TABLE_FLUSH(ch6_perf); ALTER ROLLUP ch6_perf_ru FORCE; SELECT DATE_TRUNC('minute', time) AS bucket, SUM(value), COUNT(value), AVG(value), MIN(value), MAX(value) FROM ch6_perf WHERE name = 'TEMP_01' AND time >= TO_DATE('2026-01-01 00:00:00') AND time < TO_DATE('2026-01-01 00:02:00') GROUP BY bucket ORDER BY bucket; SELECT rollup('min', 1, time) AS bucket, SUM(value), COUNT(value), AVG(value), MIN(value), MAX(value) FROM ch6_perf WHERE name = 'TEMP_01' AND time >= TO_DATE('2026-01-01 00:00:00') AND time < TO_DATE('2026-01-01 00:02:00') GROUP BY bucket ORDER BY bucket; EXPLAIN SELECT rollup('min', 1, time) AS bucket, AVG(value) FROM ch6_perf WHERE name = 'TEMP_01' GROUP BY bucket; ``` Both results show sum 30, count 2, average 15, minimum 10, maximum 20 at 00:00; and sum 30, count 1, average 30, minimum 30, maximum 30 at 00:01. Inspect the source DATE_TRUNC execution plan the same way. ## Measuring Production Load | Metric | Conditions to record | |---|---| | Ingestion throughput | Tag count, input rate, row width, and concurrent writers | | Query latency | Tag range, buckets, concurrent queries, and cold/warm cache state | | Aggregation lag | Gap, job state, and processing time at each level | | Storage | Source data, aggregates, indexes, compression, and replicas | | Change impact | Ingestion/query costs before and after wakeup or hierarchy changes | Shorter WAKEUP intervals can create partial aggregates more frequently within the same bucket. Smaller aggregation buckets increase storage and reaggregation volume. Treat the two intervals as distinct tuning parameters. Measure concurrent ingestion and queries as well as isolated runs. ## Meaning of Hierarchy Size The following logical bucket counts assume one tag has data in every interval for 30 days. | Query interval | Bucket count | |---|---:| | 1 second | 2,592,000 | | 1 minute | 43,200 | | 1 hour | 720 | | 1 day | 30 | These are not physical row counts. Measure actual storage with sample loading, including partial aggregates, empty intervals, NULLs, and conditional filters. The coarsest candidate does not always produce correct results; also check required resolution, origin, and candidate constraints. Daily results reaggregate applicable HOUR/MIN/SEC statistics. A 24 HOUR ROLLUP is not recommended as a substitute storage level for `rollup('day', 1, ...)`. Follow [Query Candidate Rules](../query-syntax-rollup/) and actual EXPLAIN output. ## Distinguishing Lag from Mismatches gap=0 means processing positions have caught up, not that source corrections have been reflected. Before comparing performance, distinguish aggregation progress from historical correction state and check matching definitions and filters. Do not use `rollup()` without an applicable ROLLUP to benchmark source queries. ## Clean Up ```sql DROP ROLLUP ch6_perf_ru; DROP TABLE ch6_perf; ``` Choose the next adjustment using [Control and Status](../ingestion-control-rollup/), [Hierarchy Design](../target-tag-table-design/), and [Troubleshooting](../../troubleshooting/rollup/). --- title: "6.12 ROLLUP Scenarios" url: https://docs.machbase.com/dbms/tag-rollup-usage/patterns-scenarios/ language: en kind: page --- # 6.12 ROLLUP Scenarios ## Source Data and Interval Statistics by Sensor Do not combine averages for sensors with different units, even if they measure at the same time. This standalone exercise manages current units as metadata and queries aggregates by tag. ### 1. Create and Insert ```sql CREATE TAG TABLE ch6_scenario ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE ) METADATA (unit VARCHAR(16)); INSERT INTO ch6_scenario METADATA VALUES ('TEMP_01', 'celsius'); INSERT INTO ch6_scenario METADATA VALUES ('PRESS_01', 'bar'); INSERT INTO ch6_scenario VALUES ('TEMP_01', TO_DATE('2026-01-01 10:00:00'), 20); INSERT INTO ch6_scenario VALUES ('TEMP_01', TO_DATE('2026-01-01 10:00:30'), 22); INSERT INTO ch6_scenario VALUES ('PRESS_01', TO_DATE('2026-01-01 10:00:00'), 1.02); CREATE ROLLUP ch6_scenario_ru ON ch6_scenario(value) INTERVAL 1 MIN; EXEC TABLE_FLUSH(ch6_scenario); ALTER ROLLUP ch6_scenario_ru FORCE; ``` A ROLLUP created after source ingestion still initially aggregates remaining data. Creation completion alone does not mean initial aggregation is finished. ### 2. Check Results ```sql SELECT name, unit FROM ch6_scenario METADATA ORDER BY name; SELECT name, DATE_TRUNC('minute', time) AS bucket, COUNT(value), AVG(value) FROM ch6_scenario GROUP BY name, bucket ORDER BY name, bucket; SELECT name, rollup('min', 1, time) AS bucket, COUNT(value), AVG(value) FROM ch6_scenario GROUP BY name, bucket ORDER BY name, bucket; SHOW ROLLUPGAP; ``` TEMP_01 has 2 samples averaging 21°C; PRESS_01 has 1 sample averaging 1.02 bar. Metadata queries return current units and do not automatically preserve historical unit changes. ### 3. Inspect Individual Observations The data uses fixed timestamps, so query the same fixed range. Applying a current-time “last 5 minutes” predicate can return no rows depending on the execution date. ```sql SELECT name, time, value FROM ch6_scenario WHERE name = 'TEMP_01' AND time >= TO_DATE('2026-01-01 10:00:00') AND time < TO_DATE('2026-01-01 10:01:00') ORDER BY time; ``` The two source values are 20 and 22. Their individual values or occurrence order cannot be reconstructed from the aggregate average 21. ### 4. Clean Up ```sql DROP ROLLUP ch6_scenario_ru; DROP TABLE ch6_scenario; ``` ## Applying ROLLUP to Workloads | Requirement | Design to check | |---|---| | Valid-quality statistics | Fix filters and candidate hints; compare with source data | | OHLC | Extension FIRST/LAST or Custom reaggregation with auxiliary timestamps | | Multiple-sensor comparison | Tag-specific units and matching buckets/query ranges | | Consumption from cumulative meters | Boundary differences and reset/replacement/missing-data rules; distinguish from sample averages | | Availability | Distinguish sample ratios from time ratios; define missing-interval policy | | Combining recent source data with long-term aggregates | Separate nonoverlapping ranges at a verified aggregation-completion point | When combining source and ROLLUP results with UNION ALL, check boundary duplicates, omissions, and differing sample counts. Do not assume a fixed lag such as the latest two minutes always being unaggregated. Pass sums and valid counts when recombining partial results into averages. Complete feature exercises are available for [Conditional](../conditional-rollup/), [Extension](../extension-rollup/), [JSON](../json-summarized-rollup/), and [Custom](../custom-rollup/) ROLLUP. If problems arise, first check state and semantics using the [Diagnostic Sequence](../../troubleshooting/rollup/). --- title: "7. LOG Table Usage" url: https://docs.machbase.com/dbms/log-table-usage/ language: en kind: section --- # 7. LOG Table Usage Storing logs and finding the logs you need are different tasks. During incident analysis, questions often arise that were overlooked during ingestion: does this timestamp represent occurrence or collection, and why does a word in a message not appear in search results? This chapter connects LOG table selection and design with ingestion, search, and retention management. It explains both how to run commands and how to check their results. LOG uses a model that continuously appends source events, so its usage differs from business tables whose stored rows are repeatedly updated. ## Chapter Contents If you are new to LOG tables, read the overview and schema sections, then follow creation, ingestion, and querying in order. Start with 7.10 for time predicates or 7.11 for message search. | Section | What you will learn | |---|---| | [7.1 Overview and Use Criteria](./overview-use-criteria/) | Distinguish LOG use cases from other table types | | [7.2 Table Structure and Schema](./table-structure-schema/) | Separate event time, search fields, and raw messages | | [7.3 Create, Alter, and Drop](./create-alter-drop/) | Change schemas while checking existing data | | [7.4 Data Ingestion](./data-input-mutation/) | Choose INSERT, Append, or file loading | | [7.5 Queries and Analysis](./query-analysis/) | Query time ranges and join reference data | | [7.6 Indexes and Performance](./index-performance/) | Choose indexes and inspect execution plans | | [7.7 Operations and Data Lifecycle](./operations-lifecycle/) | Check deletion boundaries and apply retention policies | | [7.8 Constraints, Errors, and Troubleshooting](./constraints-errors-troubleshooting/) | Identify causes and remedies from symptoms | | [7.9 Usage Patterns and Scenarios](./patterns-scenarios/) | Ingest, search, and aggregate application logs | | [7.10 _arrival_time Time Model](./arrival-time-model/) | Distinguish automatic, explicit, and out-of-order timestamps | | [7.11 Text Search and KEYWORD Indexes](./text-search-keyword-index/) | Understand how search methods affect results | | [7.12 Network Type Queries](./regex-network-query/) | Query IPV4/IPV6 addresses and ranges | ## Example Environment The examples follow the DBMS 8.7 documentation. Unless stated otherwise, SQL exercises target a Standard Edition validation environment. Use an account that can create tables and indexes. For Cluster environments, also review [Edition Differences](/dbms/reference/support-scope-constraints/edition/) and the relevant operational procedures. Example objects start with `ch7_`. Each section creates its own tables and can be followed independently. Before rerunning a section, confirm that its final cleanup SQL was executed. Intentionally failing SQL is separated from the normal exercise. Caution: `DELETE`, `TRUNCATE`, and `DROP` remove data. Do not substitute production table names for the example names. If your results differ, compare the SQL you ran with its actual results. Identifying the first step that differs helps narrow down the cause. --- title: "7.1 Overview and Use Criteria" url: https://docs.machbase.com/dbms/log-table-usage/overview-use-criteria/ language: en kind: page --- # 7.1 Overview and Use Criteria Data with timestamps does not all need the same table type. Periodic temperature readings and a device reconnection event require different analysis. When choosing LOG, start with what each row represents rather than whether it has a time column. ## LOG Table Characteristics LOG suits data that appends individual events, such as application errors, security-device block records, and job start/end history. An `_arrival_time` column is created automatically in addition to user columns, and queries can combine time-range predicates with message search. The following example shows the difference between event time and ingestion time. ```sql CREATE LOG TABLE ch7_overview ( event_time DATETIME, device VARCHAR(32), message VARCHAR(128) ); INSERT INTO ch7_overview VALUES ( TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'DEV-01', 'connection restored' ); SELECT _arrival_time, event_time, device, message FROM ch7_overview; DROP TABLE ch7_overview; ``` The query returns one row. `event_time` is the fixed timestamp supplied in the example; `_arrival_time` is assigned automatically during this insert. Running the example on another date does not change `event_time`. For explicit timestamps and adjustment rules, see [Time Model](../arrival-time-model/). ## Use Criteria Consider LOG when you frequently search for errors in the last hour, requests from an IP address, or messages containing timeout, and do not need to update stored rows. Use the Append API for continuous ingestion and loading tools for initial data or batches of files. The inability to update rows does not by itself make audit data tamper-proof. Design deletion privileges, access controls, retention policies, and backups separately. Pay particular attention to retransmission. Resending an event may store another row. LOG has no PRIMARY KEY or UNIQUE constraints, so do not expect automatic deduplication. Retain the source event ID and define retry and duplicate-handling policies during collection. ## Comparison with Other Tables | Main workload | Table to consider first | Decision criteria | |---|---|---| | Measurements by sensor name and time-series aggregates | TAG | Name/time-axis queries and ROLLUP | | Current reference data, such as device names and installation locations | LOOKUP | Query and modify small reference datasets | | Order status changes, row deletion, and transaction processing | TRANSACTION | Modify rows and process operations as transactions | | In-memory state that may be lost on restart | VOLATILE | Keep separate from source logs requiring permanent retention | LOG does not support general `UPDATE` or `DELETE WHERE` with arbitrary predicates. You can append correction events, but must store the original ID and correction reason and decide in the application which corrections queries apply. If updates are routine, another table type is a clearer choice. ## Design Criteria First distinguish whether analysis requires event time or collection time. Then identify frequently used predicates, such as device, severity, and IP address. Store these values in separate columns instead of extracting them from raw messages for every query; this makes SQL easier to understand and maintain. Define retention at this stage as well. Disk usage continues to grow if you prepare ingestion but postpone deletion. The next section, [Schema Design](../table-structure-schema/), translates these requirements into columns. If the choice is unclear, compare representative events alongside the queries you expect to run. --- title: "7.2 Table Structure and Schema" url: https://docs.machbase.com/dbms/log-table-usage/table-structure-schema/ language: en kind: page --- # 7.2 Table Structure and Schema Putting an entire message in one column makes it quick to start collection. However, repeatedly parsing raw messages to count errors by device makes queries complex. Retain the raw message and extract values used repeatedly for queries and aggregates into separate columns. ## Column Layout The following standalone example stores and checks one security event. ```sql CREATE LOG TABLE ch7_schema ( event_time DATETIME, event_id VARCHAR(64), device VARCHAR(32), severity SHORT, src_ip IPV4, dst_port INTEGER, message TEXT ); INSERT INTO ch7_schema VALUES ( TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'evt-0001', 'FW-01', 3, '192.0.2.10', 65535, 'connection blocked by policy' ); SELECT event_id, device, severity, src_ip, dst_port, message FROM ch7_schema; ``` The query returns the row `evt-0001` with port `65535`. Here, `event_id` is a tracking value, not a key constraint that prevents duplicate ingestion. Store the event timestamp recorded by the source in `event_time`. Do not redeclare the automatic `_arrival_time` column in DDL. Network delays and batch migration can naturally cause the two timestamps to differ. ## Choosing Data Types | Value | Type | What to check | |---|---|---| | Device name, short code, or event ID | `VARCHAR(n)` | LOG permits 1–32,767 bytes, not characters | | Long raw message | `TEXT` | Maximum 64 MiB; sorting and grouping the raw value are unsupported | | Severity or small code | `SHORT` or `INTEGER` | Use consistent code meanings in collectors and queries | | Port | `INTEGER` | `USHORT` reserves 65535 for NULL and cannot represent the full port range | | Cumulative byte count | `LONG` | Check the expected maximum and reserved NULL value | | Address | `IPV4` or `IPV6` | Distinguish address format from the need to retain the source string | In LOG tables, both VARCHAR and TEXT support word search through KEYWORD indexes. Full-text search alone is no reason to use TEXT for short codes. String length is a common source of mistakes. `VARCHAR(100)` does not mean 100 Korean characters. Check the byte length of UTF-8 samples and send oversized values through the actual ingestion path. Verify whether excess length causes truncation or an error with the SDK or loading tool you will use. ## Columns for Sorting and Aggregation In this schema, `device` and `severity` are query predicates and aggregation keys; `message` is used to read raw text or search for words. Applying `ORDER BY message` or `GROUP BY message` directly to TEXT causes an error. Choose the device, error code, or event timestamp you actually need instead of sorting entire messages. A KEYWORD index is not a morphological analyzer or a relevance-ranked search engine. For the difference between word search and raw substring search, see [Text Search](../text-search-keyword-index/). ## Schema Changes and Ingestion Mappings LOG supports adding, dropping, and renaming columns, and limited attribute changes. This does not mean that stored row values can be changed with UPDATE. DDL changes particularly affect Appenders that send values by column position and CSV mappings. Coordinate schema changes with ingestion program deployment. Clean up the example table, then continue to [Column Changes](../create-alter-drop/). ```sql DROP TABLE ch7_schema; ``` If you are unsure which values to extract into columns, list the questions your queries must answer. Expressing those questions in SQL makes the required columns clearer. --- title: "7.3 Create, Alter, and Drop" url: https://docs.machbase.com/dbms/log-table-usage/create-alter-drop/ language: en kind: page --- # 7.3 Create, Alter, and Drop Adding a column takes little SQL, but production changes also require checking which values appear in existing rows and whether existing ingestion programs continue to work. This section changes a schema with data already present and checks the results. ## Creating a LOG Table `CREATE TABLE` without a table type creates a TRANSACTION table. Use `CREATE LOG TABLE` in this exercise. ```sql CREATE LOG TABLE ch7_ddl ( event_id INTEGER, category VARCHAR(32), severity SHORT, message VARCHAR(128) ); INSERT INTO ch7_ddl VALUES (1, 'network', 3, 'connection timeout'); ``` Do not redeclare the automatic `_arrival_time` column in DDL. Use a separate DATETIME column for actual event time. LOG does not support PRIMARY KEY or UNIQUE constraints. ## Adding Columns and Defaults ```sql ALTER TABLE ch7_ddl ADD COLUMN (host_name VARCHAR(64)); ALTER TABLE ch7_ddl ADD COLUMN (source_kind VARCHAR(16) DEFAULT 'agent'); ALTER TABLE ch7_ddl ADD COLUMN (channels INT32[3] DEFAULT [1, NULL, 3]); SELECT event_id, host_name, source_kind, channels FROM ch7_ddl ORDER BY event_id; ``` For existing row 1, `host_name` is NULL, `source_kind` is `agent`, and `channels` is `[1, NULL, 3]`. This shows the difference between columns with and without DEFAULT. An ARRAY DEFAULT must have the same number of elements as the declared length. Next, rename a column and increase its string length. ```sql ALTER TABLE ch7_ddl RENAME COLUMN category TO event_category; ALTER TABLE ch7_ddl MODIFY COLUMN (message VARCHAR(4096)); ALTER TABLE ch7_ddl MODIFY COLUMN severity SET MINMAX_CACHE_SIZE = 1048576; SELECT event_id, event_category, severity, message FROM ch7_ddl; ``` Existing values are retained. After renaming, queries must also use `event_category`. The MINMAX example specifies 1 MiB for a numeric column; this is not a recommended value for every table. Be careful with type changes. Extending a VARCHAR length does not convert TEXT to VARCHAR. `MINMAX_CACHE_SIZE` also cannot be set on variable-length columns such as VARCHAR or TEXT. ## NOT NULL and Existing Data Because `event_category` currently contains a value, the following change is allowed. ```sql ALTER TABLE ch7_ddl MODIFY COLUMN event_category NOT NULL; ALTER TABLE ch7_ddl MODIFY COLUMN event_category NULL; ``` `NOT NULL` without an option checks existing rows. It cannot be applied to `host_name`, which contains NULL. Run the following SQL separately only if you want to verify the failure. ```sql -- Expected failure: host_name is NULL in an existing row. ALTER TABLE ch7_ddl MODIFY COLUMN host_name NOT NULL; ``` `NOT NULL NOCHECK` skips the check for existing NULL values. It neither fills existing NULL values nor guarantees that historical data satisfies the constraint. The normal exercise does not use it. ## Dropping Indexes and Columns ```sql CREATE INDEX ch7_ddl_host_idx ON ch7_ddl(host_name) INDEX_TYPE LSM; DROP INDEX ch7_ddl_host_idx; ALTER TABLE ch7_ddl DROP COLUMN (host_name); ALTER TABLE ch7_ddl DROP COLUMN (source_kind); ALTER TABLE ch7_ddl DROP COLUMN (channels); SELECT event_id, event_category, severity, message FROM ch7_ddl; ``` Drop an index before dropping a column it references. Internal columns `_ARRIVAL_TIME` and `_RID` cannot be dropped, renamed, or have their attributes changed. At least one user column must remain. A VARCHAR length can only be increased and must not exceed 32,767 bytes. ## Deleting Data and Dropping Tables Caution: the following commands remove example data. LOG data cannot be recovered with a TRANSACTION table `ROLLBACK`. ```sql TRUNCATE TABLE ch7_ddl; SELECT COUNT(*) AS remaining_rows FROM ch7_ddl; DROP TABLE ch7_ddl; ``` After TRUNCATE, the count is 0 and the definition remains. The final DROP also removes the definition. To remove only older data, use [Retention Deletion](../operations-lifecycle/). ## Operational DDL Considerations Before a change, coordinate ingestion and DDL timing. Afterward, check column names, order, and types in SQL, Appenders, and file mappings. If a resource-in-use error occurs, check which jobs use the table before retrying. If the failing change is unclear, collect the original DDL and the SQL that failed. Together they help narrow down the cause. --- title: "7.4 Data Input" url: https://docs.machbase.com/dbms/log-table-usage/data-input-mutation/ language: en kind: page --- # 7.4 Data Input Successfully inserting one or two rows does not complete ingestion preparation. Continuous collection must account for send buffers, partial row failures, and retransmission after disconnection. First verify columns and timestamps with SQL, then choose an ingestion path suited to the required throughput. ## SQL INSERT ```sql CREATE LOG TABLE ch7_input ( event_time DATETIME, event_id VARCHAR(32), device VARCHAR(32), message VARCHAR(128) ); INSERT INTO ch7_input(event_time, event_id, device, message) VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'evt-001', 'DEV-01', 'connection timeout'); SELECT _arrival_time, event_time, event_id, device, message FROM ch7_input; ``` The query returns one row, with `event_time` set to the fixed event timestamp. Because `_arrival_time` is omitted, the ingestion path uses server time. Under the default setting, out-of-order timestamps may be adjusted, so do not assume this value always exactly matches reception time. For details, see [Time Model](../arrival-time-model/). Next, check what happens when the same event is inserted again. ```sql INSERT INTO ch7_input(event_time, event_id, device, message) VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'evt-001', 'DEV-01', 'connection timeout'); SELECT event_id, COUNT(*) AS received_rows FROM ch7_input GROUP BY event_id; DROP TABLE ch7_input; ``` The count for `evt-001` is 2. LOG does not deduplicate events with the same name. Successful transmission by the collector and exactly-once storage of a source event are separate concerns. ## Choosing an Ingestion Path | Situation | Initial choice | Also check | |---|---|---| | Small inserts or functional checks | SQL INSERT | Column list, types, and date format | | Continuous bulk ingestion from applications | SDK Append | Buffer transmission, row-level failures, and reconnection policy | | CSV read by a client | csvimport or machloader | Column mapping and rejected-row files | | Load files accessible to the server | LOAD DATA INFILE | Server path and file access permissions | SQL INSERT incurs processing overhead for each statement. For continuous bulk ingestion, consider the Append API, which sends rows in batches. For runnable code in your language, see [Development and Application Integration](/dbms/development-tools-integration/). ## Append Transmission and Error Handling After a row is passed to an Appender, it may still be in a client buffer. Check the SDK's flush and close behavior, and handle remaining buffers and connections on exception paths as well as normal shutdown. A successful call does not necessarily mean every row was stored. SDKs expose results differently, through return values, error callbacks, or success/failure counts at close. First test a small batch deliberately containing oversized values, NULL values, and date-conversion errors. A common problem is disconnection before a response arrives. A retry may resend a batch already stored, so record source event IDs and processing positions. LOG INSERT and Append operations are also outside the scope of ROLLBACK in TRANSACTION table transactions. ## File Loading and Mapping Prepare samples containing Korean text, empty strings, NULL values, long messages, and different time zones. Check the source field count and target column order before processing the full file. Retain rejected-row files and logs so the same errors can be investigated later. For complete commands, see [Data Ingestion, Loading, and Export](/dbms/development-tools-integration/data-input-load-export/). To preserve `_arrival_time` during historical migration, check both sort order and existing target data. For ordinary collection, it is safer to store historical event timestamps in a separate `event_time` column. If ingestion fails, start with one failing source row rather than the full batch. Compare its field values, target types, and ingestion API to identify the cause. --- title: "7.5 Query and Analysis" url: https://docs.machbase.com/dbms/log-table-usage/query-analysis/ language: en kind: page --- # 7.5 Query and Analysis Small changes to a time range can change the row count. When aggregating consecutive days, including the endpoint in both intervals counts boundary rows twice. This section uses fixed timestamps to check ranges and result order, then joins reference data. ## Prepare Example Data ```sql CREATE LOG TABLE ch7_query ( event_id INTEGER, device VARCHAR(32), value DOUBLE ); INSERT INTO ch7_query(_arrival_time, event_id, device, value) VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, 'DEV-01', 10); INSERT INTO ch7_query(_arrival_time, event_id, device, value) VALUES (TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS'), 2, 'DEV-01', 20); INSERT INTO ch7_query(_arrival_time, event_id, device, value) VALUES (TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS'), 3, 'DEV-02', 30); INSERT INTO ch7_query(_arrival_time, event_id, device, value) VALUES (TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 4, 'DEV-02', 40); SELECT _arrival_time, event_id, device, value FROM ch7_query ORDER BY _arrival_time, event_id; ``` Results appear in the order 1, 2, 3, 4. Because rows 2 and 3 share a timestamp, include the event number as well as time in ORDER BY to guarantee the order. This number is managed explicitly in the example, not an automatic LOG unique key. ## Consecutive Intervals and Time Boundaries ```sql SELECT event_id, value FROM ch7_query WHERE _arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') AND _arrival_time < TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY event_id; ``` Rows 1, 2, and 3 are selected. Starting the next interval at 12:00 counts row 4 only in that interval. `BETWEEN` includes both endpoints and therefore has different semantics. Use the same WHERE pattern when analyzing a user-defined `event_time` column. ## DURATION Queries ```sql SELECT event_id FROM ch7_query DURATION 1 HOUR BEFORE TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY event_id; SELECT event_id FROM ch7_query DURATION 1 HOUR AFTER TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY event_id; SELECT event_id FROM ch7_query DURATION FROM TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') TO TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY event_id; ``` | Query | Time range | Selected event_id values | |---|---|---| | 1 hour before 12:00 | 11:00–12:00, inclusive | 2, 3, 4 | | 1 hour after 10:00 | 10:00–11:00, inclusive | 1, 2, 3 | | From 10:00 to 12:00 | Both endpoints included | 1, 2, 3, 4 | If the reference time is omitted, as in `DURATION 1 HOUR`, the current time is used. This may return no rows for an exercise with old fixed timestamps. Place DURATION after WHERE and before GROUP BY or ORDER BY. Do not assume DURATION applies to every time column. It is LOG-specific and uses `_arrival_time`. Use WHERE for TAG time columns or user-defined DATETIME predicates. For syntax details, see [Relative Time and DURATION Dictionary](/dbms/reference/sql/relative-time/#log-duration). ## Scan Direction and Sorting DURATION BEFORE reads from newest to oldest; AFTER reads from oldest to newest. FROM … TO changes direction according to the order of its two timestamps. The following examples check a reversed range and a range whose endpoints are equal. ```sql SELECT event_id FROM ch7_query DURATION FROM TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS') TO TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY event_id DESC; SELECT event_id FROM ch7_query DURATION FROM TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS') TO TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY event_id; ``` The first result is ordered 4, 3, 2, 1; the second, with equal endpoints, returns 2 and 3. Explicit ORDER BY clauses fix the output order independently of scan direction. Use ORDER BY whenever the final result order matters, including results with aggregates or joins. In particular, do not infer which rows will be returned from LIMIT alone. The global `TABLE_SCAN_DIRECTION` setting can affect other queries. Do not start by changing server settings to alter display order. Check the execution plan in [Query Tuning](/dbms/performance-tuning/performance-query-tuning/) before adjusting access paths. ## Joining LOOKUP Tables ```sql CREATE LOOKUP TABLE ch7_query_device ( device VARCHAR(32) PRIMARY KEY, label VARCHAR(64) ); INSERT INTO ch7_query_device VALUES ('DEV-01', 'Boiler'); INSERT INTO ch7_query_device VALUES ('DEV-02', 'Pump'); SELECT q.event_id, d.label, q.value FROM ch7_query q JOIN ch7_query_device d ON q.device = d.device WHERE q._arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') AND q._arrival_time < TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY q.event_id; ``` The results are `(1, Boiler, 10)`, `(2, Boiler, 20)`, and `(3, Pump, 30)`. Because this query combines LOG and LOOKUP, it uses a WHERE range on the LOG column instead of DURATION. This INNER JOIN also excludes events without matching reference data. Joining current LOOKUP values does not reconstruct a device description from the time of an event. For historical descriptions, store the description in the event or design a separate history with validity periods. ```sql DROP TABLE ch7_query_device; DROP TABLE ch7_query; ``` If the row count differs from expectations, first check time boundaries and the count before the join. Add predicates one at a time to locate where rows are excluded. --- title: "7.6 Indexes and Performance" url: https://docs.machbase.com/dbms/log-table-usage/index-performance/ language: en kind: page --- # 7.6 Indexes and Performance If a query does not become faster after adding an index, first check whether it can use that index. Indexes reduce read cost but increase ingestion, storage, and background processing costs. Start with representative predicates rather than creating an index on every column. ## Choosing Indexes | Query predicate | Index to consider | What to check | |---|---|---| | Values and ranges for numeric, DATETIME, and other supported types | LSM | Supported types and the actual execution plan | | Words and token patterns in VARCHAR or TEXT | KEYWORD | Uses SEARCH/ESEARCH; result semantics differ from LIKE | | Repeated-value analysis on supported types | BITMAP | Value distribution, encoding, ingestion cost, and storage cost | For LOG `_arrival_time` ranges, use the built-in time access path first. Do not add an index for the same purpose by habit. Check supported types and properties in [INDEX Syntax](/dbms/reference/sql/syntax/index-syntax/). Do not directly apply conventional RDBMS composite-index designs. ## Comparing Before and After Index Creation ```sql CREATE LOG TABLE ch7_index ( event_id INTEGER, event_time DATETIME, severity SHORT, message VARCHAR(256) ); INSERT INTO ch7_index VALUES ( 1, TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, 'service started'); INSERT INTO ch7_index VALUES ( 2, TO_DATE('2026-01-01 10:01:00', 'YYYY-MM-DD HH24:MI:SS'), 3, 'database timeout'); INSERT INTO ch7_index VALUES ( 3, TO_DATE('2026-01-01 10:02:00', 'YYYY-MM-DD HH24:MI:SS'), 3, 'connection timeout'); EXPLAIN SELECT event_id FROM ch7_index WHERE severity = 3; CREATE INDEX ch7_index_time ON ch7_index(event_time) INDEX_TYPE LSM; CREATE INDEX ch7_index_message ON ch7_index(message) INDEX_TYPE KEYWORD; CREATE INDEX ch7_index_severity ON ch7_index(severity) INDEX_TYPE BITMAP BITMAP_ENCODE = RANGE; EXEC TABLE_FLUSH(ch7_index); EXEC INDEX_FLUSH(ch7_index); EXPLAIN SELECT event_id FROM ch7_index WHERE severity = 3; EXPLAIN SELECT event_id FROM ch7_index WHERE message SEARCH 'timeout'; SELECT event_id FROM ch7_index WHERE message SEARCH 'timeout' ORDER BY event_id; SHOW INDEXES; ``` The search returns rows 2 and 3. Compare the execution-plan access paths for the value predicate and SEARCH, and use SHOW INDEXES to check the created names. These three rows illustrate behavior; they are not a performance benchmark. ## Data and Index Synchronization `TABLE_FLUSH` flushes table data, whereas `INDEX_FLUSH` waits for index building to progress. Use them separately as shown when comparing plans and timings before and after index creation. An index can exist before all ingested data has been indexed. Build lag can affect search cost. However, calling both commands for every inserted row reduces the benefit of batch ingestion. In production, monitor ingestion rate and background processing rate together, and synchronize only at required points. Do not reinsert data simply because indexing is delayed. Check the source row count and index state separately before retrying to avoid duplicates. ## Performance Measurement Criteria Compare with the same data volume, predicate values, and concurrent ingestion load. Record repeated query timings, ingestion throughput, index space, and build lag, rather than a single execution time. LIKE and REGEXP evaluate predicates against raw strings; narrowing the time range first reduces the candidates. A KEYWORD index does not turn LIKE into SEARCH. ```sql DROP INDEX ch7_index_severity; DROP INDEX ch7_index_message; DROP INDEX ch7_index_time; DROP TABLE ch7_index; ``` If the plan is difficult to interpret, compare the query and EXPLAIN output together. The diagnostic sequence in [Index Tuning](/dbms/performance-tuning/index-tuning/) helps identify the next checks. --- title: "7.7 Operations and Data Lifecycle" url: https://docs.machbase.com/dbms/log-table-usage/operations-lifecycle/ language: en kind: page --- # 7.7 Operations and Data Lifecycle If ingestion works but disk usage keeps growing, check the deletion criteria. LOG removes older data regions rather than selecting individual rows by business predicates. Check both the retention period and the actual deletion boundary. ## Choosing a Deletion Method | Goal | Command | Basis | |---|---|---| | Delete the oldest N rows | OLDEST n ROWS | Oldest ingested rows first | | Keep only the latest N rows | EXCEPT n ROWS | Number of rows to retain | | Keep only a recent period | EXCEPT n DAY, etc. | Current server time minus the period | | Delete through a fixed timestamp | BEFORE datetime_expr | Includes the specified _arrival_time boundary | | Delete all data | DELETE without a predicate, or TRUNCATE | All rows | | Manage retention periodically | Retention Policy | Retention period and execution interval | Caution: do not assume deletion can be undone. LOG data is outside TRANSACTION table ROLLBACK. In production, verify backups and the actual target range before executing deletion. ## Comparing Deletion Methods When commands run sequentially, earlier deletions affect later results. Here, copy the same three rows into separate tables for comparison. ```sql CREATE LOG TABLE ch7_lifecycle (event_id INTEGER); CREATE LOG TABLE ch7_oldest (event_id INTEGER); CREATE LOG TABLE ch7_keep (event_id INTEGER); CREATE LOG TABLE ch7_before (event_id INTEGER); INSERT INTO ch7_lifecycle(_arrival_time, event_id) VALUES (TO_DATE('2026-01-01', 'YYYY-MM-DD'), 1); INSERT INTO ch7_lifecycle(_arrival_time, event_id) VALUES (TO_DATE('2026-01-02', 'YYYY-MM-DD'), 2); INSERT INTO ch7_lifecycle(_arrival_time, event_id) VALUES (TO_DATE('2026-01-03', 'YYYY-MM-DD'), 3); INSERT INTO ch7_oldest(_arrival_time, event_id) SELECT _arrival_time, event_id FROM ch7_lifecycle ORDER BY _arrival_time; INSERT INTO ch7_keep(_arrival_time, event_id) SELECT _arrival_time, event_id FROM ch7_lifecycle ORDER BY _arrival_time; INSERT INTO ch7_before(_arrival_time, event_id) SELECT _arrival_time, event_id FROM ch7_lifecycle ORDER BY _arrival_time; SELECT COUNT(*) AS delete_candidates FROM ch7_before WHERE _arrival_time <= TO_DATE('2026-01-02', 'YYYY-MM-DD'); DELETE FROM ch7_oldest OLDEST 1 ROWS; DELETE FROM ch7_keep EXCEPT 1 ROWS; DELETE FROM ch7_before BEFORE TO_DATE('2026-01-02', 'YYYY-MM-DD'); SELECT event_id FROM ch7_oldest ORDER BY event_id; SELECT event_id FROM ch7_keep ORDER BY event_id; SELECT event_id FROM ch7_before ORDER BY event_id; ``` The pre-deletion count is 2. The following events remain in each table. | Table | Remaining event_id values | |---|---| | ch7_oldest | 2, 3 | | ch7_keep | 3 | | ch7_before | 3 | The name BEFORE can be misleading. Current LOG deletion includes rows equal to the specified timestamp. A preliminary count with `WHERE _arrival_time < boundary` can therefore differ from the deletion target. Use `<=` as shown. ```sql DELETE FROM ch7_lifecycle; SELECT COUNT(*) AS remaining_rows FROM ch7_lifecycle; DROP TABLE ch7_before; DROP TABLE ch7_keep; DROP TABLE ch7_oldest; DROP TABLE ch7_lifecycle; ``` After DELETE without a predicate, the count is 0 and the table definition remains. ## Deletion by Relative Period ```sql CREATE LOG TABLE ch7_period (event_id INTEGER); INSERT INTO ch7_period(_arrival_time, event_id) VALUES (SYSDATE - 2d, 1); INSERT INTO ch7_period(_arrival_time, event_id) VALUES (SYSDATE, 2); DELETE FROM ch7_period EXCEPT 1 DAY; SELECT event_id FROM ch7_period ORDER BY event_id; DROP TABLE ch7_period; ``` If the steps from creation through querying run immediately, only row 2 remains. The reference is the current server time, not the timestamp of the last ingested row. Account for time continuing to pass even when ingestion stops. ## Retention Policy The following validation example retains one day of data and runs every minute. These are not production recommendations. Use an account authorized to create policies and assign them to tables. ```sql CREATE LOG TABLE ch7_retention (event_id INTEGER); INSERT INTO ch7_retention(_arrival_time, event_id) VALUES (SYSDATE - 2d, 1); INSERT INTO ch7_retention(_arrival_time, event_id) VALUES (SYSDATE, 2); CREATE RETENTION ch7_policy DURATION 1 DAY INTERVAL 1 MIN; ALTER TABLE ch7_retention ADD RETENTION ch7_policy; SELECT * FROM M$RETENTION WHERE POLICY_NAME = 'CH7_POLICY'; SELECT TABLE_NAME, POLICY_NAME, STATE, LAST_DELETED_TIME FROM V$RETENTION_JOB WHERE TABLE_NAME = 'CH7_RETENTION'; SELECT event_id FROM ch7_retention ORDER BY event_id; ``` DURATION is the period to retain; INTERVAL is how often deletion runs. Both rows may be visible immediately after assignment. After one interval plus processing time, rerun the query below and verify that only row 2 remains. LAST_DELETED_TIME is the deletion cutoff, not the wall-clock completion time. ```sql SELECT TABLE_NAME, STATE, LAST_DELETED_TIME FROM V$RETENTION_JOB WHERE TABLE_NAME = 'CH7_RETENTION'; SELECT event_id FROM ch7_retention ORDER BY event_id; ``` After the exercise, detach the policy before dropping the policy and table. ```sql ALTER TABLE ch7_retention DROP RETENTION; SELECT TABLE_NAME FROM V$RETENTION_JOB WHERE TABLE_NAME = 'CH7_RETENTION'; DROP RETENTION ch7_policy; DROP TABLE ch7_retention; ``` After detachment, the job query returns 0 rows. Previously deleted rows are not restored. One policy can be assigned to a table, and a policy in use must be detached before it can be dropped. For full operational guidance, see [Data Retention Policies](/dbms/operations-configuration-recovery/policy-data-retention/). ## Verifying Backups Before Deletion Having a backup file alone does not establish recoverability. Query the period to be deleted through Mount or in an isolated Restore environment. Define retention periods separately for source data, backups, and independently aggregated data. For environment-specific commands, see [Backup, Restore, and Mount](/dbms/operations-configuration-recovery/backup-restore-mount/). ## Data and Disk Space Rows may disappear from queries before the operating system reclaims file space. Check ingestion volume, the oldest remaining timestamp, index/storage cleanup state, and disk usage together. Do not delete a wider period simply because disk usage does not decrease immediately. If deletion results differ from expectations, first check the cutoff timestamp and assigned policy. For data subject to retention obligations, stop further deletion and agree on the scope with the responsible owner. --- title: "7.8 Constraints, Errors, and Troubleshooting" url: https://docs.machbase.com/dbms/log-table-usage/constraints-errors-troubleshooting/ language: en kind: page --- # 7.8 Constraints, Errors, and Troubleshooting Repeating the same failed SQL can leave the cause unchanged while making the state harder to understand. First distinguish unsupported operations from invalid input or object-state issues. This section narrows down checks by symptom. ## Feature Support | Request | LOG support | Alternative | |---|---|---| | General UPDATE | Unsupported | Design correction events or choose a mutable table | | DELETE WHERE with arbitrary predicates | Unsupported | BEFORE, OLDEST, EXCEPT, or a different model | | PRIMARY KEY/UNIQUE constraints | Unsupported | Handle duplicates during collection or choose another table | | Value/range indexes | LSM supported | Choose according to type and predicate | | Word search | KEYWORD supported | Create on VARCHAR/TEXT, then use SEARCH/ESEARCH | | BITMAP analytical indexes | Subject to supported conditions | Check type, encoding, and value distribution | | ORDER BY/GROUP BY on TEXT itself | Unsupported | Use separate code, severity, or time columns | ## Diagnosis by Symptom | Symptom | First check | Action | |---|---|---| | Stored arrival time differs from the explicit value | Previous timestamp and TIME_INVERSION_MODE | Check adjustment; retain event time separately | | SEARCH reports an index error | KEYWORD index on the column | Check type, table, and index name | | A word exists but is not found | SEARCH tokens versus LIKE substrings | Compare both results on one raw row | | Query remains slow after index creation | Plan, build state, and time range | Check indexing progress, then measure representative load | | Column length change fails | Existing type and new length | Use VARCHAR expansion only; check the maximum | | MINMAX change fails | Whether the type is variable-length | Target only supported fixed-length LOG columns | | NOT NULL change fails | Existing NULL rows | Distinguish existing-data checks from NOCHECK semantics | | An event appears multiple times | Source ID, retries, and file reprocessing | Review retransmission policy; arbitrary row deletion is unavailable | | DDL reports a resource-in-use error | Conflicts with ingestion or queries | Reschedule operations and check again | Check server settings and the index list as follows. ```sql SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME IN ('DISK_COLUMNAR_TABLE_TIME_INVERSION_MODE', 'TABLE_SCAN_DIRECTION'); SHOW INDEXES; ``` Checking a setting and changing it are separate operations. Do not change production-wide settings before identifying the cause. ## Reproducing and Resolving Errors ```sql CREATE LOG TABLE ch7_error (event_id INTEGER, message TEXT); INSERT INTO ch7_error VALUES (1, 'connection timeout'); SELECT event_id, message FROM ch7_error; ``` The query returns one row. Each statement below intentionally fails. Run only the statement you want to verify, separately from the normal exercise. ```sql -- No KEYWORD index exists. SELECT event_id FROM ch7_error WHERE message SEARCH 'timeout'; -- Sorting and grouping TEXT itself are unsupported. SELECT message FROM ch7_error ORDER BY message; SELECT message, COUNT(*) FROM ch7_error GROUP BY message; -- LOG does not support general UPDATE or predicate-based DELETE. UPDATE ch7_error SET message = 'fixed' WHERE event_id = 1; DELETE FROM ch7_error WHERE event_id = 1; -- This statement does not convert TEXT to VARCHAR. ALTER TABLE ch7_error MODIFY COLUMN (message VARCHAR(4096)); ``` Now create the index and check the supported search path. ```sql CREATE INDEX ch7_error_msg ON ch7_error(message) INDEX_TYPE KEYWORD; EXEC TABLE_FLUSH(ch7_error); EXEC INDEX_FLUSH(ch7_error); SELECT event_id, message FROM ch7_error WHERE message SEARCH 'timeout' ORDER BY event_id; DROP TABLE ch7_error; ``` Row 1 should be returned. Adding an index does not enable TEXT sorting or LOG UPDATE. ## Diagnosing Retention Policies If expired rows remain, check the assigned policy, execution interval, LAST_DELETED_TIME, and actual `_arrival_time` together. Do not conclude deletion failed based only on `event_time`. For exercises, see [Operations and Data Lifecycle](../operations-lifecycle/). If the issue persists, collect the server version and Edition, table DDL, failing SQL, complete error message, and representative input values. Redact passwords and sensitive logs before sharing. A small reproducer is more useful for diagnosis than sending the entire dataset. --- title: "7.9 Patterns and Scenarios" url: https://docs.machbase.com/dbms/log-table-usage/patterns-scenarios/ language: en kind: page --- # 7.9 Patterns and Scenarios Real analysis combines time, host, severity, and message. After trying each feature separately, use them together to answer which errors are increasing on which server. This exercise runs independently of tables from earlier sections. ## Source Events and Current State Append a new LOG row whenever an event occurs. Mutable reference data, such as a device's current name or location, can be kept in LOOKUP. If historical state is required, retain the values in the event or design separate history. The same approach applies to security events and job tracking. Consider TAG first for measurement aggregation by sensor name, or TRANSACTION for business-row updates and transactions. ## Creating Logs and Indexes Explicit arrival timestamps make time predicates comparable regardless of the execution date. This exercise inserts in ascending order into an empty table. For ordinary collection, keep the source event time in a separate DATETIME column. ```sql CREATE LOG TABLE ch7_app ( event_id INTEGER, host VARCHAR(32), level VARCHAR(16), message TEXT ); CREATE INDEX ch7_app_message ON ch7_app(message) INDEX_TYPE KEYWORD; INSERT INTO ch7_app(_arrival_time, event_id, host, level, message) VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, 'web-01', 'INFO', 'service started'); INSERT INTO ch7_app(_arrival_time, event_id, host, level, message) VALUES (TO_DATE('2026-01-01 10:10:00', 'YYYY-MM-DD HH24:MI:SS'), 2, 'web-01', 'WARN', 'slow response'); INSERT INTO ch7_app(_arrival_time, event_id, host, level, message) VALUES (TO_DATE('2026-01-01 10:20:00', 'YYYY-MM-DD HH24:MI:SS'), 3, 'web-02', 'ERROR', 'database timeout'); INSERT INTO ch7_app(_arrival_time, event_id, host, level, message) VALUES (TO_DATE('2026-01-01 10:30:00', 'YYYY-MM-DD HH24:MI:SS'), 4, 'web-02', 'ERROR', 'connection refused'); INSERT INTO ch7_app(_arrival_time, event_id, host, level, message) VALUES (TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS'), 5, 'web-01', 'INFO', 'normal service'); EXEC TABLE_FLUSH(ch7_app); EXEC INDEX_FLUSH(ch7_app); SELECT COUNT(*) AS received_rows FROM ch7_app; ``` The inserted row count is 5. Before repeating the exercise, confirm that the final DROP ran. Simply resending data can create duplicate rows. ## Querying Errors and Time Ranges ```sql SELECT event_id, host, message FROM ch7_app WHERE _arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') AND _arrival_time < TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS') AND message SEARCH 'timeout' ORDER BY event_id; SELECT event_id, host, level, message FROM ch7_app WHERE _arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') AND _arrival_time < TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS') AND level = 'ERROR' ORDER BY event_id; ``` The first query selects event 3 on web-02; the second selects events 3 and 4. This workflow starts with a word search, then examines other errors for the same host and period. Expand only the needed interval instead of removing the time predicate entirely. ## Aggregating by Hour and Severity ```sql SELECT TO_CHAR(_arrival_time, 'YYYY-MM-DD HH24') AS event_hour, level, COUNT(*) AS event_count FROM ch7_app WHERE _arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') AND _arrival_time < TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS') GROUP BY TO_CHAR(_arrival_time, 'YYYY-MM-DD HH24'), level ORDER BY event_hour, level; ``` | event_hour | level | event_count | |---|---|---| | 2026-01-01 10 | ERROR | 2 | | 2026-01-01 10 | INFO | 1 | | 2026-01-01 10 | WARN | 1 | | 2026-01-01 11 | INFO | 1 | This query aggregates source LOG rows. It does not automatically use TAG ROLLUP. As data grows, check the query range and execution plan, then separately assess whether preaggregation is needed. A common mistake is applying `DURATION 1 HOUR` to data with fixed timestamps. That predicate uses the current time and may exclude the samples on another execution date. Distinguish recent-log queries in production from reproducible fixed-time queries. ## Collection and Retention Management Continue with [Append Ingestion](../data-input-mutation/) for continuous collection. For long-term operation, also define a [Retention Policy](../operations-lifecycle/). Source logs, backups, and separate aggregates can require different retention periods. ```sql DROP TABLE ch7_app; ``` Once the results match, substitute fields and messages from a few actual logs. Testing whether a small sample answers the same questions makes issues easier to identify before migrating the full collection pipeline. --- title: "7.10 _arrival_time Time Model" url: https://docs.machbase.com/dbms/log-table-usage/arrival-time-model/ language: en kind: page --- # 7.10 _arrival_time Time Model A source log may contain yesterday's timestamp while a query treats it as data collected today. Mixing event time and collection time can make valid ingestion look like missing data. Distinguishing them is fundamental to LOG queries and retention policies. ## Event Time and Arrival Time A user-defined DATETIME column such as `event_time` answers when the event occurred. The automatically created `_arrival_time` is the basis for LOG time-range access and retention deletion. If omitted, it uses the server time. However, explicit input and out-of-order adjustment mean that it does not always represent the actual network reception time. DATETIME represents values in nanoseconds. This does not mean the server clock measures every timestamp with nanosecond precision. Once stored, a timestamp cannot be corrected with UPDATE on a LOG table. ## Querying Late Events This example inserts explicit arrival timestamps in ascending order into an empty table. ```sql CREATE LOG TABLE ch7_time ( event_id INTEGER, event_time DATETIME, message VARCHAR(64) ); INSERT INTO ch7_time(_arrival_time, event_id, event_time, message) VALUES (TO_DATE('2026-01-02 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, TO_DATE('2026-01-02 09:59:00', 'YYYY-MM-DD HH24:MI:SS'), 'normal arrival'); INSERT INTO ch7_time(_arrival_time, event_id, event_time, message) VALUES (TO_DATE('2026-01-02 10:01:00', 'YYYY-MM-DD HH24:MI:SS'), 2, TO_DATE('2026-01-01 23:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'delayed arrival'); SELECT event_id FROM ch7_time WHERE event_time >= TO_DATE('2026-01-01', 'YYYY-MM-DD') AND event_time < TO_DATE('2026-01-02', 'YYYY-MM-DD') ORDER BY event_id; SELECT event_id FROM ch7_time DURATION FROM TO_DATE('2026-01-02 10:00:00', 'YYYY-MM-DD HH24:MI:SS') TO TO_DATE('2026-01-02 10:01:00', 'YYYY-MM-DD HH24:MI:SS'); ``` The event-time query selects only event 2; the arrival-time query selects both events 1 and 2. There is no need to alter the event timestamp of a late arrival. ## Out-of-Order Timestamps and Adjustment `DISK_COLUMNAR_TABLE_TIME_INVERSION_MODE` controls how a timestamp earlier than the previous arrival timestamp is handled. The current Standard implementation behaves as follows. | Value | Handling of out-of-order input | |---|---| | 1 (default) | Adjust to 1 ns after the previously stored `_arrival_time` | | 0 | Reject the insert with a time-inversion error | Equal timestamps are not out of order, so this rule does not guarantee a unique timestamp for every row. To guarantee ordering when timestamps are equal, add another key, such as an event number, to ORDER BY. The following optional exercise uses the same table. Check the setting first and run it only in a validation environment where the value is 1. Do not change a production server setting for this example. ```sql SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME = 'DISK_COLUMNAR_TABLE_TIME_INVERSION_MODE'; ``` ```sql -- Run with setting 1. Setting 0 is expected to reject the insert. INSERT INTO ch7_time(_arrival_time, event_id, event_time, message) VALUES (TO_DATE('2026-01-02 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), 3, TO_DATE('2026-01-02 08:59:00', 'YYYY-MM-DD HH24:MI:SS'), 'inverted arrival'); SELECT event_id, TO_CHAR(_arrival_time, 'YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn') AS stored_time FROM ch7_time ORDER BY event_id; ``` With setting 1, event 3 is stored at `2026-01-02 10:01:00 000:000:001`, not the supplied 09:00 timestamp. The event time remains unchanged. Allowing time inversion therefore does not mean preserving every historical timestamp as supplied. ## Data Migration Considerations To preserve source `_arrival_time` values, normally insert into an empty target in ascending order. Even sorted input can be adjusted or rejected if the target already contains newer rows or concurrent ingestion intervenes. Do not mix migration and ordinary real-time collection in the same table. `DURATION` uses `_arrival_time`, not `event_time`. If the range differs even after matching time zones and date formats, check which time column the query uses. For boundaries and output order, continue to [Query Examples](../query-analysis/). ```sql DROP TABLE ch7_time; ``` When reporting a time-related issue, provide the source timestamp, stored timestamp, and setting value. Comparing all three helps distinguish conversion from adjustment. --- title: "7.11 Text Search and KEYWORD Index" url: https://docs.machbase.com/dbms/log-table-usage/text-search-keyword-index/ language: en kind: page --- # 7.11 Text Search and KEYWORD Index SEARCH and LIKE can return different results even when messages contain the same characters. SEARCH finds indexed words; LIKE applies a pattern to the raw string. Before comparing performance, establish which rows each query should find. ## Prepare Search Data ```sql CREATE LOG TABLE ch7_search ( event_id INTEGER, message TEXT ); CREATE INDEX ch7_search_msg ON ch7_search(message) INDEX_TYPE KEYWORD; INSERT INTO ch7_search VALUES (1, 'ERROR connection timeout'); INSERT INTO ch7_search VALUES (2, 'connection slowly refused'); INSERT INTO ch7_search VALUES (3, 'pretimeout marker'); INSERT INTO ch7_search VALUES (4, 'normal service'); INSERT INTO ch7_search VALUES (5, NULL); INSERT INTO ch7_search VALUES (6, '대한민국 연결 오류'); INSERT INTO ch7_search VALUES (7, 'ERR-1001 network'); INSERT INTO ch7_search VALUES (8, 'timeout refused connection'); EXEC TABLE_FLUSH(ch7_search); EXEC INDEX_FLUSH(ch7_search); ``` Compare results by the sample `event_id` values. The message column is TEXT and is not used for sorting. The same KEYWORD search is available for LOG VARCHAR columns. ## SEARCH and NOT SEARCH ```sql SELECT event_id FROM ch7_search WHERE message SEARCH 'timeout' ORDER BY event_id; SELECT event_id FROM ch7_search WHERE message SEARCH 'connection refused' ORDER BY event_id; SELECT event_id FROM ch7_search WHERE message SEARCH 'connection' AND message SEARCH 'refused' ORDER BY event_id; SELECT event_id FROM ch7_search WHERE message NOT SEARCH 'timeout' ORDER BY event_id; ``` | Predicate | Selected event_id values | Reason | |---|---|---| | SEARCH 'timeout' | 1, 8 | pretimeout is a separate word | | SEARCH 'connection refused' | 2, 8 | Both words are present | | Two SEARCH predicates combined with AND | 2, 8 | Both words are checked in the same message | | NOT SEARCH 'timeout' | 2, 3, 4, 6, 7 | The word is absent; NULL rows are excluded | Multiword SEARCH is not phrase search: it does not guarantee word order or adjacency. Row 2 has an intervening word and row 8 reverses the order, but both match. To SEARCH another column, that column also needs the corresponding index. Default tokenization normalizes ordinary ASCII words to lowercase. For example, `ERROR` in row 1 also matches `SEARCH 'error'`. Do not generalize this behavior to language-specific case handling for all Unicode characters. ### Korean Tokenization ```sql SELECT event_id FROM ch7_search WHERE message SEARCH '대한' ORDER BY event_id; SELECT event_id FROM ch7_search WHERE message SEARCH '연결' ORDER BY event_id; ``` Both queries select row 6. In the default mode, `대한민국` is indexed as overlapping 2-grams such as `대한`, `한민`, and `민국`. This is not morphological or semantic analysis. Test real samples because spaces, punctuation, single characters, and mixed English/Korean values can affect token boundaries. Index options such as MODE can also change tokenization. ## ESEARCH Extended Search ```sql SELECT event_id FROM ch7_search WHERE message ESEARCH 'time%' ORDER BY event_id; SELECT event_id FROM ch7_search WHERE message ESEARCH '%time%' ORDER BY event_id; SELECT event_id FROM ch7_search WHERE message ESEARCH 'err%' ORDER BY event_id; ``` | Pattern | Selected event_id values | Meaning | |---|---|---| | time% | 1, 8 | Words starting with time | | %time% | 1, 3, 8 | Words containing time | | err% | 1, 7 | Words starting with err, such as error or err | `time%` does not match time in the middle of a word. ESEARCH is also not equivalent to applying LIKE to the entire raw string. Do not transfer raw patterns spanning spaces or punctuation directly to ESEARCH. Make complex conditions explicit by combining separate SEARCH/ESEARCH predicates with AND or OR. ESEARCH is case-insensitive for ASCII in the current comparison path. Broader keyword matches increase search cost, so it is not always faster than LIKE. This example uses ASCII keyword patterns. `NOT ESEARCH` syntax is unsupported. Substituting `NOT SEARCH` or `NOT LIKE` changes the search semantics. Redefine which rows to exclude and check NULL handling. ## LIKE and NOT LIKE ```sql SELECT event_id FROM ch7_search WHERE message LIKE '%TIMEOUT%' ORDER BY event_id; SELECT event_id FROM ch7_search WHERE message LIKE 'ERR-____' ORDER BY event_id; SELECT event_id FROM ch7_search WHERE message NOT LIKE '%timeout%' ORDER BY event_id; ``` The first query selects rows 1, 3, and 8; the second returns 0 rows; the third selects 2, 4, 6, and 7. Row 7 has text after `ERR-1001`, so it does not match the whole-string pattern `ERR-____`. `%` matches zero or more characters; `_` matches one character. Check backslash escaping rules when searching for literal `%`, `_`, or backslashes. LIKE is also case-insensitive for ASCII in the current comparison path. It does not use a KEYWORD index, but other WHERE predicates or a time range can reduce the rows tested. It is therefore also inaccurate to say that LIKE always scans the entire table. ## REGEXP and REGEXP_LIKE ```sql SELECT event_id FROM ch7_search WHERE message REGEXP '^ERR-[0-9]+' ORDER BY event_id; SELECT event_id FROM ch7_search WHERE message NOT REGEXP 'timeout' ORDER BY event_id; ``` The first query selects row 7; the second selects 2, 4, 6, and 7. REGEXP checks for a matching substring. Specify `^` or `$` to constrain a match to the start or end of the string. Use `REGEXP_LIKE` for the function form. Its input currently must be VARCHAR, and its pattern and options must be constant VARCHAR values. Passing the preceding TEXT column directly causes a type error, so prepare a separate sample. ```sql CREATE LOG TABLE ch7_regexp_fn (event_id INTEGER, message VARCHAR(200)); INSERT INTO ch7_regexp_fn VALUES (1, 'ERROR connection timeout'); INSERT INTO ch7_regexp_fn VALUES (5, NULL); SELECT event_id, REGEXP_LIKE(message, 'error') AS case_sensitive, REGEXP_LIKE(message, 'error', 'i') AS case_insensitive FROM ch7_regexp_fn WHERE event_id IN (1, 5) ORDER BY event_id; ``` Row 1 returns 0 and 1, respectively. Row 5, whose message is NULL, returns NULL for both results. Regular expressions are case-sensitive by default; the `i` option makes comparison case-insensitive. Use `c` for explicitly case-sensitive comparison. Regular expressions are not processed directly by KEYWORD indexes. Time predicates or SEARCH can narrow the candidates, but a regular expression cannot recover a row excluded by the preceding predicate. ## TEXT Limitations and Search Performance TEXT can hold raw content up to 64 MiB, but ORDER BY and GROUP BY on TEXT itself are unsupported. Keep devices, error codes, and severity values for sorting and aggregation in separate columns. Compare performance on the same data after checking index presence, build state, and query range. ```sql DROP TABLE ch7_regexp_fn; DROP TABLE ch7_search; ``` If search results differ, inspect one raw row alongside the pattern. Distinguishing word search from substring search often resolves the discrepancy. --- title: "7.12 Network Type Queries" url: https://docs.machbase.com/dbms/log-table-usage/regex-network-query/ language: en kind: page --- # 7.12 Network Type Queries Storing IP addresses as strings is readable, but can lead to the mistaken assumption that lexical order matches address-range order. Use IPV4/IPV6 types for address comparison, and retain a separate string only when the original notation is also required. ## Prepare Network Data ```sql CREATE LOG TABLE ch7_network ( event_id INTEGER, src_ip IPV4, dst_ip IPV6, dst_port INTEGER ); INSERT INTO ch7_network VALUES (1, '192.0.2.1', '2001:db8::1', 80); INSERT INTO ch7_network VALUES (2, '192.0.2.255', '2001:db8::2', 65535); INSERT INTO ch7_network VALUES (3, '198.51.100.1', '2001:db8::3', 443); INSERT INTO ch7_network VALUES (4, NULL, NULL, NULL); SELECT event_id, src_ip, dst_ip, dst_port FROM ch7_network ORDER BY event_id; ``` The query returns four rows. Ports use INTEGER because USHORT reserves its maximum value, 65535, for NULL and cannot represent the full port range. ## Equality and Range Queries ```sql SELECT event_id FROM ch7_network WHERE src_ip BETWEEN '192.0.2.1' AND '192.0.2.255' ORDER BY event_id; SELECT event_id FROM ch7_network WHERE src_ip IN ('192.0.2.1', '198.51.100.1') ORDER BY event_id; SELECT event_id FROM ch7_network WHERE dst_ip = '2001:db8::2' ORDER BY event_id; SELECT event_id FROM ch7_network WHERE dst_ip BETWEEN '2001:db8::1' AND '2001:db8::2' ORDER BY event_id; SELECT event_id FROM ch7_network WHERE src_ip IS NULL ORDER BY event_id; ``` | Predicate | Selected event_id values | |---|---| | IPv4 BETWEEN | 1, 2 | | IPv4 IN | 1, 3 | | IPv6 equality | 2 | | IPv6 BETWEEN | 1, 2 | | IPv4 IS NULL | 4 | BETWEEN includes both endpoint addresses. The IPv4 range here is explicitly bounded by two addresses; it does not automatically apply CIDR semantics. Use `CONTAINED` below to test network membership. Test NULL with `IS NULL`, not `= NULL`. ## Testing CIDR Network Membership Use `CONTAINED` to test whether an address belongs to a network. Specify the network as `address/prefix`. Both IPv4 and IPv6 are supported. ```sql SELECT event_id FROM ch7_network WHERE src_ip CONTAINED '192.0.2.0/24' ORDER BY event_id; SELECT event_id FROM ch7_network WHERE dst_ip CONTAINED '2001:db8::/32' ORDER BY event_id; SELECT event_id FROM ch7_network WHERE src_ip NOT CONTAINED '192.0.2.0/24' ORDER BY event_id; ``` | Predicate | Selected event_id values | |---|---| | IPv4 `CONTAINED '192.0.2.0/24'` | 1, 2 | | IPv6 `CONTAINED '2001:db8::/32'` | 1, 2, 3 | | IPv4 `NOT CONTAINED '192.0.2.0/24'` | 3 | The reversed form `'192.0.2.0/24' CONTAINS src_ip` has the same meaning. `CONTAINS` places the network on the left and the address on the right; `CONTAINED` does the reverse. Omitting the prefix, as in `CONTAINED '192.0.2.0'`, causes an error because the value cannot be interpreted as a network. Row 4 has a NULL address and matches none of these predicates. Add a separate `IS NULL` predicate when counting uncollected addresses. ## Address Formats and Preserving Source Notation Use IPV4 when input contains only IPv4 addresses and IPV6 for IPv6 addresses. If both are handled, define input-conversion and column-separation policies first and validate them with real samples. Do not assume implicit conversion always normalizes source addresses as intended. Pay attention to output strings. The same IPv6 address may be displayed differently from its compressed source notation. If the original notation must be retained as evidence, store the typed address and raw string in separate columns. For large datasets, limit the `_arrival_time` range together with address predicates and inspect the execution plan. For message regular expressions, see [Text Search](../text-search-keyword-index/#regex) and the [SQL Function Dictionary](/dbms/reference/sql/functions/). ```sql DROP TABLE ch7_network; ``` If an address query returns unexpected results, compare the source string, input type, and both range endpoints. This helps distinguish notation differences from actual address-range differences. --- title: "8. TRANSACTION Table Usage" url: https://docs.machbase.com/dbms/rdb-table-usage/ language: en kind: section --- # 8. TRANSACTION Table Usage Appending source logs differs from changing order status, inventory, or device information. State-changing workloads must also check how many rows changed, what rolls back after a partial failure, and how concurrent updates from another connection behave. TRANSACTION tables support these relational queries and modifications in Standard Edition only. This chapter connects schema design, updates, transactions, concurrent access, and recovery while checking results on small samples. Although SQLite is used internally for storage, Machbase SQL defines the public syntax and support scope. Not every SQLite or other RDBMS feature is available unchanged. ## Chapter Contents | Section | What to check | |---|---| | [8.1 Overview and Use Criteria](./overview-use-criteria/) | Roles compared with LOG, TAG, and LOOKUP | | [8.2 Table Structure and Schema](./table-structure-schema/) | Identifiers, business keys, types, and constraints | | [8.3 Create, Alter, and Drop](./create-alter-drop/) | DDL and existing-data checks | | [8.4 Data Ingestion and Modification](./data-input-mutation/) | Conditional updates/deletes, copying, and Append | | [8.5 Queries and Analysis](./query-analysis/) | Filtering, sorting, aggregation, and JSON queries | | [8.6 Indexes and Performance](./index-performance/) | Primary key, unique, composite, and JSON path indexes | | [8.7 Operations and Data Lifecycle](./operations-lifecycle/) | Batch cleanup and operational checks | | [8.8 Constraints, Errors, and Troubleshooting](./constraints-errors-troubleshooting/) | Symptom diagnosis and retry decisions | | [8.9 Transactions](./transaction/) | Statement failures, ROLLBACK, and commit guarantees | | [8.10 Locks, Conflicts, and Busy Timeout](./locking-conflict-timeout/) | Two-connection conflicts and snapshot retries | | [8.11 JOIN and Relational Query Design](./join-relational-query/) | Rows added or excluded by joins | | [8.12 Backup, Restore, and Mount](./backup-restore-mount/) | Verifying actual data at the backup point | | [8.13 INSERT ON DUPLICATE KEY UPDATE](./insert-on-duplicate-key-update/) | Insert/update branches and duplicate handling | For common automatic-numbering syntax, see [AUTO_INCREMENT](/dbms/reference/sql/syntax/auto-increment-syntax/). ## Example Environment and Execution Scope SQL exercises target a DBMS 8.7 Standard Edition validation environment. Each section creates and cleans up `ch8_` objects independently. Table/index creation privileges are required; backup exercises also require separate privileges and server paths. Run BEGIN through COMMIT/ROLLBACK on the same connection. Follow the specified A/B sequence in two-session exercises. Intentionally failing SQL is separated from normal flow. Complete cleanup SQL before rerunning an exercise. Caution: the TRANSACTION name does not mean all operations and all failure scenarios roll back together. First check DDL, writes to other table types, and cross-table commit boundaries during failures in [8.9 Transactions](./transaction/). --- title: "8.1 Overview and Use Criteria" url: https://docs.machbase.com/dbms/rdb-table-usage/overview-use-criteria/ language: en kind: page --- # 8.1 Overview and Use Criteria Device measurements accumulate continuously, while inspection state and inventory quantities require updates to existing values. Using one model for both can mix source-retention requirements with state changes. Start with TRANSACTION for mutable business data and TAG/LOG for source time series. ## TRANSACTION Table Characteristics TRANSACTION supports SELECT, INSERT, UPDATE, DELETE, PRIMARY KEY, UNIQUE INDEX, and secondary indexes. It is Standard Edition only. The following three forms create the same table type. | Syntax | Meaning | |---|---| | CREATE TABLE | Default TRANSACTION creation with the type omitted | | CREATE TRANSACTION TABLE | Explicit type | | CREATE TXN TABLE | Abbreviated type | Use CREATE TRANSACTION TABLE in public documentation and operational scripts to make the type explicit. CREATE RDB TABLE and CREATE TRX TABLE are unsupported. None of the three supported creation forms is available in Cluster. Specify CREATE LOG TABLE explicitly for LOG. ## State Changes and Rollback ```sql CREATE TRANSACTION TABLE ch8_overview ( item_id LONG PRIMARY KEY, qty INTEGER NOT NULL ); INSERT INTO ch8_overview VALUES (42, 10); BEGIN; UPDATE ch8_overview SET qty = qty - 3 WHERE item_id = 42 AND qty >= 3; SELECT item_id, qty FROM ch8_overview; ROLLBACK; SELECT item_id, qty FROM ch8_overview; DROP TABLE ch8_overview; ``` On the same connection, the query inside the transaction shows quantity 7; after ROLLBACK, it shows 10. `qty >= 3` is the business predicate that prevents a change when stock is insufficient. Do not interpret an error-free UPDATE as business success. If no row matches, the affected row count can be 0. The application must check that the expected one row was affected before deciding to continue or roll back. This check matters more than simply substituting numbers in the SQL example. ## Comparison with Other Tables | Main requirement | Table to consider first | |---|---| | Measurements by sensor name and ROLLUP | TAG | | Immutable source logs/events | LOG | | Small current reference datasets | LOOKUP | | Relational DML and explicit transactions | TRANSACTION | | In-memory state that may be lost on restart | VOLATILE | TRANSACTION can hold equipment inspection state, business history, and separate summary results. For bulk source collection, compare throughput and ingestion paths with TAG/LOG. TRANSACTION also supports Append, but do not assume identical throughput or batch boundaries. See [Ingestion Methods](../data-input-mutation/). LOOKUP does not replace every TRANSACTION feature. If relational transactions are required in Cluster, consider an architecture that includes a separate RDBMS. ## Design Criteria Distinguish the row identifier from the business key used to prevent duplicates. An internal number may use PRIMARY KEY, while a separate unique value such as an external-system code may need UNIQUE INDEX. Automatic numbering does not eliminate duplicate business keys. Next, define frequent WHERE predicates and business success criteria. Decide where transactions end and what to check after errors so concurrent requests or connection failures have clear handling. Read [Schema](../table-structure-schema/) together with [Transactions](../transaction/). --- title: "8.2 Table Structure and Schema" url: https://docs.machbase.com/dbms/rdb-table-usage/table-structure-schema/ language: en kind: page --- # 8.2 Table Structure and Schema Automatic numbering does not eliminate all duplicates: the same external device can still be inserted twice with different numbers. Schema design starts by distinguishing row identifiers from keys that prevent business duplicates. ## Internal Identifiers and Business Keys This example manages an internal number separately from an external device code. ```sql CREATE TRANSACTION TABLE ch8_schema ( id LONG PRIMARY KEY AUTO_INCREMENT, external_code VARCHAR(64) NOT NULL, device_name VARCHAR(128) NOT NULL, price DECIMAL(18,2), state JSON, updated_at DATETIME ); CREATE UNIQUE INDEX ch8_schema_code ON ch8_schema(external_code); INSERT INTO ch8_schema(external_code, device_name, price, state, updated_at) VALUES ('ERP-01', 'Pump A', 19900.25, '{"status":"NORMAL"}', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')); SELECT external_code, device_name, price, state->'$.status' AS status FROM ch8_schema; ``` One ERP-01 row is returned with price 19900.25 and state NORMAL. The server assigns id. Do not make consecutive or gap-free numbering a business requirement. For retrieving assigned IDs, check your SDK and [AUTO_INCREMENT](/dbms/reference/sql/syntax/auto-increment-syntax/). ## PRIMARY KEY and UNIQUE A TRANSACTION table permits one single-column PRIMARY KEY. Specify PRIMARY KEY after the column definition, or add it to an existing table with CREATE PRIMARY KEY INDEX. It cannot be created on data containing NULL or duplicate values. Use a composite UNIQUE INDEX to enforce uniqueness across multiple columns. Do not copy UNIQUE, FOREIGN KEY, or table-level PRIMARY KEY syntax inside CREATE TABLE from another DBMS. Define uniqueness with CREATE UNIQUE INDEX after table creation. UNIQUE INDEX keys containing NULL are not considered duplicates of other NULL-containing keys. If a code must exist and be unique, also declare NOT NULL as in the example. Empty strings are another potential pitfall. Check Machbase empty-string/NULL behavior through the actual input path and validate required codes during collection. The following optional exercise checks a UNIQUE violation. Run it separately from successful inserts. ```sql -- Expected failure: duplicate external_code INSERT INTO ch8_schema(external_code, device_name) VALUES ('ERP-01', 'Duplicate Pump'); ``` After failure, ERP-01 should still have one row. To update on duplicates, use the separate [UPSERT](../insert-on-duplicate-key-update/) rules. ## Choosing Data Types | Value | Type choice | What to check | |---|---|---| | Identifiers and quantities | SHORT, INTEGER, LONG, and supported unsigned types | Range and reserved NULL values | | Measurements and approximate values | FLOAT, DOUBLE | Floating-point rounding | | Money and exact decimals | DECIMAL(M,D), NUMERIC, and other aliases | Precision, scale, and input conversion | | Codes and names | VARCHAR(n) | Byte length, not character count | | Long text and binary data | TEXT/CLOB, BINARY/BLOB | Storage support versus sorting, function, and index support | | Event/change timestamps | DATETIME | Source time zone and conversion format | | Network addresses | IPV4, IPV6 | Address format and comparison semantics | | Additional attributes | JSON | Frequently searched paths and their types | | Fixed-length numeric collections | Numeric ARRAY | Element type/length, whole-array NULL, and NULL elements | Check complete ranges in the [Data Type Dictionary](/dbms/reference/sql/types/) and monetary values in [DECIMAL](/dbms/reference/sql/types/decimal-numeric-fixed-point/). Do not use DOUBLE for every monetary column simply because an example does. ## Constraints and Input Validation TRANSACTION requires at least one user column. LOG automatic arrival timestamps and TAG METADATA/BASETIME/BASEDISTANCE are unavailable. Do not assume foreign keys automatically enforce referential integrity; include required relationship validation in the application and data checks. The example UNIQUE INDEX does not validate business rules for device names or prices. Define required values, allowed states, and quantity ranges separately. ```sql SELECT COUNT(*) AS device_count FROM ch8_schema; DROP TABLE ch8_schema; ``` The count before cleanup is 1. Continue with [Create, Alter, and Drop](../create-alter-drop/) for schema changes and [Index Design](../index-performance/) for query access paths. --- title: "8.3 Create, Alter, and Drop" url: https://docs.machbase.com/dbms/rdb-table-usage/create-alter-drop/ language: en kind: page --- # 8.3 Create, Alter, and Drop Schema changes require checking existing data and ingestion programs as well as command success. Old SQL after a rename or dropping an indexed column before its index can cause errors. This section checks before/after behavior with sample data present. ## Creating a Table ```sql CREATE TRANSACTION TABLE ch8_ddl ( id LONG, code VARCHAR(32), qty INTEGER ); INSERT INTO ch8_ddl VALUES (1, 'P-01', 10); ``` ## Creating Keys and Indexes ```sql CREATE PRIMARY KEY INDEX ch8_ddl_pk ON ch8_ddl(id); CREATE UNIQUE INDEX ch8_ddl_code ON ch8_ddl(code); CREATE INDEX ch8_ddl_qty ON ch8_ddl(qty); SHOW INDEX ch8_ddl_code; ``` id is the single PRIMARY KEY; code is a separate business key. Creation can fail if existing data contains duplicates or NULL in the primary key column. Define composite uniqueness with CREATE UNIQUE INDEX. UNIQUE constraint syntax inside CREATE TABLE is unsupported. For automatic numbering, specify `LONG PRIMARY KEY AUTO_INCREMENT` at creation. This section's id values are explicit, not automatic. Do not apply both creation patterns to the same object. See the separate [AUTO_INCREMENT](/dbms/reference/sql/syntax/auto-increment-syntax/) exercise. ## Adding Columns and Defaults ```sql ALTER TABLE ch8_ddl ADD COLUMN (label VARCHAR(64)); ALTER TABLE ch8_ddl ADD COLUMN (status VARCHAR(16) DEFAULT 'NEW'); ALTER TABLE ch8_ddl ADD COLUMN (limits DECIMAL(12)[2] DEFAULT [10, 20]); SELECT id, label, status, limits FROM ch8_ddl ORDER BY id; ``` In row 1, label is NULL, status is NEW, and limits is [10, 20]. Adding an ARRAY column without DEFAULT gives existing rows a whole-array NULL. DEFAULT support differs between ADD COLUMN and CREATE TABLE. ADD COLUMN accepts a value compatible with the type, as above. In CREATE TABLE column definitions, only `DEFAULT SYSDATE` on DATETIME is supported. Other types and values are rejected with `ERR-02346` and `ERR-02347`, respectively. If an initial default is needed, first create the table and add the column with ADD COLUMN, or specify the value in INSERT. Distinguish a whole-array NULL from NULL in individual array elements. Enclose column definitions in parentheses; this syntax differs from other DBMS ALTER TABLE forms. TRANSACTION does not support changing length or type with MODIFY COLUMN. Prepare a separate migration to a new schema when needed. ## Column Changes and Dependent Objects ```sql DROP INDEX ch8_ddl_qty; ALTER TABLE ch8_ddl DROP COLUMN (qty); ALTER TABLE ch8_ddl DROP COLUMN (label); ALTER TABLE ch8_ddl DROP COLUMN (limits); ALTER TABLE ch8_ddl RENAME COLUMN code TO product_code; SELECT id, product_code, status FROM ch8_ddl; SHOW INDEX ch8_ddl_code; ``` Existing row 1 retains P-01 and NEW, and the business-key index remains. Check PRIMARY KEY, UNIQUE, ordinary, and JSON path indexes before changing referenced columns. The last user column cannot be dropped. Renaming or dropping a table/column can be rejected if a VIEW references it. Application SQL and prepared statements are also affected. After DDL, check whether existing prepared statements must be prepared again rather than blindly reusing them. ```sql ALTER TABLE ch8_ddl RENAME TO ch8_product; SELECT id, product_code, status FROM ch8_product; ``` After renaming the table, query ch8_product. ## Deleting All Rows and Dropping Tables ```sql BEGIN; TRUNCATE TABLE ch8_product; SELECT COUNT(*) AS during_delete FROM ch8_product; ROLLBACK; SELECT COUNT(*) AS after_rollback FROM ch8_product; DROP TABLE ch8_product; ``` The counts are 0 and 1, respectively. Current TRANSACTION TRUNCATE is implemented as deletion of all rows and can be rolled back inside an explicit transaction. Do not generalize this to LOG/TAG TRUNCATE. The final DROP removes data, definition, and related indexes. ## Operational DDL Considerations Distinguish this TRUNCATE behavior from schema operations such as CREATE, ALTER, and DROP. Do not assume schema changes inside BEGIN can later be rolled back. Active transactions or open cursors on the same table can block DDL; close result sets and finish business transactions first. ADD/DROP COLUMN modify both the catalog and separate storage files. If the server stops during the operation, do not repeat the DDL before restart recovery finishes. After recovery, check DESC, representative SELECT/INSERT operations, indexes, views, and server logs. Do not recover by moving, editing, or deleting internal storage files directly. If the schema differs from expectations, review the original DDL, execution sequence, and first error together. This is more useful than examining only the last error. --- title: "8.4 Data Input and Mutation" url: https://docs.machbase.com/dbms/rdb-table-usage/data-input-mutation/ language: en kind: page --- # 8.4 Data Input and Mutation A successful UPDATE response does not necessarily mean an order reached the intended state. No matching row can yield 0 affected rows without an error. Check the target before modification, affected row count, and resulting values together. ## Conditional UPDATE and DELETE ```sql CREATE TRANSACTION TABLE ch8_mutation ( order_id LONG PRIMARY KEY, amount DECIMAL(18,2), status VARCHAR(16), ordered DATETIME ); INSERT INTO ch8_mutation VALUES ( 1001, 19900.25, 'PENDING', TO_DATE('2026-01-01', 'YYYY-MM-DD')); INSERT INTO ch8_mutation VALUES ( 1002, 29900.50, 'CANCELLED', TO_DATE('2026-01-02', 'YYYY-MM-DD')); BEGIN; UPDATE ch8_mutation SET status = 'SHIPPED' WHERE order_id = 1001 AND status = 'PENDING'; SELECT order_id, status FROM ch8_mutation ORDER BY order_id; COMMIT; ``` 1001 is SHIPPED and 1002 is CANCELLED. Repeating the UPDATE affects 0 rows because the row is no longer PENDING. Use the SDK's affected row count to distinguish success, already processed, and missing targets according to business rules. For the deletion below, also check the target count before executing it in a transaction. ```sql BEGIN; SELECT COUNT(*) AS delete_candidates FROM ch8_mutation WHERE status = 'CANCELLED'; DELETE FROM ch8_mutation WHERE status = 'CANCELLED'; SELECT order_id, amount, status FROM ch8_mutation ORDER BY order_id; COMMIT; ``` One row is targeted; after deletion, only 1001 remains. UPDATE/DELETE without WHERE affect all rows. In production, another session can change data between a preliminary SELECT and the actual modification, so the preliminary count alone does not establish success. ## INSERT SELECT and Self-Reference ```sql CREATE TRANSACTION TABLE ch8_archive ( order_id LONG PRIMARY KEY, amount DECIMAL(18,2), status VARCHAR(16), ordered DATETIME ); INSERT INTO ch8_archive(order_id, amount, status, ordered) SELECT order_id, amount, status, ordered FROM ch8_mutation WHERE ordered < TO_DATE('2026-02-01', 'YYYY-MM-DD'); INSERT INTO ch8_mutation(order_id, amount, status, ordered) SELECT order_id + 10000, amount, status, ordered FROM ch8_mutation WHERE order_id = 1001; SELECT order_id FROM ch8_archive ORDER BY order_id; SELECT order_id FROM ch8_mutation ORDER BY order_id; ``` The archive contains 1001; the source contains 1001 and 11001. Reading from and inserting into the same table does not endlessly reinsert new rows in this example. Copying without changing keys can still violate uniqueness. Match target column counts/types and partition copy ranges for safe reruns. Distinguish ordinary constraint errors from connection failures. Statement failure does not automatically roll back the entire BEGIN transaction. If the commit response is lost, query again to determine whether changes were applied. See [Transactions](../transaction/) for boundaries. ```sql DROP TABLE ch8_archive; DROP TABLE ch8_mutation; ``` ## Bulk Ingestion and Batch Boundaries TRANSACTION also supports the Append API. Old filenames or anchors containing reject/unsupported do not indicate current lack of support. Choose public language APIs using [SDK Feature Support](/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-append). | Ingestion method | What to check | |---|---| | SQL INSERT/prepared execution | Statement errors and explicit transaction boundaries | | Driver batch | Actual transmission units, partial success, and autocommit | | Append | SDK buffers/server batch boundaries, error callbacks, and return values | | machloader | Mappings, rejected rows, and processed-range records | The current SQLCLI SQLAppendBatch path processes a server batch as a transaction when no separate active transaction exists. Constraint-error regression tests for this path roll back the entire failing batch. Do not extend this guarantee to every SDK logical batch, multiple flushes, or an Appender's entire lifetime as one atomic operation. For AUTO_INCREMENT and DECIMAL input, also check the dedicated rules in [SQLCLI and ODBC](/dbms/development-tools-integration/cli-odbc/). The Append protocol arrival-time field does not create a LOG-style automatic timestamp column in TRANSACTION. Before adoption, mix one duplicate-key or NULL-error row with valid rows and verify success/failure counts and stored results. Retransmission after network errors must also account for duplicates of already committed data. --- title: "8.5 Query and Analysis" url: https://docs.machbase.com/dbms/rdb-table-usage/query-analysis/ language: en kind: page --- # 8.5 Query and Analysis Even syntactically valid SQL returns no rows when predicates differ from stored state values. Insufficient sort keys can also make equal-timestamp rows appear in a different order between queries. Check filtering, sorting, and aggregation with samples covering multiple states and time boundaries. ## Prepare Example Data ```sql CREATE TRANSACTION TABLE ch8_query ( order_id LONG PRIMARY KEY, customer VARCHAR(32), item_id LONG, amount DECIMAL(18,2), status VARCHAR(16), ordered DATETIME ); CREATE TRANSACTION TABLE ch8_query_product (id LONG PRIMARY KEY, name VARCHAR(64)); INSERT INTO ch8_query_product VALUES (42, 'Pump'); INSERT INTO ch8_query_product VALUES (43, 'Valve'); INSERT INTO ch8_query VALUES ( 1001, 'C-01', 42, 10.25, 'PENDING', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')); INSERT INTO ch8_query VALUES ( 1002, 'C-01', 43, 20.50, 'PENDING', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')); INSERT INTO ch8_query VALUES ( 1003, 'C-02', 42, 30.75, 'SHIPPED', TO_DATE('2026-01-02', 'YYYY-MM-DD')); SELECT order_id, amount, status FROM ch8_query WHERE order_id = 1001; ``` The query returns 1001, 10.25, PENDING. ## Time Predicates and Sorting ```sql SELECT order_id, amount FROM ch8_query WHERE ordered >= TO_DATE('2026-01-01', 'YYYY-MM-DD') AND ordered < TO_DATE('2026-01-02', 'YYYY-MM-DD') AND status = 'PENDING' ORDER BY ordered DESC, order_id DESC LIMIT 1; ``` Only 1002 is selected. order_id fixes ordering even when ordered timestamps match. Do not expect a desired order from LIMIT alone. Use inclusive-start/exclusive-end predicates for consecutive daily aggregates to avoid boundary duplicates. LOG-specific DURATION and automatic _arrival_time do not apply to TRANSACTION. ## Joining Reference Data ```sql SELECT o.order_id, p.name, o.amount FROM ch8_query o JOIN ch8_query_product p ON o.item_id = p.id WHERE o.customer = 'C-01' ORDER BY o.order_id; ``` Results are (1001, Pump, 10.25) and (1002, Valve, 20.50). This INNER JOIN excludes orders without reference data. Duplicate keys on the other side multiply results, so also check key uniqueness. For joins with other table types, see [JOIN Examples](../join-relational-query/). ## Aggregate Queries ```sql SELECT status, COUNT(*) AS cnt, SUM(amount) AS total_amount FROM ch8_query GROUP BY status ORDER BY status; ``` PENDING has 2 rows totaling 30.75; SHIPPED has 1 row totaling 30.75. An index does not automatically accelerate every aggregate. Check ranges, group counts, and result volume; consider separate summaries for repeated workloads. ## JSON Path Queries ```sql CREATE TRANSACTION TABLE ch8_query_json (id INTEGER PRIMARY KEY, state JSON); INSERT INTO ch8_query_json VALUES (1, '{"status":"ALARM","score":90}'); INSERT INTO ch8_query_json VALUES (2, '{"status":"NORMAL","score":10}'); INSERT INTO ch8_query_json VALUES (3, '{"score":20}'); SELECT id, state->'$.status' AS status FROM ch8_query_json WHERE state->'$.status' = 'ALARM' ORDER BY id; ``` Only row 1 is selected. Include separate samples for missing paths and differing predicate values. Distinguish arrow-path string comparisons from numeric extraction function comparisons. For frequently used paths, consider [JSON Path Indexes](../index-performance/#index-strategy-rdb-json-path). ## Indexes and Execution Plans ```sql CREATE INDEX ch8_query_status_time ON ch8_query(status, ordered); EXPLAIN SELECT order_id FROM ch8_query WHERE status = 'PENDING' AND ordered >= TO_DATE('2026-01-01', 'YYYY-MM-DD'); ``` Align predicates with leading composite-index columns, but verify actual usage with EXPLAIN. Assuming Machbase delegates entire relational queries unchanged to internal SQLite can lead to incorrect interpretations of index selection and function predicates. ```sql DROP TABLE ch8_query_json; DROP TABLE ch8_query_product; DROP TABLE ch8_query; ``` If results differ, check source row counts, WHERE predicates, and sort keys in order before analyzing complex aggregates or joins. --- title: "8.6 Indexes and Performance" url: https://docs.machbase.com/dbms/rdb-table-usage/index-performance/ language: en kind: page --- # 8.6 Indexes and Performance Indexes can enforce uniqueness as well as speed queries. Distinguish indexes protecting business keys from those reducing reads so performance cleanup does not accidentally remove required constraints. ## Index Types | Type | Purpose | Composite columns | NULL | |---|---|---|---| | PRIMARY KEY | Row identification; one per table | Unsupported | Not allowed | | UNIQUE INDEX | Business-key uniqueness | Supported | NULL-containing keys are not duplicates of each other | | Ordinary index | Predicate-query access path | Supported | No uniqueness check | TRANSACTION indexes are displayed as BTREE. Use a column PRIMARY KEY or add CREATE PRIMARY KEY INDEX afterward. Do not apply LOG LSM/KEYWORD index syntax directly to TRANSACTION. ## UNIQUE INDEX and NULL ```sql CREATE TRANSACTION TABLE ch8_index_account ( id LONG PRIMARY KEY, email VARCHAR(120), tenant INTEGER NOT NULL, login VARCHAR(64) ); INSERT INTO ch8_index_account VALUES (1, 'a@example.com', 1, 'alpha'); INSERT INTO ch8_index_account VALUES (2, 'b@example.com', 1, 'beta'); INSERT INTO ch8_index_account VALUES (3, NULL, 2, NULL); INSERT INTO ch8_index_account VALUES (4, NULL, 2, NULL); CREATE UNIQUE INDEX ch8_index_email ON ch8_index_account(email); CREATE UNIQUE INDEX ch8_index_login ON ch8_index_account(tenant, login); SELECT id FROM ch8_index_account WHERE email IS NULL ORDER BY id; SHOW INDEX ch8_index_email; ``` Rows 3 and 4 both exist, and the index is created. If a business key must have values, every key column needs NOT NULL as well as UNIQUE. Use separate CREATE UNIQUE INDEX instead of UNIQUE inside CREATE TABLE. The following two optional statements each test a uniqueness violation. ```sql -- Expected failure: duplicate email INSERT INTO ch8_index_account VALUES (5, 'a@example.com', 1, 'gamma'); UPDATE ch8_index_account SET email = 'a@example.com' WHERE id = 2; ``` After failure, four rows and row 2's b@example.com should remain. Ordinary UNIQUE violations currently report ERR-01418. Check indexes and input values together rather than inferring the duplicated business key from the error text alone. ## Dropping a UNIQUE INDEX ```sql DROP INDEX ch8_index_email; INSERT INTO ch8_index_account VALUES (5, 'a@example.com', 1, 'gamma'); SELECT id, email FROM ch8_index_account WHERE email = 'a@example.com' ORDER BY id; ``` Rows 1 and 5 are now both stored. Recreating the index while duplicates remain fails. ```sql -- Expected failure: existing data contains duplicates. CREATE UNIQUE INDEX ch8_index_email ON ch8_index_account(email); ``` Remove row 5 added during the exercise, then recreate the index. ```sql DELETE FROM ch8_index_account WHERE id = 5; CREATE UNIQUE INDEX ch8_index_email ON ch8_index_account(email); SELECT COUNT(*) AS remaining_rows FROM ch8_index_account; ``` The count is 4. In production, determine whether an index provides performance or uniqueness before removing it. ## Ordinary and Composite Indexes ```sql CREATE TRANSACTION TABLE ch8_index_event ( id LONG PRIMARY KEY, status VARCHAR(16), created DATETIME, state JSON ); INSERT INTO ch8_index_event VALUES ( 1, 'OPEN', TO_DATE('2026-01-01', 'YYYY-MM-DD'), '{"status":"ALARM","code":500}'); INSERT INTO ch8_index_event VALUES ( 2, 'CLOSED', TO_DATE('2026-01-02', 'YYYY-MM-DD'), '{"status":"NORMAL","code":200}'); INSERT INTO ch8_index_event VALUES ( 3, 'OPEN', TO_DATE('2026-01-03', 'YYYY-MM-DD'), '{"code":500}'); EXPLAIN SELECT id FROM ch8_index_event WHERE status = 'OPEN' AND created >= TO_DATE('2026-01-01', 'YYYY-MM-DD'); CREATE INDEX ch8_index_status_time ON ch8_index_event(status, created); EXPLAIN SELECT id FROM ch8_index_event WHERE status = 'OPEN' AND created >= TO_DATE('2026-01-01', 'YYYY-MM-DD'); SELECT id FROM ch8_index_event WHERE status = 'OPEN' AND created >= TO_DATE('2026-01-01', 'YYYY-MM-DD') ORDER BY id; ``` Results must have the same semantics before and after index creation; the final query returns rows 1 and 3. Align the leading column with predicates, but do not assume every compound predicate uses the index. Verify Machbase plan selection and supported predicate shapes with EXPLAIN. Timings for three rows are not a benchmark. ## JSON Path Indexes ```sql CREATE INDEX ch8_index_json_status ON ch8_index_event(state->'$.status'); CREATE INDEX ch8_index_json_code ON ch8_index_event(state->'$.code'); EXPLAIN SELECT id FROM ch8_index_event WHERE state->'$.status' = 'ALARM'; SELECT id FROM ch8_index_event WHERE state->'$.status' = 'ALARM' ORDER BY id; SELECT id FROM ch8_index_event WHERE state->'$.code' = '500' ORDER BY id; ``` The status query returns row 1; the code query returns 1 and 3. An index does not mean every JSON function expression uses that path. Distinguish result types and comparison semantics of arrow paths and numeric extraction functions. For frequently repeated complex predicates, also compare a design using ordinary extracted columns. Even when a JSON path UNIQUE INDEX can be created, it is not a conflict-selection key for TRANSACTION UPSERT. Check [UPSERT Constraints](../insert-on-duplicate-key-update/). ## Read and Write Costs Compare with the same data volume, predicate values, and concurrent input rate before and after index creation. Measure INSERT/UPDATE/DELETE throughput and index space as well as query time. LIMIT reduces result volume, but ORDER BY is required to fix which rows are returned. ```sql DROP TABLE ch8_index_event; DROP TABLE ch8_index_account; ``` Replacing a UNIQUE INDEX with an ordinary index for performance removes uniqueness guarantees. First verify that results and constraints remain equivalent across tuning changes. --- title: "8.7 Operations and Data Lifecycle" url: https://docs.machbase.com/dbms/rdb-table-usage/operations-lifecycle/ language: en kind: page --- # 8.7 Operations and Data Lifecycle Deleting old business data requires more than checking dates. Cancelled orders and orders still in progress have different retention criteria, and cleanup can conflict with other writes. Define business predicates and processing units before deleting. ## Data Retention Criteria Use TAG/LOG for source time series and TRANSACTION for mutable state or summary results. Their retention periods need not match. TAG/LOG Retention Policy does not directly apply to TRANSACTION. Design DELETE predicates and external scheduling for business requirements. ## Deletion and Rollback ```sql CREATE TRANSACTION TABLE ch8_cleanup ( id LONG PRIMARY KEY, status VARCHAR(16), created DATETIME ); INSERT INTO ch8_cleanup VALUES (1, 'CANCELLED', TO_DATE('2025-12-01', 'YYYY-MM-DD')); INSERT INTO ch8_cleanup VALUES (2, 'PENDING', TO_DATE('2025-12-01', 'YYYY-MM-DD')); INSERT INTO ch8_cleanup VALUES (3, 'CANCELLED', TO_DATE('2026-02-01', 'YYYY-MM-DD')); BEGIN; SELECT COUNT(*) AS delete_candidates FROM ch8_cleanup WHERE status = 'CANCELLED' AND created < TO_DATE('2026-01-01', 'YYYY-MM-DD'); DELETE FROM ch8_cleanup WHERE status = 'CANCELLED' AND created < TO_DATE('2026-01-01', 'YYYY-MM-DD'); SELECT id, status FROM ch8_cleanup ORDER BY id; ROLLBACK; SELECT COUNT(*) AS after_rollback FROM ch8_cleanup; ``` One row is targeted. Rows 2 and 3 remain during deletion; after rollback, the count is 3. The exercise rolls back for verification. To finalize production work, choose COMMIT after business approval and result checks. Close result cursors before ending the transaction. Do not equate preliminary query counts with actual affected rows. Account for concurrent changes and snapshot conflicts, and record affected counts returned during execution and final state. See [Locks and Retries](../locking-conflict-timeout/). ## Batch Processing and Resumption Partition deletion by date interval or unique-key range instead of one long transaction. Record boundaries, processed counts, and commit results for each range so work can resume after an interruption. Also take care when copying reference data to another table before deleting the source. Do not assume atomic cross-table commit under failure for multiple TRANSACTION tables. Design copy verification and resumption according to [Transaction Guarantees](../transaction/). Avoid waiting for external APIs or long file operations inside BEGIN. ## Backup Validation Check business keys, row counts, totals, and indexes in the mounted backup, not merely backup-command success. Use three-part names `mount_name.owner.table_name`. Two-part names can be confused with production data. Even incremental backups include a complete TRANSACTION table storage snapshot at the backup point. Do not estimate additional space only from the changed row count. For exercises, see [Backup, Restore, and Mount](../backup-restore-mount/). ## Checks After Cleanup Fewer rows do not necessarily reduce operating-system file size immediately or proportionally. Check business row counts, actual file usage, and retained backup volume separately. Do not connect directly to internal SQLite files or delete files arbitrarily to reclaim space. ```sql DROP TABLE ch8_cleanup; ``` If cleanup fails, check the last successful range and commit result before attempting further deletion. These records reduce omissions and duplicate processing. --- title: "8.8 Constraints, Errors, and Troubleshooting" url: https://docs.machbase.com/dbms/rdb-table-usage/constraints-errors-troubleshooting/ language: en kind: page --- # 8.8 Constraints, Errors, and Troubleshooting When migrating SQL from another RDBMS, similar names can suggest equivalent features incorrectly. First check Edition and public syntax, then examine data constraints separately from concurrency issues. ## Feature Support TRANSACTION is Standard Edition only. Cluster rejects CREATE TABLE, CREATE TRANSACTION TABLE, and CREATE TXN TABLE. Specify CREATE LOG TABLE explicitly for LOG. | Requirement | Support or alternative | |---|---| | General SELECT/INSERT/UPDATE/DELETE | Supported; changes without WHERE target all rows | | Single-column PRIMARY KEY | Supported; one per table | | Single/composite UNIQUE INDEX | Supported; create separately after the table | | Column UNIQUE or table-level PRIMARY KEY | These creation forms are unsupported | | FOREIGN KEY, Trigger, Stored Procedure | Unsupported | | BEGIN/COMMIT/ROLLBACK | Supported; nested BEGIN and SAVEPOINT unsupported | | ADD/DROP/RENAME COLUMN, RENAME TO | Check supported conditions | | MODIFY COLUMN | Unsupported | | Append | Check SDK public paths and batch boundaries | | TAG METADATA/BASETIME/BASEDISTANCE | Not applicable to TRANSACTION | LOOKUP can support small reference-data changes in Cluster, but is not a complete replacement for explicit relational transactions. Separate requirements appropriately, such as LOG/TAG for source events and another RDBMS for relational transactions. ## Diagnosis by Error | Symptom | What to check | Next action | |---|---|---| | ERR-01418 uniqueness violation | Primary/unique keys and existing data | Correct input or review UPSERT rules | | NOT NULL violation | Omitted values, NULL, empty strings, and DEFAULT | Check input and constraints | | UPDATE affects 0 rows | Key and current-state predicates | Distinguish missing/already-processed targets | | Resource busy | Other writers, stale read snapshots, and open cursors | Wait, restart the transaction, or close cursors as appropriate | | COMMIT/ROLLBACK is busy | Open result sets on the same connection | Close result sets and retry termination | | Subsequent SQL is rejected after an error | Rollback-only state | ROLLBACK and start a new operation | | DDL fails | Referencing indexes/views and active transactions | Adjust dependencies and timing | | Mounted values differ from expectations | Mount, owner, and table names | Distinguish production from backup data | Resource busy errors require different retry strategies. See the two-connection exercises in [Locks and Busy Timeout](../locking-conflict-timeout/). Do not retry solely because the error text contains TRANSACTION. ## Constraint Errors and Data Preservation ```sql CREATE TRANSACTION TABLE ch8_error ( id LONG PRIMARY KEY, code VARCHAR(32) NOT NULL, value INTEGER ); CREATE UNIQUE INDEX ch8_error_code ON ch8_error(code); INSERT INTO ch8_error VALUES (1, 'A', 10); ``` Each optional example below intentionally fails. Run only the statement being checked, separately from normal SQL. ```sql -- Duplicate PRIMARY KEY INSERT INTO ch8_error VALUES (1, 'B', 20); -- Duplicate UNIQUE key INSERT INTO ch8_error VALUES (2, 'A', 20); -- Required-value violation INSERT INTO ch8_error VALUES (3, NULL, 30); -- Unsupported schema change ALTER TABLE ch8_error MODIFY COLUMN (code VARCHAR(64)); ``` ```sql SELECT id, code, value FROM ch8_error ORDER BY id; DROP TABLE ch8_error; ``` The final query contains only (1, A, 10). Distinguish a failed statement preserving state from automatic cancellation of earlier successful statements inside BEGIN; the latter does not follow. See the comparison in [Transactions](../transaction/). ## Collecting Diagnostic Information Collect server version/Edition, DDL and indexes, executed SQL, error code and full message, and actual affected row counts. For connection failures, also record COMMIT request/response times and business keys. Redact passwords, personal information, and sensitive business values; share only a minimal reproducer. Do not repair by editing internal storage files or recreating production tables. Establish the cause and whether changes were applied first to reduce data loss. --- title: "8.9 Transactions" url: https://docs.machbase.com/dbms/rdb-table-usage/transaction/ language: en kind: page --- # 8.9 Transactions When a statement fails midway through several SQL operations, earlier changes do not necessarily disappear. Ordinary constraint errors distinguish the failing statement from the entire transaction. This section first checks COMMIT/ROLLBACK boundaries using changes within one table. ## Executing Transactions ```sql CREATE TRANSACTION TABLE ch8_tx ( item_id LONG PRIMARY KEY, qty INTEGER NOT NULL ); INSERT INTO ch8_tx VALUES (1, 10); INSERT INTO ch8_tx VALUES (2, 20); BEGIN; UPDATE ch8_tx SET qty = qty - 3 WHERE item_id = 1 AND qty >= 3; UPDATE ch8_tx SET qty = qty + 3 WHERE item_id = 2; SELECT item_id, qty FROM ch8_tx ORDER BY item_id; ROLLBACK; SELECT item_id, qty FROM ch8_tx ORDER BY item_id; ``` Inside the transaction, values are 7 and 23; after ROLLBACK, they are 10 and 20. The application must verify that each UPDATE affected the expected one row. Updating 0 rows because a predicate does not match is not an SQL error, so the database does not automatically identify business failure. The following successful exercise commits the same changes. ```sql BEGIN; UPDATE ch8_tx SET qty = qty - 3 WHERE item_id = 1 AND qty >= 3; UPDATE ch8_tx SET qty = qty + 3 WHERE item_id = 2; COMMIT; SELECT item_id, qty FROM ch8_tx ORDER BY item_id; ``` Committed values are 7 and 23. The public syntax is BEGIN; BEGIN TRANSACTION, nested BEGIN, and SAVEPOINT are unsupported. Without an explicit transaction, TRANSACTION DML is processed statement by statement. Check driver autocommit and transaction APIs separately. ## Statement Errors and Rollback This exercise demonstrates error handling. The duplicate INSERT intentionally fails. If the SQL tool stops on error, ensure ROLLBACK is executed on the same connection. ```sql BEGIN; UPDATE ch8_tx SET qty = 100 WHERE item_id = 1; ``` ```sql -- Expected failure: duplicate item_id INSERT INTO ch8_tx VALUES (1, 999); ``` ```sql SELECT item_id, qty FROM ch8_tx ORDER BY item_id; ROLLBACK; SELECT item_id, qty FROM ch8_tx ORDER BY item_id; ``` The first query shows 100 and 23; after ROLLBACK, 7 and 23. An ordinary constraint error rolls back the failing statement, but earlier successful statements remain in the transaction. The application must choose ROLLBACK to cancel the whole business operation. Continuing is not possible after every error: a rollback-only state entered during recovery must be ended with ROLLBACK. ## TRUNCATE and Rollback ```sql BEGIN; TRUNCATE TABLE ch8_tx; SELECT COUNT(*) AS during_truncate FROM ch8_tx; ROLLBACK; SELECT COUNT(*) AS after_rollback FROM ch8_tx; ``` Results are 0 and 2. Current TRANSACTION TRUNCATE deletes all rows as part of an explicit transaction. Distinguish this from LOG/TAG cleanup and schema changes such as CREATE/ALTER/DROP. Perform schema operations outside business transactions. ## Transaction Scope by Table Type Queries and mixed joins involving LOG, TAG, LOOKUP, and VOLATILE are allowed during an active TRANSACTION transaction. Writes to those types cannot be grouped into the same transaction. Permitted reads do not give those types the same snapshot/rollback guarantees as TRANSACTION. Design consistency between source ingestion and business-state changes separately. TRANSACTION reads use snapshots that exclude other sessions' uncommitted changes. Do not assume BEGIN fixes one common read point across every table at once. Read-to-write conflicts are covered in [Locks and Retries](../locking-conflict-timeout/). ## Multitable Commit and Failures DML on multiple TRANSACTION tables can be grouped with BEGIN and normally committed or rolled back. However, storage currently uses per-table handles, and COMMIT processes those handles sequentially. Do not interpret this as guaranteed atomic commit across all tables if a failure occurs during commit. Review this limitation first for workloads requiring indivisible multitable processing. After commit failure or a lost response, sending ROLLBACK does not prove every table was restored. Check applied state by business key. This is also why the basic exercise uses two rows in one table. ## Cursors and Transaction Termination Open TRANSACTION cursors can cause COMMIT/ROLLBACK to fail with Resource busy. Close SDK result sets/statements, then retry the termination command. Disconnecting rolls back uncommitted changes, but the client must separately establish whether the server had already committed before the connection was lost. ```sql DROP TABLE ch8_tx; ``` Do not wait for external APIs or long computations inside BEGIN. Keep transactions short and distinguish retrying an operation from first checking its result to make operational decisions clearer. --- title: "8.10 Locks, Conflicts, and Busy Timeout" url: https://docs.machbase.com/dbms/rdb-table-usage/locking-conflict-timeout/ language: en kind: page --- # 8.10 Locks, Conflicts, and Busy Timeout If different rows still produce Resource busy, thinking only in terms of row locks can obscure the cause. TRANSACTION write conflicts can occur between different rows of the same table. Distinguish conflicts resolved by waiting from those requiring a new transaction. ## Example Environment This exercise targets a Standard validation environment with default WAL settings. A and B are separate connections to the same account and database. Execute blocks in the stated order and fully consume SELECT results to close cursors. Do not change production journal mode for this exercise. Prepare the table in A. ```sql SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME = 'TRANSACTION_JOURNAL_MODE'; CREATE TRANSACTION TABLE ch8_lock (id INTEGER PRIMARY KEY, val INTEGER); INSERT INTO ch8_lock VALUES (1, 10); INSERT INTO ch8_lock VALUES (2, 20); ``` TRANSACTION_JOURNAL_MODE=4 means WAL. With another value, check the environment before expecting the WAL snapshot results below. ## Concurrent Write Conflicts In A, begin a transaction and leave it open. ```sql BEGIN; UPDATE ch8_lock SET val = 11 WHERE id = 1; ``` Next query in B. Set the wait time to 0 only on the example B connection. ```sql ALTER SESSION SET TRANSACTION_BUSY_TIMEOUT_MS = 0; SELECT id, val FROM ch8_lock ORDER BY id; ``` B sees the previous values 10 and 20, not A's uncommitted 11. B's following UPDATE intentionally produces Resource busy. ```sql -- B: failure is expected; a different row still writes the same table. UPDATE ch8_lock SET val = val + 1 WHERE id = 2; ``` COMMIT in A, then repeat the UPDATE in B. ```sql -- A COMMIT; ``` ```sql -- B UPDATE ch8_lock SET val = val + 1 WHERE id = 2; SELECT id, val FROM ch8_lock ORDER BY id; ``` Values are now 11 and 21. This demonstrates why same-table write conflicts must not be interpreted as conventional row-level locking. ## WAL Snapshot Conflicts After completing the preceding steps, open a read transaction in A. ```sql -- A BEGIN; SELECT val FROM ch8_lock WHERE id = 1; ``` After A reads 11, change the value in B. B has no explicit transaction active. ```sql -- B UPDATE ch8_lock SET val = val + 10 WHERE id = 1; ``` Switching A to a write now is expected to cause a snapshot conflict. ```sql -- A: intentionally failing step UPDATE ch8_lock SET val = val + 1 WHERE id = 1; ``` Another connection has already committed, so A cannot promote its stale read snapshot to a write. Increasing busy timeout or setting it to -1 does not resolve this conflict by waiting. End A's transaction and reassess the new state instead of repeating only UPDATE. ```sql -- A ROLLBACK; BEGIN; UPDATE ch8_lock SET val = val + 1 WHERE id = 1; COMMIT; SELECT id, val FROM ch8_lock ORDER BY id; ``` Final values are 22 and 21. If the next change was calculated from a value read earlier, repeat the read and business decision in the new transaction. ## busy timeout The server default TRANSACTION_BUSY_TIMEOUT_MS is 30000 ms and is copied to new sessions. Change the current session with ALTER SESSION. | Value | Handling of temporary lock conflicts | |---|---| | -1 | Wait until cancellation, disconnection, or lock release | | 0 | Return busy without waiting | | Positive | Wait up to that many milliseconds, then proceed or return busy | Conflicts that retries cannot resolve, such as snapshot promotion conflicts, are exceptions to this policy. -1 is not an infinite retry policy for every conflict. DDL_LOCK_TIMEOUT separately controls DDL lock waits; changing it does not fix snapshot conflicts. ## Errors and Retries Retrying because the message contains TRANSACTION also repeats type, constraint, and permission errors. Use driver error codes, complete diagnostics, and operation type to identify retryable lock conflicts. To retry an explicit transaction, close open result sets, ROLLBACK, and rerun in a new transaction within bounded attempts and total request time. Connection loss and lost COMMIT responses are separate cases. Repeating counter increments or order processing without checking business keys for prior completion can apply changes twice. ## Conflict Diagnosis ```sql SELECT id, user_name, user_ip, transaction_busy_timeout_ms FROM V$SESSION WHERE closed = 0 ORDER BY id; SELECT id, sess_id, state, query FROM V$STMT WHERE state LIKE 'Execute in progress%' OR state LIKE 'Fetch in progress%'; ``` This query does not directly map lock owners. V$MUTEX contains internal server mutex statistics, not a business-row lock list. Check connection information together with application BEGIN/end records. Do not make forced session termination the first action, because it can cancel uncommitted work. Confirm that neither connection has an open transaction, then clean up in A. ```sql DROP TABLE ch8_lock; ``` Closing example connections A and B removes the effect of B's session timeout. In production, moving external API calls and long computations outside BEGIN can itself reduce waits. --- title: "8.11 JOIN and Relational Query Design" url: https://docs.machbase.com/dbms/rdb-table-usage/join-relational-query/ language: en kind: page --- # 8.11 JOIN and Relational Query Design If adding JOIN changes order counts, first check relationship cardinality. INNER JOIN excludes unmatched rows, while multiple matches multiply results. Error-free SQL does not guarantee correct business counts. ## TRANSACTION–LOOKUP Joins ```sql CREATE TRANSACTION TABLE ch8_join_order ( order_id LONG PRIMARY KEY, item_id LONG, qty INTEGER ); CREATE LOOKUP TABLE ch8_join_product (id LONG PRIMARY KEY, name VARCHAR(64)); CREATE TRANSACTION TABLE ch8_join_payment (order_id LONG PRIMARY KEY, status VARCHAR(16)); INSERT INTO ch8_join_order VALUES (1, 42, 2); INSERT INTO ch8_join_order VALUES (2, 99, 1); INSERT INTO ch8_join_product VALUES (42, 'Pump'); INSERT INTO ch8_join_payment VALUES (1, 'PAID'); SELECT o.order_id, p.name, o.qty FROM ch8_join_order o JOIN ch8_join_product p ON o.item_id = p.id ORDER BY o.order_id; SELECT o.order_id, p.name, o.qty FROM ch8_join_order o LEFT JOIN ch8_join_product p ON o.item_id = p.id ORDER BY o.order_id; ``` INNER JOIN returns only order 1; LEFT JOIN returns orders 1 and 2. Order 2's product name is NULL. A foreign key does not block inserting an order for missing product 99, so design required reference validation separately. A common mistake is putting a right-side predicate in WHERE after LEFT JOIN. Adding `WHERE p.name = 'Pump'`, for example, excludes NULL rows. Distinguish predicates for finding matches from predicates filtering final results. ## Joins Between TRANSACTION Tables ```sql SELECT o.order_id, o.qty, p.status FROM ch8_join_order o JOIN ch8_join_payment p ON o.order_id = p.order_id ORDER BY o.order_id; ``` The query returns one row, (1, 2, PAID). Multiple payment-history rows per order would produce multiple results. Check relationships and aggregation granularity to avoid duplicate totals when summing order amounts after a join. ## TAG Joins by Nearby Time This example joins every measurement within 5 seconds before or after an alarm. ```sql CREATE TRANSACTION TABLE ch8_join_alarm ( alarm_id LONG PRIMARY KEY, sensor VARCHAR(32), occurred DATETIME ); CREATE TAG TABLE ch8_join_sensor ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ); INSERT INTO ch8_join_alarm VALUES ( 1, 'TEMP-01', TO_DATE('2026-01-01 10:00:05', 'YYYY-MM-DD HH24:MI:SS')); INSERT INTO ch8_join_sensor VALUES ( 'TEMP-01', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10); INSERT INTO ch8_join_sensor VALUES ( 'TEMP-01', TO_DATE('2026-01-01 10:00:10', 'YYYY-MM-DD HH24:MI:SS'), 20); INSERT INTO ch8_join_sensor VALUES ( 'TEMP-01', TO_DATE('2026-01-01 10:00:11', 'YYYY-MM-DD HH24:MI:SS'), 30); SELECT a.alarm_id, s.time, s.value FROM ch8_join_alarm a JOIN ch8_join_sensor s ON a.sensor = s.name WHERE s.time >= a.occurred - 5s AND s.time <= a.occurred + 5s ORDER BY a.alarm_id, s.time; ``` Alarm 1 joins to two rows with values 10 and 20. Both endpoints are included; value 30 is excluded. This query does not select only the nearest measurement or an exact timestamp match. If one value is required, separately define criteria such as latest preceding value or shortest distance, plus tie-breaking rules. ## Join Design Criteria Match join-key types and formats, restrict time ranges, then inspect the execution plan. Return only required columns. Compare access paths before adding functions or conversions to join keys. Do not assume join order or algorithms match another RDBMS. Permitted mixed joins do not mean other table types share the same transaction snapshot as TRANSACTION. Joining current LOOKUP descriptions also does not reproduce historical descriptions. ```sql DROP TABLE ch8_join_sensor; DROP TABLE ch8_join_alarm; DROP TABLE ch8_join_payment; DROP TABLE ch8_join_product; DROP TABLE ch8_join_order; ``` If result counts differ, first compare counts before the join and matching-row counts per key. These two checks clarify how the query needs to change. --- title: "8.12 TRANSACTION Backup, Restore, and Mount" url: https://docs.machbase.com/dbms/rdb-table-usage/backup-restore-mount/ language: en kind: page --- # 8.12 TRANSACTION Backup, Restore, and Mount A successful backup command does not complete recovery preparation. When production and backup tables have the same name, querying the wrong one can look like successful validation. This exercise changes production values after backup and verifies that the two results differ. ## Backup and Restore Support | Operation | TRANSACTION behavior | |---|---| | BACKUP DATABASE | Includes persistent TRANSACTION data in the target scope | | BACKUP TABLE | Backs up the specified table and required metadata | | Incremental backup | Includes a complete TRANSACTION storage snapshot at that backup point | | MOUNT DATABASE | Queries the backup read-only | | Offline instance restore | Stop the server and use machadmin -r | | Online logical database restore | Restore a supported logical backup with RESTORE DATABASE | Do not treat TRANSACTION data in incremental backups as a changed-row-only delta. Use supported backup commands instead of copying internal files. A backup containing TRANSACTION is also not a workaround for using those tables in Cluster. ## Backup and Mount Validation This exercise uses SYS in a Standard validation environment. Backup/mount privileges and server file permissions are required. Paths are server-side examples; use a new, nonexistent path for every run. Check parent directories and free space. Do not delete existing backups merely to reuse paths. ```sql CREATE TRANSACTION TABLE ch8_backup ( id LONG PRIMARY KEY, code VARCHAR(32) NOT NULL, amount DECIMAL(18,2) ); CREATE UNIQUE INDEX ch8_backup_code ON ch8_backup(code); INSERT INTO ch8_backup VALUES (1, 'A', 10.25); INSERT INTO ch8_backup VALUES (2, 'B', 20.50); BACKUP TABLE ch8_backup INTO DISK = '/backup/ch8_table_20260907_a'; UPDATE ch8_backup SET amount = 99.00 WHERE id = 1; MOUNT DATABASE '/backup/ch8_table_20260907_a' TO ch8_bak; SELECT id, code, amount FROM ch8_bak.SYS.ch8_backup ORDER BY id; SELECT id, code, amount FROM ch8_backup ORDER BY id; ``` The backup contains 10.25 and 20.50; production contains 99.00 and 20.50. Mounted queries use three-part names `mount_name.owner.table_name`. If another account owns the example, replace SYS with the actual owner. Running only `SELECT ... FROM ch8_backup` is a common mistake: it queries the current connection's production table, not the mounted backup. Also do not expect tables excluded from the backup to be present. A mount is read-only, not a recovery environment for UPDATE or DDL. Finish verification, close open cursors, and unmount. ```sql UMOUNT DATABASE ch8_bak; DROP TABLE ch8_backup; ``` This cleanup removes only the example table and mount. The backup directory remains; manage it separately under the retention policy. ## Restore Validation Checks In an isolated restore environment, verify owners, row counts, business keys, monetary totals, and representative JSON values. Check retained PRIMARY KEY/UNIQUE INDEX definitions, required privileges, and application COMMIT/ROLLBACK flows. Mounted read-only validation does not establish that restored writes work. Online RESTORE DATABASE follows logical-backup and target-database requirements. Distinguish it from a complete instance image containing multiple databases. Offline restore replacing an existing instance and REPLACE are outside this exercise. Check privileges, downtime, and target-replacement requirements in [Restore Syntax](/dbms/reference/sql/syntax/backup-restore-mount-syntax/) and [Operational Procedures](/dbms/operations-configuration-recovery/backup-restore-mount/) before executing them separately. For business consistency across tables, do not rely on backup-command success alone. Define write-pausing procedures, the business reference point, and cross-table validation criteria together. --- title: "8.13 TRANSACTION INSERT ON DUPLICATE KEY UPDATE" url: https://docs.machbase.com/dbms/rdb-table-usage/insert-on-duplicate-key-update/ language: en kind: page --- # 8.13 TRANSACTION INSERT ON DUPLICATE KEY UPDATE Inserting when absent and updating when present seems simple, but the definition of a duplicate determines which row changes. Retransmitting counter increments can apply one event twice. Check keys, update targets, and retry policy together. TRANSACTION `INSERT ... ON DUPLICATE KEY UPDATE` updates an existing row on a PRIMARY KEY or ordinary UNIQUE INDEX conflict. Exercises create their own objects. Keep error-checking SQL separate from normal flow and complete cleanup before rerunning. ## Supported Syntax TRANSACTION supports the `INSERT ... VALUES ...` UPSERT form. ```text INSERT INTO table_name VALUES (...) ON DUPLICATE KEY UPDATE; INSERT INTO table_name VALUES (...) ON DUPLICATE KEY UPDATE SET column_name = expression [, ...]; INSERT INTO table_name(column_name, ...) VALUES (...) ON DUPLICATE KEY UPDATE; INSERT INTO table_name(column_name, ...) VALUES (...) ON DUPLICATE KEY UPDATE SET column_name = expression [, ...]; ``` The following keys qualify for conflict detection. - TRANSACTION PRIMARY KEY - TRANSACTION UNIQUE INDEX - TRANSACTION composite UNIQUE INDEX ## Basic Behavior Without a duplicate, a new row is added as in ordinary INSERT. ```sql CREATE TRANSACTION TABLE ch8_up_device_state ( device_id INTEGER PRIMARY KEY, status VARCHAR(16), alarm_count INTEGER, updated_at DATETIME ); INSERT INTO ch8_up_device_state VALUES (1, 'NORMAL', 0, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS')) ON DUPLICATE KEY UPDATE SET status = 'NORMAL', updated_at = TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'); ``` A duplicate PRIMARY KEY updates the existing row. ```sql INSERT INTO ch8_up_device_state VALUES (1, 'ALARM', 1, TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS')) ON DUPLICATE KEY UPDATE SET status = 'ALARM', alarm_count = alarm_count + 1, updated_at = TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'); ``` The `SET` clause cannot change the PRIMARY KEY. Right-hand expressions are evaluated against the conflicting existing row. Thus `alarm_count = alarm_count + 1` adds 1 to the existing alarm_count, not the attempted insert value. ```sql SELECT device_id, status, alarm_count, updated_at FROM ch8_up_device_state WHERE device_id = 1; ``` The expected result has the following form. ```text DEVICE_ID STATUS ALARM_COUNT UPDATED_AT --------- ------ ----------- ----------------------------- 1 ALARM 1 2026-07-10 09:05:00 000:000:000 ``` The `SET` clause after `ON DUPLICATE KEY UPDATE` is optional. ```sql CREATE TRANSACTION TABLE ch8_up_asset_cache ( asset_id INTEGER PRIMARY KEY, asset_name VARCHAR(80), location VARCHAR(80), keep_value INTEGER ); INSERT INTO ch8_up_asset_cache VALUES (1, 'compressor-a', 'plant-1', 100); INSERT INTO ch8_up_asset_cache(asset_id, asset_name, location) VALUES (1, 'compressor-a-renamed', 'plant-2') ON DUPLICATE KEY UPDATE; ``` Without SET, only non-PRIMARY KEY columns included in the INSERT target list are applied to the existing row. Here, asset_name and location change; keep_value, omitted from the list, retains its previous value. ```sql SELECT asset_id, asset_name, location, keep_value FROM ch8_up_asset_cache ORDER BY asset_id; ``` The expected result has the following form. ```text ASSET_ID ASSET_NAME LOCATION KEEP_VALUE -------- -------------------- -------- ---------- 1 compressor-a-renamed plant-2 100 ``` For a table containing only a PRIMARY KEY column, a duplicate UPSERT without SET has no columns to update, so the row remains unchanged. ## UNIQUE INDEX Duplicate Handling UNIQUE INDEX conflicts also take the update path, not only PRIMARY KEY conflicts. ```sql CREATE TRANSACTION TABLE ch8_up_account_profile ( id INTEGER PRIMARY KEY, email VARCHAR(120), display_name VARCHAR(80), login_count INTEGER ); CREATE UNIQUE INDEX ch8_up_uidx_account_profile_email ON ch8_up_account_profile(email); INSERT INTO ch8_up_account_profile VALUES (1, 'ops@example.com', 'ops-user', 1); INSERT INTO ch8_up_account_profile VALUES (2, 'ops@example.com', 'ops-renamed', 1) ON DUPLICATE KEY UPDATE SET display_name = 'ops-renamed', login_count = login_count + 1; SELECT id, email, display_name, login_count FROM ch8_up_account_profile ORDER BY id; ``` The email UNIQUE INDEX conflicts, so the row with id=1 is updated. The attempted id=2 row is not inserted. A composite UNIQUE INDEX treats the entire matching key combination as a duplicate. ```sql CREATE TRANSACTION TABLE ch8_up_daily_device_summary ( id INTEGER PRIMARY KEY, device_id INTEGER, summary_day VARCHAR(10), event_count INTEGER, last_status VARCHAR(16) ); CREATE UNIQUE INDEX ch8_up_uidx_daily_device_summary ON ch8_up_daily_device_summary(device_id, summary_day); INSERT INTO ch8_up_daily_device_summary VALUES (1, 101, '2026-07-10', 3, 'NORMAL'); INSERT INTO ch8_up_daily_device_summary VALUES (2, 101, '2026-07-10', 1, 'ALARM') ON DUPLICATE KEY UPDATE SET event_count = event_count + 1, last_status = 'ALARM'; INSERT INTO ch8_up_daily_device_summary VALUES (3, 101, '2026-07-11', 1, 'NORMAL') ON DUPLICATE KEY UPDATE SET event_count = event_count + 1; ``` The first UPSERT updates `(device_id, summary_day) = (101, '2026-07-10')`. The second inserts a new row because the date differs. UNIQUE keys containing NULL are not treated as duplicates of each other. These two inserts create separate rows instead of overwriting each other. ```sql INSERT INTO ch8_up_daily_device_summary VALUES (4, NULL, '2026-07-10', 1, 'NORMAL') ON DUPLICATE KEY UPDATE; INSERT INTO ch8_up_daily_device_summary VALUES (5, NULL, '2026-07-10', 2, 'ALARM') ON DUPLICATE KEY UPDATE; SELECT id, device_id, summary_day, event_count FROM ch8_up_daily_device_summary ORDER BY id; ``` Result IDs are 1, 3, 4, and 5, with event_count values 4, 1, 1, and 2, respectively. Required business keys need NOT NULL on their component columns as well as a UNIQUE INDEX. ## Usage Examples TAG can continuously store time-ordered measurements while TRANSACTION maintains only the latest state per device. ```sql CREATE TRANSACTION TABLE ch8_up_latest_device_status ( device_name VARCHAR(80) PRIMARY KEY, last_value DOUBLE, last_state VARCHAR(16), event_count LONG, updated_at DATETIME ); INSERT INTO ch8_up_latest_device_status VALUES ('compressor-a', 72.5, 'NORMAL', 1, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS')) ON DUPLICATE KEY UPDATE SET last_value = 72.5, last_state = 'NORMAL', event_count = event_count + 1, updated_at = TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'); INSERT INTO ch8_up_latest_device_status VALUES ('compressor-a', 91.2, 'ALARM', 1, TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS')) ON DUPLICATE KEY UPDATE SET last_value = 91.2, last_state = 'ALARM', event_count = event_count + 1, updated_at = TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'); ``` Use this pattern when dashboards need fast access only to current state. When an external system repeatedly sends reference data with the same business key, UPSERT can use its UNIQUE INDEX. ```sql CREATE TRANSACTION TABLE ch8_up_customer_device ( id LONG PRIMARY KEY AUTO_INCREMENT, external_device_id VARCHAR(64), device_name VARCHAR(80), owner_name VARCHAR(80), enabled INTEGER ); CREATE UNIQUE INDEX ch8_up_uidx_customer_device_external_id ON ch8_up_customer_device(external_device_id); INSERT INTO ch8_up_customer_device(external_device_id, device_name, owner_name, enabled) VALUES ('ERP-DEV-10001', 'compressor-a', 'line-1', 1) ON DUPLICATE KEY UPDATE SET device_name = 'compressor-a', owner_name = 'line-1', enabled = 1; INSERT INTO ch8_up_customer_device(external_device_id, device_name, owner_name, enabled) VALUES ('ERP-DEV-10001', 'compressor-a-renamed', 'line-2', 1) ON DUPLICATE KEY UPDATE SET device_name = 'compressor-a-renamed', owner_name = 'line-2', enabled = 1; ``` The first INSERT creates a row; the second updates it through an external_device_id UNIQUE INDEX conflict. The internal id remains unchanged. Use UPSERT without SET to apply source column values directly to a current-state cache. ```sql CREATE TRANSACTION TABLE ch8_up_tag_alias_cache ( alias_name VARCHAR(80) PRIMARY KEY, tag_name VARCHAR(80), unit VARCHAR(16), description VARCHAR(160), manually_checked INTEGER ); INSERT INTO ch8_up_tag_alias_cache VALUES ('compressor-a-temp', 'comp_a.temp', 'celsius', 'main compressor temp', 1); INSERT INTO ch8_up_tag_alias_cache(alias_name, tag_name, unit, description) VALUES ('compressor-a-temp', 'comp_a.temperature', 'celsius', 'renamed tag') ON DUPLICATE KEY UPDATE; ``` This statement updates only tag_name, unit, and description. manually_checked is absent from the column list and retains its value. An aggregate table can accumulate occurrence counts by key. ```sql CREATE TRANSACTION TABLE ch8_up_alarm_counter ( alarm_code VARCHAR(32) PRIMARY KEY, first_seen DATETIME, last_seen DATETIME, hit_count LONG ); INSERT INTO ch8_up_alarm_counter VALUES ( 'OVER_TEMP', TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1 ) ON DUPLICATE KEY UPDATE SET last_seen = TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), hit_count = hit_count + 1; INSERT INTO ch8_up_alarm_counter VALUES ( 'OVER_TEMP', TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'), TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'), 1 ) ON DUPLICATE KEY UPDATE SET last_seen = TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'), hit_count = hit_count + 1; ``` `hit_count = hit_count + 1` is evaluated against the existing row, making it suitable for cumulative counters. JSON columns can also be update targets. ```sql CREATE TRANSACTION TABLE ch8_up_device_json_state ( device_id INTEGER PRIMARY KEY, state JSON, updated_at DATETIME ); INSERT INTO ch8_up_device_json_state VALUES ( 1, '{"status":"NORMAL","score":10}', TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS') ) ON DUPLICATE KEY UPDATE SET state = '{"status":"NORMAL","score":10}', updated_at = TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'); INSERT INTO ch8_up_device_json_state VALUES ( 1, '{"status":"ALARM","score":90}', TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS') ) ON DUPLICATE KEY UPDATE SET state = '{"status":"ALARM","score":90}', updated_at = TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'); SELECT JSON_EXTRACT_STRING(state, '$.status') AS status, JSON_EXTRACT_INTEGER(state, '$.score') AS score FROM ch8_up_device_json_state WHERE device_id = 1; ``` Limitation: JSON path UNIQUE INDEX is excluded from conflict-key candidates. Its conflicts produce uniqueness errors instead of taking the UPSERT update path. ## Transactions and Privileges TRANSACTION UPSERT is committed or rolled back inside a transaction like ordinary INSERT/UPDATE. ```sql CREATE TRANSACTION TABLE ch8_up_tx_device_state ( id INTEGER PRIMARY KEY, status VARCHAR(16), count_value INTEGER ); INSERT INTO ch8_up_tx_device_state VALUES (1, 'NORMAL', 10); BEGIN; INSERT INTO ch8_up_tx_device_state VALUES (2, 'NORMAL', 1) ON DUPLICATE KEY UPDATE SET count_value = count_value + 1; INSERT INTO ch8_up_tx_device_state VALUES (1, 'ALARM', 1) ON DUPLICATE KEY UPDATE SET status = 'ALARM', count_value = count_value + 1; ROLLBACK; SELECT id, status, count_value FROM ch8_up_tx_device_state ORDER BY id; ``` Both insert and update paths are rolled back in this example. If a duplicate-update statement fails with an ordinary constraint violation, earlier successful changes can remain in the explicit transaction. After checking the error, the application must decide whether to continue or cancel business changes with ROLLBACK. TRANSACTION UPSERT requires both INSERT and UPDATE privileges. Grant both even when execution takes the insert path, because the statement includes an update path. The following shows only the privilege syntax. Apply it as a separate administrative operation using the actual owner, table, and existing application account. ```text GRANT INSERT ON owner.table_name TO app_user; GRANT UPDATE ON owner.table_name TO app_user; ``` SELECT privilege is not required to execute TRANSACTION UPSERT itself. It is required separately if the application executes SELECT to verify results. ## Supported Types and Constraints Columns updated in SET follow the same public type support as ordinary TRANSACTION UPDATE. | Category | Types | | --- | --- | | Integer | `SHORT`, `INT16`, `USHORT`, `UINT16`, `INT`, `INTEGER`, `INT32`, `UINTEGER`, `UINT32`, `LONG`, `INT64`, `ULONG`, `UINT64` | | Floating point | `FLOAT`, `DOUBLE` | | Fixed point | `DECIMAL`, `NUMERIC`, `DEC`, `FIXED`, `NUMBER` | | String/LOB | `VARCHAR`, `TEXT`, `CLOB`, `BINARY`, `BLOB` | | Other | `DATETIME`, `IPV4`, `IPV6`, `JSON` | This table lists scalar types used by TRANSACTION. For numeric ARRAY support, see the [Data Type Dictionary](/dbms/reference/sql/types/). Conflict keys and index types follow TRANSACTION PRIMARY KEY and UNIQUE INDEX type policies. UPSERT does not expand supported key types. The following syntax is unsupported. ```text -- Illustrative examples of unsupported syntax. -- Combining INSERT SELECT with ON DUPLICATE KEY UPDATE is unsupported. INSERT INTO ch8_up_device_state(device_id, status, alarm_count, updated_at) SELECT device_id, status, alarm_count, updated_at FROM staging_device_state ON DUPLICATE KEY UPDATE SET status = 'UPDATED'; -- The MySQL VALUES(col) function is unsupported. INSERT INTO ch8_up_device_state VALUES (1, 'ALARM', 1, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS')) ON DUPLICATE KEY UPDATE SET status = VALUES(status); -- The EXCLUDED alias is unsupported. INSERT INTO ch8_up_device_state VALUES (1, 'ALARM', 1, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS')) ON DUPLICATE KEY UPDATE SET status = EXCLUDED.status; -- Conflict-target syntax is unsupported. INSERT INTO ch8_up_device_state VALUES (1, 'ALARM', 1, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS')) ON CONFLICT (device_id) DO UPDATE SET status = 'ALARM'; ``` Target-table restrictions are as follows. - This page covers only TRANSACTION PRIMARY KEY/UNIQUE conflict behavior. The same SQL form also supports PRIMARY KEY conflicts in LOOKUP and VOLATILE. Use the [DML Dictionary](/dbms/reference/sql/syntax/dml-syntax/#on-duplicate-key-update) as the authoritative common syntax reference. - LOG and TAG DATA rows are unsupported. For TAG METADATA tag-name conflicts, see the [DML Dictionary](/dbms/reference/sql/syntax/dml-syntax/#on-duplicate-key-update). - Even a TRANSACTION table requires a PRIMARY KEY or UNIQUE INDEX for UPSERT. - JSON path UNIQUE INDEX is not used as a conflict key. ## Conflicts and Error Handling If multiple UNIQUE indexes identify the same existing row, it is updated once. If they conflict with different existing rows, the statement fails because it cannot determine which row to update. The following sample conflicts with two business keys on different rows. ```sql CREATE TRANSACTION TABLE ch8_up_user_contact ( id INTEGER PRIMARY KEY, email VARCHAR(120), phone VARCHAR(40), note VARCHAR(80) ); CREATE UNIQUE INDEX ch8_up_uidx_user_contact_email ON ch8_up_user_contact(email); CREATE UNIQUE INDEX ch8_up_uidx_user_contact_phone ON ch8_up_user_contact(phone); INSERT INTO ch8_up_user_contact VALUES (1, 'a@example.com', '010-0000-0001', 'user-a'); INSERT INTO ch8_up_user_contact VALUES (2, 'b@example.com', '010-0000-0002', 'user-b'); ``` Only the following INSERT intentionally fails in this optional exercise. ```sql -- email conflicts with id=1; phone conflicts with id=2. -- Different conflicting rows cause failure instead of selecting an update path. INSERT INTO ch8_up_user_contact VALUES (3, 'a@example.com', '010-0000-0002', 'ambiguous') ON DUPLICATE KEY UPDATE SET note = 'updated'; ``` If SET results violate another UNIQUE constraint or NOT NULL, the statement fails and preserves the existing row. ## Retransmission and Current State Counter-increment UPSERT is not automatic deduplication. Repeating the same event increments the counter again. If a COMMIT response is lost, first verify the result using business keys and event-processing records. Simple overwrites maintain the latest state only when ingestion order matches event order. Define source-time comparison and collection policies so late historical events do not overwrite newer values. For changes spanning tables, also check [Commit Scope During Failures](../transaction/). ## Operational Recommendations - Define PRIMARY KEY or UNIQUE INDEX first when the business key is clear. - Use `SET count_col = count_col + 1` for cumulative counters. - Use UPSERT without SET to apply source row values directly. Columns omitted from the list retain their values. - With multiple UNIQUE indexes, handle inputs that could conflict with different existing rows before execution. - When migrating MySQL-compatible SQL, replace VALUES(col), EXCLUDED, and ON CONFLICT with supported Machbase syntax. - Avoid JSON path UNIQUE INDEX as an UPSERT key. If needed, extract the key into an ordinary column and create a UNIQUE INDEX there. ## Verify Results and Clean Up After completing the successful exercise, recheck representative values and counts. The expectations below assume every normal statement ran once, excluding intentional errors. ```sql SELECT id, email, display_name, login_count FROM ch8_up_account_profile ORDER BY id; SELECT device_name, last_state, event_count FROM ch8_up_latest_device_status; SELECT external_device_id, device_name, owner_name FROM ch8_up_customer_device; SELECT alias_name, tag_name, manually_checked FROM ch8_up_tag_alias_cache; SELECT alarm_code, hit_count FROM ch8_up_alarm_counter; SELECT id, status, count_value FROM ch8_up_tx_device_state ORDER BY id; SELECT id, note FROM ch8_up_user_contact ORDER BY id; ``` | Sample | Expected result | |---|---| | account_profile | id=1 retained, display_name=ops-renamed, login_count=2 | | latest_device_status | ALARM, event_count=2 | | customer_device | One external-key row; name compressor-a-renamed, owner line-2 | | tag_alias_cache | tag_name=comp_a.temperature; manually_checked=1 retained | | alarm_counter | OVER_TEMP hit_count=2 | | tx_device_state | After ROLLBACK, only existing id=1, NORMAL, count_value=10 | | user_contact | user-a and user-b at id=1 and id=2 remain unchanged | ```sql DROP TABLE ch8_up_user_contact; DROP TABLE ch8_up_tx_device_state; DROP TABLE ch8_up_device_json_state; DROP TABLE ch8_up_alarm_counter; DROP TABLE ch8_up_tag_alias_cache; DROP TABLE ch8_up_customer_device; DROP TABLE ch8_up_latest_device_status; DROP TABLE ch8_up_daily_device_summary; DROP TABLE ch8_up_account_profile; DROP TABLE ch8_up_asset_cache; DROP TABLE ch8_up_device_state; ``` DROP targets only this page's example objects. For complex keys, compare attempted input with existing conflicting rows side by side. Clarifying which row was intended for update helps identify the cause. --- title: "9. LOOKUP Table Usage" url: https://docs.machbase.com/dbms/lookup-table-usage/ language: en kind: section --- # 9. LOOKUP Table Usage LOOKUP tables load persistently stored reference and master data into memory at server startup, providing fast access by PRIMARY KEY. This chapter covers the memory-resident architecture, JSON and SEQUENCE, JOIN, and DML with general predicates. ## Chapter Contents | Section | Topics | |----|------| | [Overview and Use Criteria](./overview-use-criteria/) | Purpose and selection criteria | | [Table Structure and Schema](./table-structure-schema/) | Columns, primary keys, and schema design | | [Create, Alter, and Drop](./create-alter-drop/) | CREATE, ALTER, and DROP DDL | | [Data Ingestion and Modification](./data-input-mutation/) | INSERT, Append, reload, and deletion | | [Queries and Analysis](./query-analysis/) | SELECT, JOIN, and predicate queries | | [Indexes and Performance](./index-performance/) | Red-black indexes, secondary indexes, and tuning | | [Operations and Data Lifecycle](./operations-lifecycle/) | Backup, recovery, and persistence | | [Constraints, Errors, and Troubleshooting](./constraints-errors-troubleshooting/) | Limitations, error causes, and remedies | | [Usage Patterns and Scenarios](./patterns-scenarios/) | Code tables, reference data, and thresholds | | [PRIMARY KEY Policy](./primary-key-policy/) | Natural versus surrogate keys and key immutability | | [SEQUENCE Columns](./sequence-column/) | Automatic numbering and NEXTVAL | | [JSON Columns and Queries](./json-column-query/) | Supported JSON features, path predicates, and primary key restrictions | | [UPDATE/DELETE with General Predicates](./predicate-update-delete/) | Modifications using non-PK, range, string, date, and JSON path predicates | --- title: "9.1 Overview and Use Criteria" url: https://docs.machbase.com/dbms/lookup-table-usage/overview-use-criteria/ language: en kind: page --- # 9.1 Overview and Use Criteria LOOKUP tables store relatively small, frequently referenced datasets such as code lists, device master data, thresholds, and settings. Data is persistent, but all rows used by SQL queries reside in memory. This makes them suitable for repeated key-based lookups and updates. ## LOOKUP Table Characteristics Create a LOOKUP table with `CREATE LOOKUP TABLE`. A `PRIMARY KEY` is required. ```sql CREATE LOOKUP TABLE ch9_overview ( sensor_id VARCHAR(64) PRIMARY KEY, site VARCHAR(32), unit VARCHAR(16), status VARCHAR(16) ); ``` LOOKUP tables have the following characteristics. | Item | Description | |------|------| | Main uses | Code tables, device master data, thresholds, and reference data | | Requirement | `PRIMARY KEY` required | | Storage | Persistent storage; all rows loaded into memory at server startup | | Query patterns | Optimized for primary key lookups; supports general predicates and JOIN with other tables | | Modification patterns | INSERT, UPDATE, DELETE | | Additional features | SEQUENCE columns and Append duplicate-key policy | ## Use Criteria Use a LOOKUP table when: - The dataset is relatively small and frequently referenced as a whole. - All rows and required secondary indexes fit in server memory. - You manage reference information such as codes, names, locations, units, or states. - Descriptive information must be joined to source data in TAG or LOG tables. - Reference values, such as thresholds or settings, can change during operation. - A `PRIMARY KEY` clearly identifies each row. For a JOIN that adds descriptions such as location and unit to TAG or LOG data, see [Queries and Analysis](/dbms/lookup-table-usage/query-analysis/). ## When to Consider Other Tables Consider other table types for the following requirements. | Requirement | Recommended table | |----------|-------------| | Large volumes of time-series measurements | TAG | | Append-oriented source events | LOG | | Large relational datasets that cannot all fit in memory | TRANSACTION | | Transactions and relational business processing | TRANSACTION | | Current-state cache kept only in server memory | VOLATILE | LOOKUP is suitable for reference data. Persistence does not make it a disk-oriented large-volume table. Store source data in LOG or TAG, and use LOOKUP for memory-resident reference data queried repeatedly. Use TRANSACTION when relational data exceeds available memory or requires complex business processing. Clean up the example table as follows. ```sql DROP TABLE ch9_overview; ``` ## Design Sequence Make the following decisions when designing a LOOKUP table. 1. Choose the `PRIMARY KEY` that identifies each row. 2. Choose a natural key or a surrogate key based on SEQUENCE or AUTO_INCREMENT. 3. Add indexes to columns frequently queried or joined. 4. Validate memory requirements for expected row sizes, row counts, and secondary indexes. 5. Distinguish columns updated during operation from immutable columns. 6. Prepare a query that checks the target scope before bulk changes. For schema and key design, see [Table Structure and Schema](/dbms/lookup-table-usage/table-structure-schema/) and [PRIMARY KEY Policy](/dbms/lookup-table-usage/primary-key-policy/). --- title: "9.2 Table Structure and Schema" url: https://docs.machbase.com/dbms/lookup-table-usage/table-structure-schema/ language: en kind: page --- # 9.2 Table Structure and Schema This section covers LOOKUP table structure and schema design. ## LOOKUP Table Design LOOKUP tables store code lists and reference data. A PRIMARY KEY identifies each row. They support UPDATE/DELETE by primary key or general predicates and store data persistently on disk. ### Persistent Storage and In-Memory Queries LOOKUP uses two layers to provide persistence and in-memory query performance. 1. Modified rows are written to persistent storage so they survive restarts. 2. At startup, the server reads all LOOKUP rows from persistent storage and reconstructs in-memory rows containing all column values. 3. Each in-memory row is registered in the mandatory PRIMARY KEY red-black index. 4. SQL queries use the reconstructed in-memory rows and indexes. Conceptually, each row can be viewed as a key-value entry. ``` PRIMARY KEY Other column values sensor_id = 'TEMP-01' ───────► { site, unit, status, ... } key value ``` This explains why LOOKUP is particularly suitable for PRIMARY KEY lookups while also providing a SQL table interface, general predicate queries, JOIN, and secondary indexes. Persistent storage does not mean that only requested rows are fetched from disk during queries. All rows and red-black secondary indexes consume memory. Consider variable-length columns, JSON values, and secondary index sizes as well as row counts when designing the schema. - **[Use Cases](/dbms/lookup-table-usage/patterns-scenarios/#use-cases-lookup)** - **[PRIMARY KEY Design](/dbms/lookup-table-usage/primary-key-policy/#design-primary-key)** - **[Column and Sequence Design](/dbms/lookup-table-usage/sequence-column/#design-column-lookup-sequence)** - **[JSON Columns and Queries](/dbms/lookup-table-usage/json-column-query/#condition-query-lookup-json)** - **[Reference Design Patterns](/dbms/lookup-table-usage/patterns-scenarios/#patterns-reference-design)** - **[Index Strategy](/dbms/lookup-table-usage/index-performance/#index-strategy-lookup)** - **[PRIMARY KEY Policy](/dbms/lookup-table-usage/primary-key-policy/#policy-lookup-primary-key)** - **[UPDATE/DELETE with General Predicates](/dbms/lookup-table-usage/predicate-update-delete/)** - **[Backup and Recovery Support](/dbms/lookup-table-usage/operations-lifecycle/#recovery-support-scope-backup-lookup)** - **[Limitations and Considerations](/dbms/lookup-table-usage/constraints-errors-troubleshooting/#limitations-lookup)** --- title: "9.3 Create, Alter, and Drop" url: https://docs.machbase.com/dbms/lookup-table-usage/create-alter-drop/ language: en kind: page --- # 9.3 Create, Alter, and Drop This section explains how to create, alter, and drop LOOKUP tables. ## Creating and Managing LOOKUP Tables Create a reference table as follows. A LOOKUP table must specify a `PRIMARY KEY`. ## Creating a LOOKUP Table ```sql CREATE LOOKUP TABLE ch9_ddl (id INTEGER PRIMARY KEY, name VARCHAR(20)); ``` Use meaningful column names for reference data used in production. ```sql CREATE LOOKUP TABLE ch9_ddl_equip ( equip_id LONG PRIMARY KEY, equip_name VARCHAR(128), location VARCHAR(64), status VARCHAR(16), updated_at DATETIME ); ``` The `PRIMARY KEY` uniquely identifies rows and provides a basis for UPDATE, DELETE, and JOIN. If the business key combines several columns, encode that combination in a separate key column or use a SEQUENCE-based surrogate key. ```sql CREATE LOOKUP TABLE ch9_ddl_price ( price_key VARCHAR(64) PRIMARY KEY, product_id VARCHAR(32), region VARCHAR(16), price DOUBLE ); ``` ## AUTO_INCREMENT PRIMARY KEY To have the server generate a numeric PRIMARY KEY, specify `AUTO_INCREMENT` on a single `LONG` or `INT64` column. ```sql CREATE LOOKUP TABLE ch9_ddl_registry ( equip_id LONG PRIMARY KEY AUTO_INCREMENT, equip_name VARCHAR(128), location VARCHAR(64) ); INSERT INTO ch9_ddl_registry(equip_name, location) VALUES ('compressor-01', 'SEOUL-A'); ``` The server generates a value when the primary key column is omitted or set to NULL. A single `INSERT ... VALUES` can also specify a primary key in `0..INT64_MAX`. If the specified value is at least the next automatic value, the next value advances to `specified value + 1`. Smaller values do not move it backward. Data and the next automatic value survive a normal restart. LOOKUP tables with AUTO_INCREMENT do not support `INSERT ... SELECT` or `ON DUPLICATE KEY UPDATE`. For obtaining inserted IDs through an SDK, see [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/). ## Using a SEQUENCE Column For automatic numbering, use a `LONG PROPERTY(SEQUENCE=1)` column. Obtain the next value with `NEXTVAL()` during insertion. ```sql CREATE LOOKUP TABLE ch9_ddl_alarm ( seq LONG PROPERTY(SEQUENCE=1) PRIMARY KEY, sensor_id VARCHAR(64), alarm_type VARCHAR(32), occurred_at DATETIME, message VARCHAR(256) ); INSERT INTO ch9_ddl_alarm VALUES (NEXTVAL(seq), 'TEMP-01', 'HIGH', NOW, '온도 초과'); ``` For detailed policies, see [SEQUENCE Columns](/dbms/lookup-table-usage/sequence-column/). `PROPERTY(SEQUENCE)` and `AUTO_INCREMENT` are separate features and must not be specified together on one column. ## Adding and Dropping Columns In Standard Edition, you can add and drop fixed-length numeric ARRAY columns in LOOKUP tables. ```sql ALTER TABLE ch9_ddl_equip ADD COLUMN (limits DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]); ALTER TABLE ch9_ddl_equip DROP COLUMN (limits); ``` Without DEFAULT, the new ARRAY column is a whole-array NULL in existing rows. With DEFAULT, existing rows also receive that value. The ARRAY DEFAULT must contain exactly the declared number of elements. ARRAY columns cannot be PRIMARY KEY or index keys. For supported types and limitations, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/). ## Adding Indexes Add indexes to columns frequently queried or used in JOIN predicates. ```sql CREATE INDEX ch9_ddl_loc_idx ON ch9_ddl_equip(location); CREATE INDEX ch9_ddl_status_idx ON ch9_ddl_equip(status); ``` A default index is created on the PRIMARY KEY column; do not add a duplicate index on it. More indexes increase insertion and update costs. Add them only for columns with clear query predicates. ## Deleting Data and Dropping Tables Use `DELETE` to remove rows. A primary key predicate is the clearest approach for a single-row deletion. ```sql DELETE FROM ch9_ddl_equip WHERE equip_id = 1001; ``` Bulk deletion can use general predicates. For production data, first check the target count with the same predicate. ```sql SELECT COUNT(*) FROM ch9_ddl_equip WHERE status = 'RETIRED'; DELETE FROM ch9_ddl_equip WHERE status = 'RETIRED'; ``` Use `DROP TABLE` to remove the table itself. ```sql DROP TABLE ch9_ddl_alarm; DROP TABLE ch9_ddl_registry; DROP TABLE ch9_ddl_price; DROP TABLE ch9_ddl_equip; DROP TABLE ch9_ddl; ``` `DROP TABLE` removes both the definition and data. Back up or export data first when needed. ## Considerations - A `PRIMARY KEY` is required for LOOKUP tables. - Only one column can be designated as the `PRIMARY KEY`. - To change a `PRIMARY KEY` value, delete the existing row and insert it with the new key. - Consider TRANSACTION tables when reference data grows or query/update patterns become complex. --- title: "9.4 Data Input and Mutation" url: https://docs.machbase.com/dbms/lookup-table-usage/data-input-mutation/ language: en kind: page --- # 9.4 Data Input and Mutation This section uses one runnable example to explain LOOKUP data insertion, updates, and deletion. ## Prepare the Example Table Run the following examples in order through the final cleanup statements. ```sql CREATE LOOKUP TABLE ch9_mutation ( code VARCHAR(32) PRIMARY KEY, label VARCHAR(64), status VARCHAR(16), updated_at DATETIME ); INSERT INTO ch9_mutation VALUES ('TEMP', 'Temperature', 'ACTIVE', NOW); INSERT INTO ch9_mutation VALUES ('PRESS', 'Pressure', 'ACTIVE', NOW); ``` If a sequence key is needed, see [SEQUENCE](/dbms/lookup-table-usage/sequence-column/). ## UPDATE Use a PRIMARY KEY predicate for single-row changes. ```sql UPDATE ch9_mutation SET status = 'INACTIVE', updated_at = NOW WHERE code = 'TEMP'; ``` Before changing multiple rows, query the targets with the same `WHERE` clause. For a single-row change, a `PRIMARY KEY` predicate is recommended because it identifies the target clearly and can use an index. The PRIMARY KEY column itself cannot be updated. To change a key, delete the row and insert it again with the new key. These statements cannot be grouped into a TRANSACTION table transaction, so also design for intermediate failures and changes to referencing data. ## Duplicate-Key Handling Use `ON DUPLICATE KEY UPDATE` when a duplicate key in SQL INSERT should update an existing row. ```sql INSERT INTO ch9_mutation VALUES ('TEMP', 'Temperature sensor', 'ACTIVE', NOW) ON DUPLICATE KEY UPDATE SET label = 'Temperature sensor', status = 'ACTIVE', updated_at = NOW; ``` When Append encounters a duplicate primary key, it can update the row according to `LOOKUP_APPEND_UPDATE_ON_DUPKEY`. This setting controls duplicate-key handling for the LOOKUP Append path. Check its current value before using it in production. ```sql SELECT name, value FROM v$property WHERE name = 'LOOKUP_APPEND_UPDATE_ON_DUPKEY'; ``` ## TABLE_REFRESH Run `TABLE_REFRESH` when persistently stored LOOKUP content must be reloaded into the running in-memory table. ```sql EXEC TABLE_REFRESH(ch9_mutation); ``` Do not run it after every ordinary SQL DML operation. Its target is a LOOKUP table in the current database, and it cannot run in a READ ONLY database. For name resolution, permissions, and errors, see the [EXEC Procedure Reference](/dbms/reference/sql/syntax/execute-procedure-syntax/#table-refresh). For cluster procedures, see [Operations and Lifecycle](/dbms/lookup-table-usage/operations-lifecycle/). ## Deleting LOOKUP Data Use a PRIMARY KEY predicate for single-row deletion. ```sql DELETE FROM ch9_mutation WHERE code = 'PRESS'; ``` A general predicate deletes all matching rows. Omit WHERE to delete every row. ```sql DELETE FROM ch9_mutation; DROP TABLE ch9_mutation; ``` ## Modification Checklist - Use PRIMARY KEY predicates for single-row changes. - Before bulk changes with general predicates, query the target scope using the same predicates. - Check backups or reload sources before deleting all rows. - Change PRIMARY KEY values with DELETE followed by INSERT. - Check `LOOKUP_APPEND_UPDATE_ON_DUPKEY` for Append duplicate-key handling. - Use `EXEC TABLE_REFRESH(table_name)` only when persistent LOOKUP content must be reloaded into runtime memory. --- title: "9.5 Query and Analysis" url: https://docs.machbase.com/dbms/lookup-table-usage/query-analysis/ language: en kind: page --- # 9.5 Query and Analysis This section provides runnable examples of key lookups, general predicate queries, and joins with TAG data. ## Prepare Example Data Prepare the following LOOKUP and TAG tables. ```sql CREATE LOOKUP TABLE ch9_query_master ( sensor_id VARCHAR(32) PRIMARY KEY, site VARCHAR(32), unit VARCHAR(16), status VARCHAR(16) ); INSERT INTO ch9_query_master VALUES ('TEMP-01', 'SEOUL', 'C', 'ACTIVE'); INSERT INTO ch9_query_master VALUES ('TEMP-02', 'BUSAN', 'C', 'INACTIVE'); CREATE TAG TABLE ch9_query_data ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ); INSERT INTO ch9_query_data VALUES ('TEMP-01', TO_DATE('2026-01-01 00:00:00'), 23.5); INSERT INTO ch9_query_data VALUES ('TEMP-02', TO_DATE('2026-01-01 00:00:00'), 19.0); ``` ## PRIMARY KEY Lookups Use a `PRIMARY KEY` predicate for single-row queries. ```sql SELECT sensor_id, site, unit, status FROM ch9_query_master WHERE sensor_id = 'TEMP-01'; ``` ## General Predicate Queries LOOKUP tables also support queries on ordinary columns. Add indexes to frequently used predicate columns. ```sql SELECT sensor_id, site, unit FROM ch9_query_master WHERE site = 'SEOUL' AND status = 'ACTIVE'; ``` Indexes can be added to frequently used ordinary predicate columns. For design and creation, see [Indexes](/dbms/lookup-table-usage/index-performance/). ## Joining TAG and LOG Tables LOOKUP tables commonly add descriptive information to source data in TAG or LOG tables. ```sql SELECT d.name, m.site, m.unit, d.time, d.value FROM ch9_query_data d JOIN ch9_query_master m ON d.name = m.sensor_id WHERE m.status = 'ACTIVE'; ``` ## Analysis Patterns LOOKUP tables provide analysis criteria rather than storing source data. They suit the following patterns. | Pattern | Description | |------|------| | Code translation | Convert status codes, alarm codes, and device types to labels | | Reference-value comparison | Join sensor values with thresholds to detect exceedances | | Grouping criteria | Provide aggregation keys such as location, department, or line | | Current settings | Apply settings that change during operation at query time | Similarly, join a threshold LOOKUP table with source TAG data to detect values above a threshold. Restrict large TAG or LOG time ranges before joining. ```sql DROP TABLE ch9_query_data CASCADE; DROP TABLE ch9_query_master; ``` ## Query Performance Criteria - Use `PRIMARY KEY` or indexed columns for single-row lookups and join keys. - Consider secondary indexes for ordinary columns frequently used in predicates. - Narrow the source time range before joining large source datasets. - Store reference data in LOOKUP and long-term source data in TAG or LOG. --- title: "9.6 Indexes and Performance" url: https://docs.machbase.com/dbms/lookup-table-usage/index-performance/ language: en kind: page --- # 9.6 Indexes and Performance This section covers LOOKUP index structure and performance tuning. ## Tuning LOOKUP Indexes A red-black tree index is created automatically for the LOOKUP PRIMARY KEY. All rows and indexes reside in memory during SQL queries. You can add red-black secondary indexes to non-PK columns when needed. ### LOOKUP Table Indexes #### Automatic Primary Key Red-Black Tree Index Creating a LOOKUP table automatically creates a red-black tree index on its PRIMARY KEY. Each index entry points to the in-memory row containing all column values for that key. Although the table is persistent, the query execution path is memory-based and optimized for repeated key lookups on small reference datasets. ```sql CREATE LOOKUP TABLE ch9_index_device ( device_id VARCHAR(64) PRIMARY KEY, -- Red-black tree created automatically device_name VARCHAR(128), location VARCHAR(256), category VARCHAR(32) ); INSERT INTO ch9_index_device VALUES ('DEV-01', 'Boiler', 'Seoul', 'temperature'); INSERT INTO ch9_index_device VALUES ('DEV-02', 'Pump', 'Busan', 'pressure'); ``` ```sql -- Primary key lookup using the red-black tree index SELECT device_id, device_name, location FROM ch9_index_device WHERE device_id = 'DEV-01'; ``` The query returns one row. The LOOKUP side also uses the primary key when joined to event logs. ```sql CREATE LOG TABLE ch9_index_event (device_id VARCHAR(64), level SHORT); INSERT INTO ch9_index_event VALUES ('DEV-01', 3); INSERT INTO ch9_index_event VALUES ('DEV-02', 1); EXEC TABLE_FLUSH(ch9_index_event); SELECT e.device_id, e.level, d.location FROM ch9_index_event e, ch9_index_device d WHERE e.device_id = d.device_id ORDER BY e.device_id; ``` The query returns two rows. Adding a time range on the LOG side further reduces source rows read. #### Secondary Indexes on Non-PK Columns Red-black secondary indexes can also be created on non-PK columns. Filtering on a column without a secondary index sequentially scans the entire table. ```sql -- Add a secondary index to a frequently filtered non-PK column CREATE INDEX ch9_index_device_location ON ch9_index_device(location); SELECT device_id FROM ch9_index_device WHERE location = 'Seoul'; -- An unindexed column may require a full scan SELECT device_id FROM ch9_index_device WHERE category = 'temperature'; ``` Both queries return DEV-01. The results match but access paths differ, so compare them with execution plans on production-scale data. Secondary indexes speed up queries but increase update cost and memory usage. Create them only on frequently used predicate columns. #### LOOKUP Usage Guidelines Lookup cost for primary key and red-black secondary indexes grows with tree size. Unindexed predicates scan all memory-resident rows. Do not define capacity limits from row count alone. Measure actual row sizes, variable-length values, index counts, and query/update ratios under the same workload. Also check startup time, because startup reads all persistent data to build memory rows and indexes. | Usage pattern | Suitability | |----------|-------| | Retrieve device information by primary key | Suitable | | Search lists by non-PK columns | Suitable with secondary indexes | | Small reference-code tables | Suitable | | Large reference datasets that do not all fit in server memory | Consider TRANSACTION | | Reference data requiring relational transactions | Consider TRANSACTION | ### Distinction from VOLATILE VOLATILE is a separate table type whose data is lost on restart. For its index design, see [VOLATILE Indexes and Performance](/dbms/volatile-table-usage/index-performance/). ### Large Reference Datasets Consider alternatives in the following scenario because of LOOKUP table size and secondary-index update costs. **Scenario**: Device reference data must be filtered by multiple columns while retaining change history. ```sql -- Alternative: a LOG table with LSM/BITMAP indexes CREATE LOG TABLE ch9_index_device_hist ( device_id VARCHAR(64), device_name VARCHAR(128), location VARCHAR(256), category VARCHAR(32), updated_at DATETIME ); -- Indexes can be created on non-PK columns CREATE INDEX ch9_index_hist_location ON ch9_index_device_hist (location); CREATE INDEX ch9_index_hist_category ON ch9_index_device_hist (category) INDEX_TYPE BITMAP; ``` LOG tables are append-only, so adapt the design to the reference-data update pattern. Clean up the example objects as follows. ```sql DROP TABLE ch9_index_device_hist; DROP INDEX ch9_index_device_location; DROP TABLE ch9_index_event; DROP TABLE ch9_index_device; ``` ### Key Points - The PRIMARY KEY index is created automatically. - Create secondary indexes only for repeated non-PK predicates. - Measure memory for rows, variable-length values, and indexes, together with startup time and update load. --- title: "9.7 Operations and Data Lifecycle" url: https://docs.machbase.com/dbms/lookup-table-usage/operations-lifecycle/ language: en kind: page --- # 9.7 Operations and Data Lifecycle This section covers LOOKUP backup, recovery, and data persistence. LOOKUP tables persist reference data on disk. Because values can change during operation, manage change procedures, backups, recovery, and query visibility together. Distinguish persistent storage from the data location used by queries. At startup, the server restores all persisted LOOKUP rows into in-memory tables and builds PRIMARY KEY and secondary indexes. SQL queries use this memory structure during service. ## Data Lifecycle Manage LOOKUP data through creation, insertion, updates, reference, backup, and recovery. ``` Create table └── Insert reference data └── Join or reference in TAG/LOG/TRANSACTION queries └── UPDATE/DELETE during operation └── Backup / Recovery / Mount ``` Reference data is smaller than source events but directly affects how query results are interpreted. Establish procedures to record before/after values and the time changes take effect. ## Reference-Data Change Procedure Use the following sequence to change LOOKUP data during operation. 1. Query the rows to change. 2. Check the impact scope. 3. Execute UPDATE or DELETE. 4. Execute `EXEC TABLE_REFRESH(table_name)` if needed. 5. Verify visibility with representative queries. `TABLE_REFRESH` is not required after every ordinary SQL DML operation. Use it when persistent LOOKUP content must be reloaded into the runtime memory table. For name resolution, permissions, and errors, see the [EXEC Procedure Reference](/dbms/reference/sql/syntax/execute-procedure-syntax/#table-refresh). The following exercise follows this procedure. ```sql CREATE LOOKUP TABLE ch9_ops_sensor ( sensor_id VARCHAR(32) PRIMARY KEY, site VARCHAR(16), status VARCHAR(16), updated_at DATETIME ); INSERT INTO ch9_ops_sensor VALUES ('TEMP-01', 'SEOUL', 'READY', NOW); INSERT INTO ch9_ops_sensor VALUES ('TEMP-02', 'SEOUL', 'READY', NOW); INSERT INTO ch9_ops_sensor VALUES ('TEMP-03', 'BUSAN', 'READY', NOW); -- Query the rows to change. SELECT sensor_id, site, status FROM ch9_ops_sensor WHERE sensor_id = 'TEMP-01'; -- Apply the change. UPDATE ch9_ops_sensor SET status = 'INACTIVE', updated_at = NOW WHERE sensor_id = 'TEMP-01'; -- Reload the memory table if needed. EXEC TABLE_REFRESH(ch9_ops_sensor); -- Verify with a representative query. SELECT sensor_id, status FROM ch9_ops_sensor ORDER BY sensor_id; ``` Only TEMP-01 becomes `INACTIVE`; the other two rows remain `READY`. Always check the target count before bulk changes. ```sql SELECT COUNT(*) FROM ch9_ops_sensor WHERE site = 'SEOUL' AND status = 'READY'; ``` COUNT is 1 because TEMP-01 has already changed. Counting after the change gives a different target set. ```sql DROP TABLE ch9_ops_sensor; ``` ## Backup and Recovery Support LOOKUP data is persisted on disk and included in database backups. After restore, rows are reconstructed as memory tables and indexes. Use [Backup, Restore, and Mount](/dbms/operations-configuration-recovery/backup-restore-mount/) as the authoritative reference for common BACKUP/RESTORE/MOUNT commands and Edition scope. Validate representative keys and JOIN results after recovery. ## Operational Checks - Keep reference-data change history in a separate log or operational procedure. - Check the target count before bulk UPDATE/DELETE. - Consider indexes on frequent join columns. - Check startup time and LOOKUP row/index memory usage at actual data scale. - Check `LOOKUP_APPEND_UPDATE_ON_DUPKEY` when using Append duplicate-key handling. - Verify reference results with representative JOIN queries after backup recovery. --- title: "9.8 Constraints, Errors, and Troubleshooting" url: https://docs.machbase.com/dbms/lookup-table-usage/constraints-errors-troubleshooting/ language: en kind: page --- # 9.8 Constraints, Errors, and Troubleshooting This section covers LOOKUP limitations, possible errors, and troubleshooting. ## Limitation Summary | Item | Limitation | Typical error | |---|---|---| | PRIMARY KEY | Required; only one column | `ERR-02322`, `ERR-02171` | | PRIMARY KEY column | Cannot be a `SET` target | `ERR-02176` | | Column types | `TEXT`, `CLOB`, `BLOB`, and `BINARY` unsupported | `ERR-02173` | | JSON columns | Ordinary columns supported; PRIMARY KEY unsupported | — | | Memory | Shares one limit with VOLATILE | `ERR-01344` | | UPDATE | `WHERE` required; does not execute if omitted | — | ## PRIMARY KEY Errors LOOKUP cannot be created without a PRIMARY KEY or with more than one. Each statement below fails. ```sql -- Expected failure: no PRIMARY KEY. (ERR-02322) CREATE LOOKUP TABLE ch9_err_nopk (code VARCHAR(16), label VARCHAR(64)); -- Expected failure: two PRIMARY KEY columns. (ERR-02171) CREATE LOOKUP TABLE ch9_err_twopk ( code VARCHAR(16) PRIMARY KEY, name VARCHAR(32) PRIMARY KEY ); ``` Neither statement creates a table, so no cleanup is needed. If a composite key is required, encode it in one column using a delimiter and follow [PRIMARY KEY Policy](../primary-key-policy/). PRIMARY KEY column values cannot be updated. ```sql CREATE LOOKUP TABLE ch9_err_pk (code VARCHAR(16) PRIMARY KEY, label VARCHAR(64)); INSERT INTO ch9_err_pk VALUES ('KR', '대한민국'); -- Expected failure: PRIMARY KEY cannot be a SET target. (ERR-02176) UPDATE ch9_err_pk SET code = 'KO' WHERE code = 'KR'; ``` To change a key, delete the existing row and insert it with the new key. ## Unsupported Column Types LOOKUP columns cannot use `TEXT`, `CLOB`, `BLOB`, or `BINARY`. Declare long strings as `VARCHAR`; store raw content separately in LOG when needed. ```sql -- Expected failure: unsupported column type. (ERR-02173) ALTER TABLE ch9_err_pk ADD COLUMN (memo TEXT); ``` JSON is supported for ordinary columns. For scope, see [JSON Columns and Queries](../json-column-query/). ```sql DROP TABLE ch9_err_pk; ``` ## Memory Limit LOOKUP persists data on disk but executes queries in memory. Startup loads all rows and indexes into memory. Exceeding the limit causes `ERR-01344`. This limit is **shared with VOLATILE tables**. Although the setting name begins with `VOLATILE_`, LOOKUP is included. Assess the combined usage when using both types. ```sql SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME = 'VOLATILE_TABLESPACE_MEMORY_MAX_SIZE'; SELECT * FROM V$STORAGE_DC_VOLATILE_TABLE; ``` Near the limit, reduce retained data, remove unused secondary indexes, or consider another table type for large reference datasets using the criteria in [Indexes and Performance](../index-performance/). ## Scope of Multirow Changes UPDATE/DELETE with general predicates can affect multiple rows. Check the target count using the same predicate first and follow [UPDATE/DELETE with General Predicates](../predicate-update-delete/). ## JSON PRIMARY KEY Errors JSON can be an ordinary column but cannot be declared as a PRIMARY KEY. Store the identifier in a separate scalar column and follow the type/path rules in [JSON Columns and Queries](../json-column-query/). ## Limitations and Considerations - For primary key rules, see [PRIMARY KEY Policy](../primary-key-policy/). - Measure memory scale and index cost as described in [Indexes and Performance](../index-performance/). - Choose TAG for source time series and VOLATILE for caches that may be lost on restart. - Follow the [SDK Append Matrix](/dbms/development-tools-integration/sdk-support-scope/#append-table-type-matrix) for Append availability. --- title: "9.9 Patterns and Scenarios" url: https://docs.machbase.com/dbms/lookup-table-usage/patterns-scenarios/ language: en kind: page --- # 9.9 Patterns and Scenarios This section covers LOOKUP usage patterns and scenarios. ## Use Cases LOOKUP tables are suitable for the following data. ## Suitable Data Types | Type | Examples | |------|------| | Code tables | Country, language, and status codes | | Reference data | Equipment lists, product categories, and departments | | Reference values updated in real time | Exchange-rate tables and threshold settings | | Alternative to tag metadata | Small sensor-information datasets | ## Code Tables ```sql CREATE LOOKUP TABLE ch9_pattern_country ( code VARCHAR(4) PRIMARY KEY, name VARCHAR(64), region VARCHAR(32) ); INSERT INTO ch9_pattern_country VALUES ('KR', '대한민국', 'Asia'); INSERT INTO ch9_pattern_country VALUES ('US', '미국', 'America'); UPDATE ch9_pattern_country SET name = 'United States' WHERE code = 'US'; SELECT code, name FROM ch9_pattern_country ORDER BY code; ``` Two rows are returned. Only the US row's name has changed to `United States`. Manage status and alarm codes the same way and join them to source events. ```sql CREATE LOOKUP TABLE ch9_pattern_status ( code VARCHAR(16) PRIMARY KEY, label VARCHAR(64), color VARCHAR(16) ); INSERT INTO ch9_pattern_status VALUES ('RUN', '가동', 'green'); INSERT INTO ch9_pattern_status VALUES ('STOP', '정지', 'red'); CREATE LOG TABLE ch9_pattern_event ( event_time DATETIME, device_id VARCHAR(64), status VARCHAR(16) ); INSERT INTO ch9_pattern_event VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'DEV-01', 'RUN'); INSERT INTO ch9_pattern_event VALUES (TO_DATE('2026-01-01 10:05:00', 'YYYY-MM-DD HH24:MI:SS'), 'DEV-01', 'STOP'); EXEC TABLE_FLUSH(ch9_pattern_event); SELECT e.event_time, e.device_id, c.label FROM ch9_pattern_event e JOIN ch9_pattern_status c ON e.status = c.code ORDER BY e.event_time; ``` The two rows display the labels `가동` (running) and `정지` (stopped) instead of codes. An event with a status missing from the code table is excluded by the INNER JOIN, so also check for missing codes. ## Equipment Master Data ```sql CREATE LOOKUP TABLE ch9_pattern_equip ( equip_id VARCHAR(32) PRIMARY KEY, equip_name VARCHAR(128), location VARCHAR(64), dept VARCHAR(64), install_dt DATETIME ); INSERT INTO ch9_pattern_equip VALUES ('TEMP-01', 'Boiler', 'Seoul', 'Production', TO_DATE('2025-01-01', 'YYYY-MM-DD')); INSERT INTO ch9_pattern_equip VALUES ('TEMP-02', 'Chiller', 'Busan', 'Facility', TO_DATE('2025-01-01', 'YYYY-MM-DD')); ``` Join sensor data in a TAG table to retrieve reference information such as location and department. ```sql CREATE TAG TABLE ch9_pattern_sensor ( name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ); INSERT INTO ch9_pattern_sensor VALUES ('TEMP-01', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 90.0); INSERT INTO ch9_pattern_sensor VALUES ('TEMP-02', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 20.0); EXEC TABLE_FLUSH(ch9_pattern_sensor); SELECT d.name, m.location, m.dept, d.value FROM ch9_pattern_sensor d JOIN ch9_pattern_equip m ON d.name = m.equip_id WHERE m.dept = 'Production' ORDER BY d.name; ``` Only TEMP-01 is returned. The department predicate applies to a LOOKUP column, so changing it changes the result set even when the TAG source data is unchanged. ## Threshold Settings ```sql CREATE LOOKUP TABLE ch9_pattern_threshold ( sensor_name VARCHAR(64) PRIMARY KEY, low_limit DOUBLE, high_limit DOUBLE, alert_level SHORT ); INSERT INTO ch9_pattern_threshold VALUES ('TEMP-01', 0.0, 100.0, 1); INSERT INTO ch9_pattern_threshold VALUES ('TEMP-02', 0.0, 100.0, 1); -- Change the threshold in real time UPDATE ch9_pattern_threshold SET high_limit = 85.0 WHERE sensor_name = 'TEMP-01'; ``` Join the threshold table with TAG data to evaluate alarm conditions. ```sql SELECT s.name, s.value, t.high_limit FROM ch9_pattern_sensor s JOIN ch9_pattern_threshold t ON s.name = t.sensor_name WHERE s.value > t.high_limit ORDER BY s.name; ``` Only TEMP-01 exceeds its threshold. The value 90 was normal under the previous limit of 100. Record when thresholds change because the same source value can produce a different decision. ## SEQUENCE-Based History Numbers Use a SEQUENCE column when small administrative histories or operational events need sequential identifiers. ```sql CREATE LOOKUP TABLE ch9_pattern_note ( seq LONG PROPERTY(SEQUENCE=1) PRIMARY KEY, target_id VARCHAR(64), note VARCHAR(512), created_at DATETIME ); INSERT INTO ch9_pattern_note VALUES (NEXTVAL(seq), 'TEMP-01', 'threshold changed', NOW); INSERT INTO ch9_pattern_note VALUES (NEXTVAL(seq), 'TEMP-02', 'inspection done', NOW); SELECT seq, target_id FROM ch9_pattern_note ORDER BY seq; ``` The seq values are 1 and 2. Store large source histories in LOG rather than LOOKUP. Clean up the example objects as follows. ```sql DROP TABLE ch9_pattern_note; DROP TABLE ch9_pattern_threshold; DROP TABLE ch9_pattern_sensor; DROP TABLE ch9_pattern_equip; DROP TABLE ch9_pattern_event; DROP TABLE ch9_pattern_status; DROP TABLE ch9_pattern_country; ``` ## Unsuitable Cases - Data requiring explicit transactions and general relational DML → TRANSACTION recommended - Append-only history requiring no UPDATE → LOG recommended - Sensor measurements → TAG recommended - Current-state caches that may be lost on restart → VOLATILE recommended --- title: "9.10 PRIMARY KEY Policy" url: https://docs.machbase.com/dbms/lookup-table-usage/primary-key-policy/ language: en kind: page --- # 9.10 PRIMARY KEY Policy This section covers LOOKUP primary key design principles and policies. For how SDKs identify primary key columns in SELECT results, see [PRIMARY KEY Metadata Support](/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-primary-key-metadata). ## PRIMARY KEY Design LOOKUP tables require a `PRIMARY KEY`, which uniquely identifies rows and controls duplicates. UPDATE and DELETE support general predicates in WHERE, but the primary key column itself cannot be updated. ### Basic Syntax ```text CREATE LOOKUP TABLE table_name ( pk_col type PRIMARY KEY, col2 type, ... ); ``` ### Single-Column PRIMARY KEY ```sql CREATE LOOKUP TABLE ch9_pk_country_code ( code VARCHAR(4) PRIMARY KEY, name VARCHAR(64), region VARCHAR(32) ); ``` ### When a Composite Key Is Needed ```sql CREATE LOOKUP TABLE ch9_pk_price ( price_key VARCHAR(64) PRIMARY KEY, product_id VARCHAR(32), region VARCHAR(16), price DOUBLE ); -- Insert INSERT INTO ch9_pk_price VALUES ('PROD-01:KR', 'PROD-01', 'KR', 99.0); INSERT INTO ch9_pk_price VALUES ('PROD-01:US', 'PROD-01', 'US', 79.0); -- Update by composite key UPDATE ch9_pk_price SET price = 89.0 WHERE price_key = 'PROD-01:KR'; ``` Only one LOOKUP column can be designated as the PRIMARY KEY. If a business key combines several columns, store a combined string or surrogate key in a separate PRIMARY KEY column. ### Choosing a PRIMARY KEY Type | Type | Advantages | Disadvantages | |------|------|------| | `VARCHAR(n)` | Readable, meaningful keys | String comparison cost | | `INTEGER` / `LONG` | Fast comparison, efficient storage | No business meaning; separate mapping needed | ### Considerations - PRIMARY KEY values must be unique. - PRIMARY KEY values cannot be updated; use DELETE + INSERT to change them. - An index is created automatically on the PRIMARY KEY column. - Only one column can be designated as the PRIMARY KEY. ## PRIMARY KEY Policy Consider the following policies and practices when designing primary keys. ### Natural versus Surrogate Keys #### Natural Key Use a value with business meaning directly as the PRIMARY KEY. ```sql -- Country code: a standardized natural key CREATE LOOKUP TABLE ch9_pk_country ( iso_code VARCHAR(4) PRIMARY KEY, -- ISO 3166-1 alpha-2 name VARCHAR(64) ); ``` **Advantages**: Easy to interpret; no separate lookup required. **Disadvantages**: Changing keys creates referential-integrity concerns. #### Surrogate Key Use a value without business meaning, such as a SEQUENCE column or UUID, as the PRIMARY KEY. ```sql -- Equipment master: surrogate key CREATE LOOKUP TABLE ch9_pk_equip ( equip_id LONG PROPERTY(SEQUENCE=1) PRIMARY KEY, code VARCHAR(32), -- Business key name VARCHAR(128) ); CREATE INDEX ch9_pk_equip_idx ON ch9_pk_equip(code); ``` **Advantages**: Immutable; efficient joins. **Disadvantages**: Code-to-ID mapping required. ### PRIMARY KEY Immutability PRIMARY KEY values cannot be updated. Use DELETE + INSERT when a change is required. ```sql -- Incorrect pattern (use DELETE + INSERT for key changes) -- UPDATE cannot change a primary key -- Correct pattern DELETE FROM ch9_pk_country WHERE iso_code = 'OLD'; INSERT INTO ch9_pk_country VALUES ('NEW', '새 국가명'); ``` LOOKUP DML executes statement by statement. LOOKUP DML cannot be included in a TRANSACTION table transaction enclosed by `BEGIN`/`COMMIT`. Account for reads between the two statements and for insert failure. Retain the old values and define the transition order for referencing keys before making changes. If the entire change must be atomic, consider TRANSACTION tables. Clean up the example tables as follows. ```sql DROP INDEX ch9_pk_equip_idx; DROP TABLE ch9_pk_equip; DROP TABLE ch9_pk_country; DROP TABLE ch9_pk_price; DROP TABLE ch9_pk_country_code; ``` --- title: "9.11 SEQUENCE Columns" url: https://docs.machbase.com/dbms/lookup-table-usage/sequence-column/ language: en kind: page --- # 9.11 SEQUENCE Columns This section covers configuring and using LOOKUP SEQUENCE columns. ## Defining a LOOKUP SEQUENCE Column A SEQUENCE column generates insertion identifiers through `NEXTVAL`. Because LOOKUP [requires a PRIMARY KEY](../primary-key-policy/), decide whether the SEQUENCE column or another column is the primary key. Do not interpret sequence order as event-time order. ## Why Use a SEQUENCE Column? Use it to distinguish alarms or administrative history rows that share a timestamp. Because LOOKUP keeps all rows in memory, this example is intended for small administrative histories. Consider LOG for large event volumes accumulated over long periods. ## Declaring a SEQUENCE Column SEQUENCE can be specified on `LONG` or `INT64` columns. Set the starting value with the `SEQUENCE` parameter in PROPERTY. This property is available only for LOOKUP tables. ```sql CREATE LOOKUP TABLE ch9_sequence ( seq LONG PROPERTY(SEQUENCE=1) PRIMARY KEY, sensor_id VARCHAR(40), alarm_type VARCHAR(20), occurred_at DATETIME, message VARCHAR(200) ); ``` - `SEQUENCE=1`: automatic numbering for seq starts at 1. - The starting value must be an integer at least 1 and less than 4,294,967,295. - Declaring the SEQUENCE column as PRIMARY KEY, as above, also guarantees uniqueness. ## Inserting SEQUENCE Values: NEXTVAL() The server maintains the next number as a counter for each SEQUENCE column. `NEXTVAL()` obtains that value for insertion; it does not recalculate the table maximum each time. ```sql -- Insert an automatically incremented value with NEXTVAL() INSERT INTO ch9_sequence (seq, sensor_id, alarm_type, occurred_at, message) VALUES (NEXTVAL(seq), 'TEMP-01', 'HIGH', NOW, '온도 초과'); INSERT INTO ch9_sequence (seq, sensor_id, alarm_type, occurred_at, message) VALUES (NEXTVAL(seq), 'PRESS-02', 'LOW', NOW, '압력 저하'); -- Query SELECT * FROM ch9_sequence ORDER BY seq; -- Sorted as seq=1, then seq=2 ``` ## Specifying Values Directly Direct input is also allowed for SEQUENCE columns. If the value exceeds the current counter, the counter advances to `input value + 1`. A value below the current counter does not move it backward. ```sql -- Specify a value directly; NEXTVAL is optional INSERT INTO ch9_sequence (seq, sensor_id, alarm_type, occurred_at, message) VALUES (100, 'FLOW-03', 'NORMAL', NOW, '정상 복구'); -- The next NEXTVAL() call returns 101 INSERT INTO ch9_sequence (seq, sensor_id, alarm_type, occurred_at, message) VALUES (NEXTVAL(seq), 'TEMP-01', 'NORMAL', NOW, '온도 정상'); -- seq = 101 ``` ## Usage Patterns ```sql -- Query the latest N alarms SELECT * FROM ch9_sequence ORDER BY seq DESC LIMIT 10; -- Query alarms after a specified seq SELECT * FROM ch9_sequence WHERE seq > 500 ORDER BY seq; -- Acknowledge an alarm with a primary key UPDATE UPDATE ch9_sequence SET alarm_type = 'ACKNOWLEDGED' WHERE seq = 101; ``` Clean up the example table as follows. ```sql DROP TABLE ch9_sequence; ``` ## Considerations - SEQUENCE columns support `LONG` and `INT64`. - The starting value must be positive (`SEQUENCE=1` or higher) and less than 4,294,967,295. - The server stores a counter that only increases. Deleting the row with the largest seq does not reuse its number, so gaps can occur. - Without PRIMARY KEY on the SEQUENCE column, duplicate values can be inserted directly without `NEXTVAL()`. Make it the PRIMARY KEY if uniqueness is required. --- title: "9.12 JSON Columns and Queries" url: https://docs.machbase.com/dbms/lookup-table-usage/json-column-query/ language: en kind: page --- # 9.12 JSON Columns and Queries This section covers LOOKUP JSON column support and JSON predicate queries. ## LOOKUP JSON Predicate Queries LOOKUP supports `JSON` for ordinary columns. Use JSON columns to store flexible attributes alongside reference data. ```sql CREATE LOOKUP TABLE ch9_json ( sensor_id VARCHAR(80) PRIMARY KEY, location VARCHAR(200), config JSON ); INSERT INTO ch9_json VALUES ( 'TEMP-01', 'factory1', '{"unit":"celsius","level":3,"threshold":{"high":90.0}}' ); SELECT sensor_id, config FROM ch9_json WHERE config->'$.unit' = 'celsius'; ``` ## Type-Specific JSON Predicates Use type-specific JSON extraction functions to compare numeric values as numbers. ```sql SELECT sensor_id FROM ch9_json WHERE JSON_EXTRACT_INTEGER(config, '$.level') >= 3 AND JSON_EXTRACT_DOUBLE(config, '$.threshold.high') > 80.0; ``` You can also inspect the JSON structure itself. ```sql SELECT sensor_id FROM ch9_json WHERE JSON_IS_VALID(config) = 1 AND JSON_TYPEOF(config, '$.threshold') = 'Object'; ``` ## PRIMARY KEY Restriction LOOKUP can store JSON columns, but JSON cannot be a `PRIMARY KEY`. Use a stable ordinary type such as `INTEGER`, `LONG`, or `VARCHAR` for row identifiers. ```sql -- Expected failure: JSON cannot be a primary key. CREATE LOOKUP TABLE ch9_json_bad ( config JSON PRIMARY KEY, note VARCHAR(80) ); ``` ```sql -- Recommended: use a separate identifier as the primary key. CREATE LOOKUP TABLE ch9_json_ok ( sensor_id VARCHAR(80) PRIMARY KEY, config JSON, note VARCHAR(80) ); ``` ## Design Criteria | Situation | Recommended approach | |------|----------| | Values frequently used in joins/searches | Separate columns | | Flexible attributes that differ by device | JSON column | | Numeric predicate queries | Extract into ordinary numeric columns | | Primary key | Stable identifier column | | Frequent path queries | Extract into separate columns | Dedicated JSON path indexes are unsupported. For frequent predicates, first consider extracting the values into separate indexed columns. ```sql CREATE LOOKUP TABLE ch9_json_fast ( sensor_id VARCHAR(80) PRIMARY KEY, unit VARCHAR(16), level INTEGER, config JSON ); CREATE INDEX ch9_json_unit_idx ON ch9_json_fast(unit); ``` ## UPDATE and DELETE Predicates ```sql UPDATE ch9_json SET location = 'factory2' WHERE config->'$.unit' = 'celsius'; DELETE FROM ch9_json WHERE JSON_EXTRACT_INTEGER(config, '$.level') < 2; ``` Because the target scope can be broad, check the count with the same predicate before UPDATE/DELETE. Clean up the example objects as follows. `ch9_json_bad` is excluded because its creation intentionally fails. ```sql DROP TABLE ch9_json_fast; DROP TABLE ch9_json_ok; DROP TABLE ch9_json; ``` ## Considerations - LOOKUP supports JSON as an ordinary column. - JSON cannot be a primary key. - Dedicated JSON path indexes are unsupported. - Extract frequently searched values into ordinary LOOKUP columns. - Consider TRANSACTION or TAG tables if JSON path indexes are required. --- title: "9.13 Predicate UPDATE/DELETE" url: https://docs.machbase.com/dbms/lookup-table-usage/predicate-update-delete/ language: en kind: page --- # 9.13 Predicate UPDATE/DELETE LOOKUP tables can update or delete multiple rows using general predicates as well as primary keys. Check the target row count with the same predicate before making changes. This exercise uses one table, which is cleaned up at the end. ```sql CREATE LOOKUP TABLE ch9_predicate ( equip_id VARCHAR(32) PRIMARY KEY, site VARCHAR(16), status VARCHAR(16), score INTEGER ); INSERT INTO ch9_predicate VALUES ('EQ-01', 'SEOUL', 'READY', 10); INSERT INTO ch9_predicate VALUES ('EQ-02', 'SEOUL', 'READY', 20); INSERT INTO ch9_predicate VALUES ('EQ-03', 'SEOUL', 'RETIRED', 30); INSERT INTO ch9_predicate VALUES ('EQ-04', 'BUSAN', 'READY', 40); ``` ## UPDATE All matching rows are updated. `SET` expressions can reference current row values, but the primary key column itself cannot be changed. LOOKUP UPDATE requires `WHERE`. Specify a supported predicate even when updating every row. This differs from DELETE, which permits deleting all rows without WHERE. ```sql -- Count affected rows before the change. SELECT COUNT(*) FROM ch9_predicate WHERE site = 'SEOUL' AND status = 'READY'; UPDATE ch9_predicate SET status = 'ACTIVE', score = score + 10 WHERE site = 'SEOUL' AND status = 'READY'; SELECT equip_id, site, status, score FROM ch9_predicate ORDER BY equip_id; ``` COUNT is 2. Only EQ-01 and EQ-02 become `ACTIVE`, with scores of 20 and 30. EQ-03 remains unchanged because its status differs, despite being in SEOUL; EQ-04 remains unchanged because its site differs, despite being READY. ## DELETE All matching rows are deleted. Omitting `WHERE` deletes every row in the table. ```sql SELECT COUNT(*) FROM ch9_predicate WHERE status = 'RETIRED'; DELETE FROM ch9_predicate WHERE status = 'RETIRED'; SELECT equip_id, status FROM ch9_predicate ORDER BY equip_id; ``` COUNT is 1. EQ-03 is deleted, leaving three rows. ## Predicate Design Guidelines 1. Use primary key predicates for single-row changes. 2. Check the impact scope with `SELECT COUNT(*)` using the same predicate before bulk changes. 3. Consider extracting frequently filtered JSON values into ordinary indexed columns. 4. To change a primary key, delete the existing row and insert it with the new key. Check the SQL reference for the precise scope of supported operators and JSON predicates. - [LOOKUP predicate UPDATE](/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-update-syntax/) - [LOOKUP predicate DELETE](/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-delete-syntax/) ## Permissions and Performance UPDATE and DELETE require the respective `UPDATE` and `DELETE` privileges on the target table. Grant `SELECT` only if the application itself reads before/after values. Use [Privilege Management](/dbms/security-access-control/privileges/) as the authoritative reference for privilege SQL. Primary key equality directly locates one row; general predicates evaluate conditions to collect target rows. Use prepared statements and binding for repeated single-row changes. For bulk changes, measure the row count and execution time for the same predicate in a validation environment. ```sql DROP TABLE ch9_predicate; ``` --- title: "10. VOLATILE Table Usage" url: https://docs.machbase.com/dbms/volatile-table-usage/ language: en kind: section --- # 10. VOLATILE Table Usage VOLATILE tables are in-memory tables shared across the server process. This chapter covers data loss on restart, UPSERT, and cache patterns that can be rebuilt. ## Chapter Contents | Section | Topics | |----|------| | [Overview and Use Criteria](./overview-use-criteria/) | Characteristics and selection criteria | | [Table Structure and Schema](./table-structure-schema/) | PRIMARY KEY design, column types, and schema structure | | [Create, Alter, and Drop](./create-alter-drop/) | CREATE VOLATILE TABLE, DROP, and persistence differences | | [Data Ingestion and Modification](./data-input-mutation/) | INSERT, ON DUPLICATE KEY UPDATE, and DELETE | | [Queries and Analysis](./query-analysis/) | SELECT, predicate queries, and LIKE | | [Indexes and Performance](./index-performance/) | Red-black tree indexes and primary key indexes | | [Operations and Data Lifecycle](./operations-lifecycle/) | Operational procedures and data management | | [Constraints, Errors, and Troubleshooting](./constraints-errors-troubleshooting/) | Feature limitations and error handling | --- title: "10.1 Overview and Use Criteria" url: https://docs.machbase.com/dbms/volatile-table-usage/overview-use-criteria/ language: en kind: page --- # 10.1 Overview and Use Criteria VOLATILE tables store temporary data in memory. Data is lost when the server restarts, so use them for current state that can be rebuilt, temporary aggregates, and caches shared across sessions. ## VOLATILE Table Characteristics Create a VOLATILE table with `CREATE VOLATILE TABLE`. ```sql CREATE VOLATILE TABLE ch10_overview ( sensor_id VARCHAR(64) PRIMARY KEY, value DOUBLE, updated_at DATETIME ); ``` VOLATILE tables have the following characteristics. | Item | Description | |------|------| | Main uses | Current-state caches, temporary aggregates, and intermediate results | | Storage | Memory | | Data after restart | Lost | | Sharing scope | Server-wide | | Key | Optional PRIMARY KEY | | Main features | UPDATE, DELETE, `ON DUPLICATE KEY UPDATE`, and red-black tree indexes | | Backup | Not supported | ## Use Criteria Use a VOLATILE table when: - Data may be lost after a server restart. - Data can be recalculated or rebuilt from its source at any time. - Current state, recent aggregates, or temporary results require fast queries. - Multiple sessions need to share the same temporary state. - In-memory response time is more important than disk persistence. The following example maintains the latest sensor state. ```sql INSERT INTO ch10_overview VALUES ('TEMP-01', 23.5, NOW) ON DUPLICATE KEY UPDATE SET value = 23.5, updated_at = NOW; SELECT * FROM ch10_overview WHERE sensor_id = 'TEMP-01'; -- Clean up because the next section reuses this name. DROP TABLE ch10_overview; ``` ### Usage Patterns | Pattern | Key | Source for rebuilding | Recommended expiration method | |------|-----|-------------|----------------| | Latest device state | Device ID | TAG or LOG | Update the same key | | Short-interval aggregates | Target and time bucket | TAG or LOG | Replace or rebuild the bucket | | Job progress | Job ID | Job system | Delete the key after completion | | Temporary query cache | Request or object ID | Persistent table | Rebuild the entire cache | For current-state updates, see [Data Ingestion and Modification](../data-input-mutation/). For temporary aggregates, see [Queries and Analysis](../query-analysis/). ## When to Consider Other Tables Use another table type for the following requirements. | Requirement | Recommended table | |----------|-------------| | Source data that must survive a restart | TAG or LOG | | Persistent reference data, such as code lists or device master data | LOOKUP | | Business data requiring transactions and relational updates | TRANSACTION | | Time-series data for long-term analysis | TAG | Data stored only in a VOLATILE table cannot be recovered after server shutdown. Store important data in a suitable persistent table: TAG, LOG, LOOKUP, or TRANSACTION. Use VOLATILE tables for caches or intermediate results. ## Design Sequence Make the following decisions when designing a VOLATILE table. 1. Confirm that the data can be rebuilt. 2. Decide whether a PRIMARY KEY is required. 3. Estimate the row count and memory usage. 4. Prepare an initial load procedure for use after restart. 5. Save results that must be retained to persistent tables through explicit application writes. There is no dedicated flush command that persists a VOLATILE table. For schema and primary key design, see [Table Structure and Schema](/dbms/volatile-table-usage/table-structure-schema/). For restart handling, see [Restart and Data Loss](/dbms/volatile-table-usage/operations-lifecycle/). --- title: "10.2 Table Structure and Schema" url: https://docs.machbase.com/dbms/volatile-table-usage/table-structure-schema/ language: en kind: page --- # 10.2 Table Structure and Schema This section covers primary key design and schema structure for VOLATILE tables. ## PRIMARY KEY Design You can create a VOLATILE table without a PRIMARY KEY. However, a PRIMARY KEY is required for primary key lookups and `ON DUPLICATE KEY UPDATE`. ### Single PRIMARY KEY ```sql CREATE VOLATILE TABLE ch10_schema_state ( device_id VARCHAR(32) PRIMARY KEY, state VARCHAR(16), updated_at DATETIME ); ``` ### When a Composite Key Is Needed If a combination of columns uniquely identifies a row, encode that combination in a separate PRIMARY KEY column. ```sql CREATE VOLATILE TABLE ch10_schema_hourly ( key_id VARCHAR(96) PRIMARY KEY, sensor_id VARCHAR(64), hour_ts DATETIME, avg_value DOUBLE, sample_cnt INTEGER ); -- Insert composite key values INSERT INTO ch10_schema_hourly VALUES ('TEMP-01:2026010110', 'TEMP-01', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 23.5, 60); INSERT INTO ch10_schema_hourly VALUES ('TEMP-01:2026010111', 'TEMP-01', TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS'), 24.1, 60); INSERT INTO ch10_schema_hourly VALUES ('TEMP-02:2026010110', 'TEMP-02', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 21.0, 60); -- Query by composite key SELECT sensor_id, avg_value FROM ch10_schema_hourly WHERE key_id = 'TEMP-01:2026010110'; ``` ### Using ON DUPLICATE KEY UPDATE ```sql -- Update when the PRIMARY KEY already exists INSERT INTO ch10_schema_state VALUES ('DEV-01', 'ONLINE', NOW) ON DUPLICATE KEY UPDATE SET state = 'ONLINE', updated_at = NOW; ``` ### Considerations - A table can be created without a PRIMARY KEY, but primary key operations such as UPSERT and primary key lookups are unavailable. - Multiple rows cannot have the same PRIMARY KEY. `ON DUPLICATE KEY UPDATE` updates the existing row instead of adding a duplicate. - Only one column can be designated as the PRIMARY KEY. ## VOLATILE Table Design VOLATILE tables keep data only in memory and lose it on server restart. The table definition remains. Decide which data can be lost and how to reload it. Use these tables for state or caches shared by multiple sessions that do not need to survive a restart. Review the following topics when defining the schema. - [Use Cases](../overview-use-criteria/#use-cases-volatile) - [Persistence Differences and DDL](../create-alter-drop/#differences-persistence-ddl) - [Memory Lifecycle](../operations-lifecycle/#lifecycle-memory) - [Red-Black Tree Indexes](../index-performance/#index-strategy-red-black) - [ON DUPLICATE KEY UPDATE](../data-input-mutation/#on-duplicate-key-update) - [Restart and Data Rebuilding](../operations-lifecycle/#data-loss) Clean up the example tables as follows. ```sql DROP TABLE ch10_schema_hourly; DROP TABLE ch10_schema_state; ``` --- title: "10.3 Create, Alter, and Drop" url: https://docs.machbase.com/dbms/volatile-table-usage/create-alter-drop/ language: en kind: page --- # 10.3 Create, Alter, and Drop This section explains how to create and drop VOLATILE tables and how their persistence differs from other table types. ## Creating and Managing VOLATILE Tables Use the following statements to create and drop a VOLATILE table. ### Create ```sql create volatile table vtable (id1 integer, name varchar(20)); ``` ### Drop ```sql drop table vtable; ``` ## Persistence Differences and DDL Unlike other table types, VOLATILE tables store data only in memory. ### Persistence Comparison | Item | VOLATILE | LOOKUP | TRANSACTION | TAG | LOG | |------|----------|--------|-----|-----|-----| | Storage | Memory | Disk | Disk | Disk | Disk | | Data retained after server restart | No | Yes | Yes | Yes | Yes | | Table structure (DDL) retained | Yes | Yes | Yes | Yes | Yes | ### DDL Behavior Only the data in a VOLATILE table is lost. Its definition is stored persistently, as with other table types. After a restart, perform an initial load; the table does not need to be recreated. ```sql -- Create the table definition only once. CREATE VOLATILE TABLE ch10_ddl ( sensor_id VARCHAR(64) PRIMARY KEY, value DOUBLE, updated_at DATETIME ); ``` ### Creation Syntax The basic syntax is `CREATE VOLATILE TABLE table_name (column_definition, ...)`. Designate one column as `PRIMARY KEY` when key-based updates or deletes are required. - `PRIMARY KEY` is optional. - Only one column can be designated as the PRIMARY KEY. ### AUTO_INCREMENT PRIMARY KEY To have the server generate a numeric PRIMARY KEY, specify `AUTO_INCREMENT` on a single `LONG` or `INT64` column. ```sql CREATE VOLATILE TABLE ch10_ddl_seq ( request_id LONG PRIMARY KEY AUTO_INCREMENT, payload VARCHAR(256) ); INSERT INTO ch10_ddl_seq(payload) VALUES('refresh'); ``` The server generates a value when the primary key column is omitted or set to NULL. A single `INSERT ... VALUES` statement can also specify a primary key value in the range `0..INT64_MAX`. If the specified value is at least the next automatic value, the next automatic value advances to `specified value + 1`. A smaller value does not move it backward. VOLATILE tables with AUTO_INCREMENT do not support `INSERT ... SELECT` or `ON DUPLICATE KEY UPDATE`. Because VOLATILE table data is lost on server restart, the next automatic value also restarts at 1. The table definition remains and does not need to be recreated. For obtaining the inserted ID through an SDK, see [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/). ### Adding and Dropping Columns In Standard Edition, you can add and drop fixed-length numeric ARRAY columns in VOLATILE tables. ```sql ALTER TABLE ch10_ddl ADD COLUMN (thresholds DOUBLE[2] DEFAULT [10.0, 20.0]); ALTER TABLE ch10_ddl DROP COLUMN (thresholds); ``` As with scalar `ADD COLUMN`, VOLATILE does not backfill rows that existed before ALTER with the DEFAULT value. Even with an ARRAY DEFAULT, the new column is a whole-array NULL in existing rows. This differs from the backfill rules for LOG, LOOKUP, TRANSACTION, and TAG METADATA. For supported ARRAY element types, cardinality, and DEFAULT rules, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/). ### Drop ```sql DROP TABLE ch10_ddl; DROP TABLE ch10_ddl_seq; ``` ### Considerations - VOLATILE table DDL is stored in the database and survives server restart. - Data is not restored automatically after restart. Configure an initial load script, for example by running machsql at startup. --- title: "10.4 Data Input and Mutation" url: https://docs.machbase.com/dbms/volatile-table-usage/data-input-mutation/ language: en kind: page --- # 10.4 Data Input and Mutation This section provides runnable examples of `INSERT`, duplicate-key updates, and `DELETE` for VOLATILE tables. ## Inserting and Updating Data Run the following examples in order through the final cleanup statement. To repeatedly change values for the same key, such as current state, define a `PRIMARY KEY` and use `ON DUPLICATE KEY UPDATE`. ```sql CREATE VOLATILE TABLE ch10_mutation ( id INTEGER PRIMARY KEY, direction VARCHAR(10), refcnt INTEGER ); INSERT INTO ch10_mutation VALUES (1, 'west', 0); INSERT INTO ch10_mutation VALUES (2, 'east', 0); INSERT INTO ch10_mutation VALUES (1, 'south', 0) ON DUPLICATE KEY UPDATE; INSERT INTO ch10_mutation VALUES (1, 'south', 0) ON DUPLICATE KEY UPDATE SET refcnt = 1; SELECT * FROM ch10_mutation ORDER BY id; ``` If the key does not exist, a new row is inserted. If it exists, the statement without `SET` updates the entire row with the input values; the statement with `SET` updates only the specified columns. The `PRIMARY KEY` itself cannot be updated. Bulk ingestion APIs differ by language and driver in initialization, binding, and error handling. Use the corresponding driver example in [SDKs and Integration](/dbms/development-tools-integration/) instead of copying incomplete snippets. ## Conditional Updates Use `UPDATE` to change selected columns of an existing row. `INSERT ... ON DUPLICATE KEY UPDATE` inserts a missing row or updates an existing one; `UPDATE` changes values only when the target row exists. `UPDATE` on a VOLATILE table requires `WHERE` and supports only a `PRIMARY KEY = value` predicate, as with conditional deletion. Predicates on other columns and compound predicates are unsupported. Updating all rows by omitting `WHERE` is also unsupported. ```sql UPDATE ch10_mutation SET refcnt = refcnt + 1 WHERE id = 2; SELECT * FROM ch10_mutation ORDER BY id; ``` The `SET` clause cannot specify the `PRIMARY KEY` column. To change a key, delete the existing row and insert it again with the new key. ## Deleting Data Conditional deletion supports only a `PRIMARY KEY = value` predicate. Predicates on other columns and compound predicates are unsupported. ```sql DELETE FROM ch10_mutation WHERE id = 2; SELECT * FROM ch10_mutation ORDER BY id; DROP TABLE ch10_mutation; ``` To remove all rows while retaining the table definition, omit WHERE, as in `DELETE FROM table_name`. To reset the schema as well, drop and recreate the table. A server restart removes only the data and preserves the definition, so maintain a separate reload script rather than a recreation script. --- title: "10.5 Query and Analysis" url: https://docs.machbase.com/dbms/volatile-table-usage/query-analysis/ language: en kind: page --- # 10.5 Query and Analysis This section provides runnable examples of key lookups, general predicate queries, and temporary aggregates for VOLATILE tables. ## Prepare Example Data Query VOLATILE tables with `SELECT`, as with other table types. Run the following examples in order through the final cleanup statements. ```sql CREATE VOLATILE TABLE ch10_query ( device_id VARCHAR(64) PRIMARY KEY, status VARCHAR(16), value DOUBLE, updated_at DATETIME ); INSERT INTO ch10_query VALUES ('DEV-01', 'RUNNING', 42.5, NOW); INSERT INTO ch10_query VALUES ('DEV-02', 'STOPPED', 0, NOW); ``` ## PRIMARY KEY Lookups A key predicate is suitable for retrieving a single row from a current-state cache. ```sql SELECT device_id, status, value, updated_at FROM ch10_query WHERE device_id = 'DEV-01'; ``` ## General Predicate Queries Consider a secondary index for repeated queries on columns other than the `PRIMARY KEY`. ```sql CREATE INDEX ch10_query_status_idx ON ch10_query(status); SELECT device_id, value, updated_at FROM ch10_query WHERE status = 'RUNNING'; ``` Indexes also consume memory. Create them only on columns needed by actual queries. ## Querying Temporary Aggregates Storing aggregates for short intervals reduces repeated calculations for dashboards and alarm evaluation. ```sql CREATE VOLATILE TABLE ch10_query_summary ( summary_key VARCHAR(96) PRIMARY KEY, sensor_id VARCHAR(64), bucket_time DATETIME, avg_value DOUBLE, max_value DOUBLE, sample_cnt LONG ); INSERT INTO ch10_query_summary VALUES ('TEMP-01:2026-01-01T00:00', 'TEMP-01', TO_DATE('2026-01-01 00:00:00'), 21.5, 23.0, 60); SELECT sensor_id, bucket_time, avg_value, max_value FROM ch10_query_summary WHERE sensor_id = 'TEMP-01' ORDER BY bucket_time DESC LIMIT 10; DROP TABLE ch10_query_summary; DROP TABLE ch10_query; ``` If aggregate results require long-term retention, copy them periodically to a LOG or TRANSACTION table. ## Query Considerations - Data is empty after a server restart. First check whether the initial load has completed. - Define a `PRIMARY KEY` when key lookups are the primary access pattern. - Consider secondary indexes for columns frequently used in range queries or sorting. - Store important source data in persistent tables and use VOLATILE as a cache. --- title: "10.6 Indexes and Performance" url: https://docs.machbase.com/dbms/volatile-table-usage/index-performance/ language: en kind: page --- # 10.6 Indexes and Performance This section explains how to create and choose indexes for VOLATILE tables. ## Supported Indexes Declaring a `PRIMARY KEY` creates an index for key lookups. You can add `REDBLACK` indexes to ordinary columns. VOLATILE tables do not support `BITMAP` or `KEYWORD` indexes. Run the following example in order from table creation through cleanup. ```sql CREATE VOLATILE TABLE ch10_index ( id INTEGER PRIMARY KEY, name VARCHAR(20), status VARCHAR(16) ); CREATE INDEX ch10_index_name_idx ON ch10_index(name) INDEX_TYPE REDBLACK; INSERT INTO ch10_index VALUES (1, 'west device', 'ACTIVE'); INSERT INTO ch10_index VALUES (2, 'east device', 'INACTIVE'); SELECT id, name FROM ch10_index WHERE name = 'west device'; DROP INDEX ch10_index_name_idx; DROP TABLE ch10_index; ``` ## Design Criteria - Use a `PRIMARY KEY` for single-row key lookups and updates. - Add secondary indexes only for repeated equality or range predicates on ordinary columns. - Indexes consume memory as well as data. Remove unnecessary indexes. - Compare response time and memory usage before and after creating indexes, using actual query predicates and row counts. For syntax details, see [Index Syntax](/dbms/reference/sql/syntax/index-syntax/). --- title: "10.7 Operations and Data Lifecycle" url: https://docs.machbase.com/dbms/volatile-table-usage/operations-lifecycle/ language: en kind: page --- # 10.7 Operations and Data Lifecycle This section describes the procedures for creating, loading, using, discarding, and rebuilding VOLATILE table data. ## Data Lifecycle 1. Run the table creation SQL after the server starts. 2. Load initial data from a persistent source if needed. 3. Start application queries and updates. 4. Write results that must be retained to persistent tables. 5. Data is lost when the server shuts down. Table definitions remain. ## Sharing Across Sessions VOLATILE tables are shared server-wide. A row inserted by one session can be queried by another. Closing a connection alone does not remove data. ## Separating Temporary and Persistent Data Store only current state or intermediate results that can be rebuilt from source data in VOLATILE. Store audit records, source events, and results that cannot be recreated in TAG, LOG, LOOKUP, or TRANSACTION tables. Manage copy SQL as a separate job, including source and target columns, duplicate handling, and execution frequency. ## Restart Procedure - Check whether the table exists. A restart preserves its definition, so recreation is usually unnecessary. - If a persistent source exists, load only data for the defined reference point in time. - Check the expected row count and latest timestamp. - Resume collector and application writes after validation. - If rebuilding fails, confirm that the service operates safely with an empty cache. ## Operations Checklist - Keep initial load SQL in version control, together with creation SQL for the first deployment. - Validate scripts in advance using the operational account and actual connection settings. - Monitor row counts and memory limits. - Check that data requiring retention is not stored only in VOLATILE. - Verify the loading and validation sequence during restart drills. ## Checking Memory and Rebuilding Caches ```sql SELECT * FROM V$STORAGE_DC_VOLATILE_TABLE; SELECT * FROM V$SYSMEM; SELECT * FROM V$SESMEM; SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME = 'VOLATILE_TABLESPACE_MEMORY_MAX_SIZE'; ``` Check the view definitions for your deployed version instead of relying on specific internal column names. When rebuilding a cache, record the row count and sample values, redirect its consumers, and then create the table, load initial data, and validate it in that order. The service must be able to operate safely with an empty cache if rebuilding fails. --- title: "10.8 Constraints, Errors, and Troubleshooting" url: https://docs.machbase.com/dbms/volatile-table-usage/constraints-errors-troubleshooting/ language: en kind: page --- # 10.8 Constraints, Errors, and Troubleshooting This section covers VOLATILE table limitations, possible errors, and troubleshooting. Most issues involve memory limits, primary key design, unsupported column types, or data loss after restart. ## Limitations Consider the following limitations when using VOLATILE tables. | Item | Limitation | |------|------| | Storage | Memory | | Data after restart | Lost | | Backup and mount | Not supported | | JSON columns | Not supported | | PRIMARY KEY | Optional; only one column | | UPDATE/DELETE | Only `PRIMARY KEY = value` predicates are supported | | Memory limit | Subject to the total memory limit for Volatile/Lookup tables | ```sql -- Expected failure: VOLATILE tables do not support JSON columns. CREATE VOLATILE TABLE ch10_err_json ( session_id VARCHAR(64) PRIMARY KEY, payload JSON ); ``` For flexible attributes, extract frequently queried values into ordinary columns. If persistent JSON columns are needed, consider TRANSACTION or TAG tables. ## Insufficient Memory VOLATILE table data and indexes consume memory. Increasing row counts or too many indexes can exhaust the memory limit. Diagnose the issue in the following order. The example tables are cleaned up at the end of this page. ```sql -- Create a table for the diagnostic example. CREATE VOLATILE TABLE ch10_diag ( device_id VARCHAR(64) PRIMARY KEY, value DOUBLE ); INSERT INTO ch10_diag VALUES ('DEV-01', 10.0); -- 1. Check the target table row count. SELECT COUNT(*) FROM ch10_diag; ``` ```sql -- 2. Check memory usage across VOLATILE tables. SELECT * FROM V$STORAGE_DC_VOLATILE_TABLE; ``` If needed, check the `VOLATILE_TABLESPACE_MEMORY_MAX_SIZE` setting. ```sql SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME = 'VOLATILE_TABLESPACE_MEMORY_MAX_SIZE'; ``` To resolve the issue: - Delete unnecessary rows. - Reduce the amount of data retained in the cache. - Remove unused indexes. - Move important data to persistent tables before rebuilding the VOLATILE table. - Consider adjusting the memory limit according to operational policy. ## PRIMARY KEY Errors A PRIMARY KEY is required for `ON DUPLICATE KEY UPDATE`, [primary key UPDATE](../data-input-mutation/#volatile-primary-key-update), and primary key DELETE. ```sql CREATE VOLATILE TABLE ch10_err_device ( device_id VARCHAR(64) PRIMARY KEY, status VARCHAR(16), updated_at DATETIME ); ``` PRIMARY KEY values must be unique. Use `ON DUPLICATE KEY UPDATE` to treat duplicate inserts as updates. ```sql INSERT INTO ch10_err_device VALUES ('DEV-01', 'ONLINE', NOW) ON DUPLICATE KEY UPDATE SET status = 'ONLINE', updated_at = NOW; ``` The PRIMARY KEY column itself cannot be updated. To change a key, delete the existing row and insert it with the new key. ## Data Loss After Restart VOLATILE table data is lost on normal shutdown, abnormal termination, or restart. This is a characteristic of the table type, not an error. When an issue occurs, check the following. 1. Check whether the server has restarted. 2. Check whether the VOLATILE table creation script was executed. 3. Check whether the initial load query completed successfully. 4. Rebuild the cache from the source TAG/LOG/TRANSACTION table. ```sql SELECT COUNT(*) FROM ch10_diag; ``` If the result is 0, run the initial load procedure again. Clean up the example tables as follows. ```sql DROP TABLE ch10_diag; DROP TABLE ch10_err_device; ``` ## Troubleshooting Checklist - Confirm that the stored data can be rebuilt. - Check whether the operation requires a PRIMARY KEY. - Use `COUNT(*)` and `V$STORAGE_DC_VOLATILE_TABLE` to check size and memory usage. - Run the initial load SQL again after restart. The table does not need to be recreated. - For persistent retention, use TAG, LOG, LOOKUP, or TRANSACTION tables instead of VOLATILE. --- title: "11. Development and Application Integration" url: https://docs.machbase.com/dbms/development-tools-integration/ language: en kind: section --- # 11. Development and Application Integration Choose an integration method for your application, then review SDK installation, APIs, and shared operational principles. Use SDK pages for language-specific implementations and the selection, concepts, and support pages for guidance shared across SDKs. ## Reading Order 1. [Choose an Integration Method](selection-integration-method/) for your language and input pattern. 2. Review authentication, time values, binding, transactions, and retries in [Common Integration Concepts](concepts-common/). 3. Compare actual support in [SDK Feature Support](sdk-support-scope/). 4. Follow the relevant SDK page for installation, connections, and executable code. 5. Apply task-specific procedures in [Data Ingestion and Export](data-input-load-export/). For SQL ROWID semantics, see [ROWID](../reference/sql/rowid/). For partial ARRAY input in Machbase DBMS 8.7.0, see [Sparse ARRAY and Selected-Column Append API](data-input-load-export/array-append/). ## SDK References | Environment | Documentation | |---|---| | Native C/C++ or ODBC | [Machbase SQLCLI and ODBC](cli-odbc/) | | Java/Spring | [JDBC](jdbc/) | | Python | [Python](python/) | | Node.js/TypeScript | [Node.js / TypeScript](node-js-typescript/) | | C#/VB.NET | [.NET Connector](net-connector/) | | Native Go/`database/sql` | [Go](go/) | ## Common Connection Information | Item | Default | Description | |---|---|---| | HOST | `127.0.0.1` | Server host name or IP address | | PORT | `5656` | Server port (`PORT_NO` in `machbase.conf`) | | USER | `SYS` | User ID | | PASSWORD | `MANAGER` | User password | Use a dedicated user with the minimum required privileges in production. See [Accounts, Privileges, and Access Control](../security-access-control/) for account and authentication settings. ## Existing Support Links See [SDK Feature Support](sdk-support-scope/) for NULL/PRIMARY KEY metadata, ROWID, Append, and AUTH KEY support by SDK. --- title: "11.1 Choose an Integration Method" url: https://docs.machbase.com/dbms/development-tools-integration/selection-integration-method/ language: en kind: section --- # 11.1 Choose an Integration Method Choose an integration method for the project language, ingestion pattern, and deployment environment. ## Selection Criteria | Requirement | First option to consider | |----------|------------------| | Native C/C++ collector | SQLCLI | | ODBC manager/DSN application | ODBC | | Java/Spring | JDBC | | Python analytics/automation | `machbaseapi` | | C#/VB.NET | .NET Connector | | Go collector/service | Native `machgo` or `database/sql` | | Node.js/TypeScript backend | `@machbase/ts-client` | | R analytics | Machbase ODBC driver with RODBC | | Bulk file ingestion/export | machloader, csvimport, csvexport | | Continuous bulk TAG/LOG ingestion | The chosen SDK's Append API | Do not connect a browser directly to port 5656. Execute queries in a backend and return only the required results. ## Decision Sequence 1. Choose an official driver maintainable in the application language. 2. Check port 5656 connectivity, operating system support, and runtime compatibility. 3. Identify required SQL, prepared statement, Append, and transaction features. 4. Check actual support in the [SDK Feature Matrix](../sdk-support-scope/). 5. Round-trip sample timestamps, NULLs, numbers, and strings. 6. Load-test target row sizes, concurrent connections, and batch sizes. Do not choose a driver on Append support alone. Verify flush latency, server error responses, reconnection, and failed-row handling in the actual SDK. For TRANSACTION DML, check explicit transaction support. Do not assume TAG/LOG Append shares its rollback scope. ## Detailed Documentation by Topic | Topic | Detailed documentation | |------|------| | SDK installation, connections, APIs, complete code | SDK pages in this chapter | | Shared authentication, binding, transactions, retries | [Common Integration Concepts](../concepts-common/) | | SDK feature support | [SDK Feature Support](../sdk-support-scope/) | | SQL, configuration, command-line details | [Chapter 16 Reference](/dbms/reference/) | | Choose ingestion/export methods | [Data Ingestion and Export](../data-input-load-export/) | After choosing an integration method, run its SDK installation and connection examples. Check both documented versions and actual deployment artifacts for feature support. --- title: "11.2 Common Integration Concepts" url: https://docs.machbase.com/dbms/development-tools-integration/concepts-common/ language: en kind: section --- # 11.2 Common Integration Concepts This page covers connection, binding, transaction, bulk ingestion, and error-handling principles shared across drivers and languages. See the SDK pages for function names and complete code. ## Connection Strings and Authentication Connections require a host, native port, user, and authentication information. The default port is `5656`; check `machbase.conf` in the deployed environment. | Item | Check | |------|-----------| | Host/port | TCP reachability from the application host | | User | Minimum privileges for the target database and tables | | Password | Supply through environment variables or a secret manager | | Database | SDK support for initial database selection | | Timeouts | Connection, command, and read limits appropriate for the workload | | Time zone | Supported option names and scope in the SDK and server | Example `SYS`/`MANAGER` credentials are for local validation. Create dedicated accounts for production applications; do not record passwords in source, command history, or logs. AUTH KEY signs challenges with a private key instead of a password. Check key formats, file permissions, and SDK options in [AUTH KEY Authentication](/dbms/security-access-control/authentication-auth-key/) and the driver documentation. With connection pools, verify reset behavior so a returned connection's database, session settings, and open statements do not affect the next request. ## Time Zones and Time Values Machbase `DATETIME` supports nanosecond precision. Manage the meaning of a timestamp separately from its representation. - Specify the time reference for collected data: UTC or the business time zone. - Fix both format and time zone when binding strings. - Check whether the SDK expects epoch seconds, milliseconds, microseconds, or nanoseconds. - Round-trip output time zones through the actual connection options or `TO_CHAR()` path. - Do not interchange `NOW` and `SYSDATE` in business rules; check their meanings in the SQL reference. For string round-trip tests, compare input, query output, and output after a time zone change on the same connection. See [SQL Functions](/dbms/reference/sql/functions/functions-full/) for function details. ## Prepared statement Prepared statements separate SQL structure from values and support repeated execution of the same SQL. ```text INSERT INTO sensor_data VALUES (?, ?, ?) SELECT value FROM sensor_data WHERE name = ? AND time >= ? ``` Check that the preparing connection and current database have not changed. Close the statement after use. For SDK statement caches, check cache scope, eviction policy, and reset behavior on database changes. Some syntax positions, such as CTEs or LIMIT, may not allow parameter placeholders. On a syntax error, check [Named Bind Parameter](/dbms/reference/sql/syntax/named-bind-parameter-syntax/) and SDK placeholder support before concatenating values into SQL. ## Parameter binding | Value | Recommended method | |---------|-----------| | Integers/floating-point numbers | Match fixed-width language types to SQL ranges | | Strings | Check encoding and maximum length | | DATETIME | Use SDK time objects or the specified epoch unit | | NULL | Specify the language NULL representation and SQL type | | DECIMAL | Prefer the SDK exact fixed-point type over string conversion | | Binary/IP | Use SDK-required byte arrays or dedicated types | Positional `?` placeholders bind in occurrence order. Use named `:name` placeholders only with supported servers and SDKs, and check repeated-name rules. Identifiers and SQL keywords cannot be bound as values; validate them against an allowlist before constructing SQL. ## DML Affected-Row Counts After `INSERT`, `UPDATE`, or `DELETE`, check the SDK affected-row count. A success response alone does not prove the intended business record changed. - For a single-row change, check that the count is 1. - For 0 rows, check whether no row matched or the change was already applied. - Check error codes and exceptions separately for insufficient privileges or unsupported DML. - Before bulk changes, check the scope with `COUNT(*)` using the same condition. - For Append, check success/failure counts from close/server responses instead of SQL affected rows. ## Transactions Use explicit `BEGIN`, `COMMIT`, and `ROLLBACK` for relational DML on TRANSACTION tables. Do not assume LOG/TAG Append shares the same rollback scope. 1. Check whether the SDK provides a transaction API. 2. If not, execute supported transaction-control SQL on the same connection. 3. Verify rollback and connection reuse on error paths. 4. Leave no unfinished transaction when returning a pooled connection. 5. For mixed table types, verify each statement's commit scope in advance. See [TRANSACTION Table Transactions](/dbms/rdb-table-usage/transaction/) for complete SQL examples. ## Append APIs and Batches See [Data Ingestion and Export](../data-input-load-export/) for input choices and result checks, and the [SDK Append Matrix](../sdk-support-scope/#append-table-type-matrix) for client/table-type support. Separate Append and ordinary query connections, and check flush, close, and failed rows. ## Error Handling and Retries Classify errors as connection, authentication/authorization, SQL/schema, data, or resource exhaustion. - Retry only disconnects and transient timeouts, with bounded attempts and backoff. - Do not automatically retry authentication, privilege, syntax, or type errors before fixing them. - Clean up statements, cursors, Append handles, and connections before retrying. - Make INSERT retries idempotent with business keys or duplicate-handling policies. - Log server error codes and messages, excluding credentials and raw sensitive data. - Validate failed pooled connections before returning them, or discard them. See [Troubleshooting](/dbms/troubleshooting/) for operational error classification and diagnosis. --- title: "11.3 SDK Feature Support" url: https://docs.machbase.com/dbms/development-tools-integration/sdk-support-scope/ language: en kind: section --- # 11.3 SDK Feature Support Compare feature support and API entry points to choose an SDK for your application. See each SDK page for installation, connections, functions, and runnable examples. If choosing an SDK for the first time, read [Choose an Integration Method](../selection-integration-method/) first, then use this page to compare required features and exact API paths. ## Nullable Metadata Machbase reports SELECT result column nullability as `NO_NULLS`, `NULLABLE`, or `UNKNOWN`. Applications must handle NULL for both `NULLABLE` and `UNKNOWN`. | SDK | Retrieval method | |---|---| | JDBC | `ResultSetMetaData.isNullable()` | | Python | `cursor.description[i][6]` | | Go native | `api.Column.Nullability` | | Go `database/sql` | `Rows.ColumnTypeNullable()` | | Node.js | `ColumnMeta.nullable` | | .NET | `AllowDBNull` in `GetSchemaTable()` | | SQLCLI/ODBC | Descriptor nullable attribute | Expressions, aggregates, VIEWs, and JOIN results may report `UNKNOWN`. Do not equate a source column schema constraint with query result metadata. ## PRIMARY KEY Metadata | SDK | Result columns | Table catalog | |---|:---:|:---:| | JDBC | O | `DatabaseMetaData.getPrimaryKeys()` | | Python | O | Catalog SQL | | Go native | O | Catalog SQL | | Go `database/sql` | No standard API | Catalog SQL | | Node.js | O | Catalog SQL | | .NET | O | Catalog SQL | | ODBC | No separate result API | `SQLPrimaryKeys()` | Expressions, aggregates, and the NULL-supplying side of an outer join may not preserve the source column primary key attribute. ## ROWID from INSERT In Machbase 8.7.0 Standard Edition, a successful single `INSERT ... VALUES` can provide a ROWID to supported SDKs. | SDK/tool | Retrieval method | When absent | |---|---|---| | machsql | `SHOW LAST ROWID` | `NULL` | | Machbase SQLCLI | `SQLGetGeneratedRowID()` | `SQL_NO_DATA` | | Standard ODBC | No dedicated standard API | - | | JDBC | `Statement.getGeneratedKeys()` | Empty `ResultSet` | | Python | `cursor.lastrowid` | `None` | | .NET | `MachCommand.RowId` | `null` | | Go `database/sql` | `Result.LastInsertId()` | Error | | Go native | Unsupported | - | | Node.js | Execution result `rowId` | `undefined` | Batches, `executemany()`, Append, loaders, `INSERT ... SELECT`, and UPSERT do not return a single ROWID. See [ROWID](/dbms/reference/sql/rowid/) for SQL semantics and table-specific constraints. ## Append APIs and Table Types | API path | LOG | TAG | LOOKUP | VOLATILE | TRANSACTION | Basis | |---|:---:|:---:|:---:|:---:|:---:|---| | SQLCLI `SQLAppend*` extension | O | O | O | O | O | TRANSACTION requires Standard | | JDBC `MachStatement.executeAppend*` | O | O | O | O | O | NFX cce422d source/tests | | Python 2.4 `append*` | O | O | O | O | O | NFX cce422d source/tests | | .NET `MachAppendWriter` | O | O | O | O | O | NFX cce422d provider | | Go v1.8.4 native `Appender` | O | O | X | X | O | TRANSACTION requires Standard | | Go `database/sql` standard API | X | X | X | X | X | `sql.Conn.Raw()` extensions follow the native contract | | Node source `appendBatch()` | O | △ | △ | △ | O | NFX cce422d source build | | Node source `appendOpen()` | O | O | △ | △ | △ | Generic native/fallback path; table-specific validation required | Keep ordinary query connections and Append handle lifecycles distinct, and check close and flush results. `O` indicates support verified in the cited source/tests. `△` means only a generic path is available and further table-specific regression testing is needed. Append extensions are not standard ODBC or `database/sql` features. ### ARRAY and Selected-Column Append Machbase DBMS 8.7.0 ARRAY support is as follows: | SDK | Dense ARRAY retrieval/input | Sparse ARRAY | Selected-column Append | |---|:---:|:---:|:---:| | SQLCLI/C++ | O | O | O | | Machbase ODBC extension | O | O | O | | JDBC | O | O | O | | Python | O | O | O | | Node.js | O | O | O | | .NET full/legacy provider | O | O | O | | Go | v2 main source | v2 main source | v2 main source | Use a Machbase DBMS 8.7.0 server with an SDK build that includes ARRAY support. SQL ARRAY element positions and Machbase-specific SDK positions are 0-based. Existing full-row scalar Append APIs are unchanged. The Node.js prepared fallback also supports `SparseArray`. Go requires v2 main source after [`neo-client` PR #17](https://github.com/machbase/neo-client/pull/17); until a public v2 release is specified, do not assume a published module version provides support. See [Sparse ARRAY and Selected-Column Append API](../data-input-load-export/array-append/) for input methods and APIs. ## AUTH KEY | SDK/tool | Support | |---|:---:| | machsql, Machbase SQLCLI, ODBC, JDBC | O | | Go native, Go `database/sql` | O (neo-client v1.5.0+) | | Python, Node.js, .NET | X | See [AUTH KEY Authentication](/dbms/security-access-control/authentication-auth-key/) for key generation, registration, and rotation. See supported SDK pages for connection options. ## Transactions, Prepare, and Binding | SDK | Transaction API | Server prepared | Named bind API | |---|:---:|:---:|:---:| | JDBC | O | O | △ (Machbase extension) | | Python | X | O | O | | Go native | △ | O | O | | Go `database/sql` | O | O | O | | .NET | X | X | △ | | Node.js | X | O | O | | SQLCLI | △ | O | O | | ODBC | △ | O | Positional binding | Prepared statements and parameter binding are separate from transaction support. See [Named Bind Parameter](/dbms/reference/sql/syntax/named-bind-parameter-syntax/) for placeholder syntax. For TAG data UPDATE in Machbase 8.7.0 Standard Edition, existing positional/named SDK APIs can bind NAME and BASETIME predicate values. NFX #4127 regression tests cover C/C++ SQLCLI, Go `database/sql`, JDBC, Node.js, Python, and .NET. ODBC is not included in that SDK regression matrix; it binds `?` or named SQL placeholders by ordinal through standard `SQLBindParameter()`. See [TAG Data UPDATE Binding](/dbms/reference/sql/syntax/dml-syntax/tag-data-update-syntax/#tag-data-update-predicate-bind) for predicate requirements. `△` in the Transaction column means executing transaction SQL on the same connection instead of using a dedicated object. `△` in Named bind means a driver extension or a client path that converts values to SQL literals, rather than a standard named binding API. ## Verified Versions and Provenance | SDK | Verification basis | |---|---| | SQLCLI/JDBC/Python | NFX `cce422d2972`; Python package 2.4 | | Node.js | NFX `cce422d2972` source build (`package.json` 1.0.1) | | .NET | Uni 8.0.55, limited 3.1.3, full 3.2.2 | | Go | Released neo-client v1.8.4; AUTH KEY v1.5.0+, database selection v1.8.3+ | Some Node features in NFX cce422d were added after the public npm 1.0.1 release. Do not assume feature parity from the registry package version string. Check the artifact commit provenance or use an NFX source build. ARRAY and selected-column Append were verified against NFX `655d1333870313c4951698b89c9a3c9ada11d630` and merge commit `f756986c4836982723e2aa7727ec05b7e05e9707`. Use Machbase DBMS 8.7.0 as the server baseline and verified SDK artifacts containing those changes as the client baseline. ## SDK References | SDK | Detailed documentation | |---|---| | Machbase SQLCLI/ODBC | [SQLCLI and ODBC](../cli-odbc/) | | JDBC | [JDBC](../jdbc/) | | Python | [Python](../python/) | | Node.js / TypeScript | [Node.js / TypeScript](../node-js-typescript/) | | .NET Connector | [.NET Connector](../net-connector/) | | Go | [Go](../go/) | --- title: "11.4 Machbase SQLCLI and ODBC" url: https://docs.machbase.com/dbms/development-tools-integration/cli-odbc/ language: en kind: section --- # 11.4 Machbase SQLCLI and ODBC Machbase SQLCLI is a Call-Level Interface for C/C++ applications. The ODBC driver serves standard ODBC applications. Both interfaces share an execution flow based on environment, connection, and statement handles. SQLCLI adds extension functions for high-speed Append. ## Choose an Interface | Requirement | Interface | |----------|------------| | Develop C/C++ applications with the Machbase installation package | SQLCLI | | Use generic ODBC tools or a driver manager | ODBC | | Bulk ingestion through Append extensions | SQLCLI | | Execute standard SQL and retrieve results | SQLCLI or ODBC | ## Headers and Libraries Check the following files in the installation directory: ```bash test -f "$MACHBASE_HOME/include/machbase_sqlcli.h" test -f "$MACHBASE_HOME/lib/libmachbasecli_dll.so" ``` Example dynamic linking on Linux: ```bash gcc cli_quickstart.c -I"$MACHBASE_HOME/include" -L"$MACHBASE_HOME/lib" -lmachbasecli_dll -o cli_quickstart LD_LIBRARY_PATH="$MACHBASE_HOME/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" MACHBASE_PASSWORD='your-password' ./cli_quickstart ``` Base production builds on the installation package's `install/machbase_env.mk` and platform-specific linker settings. ## Connection Strings The basic SQLCLI connection string uses these keys: ```text SERVER=127.0.0.1;PORT_NO=5656;UID=APP_USER;PWD=secret;CONNTYPE=1 ``` For an ODBC data source, specify the DSN, user, and password. ```text DSN=MACHBASE;UID=APP_USER;PWD=secret ``` Drivers that support an initial database for multi-database operation accept `DATABASE` or `DBNAME`. Check support in the deployed driver, then run `SELECT CURRENT_DATABASE()` after connecting to verify the selection. ## Quick Start This program connects to port 5656, queries a system table, and releases all handles. The password is supplied through an environment variable. ```c #include #include #include int main(void) { SQLHENV env = SQL_NULL_HENV; SQLHDBC dbc = SQL_NULL_HDBC; SQLHSTMT stmt = SQL_NULL_HSTMT; char conn[512]; const char *password = getenv("MACHBASE_PASSWORD"); if (password == NULL) { fputs("MACHBASE_PASSWORD is required\n", stderr); return 2; } snprintf(conn, sizeof(conn), "SERVER=127.0.0.1;PORT_NO=5656;" "UID=SYS;PWD=%s;CONNTYPE=1", password); if (SQLAllocEnv(&env) != SQL_SUCCESS) { return 3; } if (SQLAllocConnect(env, &dbc) != SQL_SUCCESS) { SQLFreeEnv(env); return 4; } if (SQLDriverConnect( dbc, NULL, (SQLCHAR *)conn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT) != SQL_SUCCESS) { SQLFreeConnect(dbc); SQLFreeEnv(env); return 5; } if (SQLAllocStmt(dbc, &stmt) != SQL_SUCCESS) { SQLDisconnect(dbc); SQLFreeConnect(dbc); SQLFreeEnv(env); return 6; } if (SQLExecDirect( stmt, (SQLCHAR *)"SELECT COUNT(*) FROM V$TABLES", SQL_NTS) != SQL_SUCCESS) { SQLFreeStmt(stmt, SQL_DROP); SQLDisconnect(dbc); SQLFreeConnect(dbc); SQLFreeEnv(env); return 7; } puts("query succeeded"); SQLFreeStmt(stmt, SQL_DROP); SQLDisconnect(dbc); SQLFreeConnect(dbc); SQLFreeEnv(env); return 0; } ``` To report failures, read SQLSTATE, the native error code, and the message using `SQLGetDiagRec()` or `SQLError()` in existing code. ## Standard Execution Flow 1. Allocate environment and connection handles. 2. Connect with `SQLDriverConnect()` or `SQLConnect()`. 3. Allocate a statement handle. 4. Execute SQL with `SQLPrepare()` and `SQLExecute()`, or `SQLExecDirect()`. 5. Read SELECT results with `SQLBindCol()` and `SQLFetch()`. 6. Release statement, connection, and environment resources in that order. Bind input with `SQLBindParameter()` instead of concatenating strings. Check nullability with the last argument of `SQLDescribeCol()` or with `SQLColAttribute(..., SQL_DESC_NULLABLE, ...)`. ## Named Bind Parameter If the server and driver support named parameters, use `:name` placeholders and `SQLBindParameterByName()`. A repeated name binds one value to all matching positions. See [Named Bind Parameter](/dbms/reference/sql/syntax/named-bind-parameter-syntax/) for common constraints and examples. When support is unverified, use standard `?` placeholders and `SQLBindParameter()`. ## ROWID from INSERT To obtain the generated ROWID after a successful single `INSERT ... VALUES` in Standard Edition, use the following: - SQLCLI extension: `SQLGetGeneratedRowID()` - Standard ODBC: no standard API dedicated to generated ROWID Do not assume the same return behavior for batches, Append, `INSERT ... SELECT`, or UPSERT. See [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/) for the exact scope. ## Append Extensions High-speed ingestion uses an Append flow separate from ordinary statements. | Step | Main functions | |------|-----------| | Open | `SQLAppendOpen()`; `SQLAppendOpenColumns()`/`W()` for selected columns | | Send a row | `SQLAppendDataV2()` or an Append function supported by the version | | Send a batch | `SQLAppendBatch()` | | Flush to the server | `SQLAppendFlush()` | | Error callback | `SQLAppendSetErrorCallback()` | | Close | `SQLAppendClose()` | Append column order and types must match the target schema exactly. Represent strings, binary data, IP addresses, DATETIME, and NULL according to `SQL_APPEND_PARAM` in the installed `machbase_sqlcli.h`. Record failed rows and server errors in the callback, without logging passwords or raw sensitive data. Do not share a connection with an active Append handle with ordinary queries. Check success and failure counts returned by close. ## Threads and Resource Management - Use separate connections and statements per thread. - Do not use a statement or Append handle concurrently from multiple threads. - Provide cleanup routines that release handles in reverse order on every error path. - Before retrying, ensure the previous connection and Append state are fully closed. - Record both success and failure counts for bulk ingestion. ## Check API Details The installed `$MACHBASE_HOME/include/machbase_sqlcli.h` is the reference for function prototypes, constants, and structures matching the library. Do not mix examples with headers from another version. Include compilation, linking, and a port 5656 connection test in the deployment pipeline. ## DECIMAL Append For `DECIMAL` or `NUMERIC` input through `SQLAppendDataV2()` and `SQLAppendBatch()`, use the 32-byte opaque `SQL_APPEND_NUMERIC` type and its public constructors. Do not create or modify its internal bytes in application code. | Input | Function | |---|---| | UTF-8 numeric string | `SQLAppendNumericFromString()` | | Signed/unsigned integer | `SQLAppendNumericFromInt64()`, `SQLAppendNumericFromUInt64()` | | `SQL_NUMERIC_STRUCT` | `SQLAppendNumericFromSQLNumeric()` | | NULL | `SQLAppendNumericSetNull()` | Prefer strings or `SQL_NUMERIC_STRUCT` to preserve exact values. Specify `SQL_APPEND_TYPE_NUMERIC` or `SQL_APPEND_TYPE_DECIMAL` in the type array. Check overflow and rounding against the target column precision and scale. ## ARRAY and Selected-Column Append Machbase DBMS 8.7.0 supports typed ARRAY retrieval and binding with `SQL_MACHBASE_ARRAY_DESC`, and sparse input with `SQL_MACHBASE_SPARSE_ARRAY_DESC`. Standard Open can also pass a sparse descriptor to an ARRAY column. ```c SQLAppendOpen(statement, (SQLCHAR *)"ARRAY_APPEND_FULL_EXAMPLE", 0); row[0].mLong = 1; row[1].mVar.mData = &sparse; row[1].mVar.mLength = SQL_APPEND_SPARSE_ARRAY_DESC_LENGTH; SQLAppendDataV3(statement, row, 2); SQLAppendClose(statement, &success, &failure); ``` This code follows the input order of a table with `ID LONG, A INT32[4]`. Start with the [complete standard Open example](../data-input-load-export/array-append/#c-full-open), including connection, descriptor and buffer setup, and error handling. This differs from passing descriptors to the legacy `SQLAppendData(void *[])` API. To select specific columns or fixed ARRAY elements, use `SQLAppendOpenColumns()` or `SQLAppendOpenColumnsW()`. ```c SQLCHAR *targets[] = { (SQLCHAR *)"ID", (SQLCHAR *)"CHANNELS[0]", (SQLCHAR *)"CHANNELS[3]", NULL }; SQLAppendOpenColumns(statement, (SQLCHAR *)"SENSOR_ARRAY", targets, 0); ``` ARRAY element targets and sparse descriptor positions are 0-based. The column-name list must end with `NULL`. `SQLAppendBatch()` does not support ARRAY. See [Sparse ARRAY and Selected-Column Append API](../data-input-load-export/array-append/) for descriptor definitions, whole-array and element NULL handling, and direct ODBC handle restrictions. --- title: "11.5 JDBC" url: https://docs.machbase.com/dbms/development-tools-integration/jdbc/ language: en kind: section --- # 11.5 JDBC The Machbase JDBC driver provides core JDBC 4.2 APIs with a Java 8 baseline. Use standard JDBC APIs for connections, PreparedStatements, typed retrieval and binding, database metadata, local transactions, and connection pools. | Item | Value | |------|----| | Java bytecode baseline | Java 8 | | Reported JDBC version | 4.2 | | Driver version | 3.0.0 | | JDBC URL | `jdbc:machbase:///[database]` | | `Driver.jdbcCompliant()` | `false` | A `false` result from `jdbcCompliant()` concerns full SQL-92 Entry Level compliance, not JDBC 4.2 API support. Check required optional features through `DatabaseMetaData` capability methods. ## Multiple Databases Specify the initial database in the URL path or the `database` connection property. ```java String url = "jdbc:machbase://127.0.0.1:5656/factory_a"; Connection conn = DriverManager.getConnection(url, "APP_A", password); System.out.println(conn.getCatalog()); conn.setCatalog("FACTORY_A"); ``` `getCatalog()` and `setCatalog()` synchronize with the server's current database. If both the URL path and property specify a database, their values must match. In JDBC metadata, a catalog is a database and a schema is an owner. Check that pooled connections restore the initial catalog when returned. Prepared statements and append handles remain bound to the database in which they were created. ## Install the Driver ### Use a JAR File Add `machbase.jar` from the Machbase installation directory to the classpath. ```bash ls -l "$MACHBASE_HOME/lib/machbase.jar" javac -classpath ".:$MACHBASE_HOME/lib/machbase.jar" MyApp.java java -classpath ".:$MACHBASE_HOME/lib/machbase.jar" MyApp ``` The JAR includes `META-INF/services/java.sql.Driver`. In JDBC 4.0 and later environments, the driver registers automatically without `Class.forName("com.machbase.jdbc.MachDriver")`. Existing explicit calls remain valid. ### Maven ```xml com.machbase machjdbc {{< jdbc_version >}} ``` ### Gradle ```groovy dependencies { implementation 'com.machbase:machjdbc:{{< jdbc_version >}}' } ``` Check artifact versions in [Maven Central](https://mvnrepository.com/artifact/com.machbase/machjdbc). The runtime metadata version `3.0.0` and distribution artifact versions use different versioning schemes. ## Connect to the Server Supply user names and passwords through environment variables or a secret manager instead of embedding them in source code. ```java import java.sql.Connection; import java.sql.DriverManager; import java.util.Properties; String url = "jdbc:machbase://127.0.0.1:5656/machbasedb"; Properties properties = new Properties(); properties.setProperty("user", "SYS"); properties.setProperty("password", System.getenv("MACHBASE_PASSWORD")); try (Connection connection = DriverManager.getConnection(url, properties)) { // Execute SQL. } ``` ### Connection Options Specify connection options through `Properties` or URL query parameters. Set `randomHost` in `Properties`, or use `^` separators in a multi-host URL. | Option | Description | |------|------| | `user`, `password` | Password authentication credentials | | `TIMEZONE` | Session time zone in `+0900` format | | `randomHost` | Selects the first connection host randomly from the list | | `maxStatements` | Maximum cached Statements for a pooled connection | | `CONNECTION_TIMEOUT` | Socket connection timeout in seconds; `0` means unlimited | | `SOCKET_TIMEOUT` | Socket read timeout in seconds; `0` means unlimited | | `characterEncoding` | Client character encoding | | `AUTH_MODE` | `PASSWORD` or `CHALLENGE` | | `AUTH_SIG_SCHEME` | `ECDSA`, `RSA_PKCS1_V15`, `RSA_PSS` | | `AUTH_KEY_FILE` | Path to a PEM private key file | ```java String url = "jdbc:machbase://127.0.0.1:5656/machbasedb?TIMEZONE=+0900"; ``` ### Multiple Hosts The Machbase 8.7.0 JDBC driver accepts multiple hosts in one URL. | Selection | Syntax | Behavior | |-----------|-----------|------| | Sequential | Separate hosts with `,` | Attempts connections in URL order | | Random start | Separate hosts with `^` | Randomly selects the first host | | Random start | Set `randomHost=true` in `Properties` | Randomly selects the first host from a comma-separated list | This URL tries `db2` if connecting to `db1` fails: ```java String url = "jdbc:machbase://db1.example.com:5656,db2.example.com:5656/" + "machbasedb?CONNECTION_TIMEOUT=5"; ``` The `^` separator selects the first host randomly: ```java String url = "jdbc:machbase://db1.example.com:5656^db2.example.com:5656/" + "machbasedb?CONNECTION_TIMEOUT=5"; ``` When using the `randomHost` property, separate hosts with commas: ```java Properties properties = new Properties(); properties.setProperty("randomHost", "true"); String url = "jdbc:machbase://db1.example.com:5656,db2.example.com:5656/" + "machbasedb?CONNECTION_TIMEOUT=5"; ``` - Do not mix `,` and `^` separators in one URL. - Connection-stage I/O errors, such as connection refusal, connection timeout, or socket errors, cause an attempt to the next host. If all hosts fail, `DriverManager.getConnection()` throws `SQLException`. - `CONNECTION_TIMEOUT` applies per host attempt. Total connection wait time can therefore increase with the number of hosts and their response times. - `SOCKET_TIMEOUT` limits reads on the connected socket; it does not change host selection order. Multi-host failover applies to socket establishment for new connections or reconnections. Even if automatic reconnection succeeds after a disconnect, do not reuse earlier Statements, PreparedStatements, or ResultSets. It does not guarantee whether in-flight SQL succeeded or can be safely retried. On a connection error in an active transaction, discard the connection and retry the entire transaction according to the application idempotency policy. ## AUTH KEY Authentication Public-key challenge authentication signs the server challenge with a local private key instead of using a password. ```java Properties properties = new Properties(); properties.setProperty("user", "app_user"); properties.setProperty("AUTH_MODE", "CHALLENGE"); properties.setProperty("AUTH_SIG_SCHEME", "ECDSA"); properties.setProperty( "AUTH_KEY_FILE", "/opt/machbase/keys/app_user_ecdsa.pem"); Connection connection = DriverManager.getConnection( "jdbc:machbase://127.0.0.1:5656/machbasedb", properties); ``` - `AUTH_MODE=CHALLENGE` does not use `password` for authentication. - `AUTH_KEY_FILE` is required. - If `AUTH_SIG_SCHEME` is omitted, a default scheme is selected for the key type. - On POSIX systems, restrict private key file permissions to `600`. ## Quick Start This example inserts values into a LOG table and queries them. ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; public class JdbcQuickStart { public static void main(String[] args) throws Exception { Properties properties = new Properties(); properties.setProperty("user", "SYS"); properties.setProperty( "password", System.getenv("MACHBASE_PASSWORD")); try (Connection connection = DriverManager.getConnection( "jdbc:machbase://127.0.0.1:5656/machbasedb", properties); Statement statement = connection.createStatement()) { statement.execute( "CREATE LOG TABLE jdbc_sensor " + "(ts DATETIME, name VARCHAR(40), value DOUBLE)"); try (PreparedStatement insert = connection.prepareStatement( "INSERT INTO jdbc_sensor VALUES (?, ?, ?)")) { insert.setLong(1, System.currentTimeMillis() * 1_000_000L); insert.setString(2, "sensor-1"); insert.setDouble(3, 25.3); insert.executeUpdate(); } try (ResultSet result = statement.executeQuery( "SELECT name, value FROM jdbc_sensor")) { while (result.next()) { System.out.printf("%s %.1f%n", result.getString("NAME"), result.getDouble("VALUE")); } } } } } ``` Use `long` to pass DATETIME values as epoch nanoseconds. If the example table already exists, omit `CREATE LOG TABLE` or use a different name. ## ROWID from INSERT After a successful single `INSERT ... VALUES` in Standard Edition, use the standard JDBC generated keys API to retrieve the inserted row's ROWID. ```java String sql = "INSERT INTO jdbc_sensor VALUES (?, ?, ?)"; try (PreparedStatement insert = connection.prepareStatement( sql, Statement.RETURN_GENERATED_KEYS)) { insert.setLong(1, System.currentTimeMillis() * 1_000_000L); insert.setString(2, "sensor-2"); insert.setDouble(3, 26.1); insert.executeUpdate(); try (ResultSet keys = insert.getGeneratedKeys()) { if (keys.next()) { java.sql.RowId rowId = keys.getRowId("ROWID"); } } } ``` The result has one `ROWID` column and at most one row. If there is no ROWID to return, the `ResultSet` is empty. Check `DatabaseMetaData.supportsGetGeneratedKeys()` for support. See [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/) for differences in batches, Append, `INSERT ... SELECT`, and UPSERT. ## Check Versions ```java import java.sql.DatabaseMetaData; DatabaseMetaData metadata = connection.getMetaData(); System.out.println(metadata.getDriverName()); System.out.println(metadata.getDriverVersion()); System.out.println(metadata.getJDBCMajorVersion()); // 4 System.out.println(metadata.getJDBCMinorVersion()); // 2 ``` ## Related Documents | Document | Content | |------|------| | [PreparedStatement and Types](./prepared-types/) | Parameter metadata, named binding, SQLType, NULL, and type conversion | | [ResultSet, Statement, and LOB](./resultset-lob/) | Typed retrieval, streams, LOBs, timeouts, and resource management | | [Transactions and Connection Pools](./transaction-pooling/) | Standard local transactions, DataSource, and connection pools | | [DatabaseMetaData](./database-metadata/) | Tables, columns, keys, indexes, and capabilities | | [Append API](./append-api/) | High-speed ingestion through `MachStatement` | | [Migration and Troubleshooting](./migration-troubleshooting/) | Migration from earlier drivers, unsupported features, and error handling | --- title: "11.5.1 PreparedStatement and Types" url: https://docs.machbase.com/dbms/development-tools-integration/jdbc/prepared-types/ language: en kind: page --- # 11.5.1 PreparedStatement and Types PreparedStatement prepares SQL on the server and executes it repeatedly with different parameter values. Machbase JDBC supports standard positional parameters and a named-parameter extension. ## ParameterMetaData Use `PreparedStatement.getParameterMetaData()` to inspect parameter counts and types before execution. The same API applies to INSERT, UPDATE, and SELECT. ```java import java.sql.ParameterMetaData; import java.sql.PreparedStatement; try (PreparedStatement statement = connection.prepareStatement( "INSERT INTO sensor_tx " + "(id, value, created_at) VALUES (?, ?, ?)")) { ParameterMetaData metadata = statement.getParameterMetaData(); for (int index = 1; index <= metadata.getParameterCount(); index++) { System.out.printf( "%d: type=%s precision=%d scale=%d nullable=%d%n", index, metadata.getParameterTypeName(index), metadata.getPrecision(index), metadata.getScale(index), metadata.isNullable(index)); } } ``` Parameter indexes start at 1. An index of 0 or greater than the parameter count raises `SQLException`. Interpret precision according to the type: for numeric types, it is the JDBC number of decimal digits, not storage size in bytes. DATETIME maps to `java.sql.Types.TIMESTAMP`, but its database type name is `DATETIME`. ## Named Bind Parameter The `:name` placeholder and `MachPreparedStatement.setObject(String, Object)` are Machbase extensions. When a name occurs more than once, the value is bound to every matching position. ```java import com.machbase.jdbc.MachPreparedStatement; try (MachPreparedStatement statement = (MachPreparedStatement) connection.prepareStatement( "SELECT id FROM sensor_tx " + "WHERE id = :id OR parent_id = :id")) { statement.setObject("id", Integer.valueOf(10)); try (ResultSet result = statement.executeQuery()) { while (result.next()) { System.out.println(result.getInt("ID")); } } } ``` - Names may include or omit the leading colon. - Names are case-sensitive. - Do not mix named setters and numeric-index setters in one statement. - An unknown name or mixed named/positional binding raises SQLState `07009`. - An older server without named binding support raises SQLState `0A000`. For portability, use the JDBC standard `?` placeholder and numeric-index setters. See [Named Bind Parameter](/dbms/reference/sql/syntax/named-bind-parameter-syntax/) for the shared syntax. ## Reexecute a Prepared SELECT You can execute SELECT repeatedly with the same PreparedStatement. Close the previous ResultSet and bind new values; the next execution returns a new ResultSet. ```java try (PreparedStatement statement = connection.prepareStatement( "SELECT id, name FROM sensor_tx WHERE id = ?")) { ResultSetMetaData metadata = statement.getMetaData(); System.out.println(metadata.getColumnCount()); for (int id = 1; id <= 2; id++) { statement.setInt(1, id); try (ResultSet result = statement.executeQuery()) { while (result.next()) { System.out.println(result.getString("NAME")); } } } } ``` Machbase JDBC does not support multiple open results on one Statement. Consume and close each ResultSet before the next execution. You can retrieve prepare-time `ResultSetMetaData` again while the Statement remains open. ## JDBC 4.2 SQLType Binding Use Java 8 `JDBCType` to specify a parameter SQL type. ```java import java.math.BigDecimal; import java.sql.JDBCType; import java.sql.Timestamp; try (PreparedStatement statement = connection.prepareStatement( "INSERT INTO sensor_tx " + "(id, name, value, created_at, payload) " + "VALUES (?, ?, ?, ?, ?)")) { statement.setObject(1, Integer.valueOf(1), JDBCType.INTEGER); statement.setObject(2, "sensor-1", JDBCType.VARCHAR); statement.setObject( 3, new BigDecimal("12.3400"), JDBCType.DECIMAL, 4); statement.setObject( 4, Timestamp.valueOf("2026-07-26 10:00:00"), JDBCType.TIMESTAMP); statement.setObject(5, new byte[] {1, 2, 3}, JDBCType.BINARY); statement.executeUpdate(); } ``` An unknown vendor `SQLType` raises `SQLFeatureNotSupportedException`. Use `BigDecimal` for DECIMAL and NUMERIC; values are bound with the specified scale. ### SQL NULL `setNull()` or `setObject(index, null, JDBCType)` sends SQL NULL for the target type. The following types also support typed NULL: - `REAL`, `BIT`, `TINYINT`, `BOOLEAN` - `VARBINARY`, `LONGVARBINARY`, `BLOB`, `CLOB` - `LONGVARCHAR` NULL for an unsigned parameter is converted to the native NULL value using ParameterMetaData. The wire NULL sentinel, one greater than the maximum unsigned data value, cannot be stored as data. Passing that value raises SQLState `22003`. | Machbase type | Java type | Data range | |---------------|-----------|-------------| | `USHORT` | `Integer` | 0–65534 | | `UINTEGER` | `Long` | 0–4294967294 | | `ULONG` | `BigInteger` | 0–18446744073709551614 | Use `setNull()` to insert NULL instead of passing the sentinel directly. ## Boolean `setBoolean()` and `setObject(index, value, JDBCType.BOOLEAN)` send 1 for `true` and 0 for `false`. String input accepts only `true` and `false`, case-insensitively. Other values raise SQLState `22018`. ## IPv4 and IPv6 Use the `MachPreparedStatement` extension setters for IP address columns. ```java MachPreparedStatement statement = (MachPreparedStatement) connection.prepareStatement( "INSERT INTO net_log(ts, src_ip, dst_ip) VALUES (?, ?, ?)"); statement.setLong(1, System.currentTimeMillis() * 1_000_000L); statement.setIpv4(2, "192.168.1.100"); statement.setIpv6(3, "::1"); statement.executeUpdate(); ``` ## Nullable Metadata `ParameterMetaData.isNullable()` returns `parameterNoNulls`, `parameterNullable`, or `parameterNullableUnknown`. Do not interpret `parameterNullableUnknown` as NOT NULL. See [Nullable Metadata Support](/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-nullable-metadata) for rules for each SQL statement. --- title: "11.5.2 ResultSet, Statement, and LOB" url: https://docs.machbase.com/dbms/development-tools-integration/jdbc/resultset-lob/ language: en kind: page --- # 11.5.2 ResultSet, Statement, and LOB Machbase JDBC ResultSet is a forward-only, read-only cursor. Close Connections, Statements, and ResultSets with try-with-resources. ```java statement.getResultSetType(); // ResultSet.TYPE_FORWARD_ONLY statement.getResultSetConcurrency(); // ResultSet.CONCUR_READ_ONLY ``` Scrollable and updatable ResultSets are not supported. Getter calls before `next()`, after the last row, or after close, and out-of-range column indexes raise `SQLException`. ## Typed Retrieval Both `getObject(index, Class)` and `getObject(label, Class)` are supported. ```java import java.math.BigDecimal; import java.sql.Timestamp; try (ResultSet result = statement.executeQuery( "SELECT id, value, created_at FROM sensor_tx")) { while (result.next()) { Integer id = result.getObject("ID", Integer.class); BigDecimal value = result.getObject("VALUE", BigDecimal.class); Timestamp createdAt = result.getObject("CREATED_AT", Timestamp.class); } } ``` | Java type | Typical Machbase type | |-----------|-------------------------| | `String` | CHAR, VARCHAR, TEXT, IPV4, IPV6, JSON | | `Short`, `Integer`, `Long` | Integer types | | `Float`, `Double` | Floating-point types | | `BigDecimal` | DECIMAL, NUMERIC | | `Boolean` | BOOLEAN | | `Timestamp`, `Date`, `Time` | DATETIME | | `byte[]` | BINARY | | `Blob`, `Clob` | BLOB, CLOB | Object getters return Java `null` for SQL NULL. Primitive getters return 0 or `false`; call `wasNull()` immediately afterward to check for SQL NULL. Unsupported conversions and a null target class raise `SQLException`. In Machbase SQL, the empty string literal `''` is SQL `NULL`. For that result column, `ResultSetMetaData.isNullable()` returns `columnNullable`, and `getObject()` returns `null`. The literal `''''` is a single quote character, so it is a non-NULL string. The default object mappings for unsigned types are: | Machbase type | `getObject()` return type | |---------------|-------------------------| | `USHORT` | `Integer` | | `UINTEGER` | `Long` | | `ULONG` | `BigInteger` | `SHORT` returns an `Integer` object; 32-bit `FLOAT` returns a `Float` object. BOOLEAN strings accept only `true` and `false`. ## Character and Binary Streams `setAsciiStream()`, `setBinaryStream()`, and `setCharacterStream()` provide overloads with `int` length, `long` length, or no length. `setNCharacterStream()` and `setNString()` are aliases for the VARCHAR path, not a separate NCHAR storage type. ResultSet supports the following getters by index or column name: - `getAsciiStream()`, `getBinaryStream()` - `getCharacterStream()`, `getNCharacterStream()` - `getNString()` Input shorter than its declared length, a negative length, or a length greater than `Integer.MAX_VALUE` raises `SQLException`. Streams currently materialize in client memory; do not use them for constant-memory streaming of large values. ## BLOB and CLOB Use standard `Blob` and `Clob` objects to retrieve and bind BLOB/CLOB columns in LOG tables. ```java import java.io.ByteArrayInputStream; import java.io.StringReader; import java.sql.Blob; import java.sql.Clob; try (PreparedStatement insert = connection.prepareStatement( "INSERT INTO event_log (payload, message) VALUES (?, ?)")) { insert.setBlob(1, new ByteArrayInputStream(payload)); insert.setClob(2, new StringReader(message)); insert.executeUpdate(); } try (ResultSet result = statement.executeQuery( "SELECT payload, message FROM event_log")) { while (result.next()) { Blob payloadObject = result.getBlob("PAYLOAD"); Clob messageObject = result.getClob("MESSAGE"); byte[] payloadBytes = payloadObject.getBytes( 1, (int) payloadObject.length()); String messageText = messageObject.getSubString( 1, (int) messageObject.length()); payloadObject.free(); messageObject.free(); } } ``` Create mutable objects with `Connection.createBlob()` and `createClob()`, then use `setBytes()`, `setString()`, `setBinaryStream()`, `setCharacterStream()`, or `truncate()`. Call `free()` when finished. LOB positions are 1-based, as required by JDBC. The entire requested partial-stream range must fit within the value. A range beyond the end raises SQLState `22003` instead of returning a truncated result. A negative length or a length that a Java array cannot represent raises `HY090`. Reusing an object after `free()` raises `SQLException`. LOBs materialize the entire value in client memory. This is not a streaming LOB implementation that processes values of hundreds of MiB or more with constant memory. ## ResultSet Metadata Use `ResultSetMetaData.isNullable()` to inspect nullability of SELECT result columns. ```java ResultSetMetaData metadata = result.getMetaData(); int nullable = metadata.isNullable(columnIndex); ``` `columnNullableUnknown` does not mean NOT NULL. Check table column constraints with `DatabaseMetaData.getColumns()` and retrieve PRIMARY KEY information separately with `DatabaseMetaData.getPrimaryKeys()`. ## Row Counts and Fetch Settings The JDBC 4.2 large update API returns affected-row counts as `long`. ```java long count = statement.executeLargeUpdate( "DELETE FROM sensor_tx WHERE id < 100"); long[] counts = statement.executeLargeBatch(); ``` `setLargeMaxRows()` and `getLargeMaxRows()` are also available. `setMaxRows()` or `setLargeMaxRows()` limits the number of rows retrieved from a ResultSet without changing the Statement `fetchSize`. ## Statement Lifecycle - With `closeOnCompletion()`, the Statement closes when its last ResultSet closes. - Close the previous ResultSet before reexecuting a Statement. - Commit closes ResultSets, but Statements and PreparedStatements remain reusable. - Do not call `next()` and getters concurrently from multiple threads on one ResultSet. ## Cancellation and Query Timeout `Statement.cancel()` cancels the current statement through a separate session. If no statement is running, it does nothing. PreparedStatement bindings and metadata are preserved. When `setQueryTimeout(seconds)` expires, it raises `SQLTimeoutException` with SQLState `HYT00`. After handling the exception, you can reuse the Statement for the next query. A timeout task from a previous execution does not cancel the next execution. To run independent queries in parallel, obtain one logical Connection per worker from a connection pool instead of sharing one Connection. To stop an ongoing fetch, another thread may call `close()`, `cancel()`, or `Connection.abort()`. --- title: "11.5.3 Transactions and Connection Pools" url: https://docs.machbase.com/dbms/development-tools-integration/jdbc/transaction-pooling/ language: en kind: page --- # 11.5.3 Transactions and Connection Pools Machbase JDBC supports standard JDBC local transactions on Standard Edition TRANSACTION tables. Cluster Edition has no TRANSACTION tables, so the transaction features on this page do not apply. ## Create a TRANSACTION Table ```sql CREATE TRANSACTION TABLE sensor_tx ( id INTEGER PRIMARY KEY, parent_id INTEGER, name VARCHAR(64), value DECIMAL(20, 4), created_at DATETIME, payload BINARY ); ``` ## Commit and Rollback Use `setAutoCommit(false)`, `commit()`, and `rollback()`. Applications do not need to send SQL `BEGIN` explicitly. ```java import java.sql.PreparedStatement; import java.sql.SQLException; connection.setAutoCommit(false); try (PreparedStatement statement = connection.prepareStatement( "INSERT INTO sensor_tx (id, value) VALUES (?, ?)")) { statement.setInt(1, 1); statement.setBigDecimal(2, new BigDecimal("10.5000")); statement.executeUpdate(); connection.commit(); } catch (SQLException exception) { try { connection.rollback(); } catch (SQLException rollbackException) { exception.addSuppressed(rollbackException); } throw exception; } ``` `setAutoCommit(false)` does not send `BEGIN` immediately. The transaction starts when the first Statement runs in manual mode. After commit or rollback, auto-commit remains `false`, and the next Statement starts a new transaction. - Switching to `setAutoCommit(true)` first commits any active transaction. - Calling `commit()` or `rollback()` when auto-commit is `true` raises SQLState `25000`. - Closing a Connection rolls back unfinished transactions. - Commit and rollback close open ResultSets; Statements remain reusable. ## Isolation Level and Cursors The supported isolation level is `Connection.TRANSACTION_SERIALIZABLE`. Requesting another level raises `SQLFeatureNotSupportedException`. The supported holdability is `ResultSet.CLOSE_CURSORS_AT_COMMIT`. Consume required results before committing, or execute the query again after commit. ## Behavior by Table Type | Operation | Behavior in a manual transaction | |------|--------------------------| | TRANSACTION table DML/SELECT | Participates in the transaction. | | LOG/TAG table SELECT | Allowed. | | First LOG DML before a TRANSACTION change | May be reexecuted with auto-commit through the compatibility path. | | Standalone TAG DML | Participates in the transaction and can be rolled back. | | LOG/TAG DML or DDL after a TRANSACTION change | Raises an error. | LOG DML reexecuted with auto-commit through the compatibility path cannot be rolled back later. Use TRANSACTION tables for data that requires rollback. Normal commit and rollback across multiple TRANSACTION tables are supported, but global atomicity is not guaranteed if a failure occurs during backend commit. Keep critical atomic operations within one TRANSACTION table. ## DataSource Use `MachDataSource` to supply connection properties to an application server or framework. ```java import com.machbase.jdbc.MachDataSource; import java.sql.Connection; MachDataSource dataSource = new MachDataSource(); dataSource.setUrl("jdbc:machbase://127.0.0.1:5656/machbasedb"); dataSource.setUser("SYS"); dataSource.setPassword(System.getenv("MACHBASE_PASSWORD")); dataSource.setLoginTimeout(10); try (Connection connection = dataSource.getConnection()) { // Execute SQL. } ``` DataSource supports the URL, user, password, login timeout, log writer, and JDBC `Wrapper` contract. ## ConnectionPoolDataSource `MachConnectionPoolDataSource` returns logical Connections without exposing physical connections. ```java import com.machbase.jdbc.MachConnectionPoolDataSource; import java.sql.Connection; import javax.sql.PooledConnection; MachConnectionPoolDataSource source = new MachConnectionPoolDataSource(); source.setUrl("jdbc:machbase://127.0.0.1:5656/machbasedb"); source.setUser("SYS"); source.setPassword(System.getenv("MACHBASE_PASSWORD")); PooledConnection pooled = source.getPooledConnection(); try { try (Connection logical = pooled.getConnection()) { // Use the logical connection. } } finally { pooled.close(); } ``` Only one logical handle is active per PooledConnection. Closing a logical Connection resets the following state, then fires `connectionClosed` once: - Roll back unfinished transactions - Restore auto-commit - Restore the initial catalog determined by the URL - Restore the network timeout The next connection lease is not issued until calls on the closing logical handle finish. A closed Connection, Statement, or DatabaseMetaData cannot be reused in the next lease; doing so raises SQLState `08003`. Statement pooling is not supported. A fatal connection error in SQLState class `08` discards the physical connection and fires `connectionErrorOccurred`. Class `23` errors, such as duplicate keys, do not indicate a damaged connection and do not fire a connection error event. ## HikariCP ```java import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:machbase://127.0.0.1:5656/machbasedb"); config.setUsername("SYS"); config.setPassword(System.getenv("MACHBASE_PASSWORD")); config.setMaximumPoolSize(10); config.setMinimumIdle(2); config.setConnectionTimeout(30_000); config.setIdleTimeout(600_000); config.setMaxLifetime(1_800_000); config.addDataSourceProperty("TIMEZONE", "+0900"); try (HikariDataSource dataSource = new HikariDataSource(config); Connection connection = dataSource.getConnection()) { // Execute SQL. } ``` Return logical Connections promptly with try-with-resources. Do not retain returned handles. ## Network timeout `setNetworkTimeout(executor, milliseconds)` sets the socket read timeout in milliseconds; `0` means no limit. A negative value, null executor, or executor that rejects tasks raises `SQLException`. An actual network timeout raises an exception in SQLState class `08` and invalidates the physical connection. Obtain a new connection instead of reusing Statements or ResultSets from the failed connection. I/O failures in active transactions are not retried automatically. --- title: "11.5.4 DatabaseMetaData" url: https://docs.machbase.com/dbms/development-tools-integration/jdbc/database-metadata/ language: en kind: page --- # 11.5.4 DatabaseMetaData `Connection.getMetaData()` returns information about the driver, server, schema objects, and JDBC capabilities. Result columns use JDBC standard names and ordering; read columns by name rather than numeric position. ```java import java.sql.DatabaseMetaData; DatabaseMetaData metadata = connection.getMetaData(); System.out.println(metadata.getDriverName()); System.out.println(metadata.getDriverVersion()); System.out.println(metadata.getDatabaseProductName()); System.out.println(metadata.getDatabaseProductVersion()); ``` ## Tables and Views ```java try (ResultSet tables = metadata.getTables( null, null, "%", new String[] {"TABLE", "VIEW"})) { while (tables.next()) { System.out.printf("%s %s%n", tables.getString("TABLE_NAME"), tables.getString("TABLE_TYPE")); } } ``` `getTables()` distinguishes TABLE from VIEW. See `REMARKS` for the specific Machbase table type. Applications should use standard column names instead of depending on column positions. ## Columns ```java try (ResultSet columns = metadata.getColumns( null, null, "SENSOR_TX", "%")) { while (columns.next()) { System.out.printf( "%s %s size=%d nullable=%s%n", columns.getString("COLUMN_NAME"), columns.getString("TYPE_NAME"), columns.getInt("COLUMN_SIZE"), columns.getString("IS_NULLABLE")); } } ``` `NULLABLE` returns a numeric constant; `IS_NULLABLE` returns `YES`, `NO`, or an empty string. PRIMARY KEY columns in LOOKUP and VOLATILE tables return `columnNoNulls` and `NO` even without an explicit NOT NULL clause. `DECIMAL_DIGITS` and `NUM_PREC_RADIX` are SQL NULL for columns without these numeric attributes, such as VARCHAR, DATETIME, BINARY, BLOB, and CLOB. Check NULL with `getObject()` or `wasNull()` instead of relying on a 0 returned by `getInt()`. ## Primary Keys and Indexes ```java try (ResultSet keys = metadata.getPrimaryKeys( null, null, "SENSOR_TX")) { while (keys.next()) { System.out.printf("%s position=%d%n", keys.getString("COLUMN_NAME"), keys.getShort("KEY_SEQ")); } } try (ResultSet indexes = metadata.getIndexInfo( null, null, "SENSOR_TX", false, false)) { while (indexes.next()) { System.out.printf("%s %s%n", indexes.getString("INDEX_NAME"), indexes.getString("COLUMN_NAME")); } } ``` Do not infer PRIMARY KEY membership from `ResultSetMetaData.isNullable()`. Use `getPrimaryKeys()` and `getIndexInfo()`. For a direct column in a SELECT result, the Machbase JDBC extension `MachResultSetMetaData.isPrimaryKey(column)` reports PRIMARY KEY membership. ```java import com.machbase.jdbc.MachResultSetMetaData; try (ResultSet result = statement.executeQuery( "SELECT ID, ID + 1 AS ID_EXPR FROM SENSOR_TX")) { MachResultSetMetaData resultMetadata = (MachResultSetMetaData) result.getMetaData(); System.out.println(resultMetadata.isPrimaryKey(1)); // true or false System.out.println(resultMetadata.isPrimaryKey(2)); // expression: false } ``` `getPrimaryKeys()` reads primary keys from the table catalog; `isPrimaryKey()` reads column metadata for the current SELECT result. An older server or SDK may return `false` for the result-column primary key flag. ## Schema and Type Information The following methods return ResultSets in the standard JDBC format: - `getSchemas()`, `getCatalogs()`, `getTableTypes()` - `getTypeInfo()` - `getTables()`, `getColumns()` - `getPrimaryKeys()`, `getIndexInfo()` Unsupported optional metadata queries may return an empty ResultSet with standard columns instead of null or a nonstandard ResultSet. Check the capability methods before using a feature. ```java if (metadata.supportsSavepoints()) { // Use savepoints only where supported. } ``` ## catalog `Connection.getCatalog()` and `setCatalog()` manage the current catalog value exposed by the driver. Catalog arguments to metadata methods filter requests against this value. ```java String initialCatalog = connection.getCatalog(); connection.setCatalog(initialCatalog); ``` Returning a logical Connection to a pool restores the initial catalog determined by the URL. Do not reuse a DatabaseMetaData object from a previous connection lease in the next lease. ## Check Supported Features Machbase JDBC capability methods reflect actual support. For example, check transaction isolation levels, ResultSet types, savepoints, generated keys, and multiple open results as follows: ```java System.out.println(metadata.supportsTransactions()); System.out.println(metadata.supportsTransactionIsolationLevel( Connection.TRANSACTION_SERIALIZABLE)); System.out.println(metadata.supportsResultSetType( ResultSet.TYPE_FORWARD_ONLY)); System.out.println(metadata.supportsSavepoints()); System.out.println(metadata.supportsGetGeneratedKeys()); System.out.println(metadata.supportsMultipleOpenResults()); ``` A `false` result from `Driver.jdbcCompliant()` is separate from support for individual JDBC APIs. Applications should check the features they require. When connected to a Standard Edition server that supports ROWID, `supportsGetGeneratedKeys()` returns `true`, and `getRowIdLifetime()` returns `ROWID_VALID_OTHER`. On an unsupported server or Cluster Edition, they return `false` and `ROWID_UNSUPPORTED`, respectively. See [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/) for examples. --- title: "11.5.5 Append API" url: https://docs.machbase.com/dbms/development-tools-integration/jdbc/append-api/ language: en kind: page --- # 11.5.5 Append API The Machbase Append API ingests many rows in sequence. JDBC exposes it through `MachStatement` extension methods. This page focuses on LOG ingestion; check the [SDK Support Matrix](../../sdk-support-scope/#append-table-type-matrix) for other table types. ## API | Method | Description | |--------|------| | `executeAppendOpen(tableName, errorCheckCount)` | Starts an Append session and returns column metadata. | | `executeAppendOpen(tableName, inputColumns, errorCheckCount)` | Starts an Append session targeting selected columns or ARRAY elements in Machbase DBMS 8.7.0. | | `executeAppendData(metadata, data)` | Sends one row. | | `executeAppendDataByTime(metadata, time, data)` | Sends one row with a timestamp in nanoseconds. | | `executeAppendFlush()` | Synchronizes pending responses. | | `executeAppendClose()` | Closes the Append session. | | `executeSetAppendErrorCallback(callback)` | Registers a row-error callback. | | `getAppendSuccessCount()` | Returns the number of successful rows. | | `getAppendFailureCount()` | Returns the number of failed rows. | The public `executeAppendData()` returns `1` on success and throws `SQLException` for an invalid internal result. Also check final success/failure counts and callback results. ## Ingestion Example ```sql CREATE LOG TABLE sensor_data ( time DATETIME, name VARCHAR(40), value DOUBLE ); ``` ```java import com.machbase.jdbc.MachStatement; import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.util.ArrayList; try (MachStatement statement = (MachStatement) connection.createStatement()) { ResultSet appendResult = statement.executeAppendOpen("sensor_data", 100); ResultSetMetaData metadata = appendResult.getMetaData(); statement.executeSetAppendErrorCallback( (errorNumber, errorMessage, rowMessage) -> System.err.printf( "Append error [%05d]: %s%n%s%n", errorNumber, errorMessage, rowMessage)); long baseTime = System.currentTimeMillis() * 1_000_000L; for (int index = 0; index < 10_000; index++) { ArrayList row = new ArrayList<>(); row.add(baseTime + index); row.add("sensor-" + (index % 10)); row.add(20.0 + index * 0.001); int result = statement.executeAppendData(metadata, row); if (result != 1 && result != 2) { throw new SQLException( "Append failed at row " + index); } } statement.executeAppendFlush(); statement.executeAppendClose(); appendResult.close(); System.out.printf("success=%d failure=%d%n", statement.getAppendSuccessCount(), statement.getAppendFailureCount()); } ``` ## ARRAY and Selected Columns Column selection is not required for sparse ARRAY ingestion. Open with the standard `executeAppendOpen(tableName, errorCheckCount)` and pass `MachSparseArray` as the row ARRAY value according to the returned metadata. ```java ResultSet opened = statement.executeAppendOpen("ARRAY_APPEND_FULL_EXAMPLE", 0); ``` Start with the [standard Open example](../../data-input-load-export/array-append/#jdbc-full-open), which covers connection, ingestion, Close, and queries. Pass `ID` and the ARRAY column in declaration order. Do not add the automatic `_arrival_time` to the row. In Machbase DBMS 8.7.0, an `executeAppendOpen()` overload accepts column names or `ARRAY_COLUMN[position]` targets. ```java ResultSet appendResult = statement.executeAppendOpen( "sensor_array", new String[] {"ID", "CHANNELS[0]", "CHANNELS[3]"}, 0); ``` To populate different ARRAY positions for each row, create a `MachSparseArray` with `MachConnection.createSparseArrayOf()`. Map keys are 0-based. An empty map represents an ARRAY with all NULL elements; Java `null` represents a NULL array. ```java Map entries = new HashMap(); entries.put(Integer.valueOf(1), Integer.valueOf(200)); entries.put(Integer.valueOf(3), Integer.valueOf(400)); MachSparseArray sparse = connection.createSparseArrayOf( "INT32", 4, entries); ``` Use `java.sql.Array`, `Connection.createArrayOf()`, and `PreparedStatement.setArray()` for dense ARRAY retrieval and prepared input. See [Sparse ARRAY and Selected-Column Append API](../../data-input-load-export/array-append/) for complete examples and target conflict rules. SQL ARRAY element targets and `MachSparseArray` positions are 0-based. Standard JDBC parameter positions and the slice index in `java.sql.Array.getArray(index, count)` remain 1-based. Do not mix these conventions. ## DATETIME Pass Append DATETIME values as `long` epoch nanoseconds. ```java long epochNanoseconds = System.currentTimeMillis() * 1_000_000L; ``` Use `executeAppendDataByTime()` for table ingestion paths that accept a separate timestamp. Match input column order and Java types to the ResultSetMetaData returned by `executeAppendOpen()`. ## Flush and Close 1. Start a session with `executeAppendOpen()`. 2. Call `executeAppendData()` repeatedly. 3. Call `executeAppendFlush()` for an intermediate check if needed. 4. Call `executeAppendClose()` after sending all input. 5. Check success/failure counts and callback results. Use try-with-resources and `finally` to close the Append session and Statement even on exceptions. Save or log failed rows in the callback. Use business keys to prevent duplicate ingestion from unconditional retries. ## Size and Scope Ordered append shares the protocol packet limit. Keep each fully encoded row below 64KiB. For large values such as BLOB/CLOB, check both row size and client memory usage. Append batches on TRANSACTION tables are applied independently of SQL transactions. Use [JDBC Transactions](../transaction-pooling/) for multiple DML operations that require rollback. --- title: "11.5.6 Migration and Troubleshooting" url: https://docs.machbase.com/dbms/development-tools-integration/jdbc/migration-troubleshooting/ language: en kind: page --- # 11.5.6 Migration and Troubleshooting The current Machbase JDBC driver targets Java 8/JDBC 4.2 and aligns version reporting, metadata, type conversion, transactions, and resource lifecycles with standard JDBC contracts. Applications that rely on earlier behavior should review these differences. ## Migrate from an Earlier Driver | Area | Current behavior | Application checks | |------|-----------|------------------------| | Java/JDBC baseline | Java 8 bytecode; reports JDBC 4.2 | Run on JDK 8 or later. | | Driver version | Driver and metadata report 3.0.0 | Update version-detection logic. | | Automatic discovery | JDBC service provider included | Explicit `Class.forName()` is optional. | | ParameterMetaData | Returns JDBC precision, database type names, and Java classes | Interpret precision by type, not as storage bytes. | | Transactions | Lazy `BEGIN`; actual commit/rollback | Explicitly complete Standard TRANSACTION operations. | | Holdability | `CLOSE_CURSORS_AT_COMMIT` | Requery ResultSets after commit. | | DatabaseMetaData | Standard result structure and capabilities | Use standard column names instead of driver-specific positions. | | Type APIs | Typed `getObject()`, `JDBCType`, Boolean, unsigned, LOB | Retrieve and bind using the Java classes in metadata. | | Errors | Standard `SQLException` for invalid states | Classify errors by SQLState. | | Timeouts | Query and network timeouts supported | Discard connections after a network timeout. | | Connection pools | Logical connection leases and state reset | Do not reuse closed handles or metadata. | | Generated keys | Returns ROWID for a single Standard INSERT | Read `ROWID` from `getGeneratedKeys()`. | Use named binding with a compatible server. An older server without named binding support raises SQLState `0A000`; switch to positional `?` parameters. ## Unsupported Features The following optional JDBC features are not supported: - Savepoints - XA and distributed transactions - Stored procedures and successful CallableStatement execution - Scrollable or updatable ResultSets - Statement pooling - Multiple open results - Struct, Ref, SQLXML, and UDT type mapping - Separate NClob storage and factories - A Machbase-specific RowSet provider - JDBC 4.3 sharding and request boundary APIs Machbase DBMS 8.7.0 with an ARRAY-capable JDBC build supports `java.sql.Array`, `createArrayOf()`, and `setArray()`. Do not apply older drivers' ARRAY restrictions. Check the version and index conventions in [ARRAY and Selected-Column Append](../append-api/#array와-선택-컬럼). Unsupported features generally raise `SQLFeatureNotSupportedException` with SQLState `0A000`. Check DatabaseMetaData capabilities before calling a feature. ## `No suitable driver` **Symptom** `DriverManager.getConnection()` raises `No suitable driver`. **Checks and Resolution** 1. Check that `machbase.jar` is on the runtime classpath. 2. Check that the JAR contains `META-INF/services/java.sql.Driver`. 3. Check that the URL uses `jdbc:machbase://:/machbasedb`. 4. Check that multiple Machbase JDBC JAR versions are not included together. ## SQLState `0A000` The selected feature or server does not support the API. Use alternatives to savepoints, scrollable cursors, and XA. Generated keys require Standard Edition and a server/JDBC combination with ROWID support; check `DatabaseMetaData.supportsGetGeneratedKeys()`. For named binding errors, use positional `?` parameters. ## ResultSet Closes After Commit This is expected. Machbase transaction holdability is `CLOSE_CURSORS_AT_COMMIT`. Consume results before committing or run the query again afterward. Statements and PreparedStatements remain reusable. ## LOG DML Is Not Rolled Back The first LOG DML executed before a TRANSACTION table change in a manual transaction may be reexecuted with auto-commit through the compatibility path. This input cannot be rolled back later. Use TRANSACTION tables for data that requires rollback. ## Commit Multiple TRANSACTION Tables Together Normal commit and rollback are supported, but global atomicity across multiple TRANSACTION tables is not guaranteed if a failure occurs during backend commit. Keep critical atomic operations within one TRANSACTION table. ## Network Timeout or Connection Error After a socket read timeout or a connection error in SQLState class `08`, do not reuse the physical connection. Obtain a new connection from the pool and restart active transactions according to the application idempotency policy. Do not infer commit success from an exception alone. ## Reuse of Closed Pool Objects Reusing Statements, ResultSets, or DatabaseMetaData from a closed logical Connection in the next connection lease raises SQLState `08003`. Keep each lease's objects within its try-with-resources scope. --- title: "11.6 Python" url: https://docs.machbase.com/dbms/development-tools-integration/python/ language: en kind: section --- # 11.6 Python ## Overview This page describes package 2.4. The PyPI package is `machbaseapi` (lowercase). Its pure Python implementation requires no native binaries (`.so/.dll/.dylib`). The existing `machbase` workflow remains available. - Installation package: `machbaseapi` - Continue using `import machbaseAPI`. - Supports DB-API `connect()` and `cursor()`. - Since 2.4, `cursor(prepared=True)` reuses server statements across calls. - `append*` can accept an `on_ack` callback to observe ACKs. - `append()`, `appendByTime()`, `appendData()`, and `appendDataByTime()` work without a type list; types are inferred from server metadata. - Since 2.3, omitted trailing append columns are stored as `NULL` through append null bits. - TAG input must include values through the `value` column; omitted subsequent data and metadata columns can be stored as `NULL`. - Connection pool options (`pool_name`, `pool_size`, `pool_reset_session`) are unsupported. ## Multiple Databases Specify the initial database with `connect(database=...)`. There is no current-catalog getter/setter. Verify it with `SELECT CURRENT_DATABASE()` after connecting and change it with SQL `USE`. ```python conn = connect( host='127.0.0.1', port=5656, user='APP_A', password='secret', database='FACTORY_A', ) cur = conn.cursor() cur.execute('SELECT CURRENT_DATABASE()') print(cur.fetchone()) cur.execute('USE FACTORY_B') ``` The legacy `machbase.open()` has no database argument. Use the current `connect()` API for multi-database work. See the [Multi-Database Operations Guide](/dbms/operations-configuration-recovery/multi-database/#94-python) for connection pool and statement binding rules. ## Installation ### Requirements - Python 3.6 or later with `pip` - A reachable Machbase server and credentials (default `SYS/MANAGER`, port `5656`) - Version 2.4 has no native library dependencies. ### Install from PyPI ```bash pip3 install machbaseapi ``` If `pip3` is not on PATH, use `python3 -m pip install machbaseapi`. ### Offline Installation from the Distribution Package Without internet access, install the wheel included in the Machbase distribution package. ```bash python3 -m pip install \ $MACHBASE_HOME/3rd-party/python3-module/machbaseapi-2.4-py3-none-any.whl ``` The source distribution `machbaseapi-2.4.tar.gz` in the same directory is also available. Check that Python is 3.6 or later before installing. ### Verify the Module ```bash python3 - <<'PY' from machbaseAPI import machbase, connect print('machbase class import:', bool(machbase)) print('connect function exists:', callable(connect)) print('module import:', __import__('machbaseAPI')) PY ``` If this command succeeds, the package imports correctly. ## Quick Start This DB-API example creates a sample LOG table, inserts and queries data, then removes the table and closes the connection. The password comes from an environment variable. ```python import os from machbaseAPI import connect conn = connect( host=os.getenv('MACH_HOST', '127.0.0.1'), port=int(os.getenv('MACH_PORT', '5656')), user=os.getenv('MACH_USER', 'SYS'), password=os.environ['MACHBASE_PASSWORD'], ) cur = conn.cursor() try: cur.execute( 'CREATE LOG TABLE py_sample ' '(ts DATETIME, device VARCHAR(40), value DOUBLE)' ) cur.execute( "INSERT INTO py_sample VALUES (" "TO_DATE('2026-01-01','YYYY-MM-DD'), 'sensor-1', 20.5)" ) cur.execute('SELECT device, value FROM py_sample') print(cur.fetchall()) finally: cur.execute('DROP TABLE py_sample') cur.close() conn.close() ``` ## Handle Results DB-API cursors provide `execute()`, `fetchone()`, and `fetchall()`. Close the cursor and connection when finished, and remove sample objects from production databases. ### ROWID from INSERT After a single `INSERT ... VALUES` through a DB-API cursor in Standard Edition, read the inserted row's ROWID from `cursor.lastrowid`. ```python cursor.execute( "INSERT INTO orders(item) VALUES(%s)", ("pump",), ) row_id = cursor.lastrowid ``` The value is an arbitrary-precision Python `int`, preserving unsigned 64-bit ROWIDs as positive integers. Executions without a ROWID return `None`. `executemany()`, Append, `INSERT ... SELECT`, and UPSERT do not return ROWIDs. Do not reuse a previous value after an execution failure. See [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/) for detailed conditions. ### Nullable Metadata in DB-API Results For DB-API cursors, `null_ok` at `cursor.description[i][6]` reports SELECT result column nullability. ```python cursor.execute(sql) for column in cursor.description: name = column[0] null_ok = column[6] print(name, null_ok) ``` | `null_ok` | Meaning | |-----------|------| | `False` | Cannot be NULL | | `True` | Can be NULL | | `None` | Unknown | `None` does not mean `NOT NULL`; handle it as potentially nullable. See [Nullable Metadata Support](/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-nullable-metadata) for SQL result rules. In Machbase SQL, `''` is SQL `NULL`, so `null_ok` is `True`. For legacy compatibility, the Python connector may return string SQL `NULL` as the Python empty string `""`. `null_ok` describes column nullability, not whether an individual row is NULL. To distinguish individual rows, also query an SQL `IS NULL` predicate or a CASE expression based on it. ### PRIMARY KEY Metadata in SELECT Results With a Machbase 8.7.0 server and matching SDK, `is_primary_key` in `cursor.column_metadata` reports whether a direct SELECT result column is a PRIMARY KEY. ```python cursor.execute("SELECT ID, VALUE, ID + 1 AS ID_EXPR FROM T_PK") for column in cursor.column_metadata: print(column.name, column.is_primary_key) ``` The standard seventh DB-API field in `cursor.description` (`null_ok`) still reports only nullability. Expressions, aggregates, and columns on the NULL-supplying side of outer joins are not primary keys, so `is_primary_key` is `False`. Older servers or SDKs may not provide the primary key flag. ### Named Bind Parameter The Python DB-API module uses `paramstyle = "named"`. Passing mappings to `cursor.execute()` or `cursor.executemany()` executes `:name` SQL through server prepare/bind. ```python from decimal import Decimal from machbaseAPI import connect conn = connect(host="127.0.0.1", port=5656, user="SYS", password="MANAGER") cur = conn.cursor(dictionary=False) cur.execute( """INSERT INTO SENSOR_DATA (ID, NAME, VALUE) VALUES (:id, :name, :value)""", { "id": 600, "name": "python-client", "value": Decimal("52.125000"), }, ) cur.execute( """SELECT ID, NAME FROM SENSOR_DATA WHERE ID = :id OR PARENT_ID = :id""", {"id": 600}, ) ``` Pass each row as a mapping to `executemany()`. ```python cur.executemany( "INSERT INTO SENSOR_DATA (ID, NAME, VALUE) " "VALUES (:id, :name, :value)", [ {"id": 601, "name": "batch-a", "value": Decimal("1.5")}, {"id": 602, "name": "batch-b", "value": None}, ], ) ``` Server Prepared Statement lifetime depends on the cursor type and call: | Cursor | Call | Server statement reuse | |--------|------|----------------------------| | Regular cursor | `execute(sql, params)` | This call only | | Regular cursor | `executemany(sql, rows)` | Within this call | | Prepared cursor | `execute()` / `executemany()` | Subsequent calls using identical original SQL | A regular cursor uses server prepare/bind for `:name` with a mapping, but closes the statement when the call ends. Use `cursor(prepared=True)` to reuse a statement across calls. Mapping keys omit the leading colon and are case-sensitive. A repeated name applies one value to every matching position. Missing names, extra keys, and mixed named/positional binding raise `ProgrammingError`. Named APIs on older servers raise `NotSupportedError` with SQLSTATE `0A000`. For compatibility, `%s` and `%(name)s` remain supported. On regular cursors, these use the legacy client-side SQL literal rendering path. Prepared cursors convert `%s` to `?` and `%(name)s` to `:name`, then use server prepare/bind. See [Named Bind Parameter Syntax](../../reference/sql/syntax/named-bind-parameter-syntax/) for shared name syntax. ## Prepared Cursor (2.4) `connection.cursor(prepared=True)` retains one server Prepared Statement and reuses it when executing the same SQL repeatedly. Use it for repeated INSERTs, parameterized queries, and batches of the same SQL. ```python from machbaseAPI import connect conn = connect( host="127.0.0.1", port=5656, user="SYS", password="MANAGER", ) cur = conn.cursor(dictionary=False, raw=False, prepared=True) sql = "INSERT INTO SENSOR_DATA (ID, NAME, VALUE) VALUES (%s, %s, %s)" cur.execute(sql, (700, "sensor-a", 21.5)) cur.execute(sql, (701, "sensor-b", 22.1)) cur.executemany( sql, [ (702, "sensor-c", 23.0), (703, "sensor-d", None), ], ) cur.close() conn.close() ``` Relevant `cursor()` arguments: - `dictionary=True`: Return results as dictionaries keyed by column name. - `dictionary=False`: Return results as tuples. - `raw=True`: Preserve the existing raw-result contract. - `prepared=True`: Return the public `MachbasePreparedCursor` type. - `prepared=False`: Return a regular cursor; this is the default. ### Parameter marker Prepared cursors support both Python DB-API and native Machbase formats. | Public placeholder | Server placeholder | Parameter form | |---------------|-------------|----------------| | `%s` | `?` | Sequence, such as tuple or list | | `?` | `?` | Sequence, such as tuple or list | | `%(name)s` | `:name` | Mapping, such as dictionary | | `:name` | `:name` | Mapping, such as dictionary | Placeholder-like text in string literals, quoted identifiers, `--` comments, and `/* ... */` comments is not converted. Do not mix positional and named placeholders in one SQL statement. Names start with a letter, `_`, or `$`; subsequent characters may include digits. Named placeholders require a Machbase 8.7.0 server and matching SDK. ```python sql = ( "SELECT ID, NAME FROM SENSOR_DATA " "WHERE ID = %(target)s OR PARENT_ID = %(target)s" ) cur.execute(sql, {"target": 700}) rows = cur.fetchall() ``` ### Statement Reuse A prepared cursor reuses its cached server statement only when the original SQL string exactly matches the previous call. Any difference, including whitespace or comments, releases the old statement and prepares a new one. ```python insert_cur = conn.cursor(prepared=True) select_cur = conn.cursor(prepared=True) ``` One cursor retains one server statement. To keep multiple SQL statements reusable, create a prepared cursor per SQL statement as above. The statement remains after `executemany()` and is reused by subsequent `execute()` or `executemany()` with the same SQL. An empty parameter list returns `0` without preparing or executing a statement. ### Errors and Close The following inputs raise `ProgrammingError`: - Placeholders with no parameters supplied - A mapping for positional placeholders or a sequence for named placeholders - Mixed positional and named placeholders - Missing or extra named parameter keys - Nonempty parameters for SQL without placeholders For SQL without placeholders, pass `None`, an empty sequence, or an empty mapping to indicate no parameters. An empty mapping is normalized to `None` internally, preserving the same meaning across protocol versions. Parameter errors preserve the cached statement, so the same SQL can run again with valid parameters. On older servers, named parameters raise `NotSupportedError` with SQLSTATE `0A000` before server PREPARE. This error does not release or replace the cached statement. Use positional placeholders on older servers. `cursor.close()` releases the cached server statement. Closing a cursor twice is safe. If the connection is already closed, only local state is cleaned up, without a network request. Calling `execute()`, `executemany()`, or fetch APIs on a closed prepared cursor raises `InterfaceError`. Prepared cursors do not change allowed SQL operations or Python API auto-commit behavior. See [Support Scope and Constraints](../../reference/support-scope-constraints/) for DML support by table type. ## Supported API Matrix | Class | API | Description | Returns | | -- | -- | -- | -- | | `machbase` | `open(host, user, password, port)` | Connects to the Machbase server using the specified credentials and port. | `1` on success, `0` on failure | | `machbase` | `openEx(host, user, password, port, conn_str)` | Connects with additional connection-string properties. | `1` or `0` | | `machbase` | `close()` | Closes the current session. | `1` or `0` | | `machbase` | `isOpened()` | Checks whether the handle is open. | `1` or `0` | | `machbase` | `isConnected()` | Checks the server connection state. | `1` or `0` | | `machbase` | `execute(sql)` | Executes SQL directly. Routes `SELECT`, `WITH`, `DESC`, `DESCRIBE`, and `SHOW` to `select()`; other SQL uses `exec_direct()`. | `1` or `0` | | `machbase` | `schema(sql)` | Executes schema commands. | `1` or `0` | | `machbase` | `tables()` | Retrieves metadata for all tables. | `1` or `0` | | `machbase` | `columns(table_name)` | Retrieves column metadata for a table. | `1` or `0` | | `machbase` | `column(table_name)` | Retrieves column layout through a low-level catalog call. | `1` or `0` | | `machbase` | `statistics(table_name, user='SYS')` | Requests table statistics through CLI. | `1` or `0` | | `machbase` | `select(sql)` | Executes a streaming `SELECT` or `DESC`. | `1` or `0` | | `machbase` | `fetch()` | Fetches the next row after `select()`. | `(rc, json_str)` | | `machbase` | `selectClose()` | Closes the open result cursor. | `1` or `0` | | `machbase` | `result()` | Returns the latest JSON payload. | JSON string | | `machbase` | `appendOpen(table_name, types=None)` | Starts Append with column type codes; if omitted, uses server metadata. | `1` or `0` | | `machbase` | `appendOpenColumns(table_name, columns, types=None)` | Starts Append for selected columns or ARRAY elements in Machbase DBMS 8.7.0. | `1` or `0` | | `machbase` | `appendData(table_name, rows_or_types, values=None, format='YYYY-MM-DD HH24:MI:SS', on_ack=None)` | Adds rows to an active Append session. Pass rows as the second argument to omit types. Sends data packets immediately. | `1` or `0` | | `machbase` | `appendDataByTime(table_name, rows_or_types, values=None, format='YYYY-MM-DD HH24:MI:SS', aTimes=None, on_ack=None)` | Adds rows with explicit timestamps. Pass rows as the second argument to omit types and supply timestamps through `aTimes`. Sends data packets immediately. | `1` or `0` | | `machbase` | `appendFlush()` | Synchronizes pending server responses for already transmitted Append data. It does not flush a deferred transmission buffer. | `1` or `0` | | `machbase` | `appendClose()` | Closes the Append session. | `1` or `0` | | `machbase` | `append(table_name, rows_or_types, aValues=None, format='YYYY-MM-DD HH24:MI:SS')` | Opens, appends, and closes in one call. Pass rows as the second argument to omit types. | `1` or `0` | | `machbase` | `appendByTime(table_name, rows_or_types, aValues=None, format='YYYY-MM-DD HH24:MI:SS', aTimes=None)` | Convenience function for timestamp-aware Append. Pass rows as the second argument to omit types and supply timestamps through `aTimes`. | `1` or `0` | ## DB-API Style APIs (2.4) | API | Description | Returns | | -- | -- | -- | | `connect(**kwargs)` | Creates a DB-API connection; pass `host`, `port`, `user`, `password`, and other properties as keywords | `MachbaseConnection` | | `cursor(dictionary=True, raw=False, prepared=False)` | Creates a regular or prepared cursor | `MachbaseCursor` or `MachbasePreparedCursor` | | `cursor.execute(sql, params=None)` | Executes SQL | `cursor` | | `cursor.executemany(sql, seq_of_params)` | Executes the same SQL with multiple mappings or sequences | Execution count | | `cursor.fetchone()` | Fetches one row | `tuple` / `dict` / `None` | | `cursor.fetchmany(size)` | Fetches up to `size` rows | `list` | | `cursor.fetchall()` | Fetches all rows | `list` | | `cursor.description` | Result column metadata; the seventh field is `null_ok` | `tuple` / `None` | | `cursor.lastrowid` | ROWID of a successful single INSERT; `None` for unsupported input methods or after failure | `int` / `None` | | `cursor.close()` | Closes the cursor | `None` | | `cursor.rowcount` | Affected-row count | `int` | | `connection.append(table, rows, *, types=None, times=None, date_format=..., strict=False, columns=None)` | Appends rows; `columns` specifies selected columns or ARRAY element targets | Input row count | ## Omit Append Types and Pad Trailing NULLs in 2.3 (Recommended) Call `append()` and `appendByTime()` without a type list. Pass rows directly as the second argument to use server metadata. Since 2.3, omitted trailing input columns are stored as `NULL` through append null bits. ```python #!/usr/bin/env python3 from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0: raise SystemExit(db.result()) try: db.execute('drop table py_append_auto') db.result() ddl = 'create table py_append_auto(ts datetime, tag varchar(16), reading double)' if db.execute(ddl) == 0: raise SystemExit(db.result()) db.result() rows = [ ['2024-01-01 10:00:00', 'node-1', 30.0], ['2024-01-01 10:01:00', 'node-1', 30.5], ] if db.append('PY_APPEND_AUTO', rows) == 0: raise SystemExit(db.result()) print('append without types result:', db.result()) finally: if db.close() == 0: raise SystemExit(db.result()) if __name__ == '__main__': main() ``` ### DB-API Append with Trailing NULLs `connect().append()` uses the same trailing `NULL` padding rules. Positional input cannot skip intermediate columns; explicitly place `None` at a position to store an intermediate value as `NULL`. ```python from machbaseAPI import connect conn = connect(host='127.0.0.1', port=5656, user='SYS', password='MANAGER') cur = conn.cursor() try: cur.execute('drop table py_append_null') except Exception: pass cur.execute('create table py_append_null(ts datetime, name varchar(20), value double, note varchar(40))') conn.append('PY_APPEND_NULL', [ ['2024-01-01 10:00:00', 'sensor-1', 12.3], ['2024-01-01 10:00:01', 'sensor-2', None, 'manual null'], ]) cur.execute('select ts, name, value, note from py_append_null order by ts') print(cur.fetchall()) conn.close() ``` The first row omits `note`, so it is stored as `NULL`. The second row explicitly passes `None` at the `value` position, so `value` is stored as `NULL`. ### TAG Append and NULL Metadata TAG rows must supply values through the `name`, `time`, and `value` columns. Additional data or metadata columns defined after `value` can be omitted and are stored as `NULL`. ```python from machbaseAPI import connect conn = connect(host='127.0.0.1', port=5656, user='SYS', password='MANAGER') cur = conn.cursor() try: cur.execute('drop table py_tag_append_null') except Exception: pass cur.execute(''' create tag table py_tag_append_null ( name varchar(40) primary key, time datetime basetime, value double summarized, status varchar(20) ) metadata ( site varchar(20), line integer ) ''') conn.append('PY_TAG_APPEND_NULL', [ ['tag-1', '2024-01-01 10:00:00', 12.3], ]) cur.execute('select name, time, value, status, site, line from py_tag_append_null') print(cur.fetchall()) conn.close() ``` In this example, `status`, `site`, and `line` are all stored as `NULL`. A TAG append that omits `value` fails. ## Compatible `machbase` Class API The `machbase` class is retained for compatibility with existing applications. Prefer the DB-API `connect()` approach above for new code. APIs such as `getSessionId()`, `count()`, and `checkBit()` existed in the old native package but are not provided by the current pure-Python implementation. Use the 2.4 DB-API examples where needed. Adjust host, port, and credentials in each script to your environment. All examples run independently with `python3 script.py`. ### Connection Management #### machbase.open(), machbase.isOpened(), machbase.isConnected(), machbase.close() ```python #!/usr/bin/env python3 from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() print('isOpened before open:', db.isOpened()) print('isConnected before open:', db.isConnected()) if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0: raise SystemExit(db.result()) print('isOpened after open:', db.isOpened()) print('isConnected after open:', db.isConnected()) if db.close() == 0: raise SystemExit(db.result()) print('isOpened after close:', db.isOpened()) print('isConnected after close:', db.isConnected()) if __name__ == '__main__': main() ``` #### machbase.openEx() ```python #!/usr/bin/env python3 from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() conn_str = 'APP_NAME=python-demo' if db.openEx('127.0.0.1', 'SYS', 'MANAGER', 5656, conn_str) == 0: raise SystemExit(db.result()) print('connected with openEx:', db.isConnected()) if db.close() == 0: raise SystemExit(db.result()) if __name__ == '__main__': main() ``` ### DML and Result Buffers #### machbase.execute(), machbase.result() ```python #!/usr/bin/env python3 import json from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0: raise SystemExit(db.result()) try: rc = db.execute('drop table py_exec_demo') print('drop table rc:', rc) print('drop table result:', db.result()) ddl = 'create table py_exec_demo(id integer, note varchar(32))' if db.execute(ddl) == 0: raise SystemExit(db.result()) print('create table result:', db.result()) for idx in range(2): sql = f"insert into py_exec_demo values ({idx}, 'row-{idx}')" if db.execute(sql) == 0: raise SystemExit(db.result()) print('insert result:', db.result()) if db.execute('select * from py_exec_demo order by id') == 0: raise SystemExit(db.result()) payload = db.result() print('select payload:', payload) rows = json.loads(payload) print('decoded rows:', rows) print('row count:', len(rows)) finally: if db.close() == 0: raise SystemExit(db.result()) if __name__ == '__main__': main() ``` ### Streaming SELECT Helpers #### machbase.select(), machbase.fetch(), machbase.selectClose() ```python #!/usr/bin/env python3 import json from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0: raise SystemExit(db.result()) try: rc = db.execute('drop table py_select_demo') print('drop table rc:', rc) print('drop table result:', db.result()) ddl = 'create table py_select_demo(id integer, value double)' if db.execute(ddl) == 0: raise SystemExit(db.result()) print('create table result:', db.result()) for idx in range(5): sql = f"insert into py_select_demo values ({idx}, {idx * 1.5})" if db.execute(sql) == 0: raise SystemExit(db.result()) print('insert result:', db.result()) if db.select('select id, value from py_select_demo order by id') == 0: raise SystemExit(db.result()) fetched = 0 while True: rc, payload = db.fetch() if rc == 0: break print('fetched row:', json.loads(payload)) fetched += 1 print('fetched rows:', fetched) db.selectClose() finally: if db.close() == 0: raise SystemExit(db.result()) if __name__ == '__main__': main() ``` ### Schema Helpers #### machbase.schema() ```python #!/usr/bin/env python3 from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0: raise SystemExit(db.result()) try: rc = db.schema('drop table py_schema_demo') print('schema drop rc:', rc) print('schema drop result:', db.result()) ddl = 'create table py_schema_demo(name varchar(20), created datetime)' if db.schema(ddl) == 0: raise SystemExit(db.result()) print('schema create result:', db.result()) finally: if db.close() == 0: raise SystemExit(db.result()) if __name__ == '__main__': main() ``` ### Metadata and Statistics #### machbase.tables(), machbase.columns(), machbase.column(), machbase.statistics() ```python #!/usr/bin/env python3 from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0: raise SystemExit(db.result()) try: if db.tables() == 0: raise SystemExit(db.result()) print('tables metadata:', db.result()) if db.columns('PY_EXEC_DEMO') == 0: raise SystemExit(db.result()) print('columns metadata:', db.result()) if db.column('PY_EXEC_DEMO') == 0: raise SystemExit(db.result()) print('column metadata:', db.result()) if db.statistics('PY_EXEC_DEMO') == 0: raise SystemExit(db.result()) print('statistics output:', db.result()) finally: if db.close() == 0: raise SystemExit(db.result()) if __name__ == '__main__': main() ``` ### Append Protocol Basics Combine `appendOpen()`, `appendData()`, `appendFlush()`, and `appendClose()` to stream rows efficiently. Since 2.1, `appendOpen()` can omit types. `appendData()` and `appendDataByTime()` send data packets immediately. `appendFlush()` is a synchronization point that checks pending server responses for already transmitted append data. ```python #!/usr/bin/env python3 from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0: raise SystemExit(db.result()) try: rc = db.execute('drop table py_append_demo') print('drop table rc:', rc) print('drop table result:', db.result()) ddl = 'create table py_append_demo(ts datetime, device varchar(32), value double)' if db.execute(ddl) == 0: raise SystemExit(db.result()) print('create table result:', db.result()) if db.appendOpen('PY_APPEND_DEMO') == 0: raise SystemExit(db.result()) rows = [ ['2024-01-01 09:00:00', 'sensor-a', 21.5], ['2024-01-01 09:05:00', 'sensor-b', 22.1], ] if db.appendData('PY_APPEND_DEMO', rows) == 0: raise SystemExit(db.result()) print('appendData result:', db.result()) if db.appendFlush() == 0: raise SystemExit(db.result()) print('appendFlush result:', db.result()) if db.appendClose() == 0: raise SystemExit(db.result()) print('appendClose result:', db.result()) finally: if db.close() == 0: raise SystemExit(db.result()) if __name__ == '__main__': main() ``` ### Append Convenience Functions #### machbase.append() ```python #!/usr/bin/env python3 from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0: raise SystemExit(db.result()) try: db.execute('drop table py_append_auto') db.result() ddl = 'create table py_append_auto(ts datetime, tag varchar(16), reading double)' if db.execute(ddl) == 0: raise SystemExit(db.result()) db.result() values = [ ['2024-01-01 10:00:00', 'node-1', 30.0], ['2024-01-01 10:01:00', 'node-1', 30.5], ] if db.append('PY_APPEND_AUTO', values) == 0: raise SystemExit(db.result()) print('append() result:', db.result()) finally: if db.close() == 0: raise SystemExit(db.result()) if __name__ == '__main__': main() ``` #### machbase.appendDataByTime(), machbase.appendByTime() ```python #!/usr/bin/env python3 from machbaseAPI.machbaseAPI import machbase def main(): db = machbase() if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0: raise SystemExit(db.result()) try: db.execute('drop table py_append_time') db.result() ddl = 'create table py_append_time(ts datetime, tag varchar(16), reading double)' if db.execute(ddl) == 0: raise SystemExit(db.result()) db.result() rows = [ ['2024-01-01 11:00:00', 'node-2', 40.1], ['2024-01-01 11:01:00', 'node-2', 40.7], ] epoch_times = [ 1704106800 * 1_000_000_000, 1704106860 * 1_000_000_000, ] if db.appendOpen('PY_APPEND_TIME') == 0: raise SystemExit(db.result()) if db.appendDataByTime('PY_APPEND_TIME', rows, aTimes=epoch_times) == 0: raise SystemExit(db.result()) print('appendDataByTime result:', db.result()) db.appendClose() if db.appendByTime('PY_APPEND_TIME', rows, aTimes=epoch_times) == 0: raise SystemExit(db.result()) print('appendByTime result:', db.result()) finally: if db.close() == 0: raise SystemExit(db.result()) if __name__ == '__main__': main() ``` `aTimes` is a sequence of epoch nanoseconds in the same order as the rows. Do not pass Unix timestamps in seconds unchanged. ## ARRAY and Selected-Column Append Machbase DBMS 8.7.0 returns ARRAY values as Python `list`; prepared input accepts `list` or `tuple`. An element NULL is `None` within the collection; whole-array NULL is `None` for the column value itself. You can also pass `SparseArray` to `connection.append(table, rows)` without a column list. ```python from machbaseAPI import SparseArray sparse = SparseArray(4).set(1, 200).set(3, 400) connection.append("ARRAY_APPEND_FULL_EXAMPLE", [[2, sparse]]) ``` This code assumes a table with `ID LONG, A INT32[4]` and an open connection. See the [standard input example](../data-input-load-export/array-append/#python-full-open) for whole NULL, empty sparse arrays, and result checks. The legacy wrapper has an [`appendOpen(table)` example](../data-input-load-export/array-append/#python-legacy-full-open). Specify selected targets with `connection.append(..., columns=...)`. Use `SparseArray` for positions that vary by row. Element targets and positions in `SparseArray.set()` are 0-based. ```python from machbaseAPI import SparseArray, connect connection = connect( host="127.0.0.1", port=5656, user="SYS", password="MANAGER", ) try: connection.append( "ARRAY_APPEND_EXAMPLE", [[1, 10, 40]], columns=["ID", "A[0]", "A[3]"], ) sparse = SparseArray(4).set(1, 200).set(3, 400) connection.append( "ARRAY_APPEND_EXAMPLE", [[2, sparse]], columns=["ID", "A"], ) finally: connection.close() ``` `SparseArray.clear()` resets all elements to NULL while preserving the element count. See [Sparse ARRAY and Selected-Column Append API](../data-input-load-export/array-append/) for NULL distinctions, validation, and legacy API examples. --- title: "11.7 Node.js / TypeScript" url: https://docs.machbase.com/dbms/development-tools-integration/node-js-typescript/ language: en kind: section --- # 11.7 Node.js / TypeScript ## Overview The Machbase TypeScript client (`@machbase/ts-client`) connects to Machbase Standard Edition without native bindings. Node.js applications can execute SQL, retrieve results, use Prepared Statements, and append log data. This document covers installation, core APIs, examples, testing, and behavior. ## Multiple Databases Set `database` in the connection configuration or URL to select the initial database. There is no catalog getter; use SQL `CURRENT_DATABASE()` and `USE` to inspect and change it. ```typescript const conn = createConnection({ host: '127.0.0.1', port: 5656, user: 'APP_A', password: 'secret', database: 'FACTORY_A', }); await conn.connect(); const [rows] = await conn.query('SELECT CURRENT_DATABASE()'); console.table(rows); ``` Appenders and prepared statements remain bound to the database selected at open/prepare time. See the [Multi-Database Operations Guide](/dbms/operations-configuration-recovery/multi-database/#95-nodejs) for details. ## Installation ### Requirements - Node.js 18 or later (LTS recommended) - A reachable Machbase server (Standard Edition) ### Install from npm Install with a package manager: ```bash npm install @machbase/ts-client # or yarn add @machbase/ts-client # or pnpm add @machbase/ts-client ``` ### Offline Installation If Machbase supplied a `.tgz` package: ```bash # example file name; your version may differ npm install ./machbase-ts-client-.tgz ``` ### Verify Installation ```bash node -e "const { createConnection } = require('@machbase/ts-client'); console.log(typeof createConnection === 'function' ? 'ts-client import ok' : 'ts-client import failed')" ``` > **Note:** This client uses TCP sockets in Node.js. It does not provide a browser library > with WebSocket transport. > The NFX `cce422d2972` source tree reports `@machbase/ts-client` 1.0.1 in `package.json`. > Some named binding, nullable, PK, ROWID, and TRANSACTION features were added after the > public 1.0.1 release while retaining that version string. Check artifact commit > provenance or build from this NFX source instead of assuming parity from the npm version. > > The default `SYS`/`MANAGER` credentials in this document are for local tests. Use > dedicated credentials in production. ## Quick Start This example connects to a local server, queries a system table, and closes the session. ```typescript // src/example.ts import { createConnection } from '@machbase/ts-client'; const conn = createConnection({ host: process.env.MACH_HOST ?? '127.0.0.1', port: +(process.env.MACH_PORT ?? 5656), user: process.env.MACH_USER ?? 'SYS', password: process.env.MACH_PASS ?? 'MANAGER', }); await conn.connect(); const [rows] = await conn.query('SELECT NAME FROM V$TABLES ORDER BY NAME LIMIT ?', [5]); console.log(rows); await conn.end(); ``` > **Transactions:** The server supports plain `BEGIN`, `COMMIT`, and `ROLLBACK` SQL for > TRANSACTION tables. This client does not implement `beginTransaction`, `commit`, or > `rollback` convenience methods; execute the SQL directly through `execute()`. ## Common Problems - **ECONNREFUSED** – Check server status (`machadmin -e`), host and port, and firewall access to the listener. The default SQL port is 5656. - **Authentication failed** – Check credentials and account connection privileges. ## API Reference ### Connection Management #### createConnection(config) Connects to the Machbase listener and creates a database session. | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `host` | string | `127.0.0.1` | Server IP address or host name | | `port` | number | `5656` | Listener port | | `user` | string | – | Database user (default `SYS`) | | `password` | string | – | Password (default `MANAGER`) | | `database` | string | `data` | Database name | | `clientId` | string | `NPM` | Client ID shown in server logs | | `showHiddenColumns` | boolean | `false` | Include hidden columns in metadata | | `timezone` | string | Empty | Optional time zone identifier | | `connectTimeout` | number | 5000 | Socket connection timeout (ms) | | `queryTimeout` | number | 60000 | Per-command timeout (ms) | ```javascript const conn = createConnection({ host: '192.168.1.10', user: 'SYS', password: 'MANAGER' }); await conn.connect(); ``` The promise rejects on socket connection failure, authentication error, or invalid handshake response. #### connect() Opens the server connection. ```javascript await conn.connect(); ``` #### end() Closes the socket connection. Further operations after `end()` raise an error. ```javascript await conn.end(); ``` ### Execute SQL #### execute(sql, values?) Executes commands that may not return a result set. Use for DDL (`CREATE`, `ALTER`, `DROP`) or DML (`INSERT`, `UPDATE`, `DELETE`). ```javascript const [create] = await conn.execute('CREATE TRANSACTION TABLE demo (ID INTEGER, NAME VARCHAR(32))'); console.log('Rows affected:', create.affectedRows); // -> 0 for DDL await conn.execute('BEGIN'); const [insert] = await conn.execute("INSERT INTO demo VALUES (1, 'alpha')"); console.log('Rows affected:', insert.affectedRows); // -> 1 await conn.execute('COMMIT'); ``` After a successful single `INSERT ... VALUES` in Standard Edition, the execution result includes the ROWID in `rowId`. Use `bigint`, not `number`, to preserve 64-bit precision. ```javascript const [result] = await conn.execute( 'INSERT INTO sensor_log(message) VALUES(?)', ['started'] ); if (result.rowId !== undefined) { const rowId = result.rowId; // bigint } ``` Executions without a ROWID have `rowId` set to `undefined`. See [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/) for batches, Append, `INSERT ... SELECT`, and UPSERT. #### query(sql, values?) Executes a query that returns rows. Returns a two-element tuple, `[rows, fields]`. ```javascript const [rows, fields] = await conn.query('SELECT ID, NAME FROM demo ORDER BY ID'); console.table(rows); ``` #### Named Bind Parameter For `execute()`, `query()`, and Prepared Statement `execute()`, arrays provide positional input and plain objects provide named input. ```typescript export type MachbaseNamedBindInput = Record; export type MachbaseExecuteInput = MachbaseBindInput[] | MachbaseNamedBindInput; ``` ```javascript await conn.execute( 'INSERT INTO demo (ID, NAME) VALUES (:id, :name)', { id: 1, name: 'node-client' }, ); const [rows] = await conn.query( 'SELECT ID, NAME FROM demo WHERE ID = :id OR PARENT_ID = :id', { id: 1 }, ); ``` Pass an object to Prepared Statements as well: ```javascript const stmt = await conn.prepare( 'SELECT ID, NAME FROM demo WHERE ID = :id' ); try { const [rows] = await stmt.execute({ id: 1 }); } finally { await stmt.close(); } ``` Object keys omit the leading colon and are case-sensitive. Repeated names receive the same value. Object input with `?` placeholders, missing required keys, or keys absent from SQL raises an error. | Error code | Condition | |---|---| | `ERR_MACHBASE_BIND_MISSING` | Required name missing | | `ERR_MACHBASE_BIND_EXTRA` | Name absent from SQL supplied | | `ERR_MACHBASE_BIND_MIXED` | Mixed named and anonymous placeholders | | `ERR_MACHBASE_NAMED_BIND_UNSUPPORTED` | Server does not support named binding | Each `ColumnMeta` object in `fields` provides a `nullable` property. ```typescript import { ColumnNullable } from '@machbase/ts-client'; const [rows, fields] = await conn.query( 'SELECT ID, NAME, ID + 1 AS EXPR_VALUE FROM demo ORDER BY ID' ); for (const field of fields) { if (field.nullable === ColumnNullable.NoNulls) { console.log(field.name, 'NO_NULLS'); } else { console.log(field.name, 'NULL handling required'); } } ``` | Enum | Numeric value | Meaning | |--------|:------:|------| | `ColumnNullable.NoNulls` | `0` | Cannot be NULL | | `ColumnNullable.Nullable` | `1` | Can be NULL | | `ColumnNullable.Unknown` | `2` | Unknown | `ColumnNullable.Unknown` does not mean `NOT NULL`; handle it as potentially nullable. See [Nullable Metadata Support](/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-nullable-metadata) for SQL result rules. In Machbase SQL, `''` is SQL `NULL`: `field.nullable` is `ColumnNullable.Nullable`, and the row value is JavaScript `null`. The literal `''''` is one single quote character, returning `ColumnNullable.NoNulls` and the string `'`. ### PRIMARY KEY Metadata in SELECT Results With a Machbase 8.7.0 server and matching SDK, `isPrimaryKey` in the `fields` array returned by `query()` or `execute()` reports primary key membership for direct columns. ```ts const [rows, fields] = await conn.query( 'SELECT ID, VALUE, ID + 1 AS ID_EXPR FROM T_PK' ); for (const field of fields) { console.log(field.name, field.isPrimaryKey); } ``` Expressions, aggregates, and columns on the NULL-supplying side of outer joins report `false`. Older servers or SDKs may not provide the primary key flag. ### Use Prepared Statements #### prepare(sql) Creates a Prepared Statement on the server. ```javascript const stmt = await conn.prepare('SELECT NAME FROM demo WHERE ID = ?'); try { const [rows] = await stmt.execute([1]); console.log(rows); // -> [ { NAME: 'alpha' } ] } finally { await stmt.close(); } ``` The returned object provides these methods: - `execute(parameters?)` – Executes the statement and returns `[rowsOrPacket, fields]`. - `getColumns()` – Returns cached column metadata. - `getLastMessage()` – Returns the latest server message. - `getStatementId()` – Returns the internal Statement ID. - `close()` – Releases server resources; repeated calls are safe. `ColumnMeta` returned by `getColumns()` includes the same `nullable` values. ```typescript const stmt = await conn.prepare('SELECT ID, NAME FROM demo WHERE ID = ?'); for (const column of stmt.getColumns()) { console.log(column.name, ColumnNullable[column.nullable]); } ``` #### Prepared Statement Examples **Reuse a Prepared SELECT:** ```javascript const select = await conn.prepare('SELECT DEVICE_ID, SENSOR_VALUE FROM sensors WHERE DEVICE_ID = ?'); for (const { id } of samples) { const [rows] = await select.execute([id]); console.log(`selected ${id}:`, rows); } await select.close(); ``` **Prepared Upsert:** ```javascript const upsert = await conn.prepare( 'INSERT INTO devices (DEVICE_ID, SENSOR_VALUE) VALUES (?, ?) ' + 'ON DUPLICATE KEY UPDATE SET SENSOR_VALUE = ?', ); const [result] = await upsert.execute([deviceId, firstValue, firstValue]); console.log('Affected rows:', result.affectedRows); await upsert.close(); ``` **Typed Arguments and NULL Handling:** ```javascript await update.execute([ { value: null, type: 'varchar' }, { value: new Date(), type: 'varchar' }, { value: 'sensor-200', type: 'varchar' }, ]); ``` Runnable example scripts are usually generated under `dist/examples/` after `npm run build`. Examples typically resolve credentials in this order: `MACHBASE_EXAMPLE_*`, `MACHBASE_SMOKE_*`, then `SYS/MANAGER@127.0.0.1`. ### Append API #### appendBatch(table, columns, rows, options?) Use `appendBatch()` to add multiple rows to a **LOG table**. Supply only user-visible columns; LOG tables automatically include `_arrival_time` and `_rid`. ```javascript const appendResult = await conn.appendBatch( 'sensor_log', [ { name: 'ID', type: 'int32' }, { name: 'NAME', type: 'varchar' }, { name: 'VALUE', type: 'float64' }, ], [ [1, 'alpha', 0.5], { values: [2, 'bravo', 1.25], arrivalTime: BigInt(Date.now()) * 1_000_000n }, ], ); console.log('Appended rows:', appendResult.rowsAppended); ``` Supported column types: `int32`, `int64`, `float64`, `varchar`. - `rows` accepts arrays of values or `{ values, arrivalTime }` objects. `null` is automatically encoded as a Machbase sentinel. - `options` accepts `arrivalTime` (one default) or `arrivalTimes` (one value per row). - Convert to `bigint` before calculating epoch nanoseconds. Multiplication with `number` exceeds the safe integer range. Returns `{ table, rowsAppended, rowsFailed, message }`. > **Tip:** A column-count mismatch error occurs if the target is not a LOG table or > column order does not match the schema. Use `appendOpen()` for TAG tables. #### appendOpen(table, columns, options?) Opens a lightweight Append session. By default, it uses native APPEND open/data/close. Successful native writes do not return per-chunk responses. ```javascript const stream = await conn.appendOpen('sensor_log', [ { name: 'ID', type: 'int32' }, { name: 'NAME', type: 'varchar' }, { name: 'VALUE', type: 'float64' }, ]); await stream.append([ [1, 'alpha', 0.5], [2, 'bravo', 1.25], ]); await stream.append({ values: [3, 'charlie', 2.5] }); await stream.close(); ``` Set `MACHBASE_NATIVE_APPEND=0` to disable native Append and force Prepared Statements. If the server does not support native Append for a table type or session, the facade automatically falls back to Prepared Statements. Pass `Date` objects or `bigint` epoch values to DATETIME columns in TAG tables. Pass sparse ARRAY values through `appendOpen()`. The current `@machbase/ts-client` requires `columns`, so define all input columns in order even for full-row input. Automatic inference from `appendOpen(table)` or an empty column list is unsupported. If `ID` and `A` below are all the table input columns, this is full-row input. Each row's `SparseArray` chooses positions within the ARRAY. See the [all-column definition example](../data-input-load-export/array-append/#node-full-columns) for connection, four-row ingestion, Close, and queries. For selected-column Append in Machbase DBMS 8.7.0, set `name` to an ordinary column or `ARRAY_COLUMN[position]`. To vary positions by row, pass `SparseArray` to a whole-array target. Element targets and `SparseArray.set()` positions are 0-based. ```javascript const { SparseArray } = require('@machbase/ts-client'); const stream = await conn.appendOpen('array_append_example', [ { name: 'ID', type: 'int64' }, { name: 'A', type: 'int32-array' }, ]); const sparse = new SparseArray(4).set(1, 200).set(3, 400); await stream.append([[2n, sparse]]); await stream.close(); ``` Even when `MACHBASE_NATIVE_APPEND=0` forces the prepared fallback, `SparseArray` is treated as an ARRAY-compatible value. See [Sparse ARRAY and Selected-Column Append API](../data-input-load-export/array-append/) for complete examples and NULL distinctions. #### append(rows) on an append stream Sends one or more rows to an open Append stream. ```javascript const frames = await stream.append([ ['S-001', new Date(), 1.0], ['S-002', new Date(Date.now() + 1), 2.0], ]); console.log('frames sent:', frames); ``` Native mode omits success responses for maximum throughput; only errors return failure packets. ### Helper Methods #### ping() Checks the connection with `SELECT 1 FROM V$TABLES`. ```javascript await conn.ping(); ``` #### promise() Provides a familiar `.promise()`-style wrapper. ```javascript const p = conn.promise(); await p.ping(); const [rows] = await p.query('SELECT NAME FROM V$TABLES ORDER BY NAME LIMIT ?', [5]); ``` #### escape, escapeId, format Utilities for constructing SQL strings safely. ```javascript const safeName = conn.escapeId('table_name'); const safeValue = conn.escape('user input'); ``` ## Testing and Diagnosis ### Scripts - `npm run build` – Compiles TypeScript - `npm run lint` – Runs ESLint on `src/` - `npm run smoke` – Optional smoke tests (skipped without environment variables) - `npm test` – Integration suite (requires a live server) 1. Creates a LOG table 2. Inserts and queries sample data 3. Demonstrates prepared positional binding 4. Runs append load tests (default: 5 batches × 200 rows) and verifies counts 5. Checks direct SQL `BEGIN`/`ROLLBACK`/`COMMIT` on TRANSACTION tables 6. Verifies the Machbase facade and `UPDATE` restrictions Sample output: ```text TRANSACTION transaction commit returned 1 row. machbase-facade-basic callback query returned 3 rows. machbase-facade-update-log-fails message: UPDATE is not supported for LOG tables. append-batch progress: batch 4/5 { table: 'TS_CLIENT_IT_...', rowsAppended: 200, rowsFailed: 0 } append-batch final count: 1004 ``` ## Tutorials ### Quick Start (LOG Table) ```javascript // quickstart-log.js const { createConnection } = require('@machbase/ts-client'); (async () => { const conn = createConnection({ host: '127.0.0.1', port: 5656, user: 'SYS', password: 'MANAGER' }); await conn.connect(); const table = 'JS_LOG_' + Math.random().toString(36).slice(2, 7).toUpperCase(); try { await conn.execute(`CREATE LOG TABLE "${table}" (ID INTEGER, NAME VARCHAR(64), VALUE DOUBLE)`); await conn.execute(`INSERT INTO "${table}" VALUES (1, 'A', 0.5)`); const [rows] = await conn.query(`SELECT * FROM "${table}" ORDER BY ID`); console.table(rows); } finally { await conn.execute(`DROP TABLE "${table}"`); await conn.end(); } })(); ``` ### Reuse Prepared Statements ```javascript // prepared-reuse.js const { createConnection } = require('@machbase/ts-client'); (async () => { const conn = createConnection({ host: '127.0.0.1', user: 'SYS', password: 'MANAGER' }); await conn.connect(); const table = 'JS_VOL_' + Math.random().toString(36).slice(2, 7).toUpperCase(); try { await conn.execute(`CREATE VOLATILE TABLE "${table}" (ID INTEGER PRIMARY KEY, NAME VARCHAR(64))`); for (let i = 1; i <= 3; i++) await conn.execute(`INSERT INTO "${table}" VALUES (${i}, 'N${i}')`); const stmt = await conn.prepare(`SELECT NAME FROM "${table}" WHERE ID = ?`); try { for (const id of [1, 2, 3]) { const [rows] = await stmt.execute([id]); console.log(id, rows[0]?.NAME); } } finally { await stmt.close(); } } finally { await conn.execute(`DROP TABLE "${table}"`); await conn.end(); } })(); ``` ### Batch Append to a LOG Table ```javascript // append-batch.js const { createConnection } = require('@machbase/ts-client'); (async () => { const conn = createConnection({ host: '127.0.0.1', user: 'SYS', password: 'MANAGER' }); await conn.connect(); const table = 'JS_LOGAPP_' + Math.random().toString(36).slice(2, 7).toUpperCase(); try { await conn.execute(`CREATE LOG TABLE "${table}" (ID INTEGER, NAME VARCHAR(64), VALUE DOUBLE)`); const result = await conn.appendBatch( table, [ { name: 'ID', type: 'int32' }, { name: 'NAME', type: 'varchar' }, { name: 'VALUE', type: 'float64' }, ], [[1, 'X', 0.5], [2, 'Y', 1.25]], ); console.log(result); } finally { await conn.execute(`DROP TABLE "${table}"`); await conn.end(); } })(); ``` ### Streaming Append to a TAG Table ```javascript // append-tag-stream.js const { createConnection } = require('@machbase/ts-client'); (async () => { const conn = createConnection({ host: '127.0.0.1', user: 'SYS', password: 'MANAGER' }); await conn.connect(); const table = 'JS_TAG_' + Math.random().toString(36).slice(2, 7).toUpperCase(); try { await conn.execute(`CREATE TAG TABLE "${table}" (name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED)`); const stream = await conn.appendOpen(table, [ { name: 'NAME', type: 'varchar' }, { name: 'TIME', type: 'int64' }, { name: 'VALUE', type: 'float64' }, ]); const now = Date.now(); await stream.append([ ['T-0001', new Date(now), 1.0], ['T-0002', new Date(now + 1), 2.0], ]); await stream.close(); const [rows] = await conn.query(`SELECT COUNT(*) AS CNT FROM "${table}"`); console.log('count', rows[0]?.CNT); } finally { await conn.execute(`DROP TABLE "${table}"`); await conn.end(); } })(); ``` > Native mode is enabled by default. Set `MACHBASE_NATIVE_APPEND=0` to disable it. > Successful chunks have no response; only errors return failure responses. ### Promise Wrapper and Ping ```javascript // promise-and-ping.js const { createConnection } = require('@machbase/ts-client'); (async () => { const conn = createConnection({ host: '127.0.0.1', user: 'SYS', password: 'MANAGER' }); await conn.connect(); try { const p = conn.promise(); await p.ping(); // SELECT 1 FROM V$TABLES const [rows] = await p.query('SELECT NAME FROM V$TABLES ORDER BY NAME LIMIT ?', [5]); console.log(rows.map(r => r.NAME)); } finally { await conn.end(); } })(); ``` ## Behavior and Limitations ### Transactions Server SQL transactions work on TRANSACTION tables, but facade transaction convenience methods are not implemented. Execute SQL directly on the same connection. ```javascript await conn.execute('BEGIN'); await conn.execute('UPDATE orders SET status = ? WHERE order_id = ?', ['DONE', 1001]); await conn.execute('COMMIT'); ``` ### Result Buffering and Pagination The wrapper `query` method buffers the entire result set before returning it. For large tables, paginate explicitly with `ORDER BY … LIMIT` or primary key ranges. ### Parameter Binding Arrays bind to positional `?` placeholders; objects bind to `:name` placeholders. Supported types include common scalar types such as `int32`, `int64`, `float64`, and `varchar`. Supply an explicit type when passing `null`. ```javascript { value: null, type: 'varchar' } ``` See [Named Bind Parameter Syntax](../../reference/sql/syntax/named-bind-parameter-syntax/) for name rules and the maximum parameter count. ### Append API Use `appendBatch` for LOG tables and `appendOpen`/`append` for incremental input. If a table type, such as TAG, does not support the ingestion path, it automatically falls back to repeated prepared execution. In production, split data into chunks and check `rowsFailed`. ### Error Handling Errors are passed as standard `Error` objects (`QueryError` with the wrapper). Inspect `error.message` or the `code` and `sql` fields of `QueryError` for diagnosis. Integration tests deliberately query nonexistent tables and attempt unsupported `UPDATE` operations to check that error messages are informative. ### SQL Considerations by Table Type - **LOG tables** do not support `UPDATE`. - **TAG table** data UPDATE is supported only in Standard Edition. It requires tag selection and BASETIME predicates. Tag names, the time axis, and metadata columns cannot be SET targets. SET expressions cannot reference existing-row columns. - **VOLATILE table** UPDATE/DELETE uses primary key predicates. **LOOKUP tables** support both primary key predicates and general conditions; primary key predicates are efficient for single-row changes. ## Best Practices 1. **Always close connections:** Use `try...finally` to ensure `conn.end()` runs. 2. **Reuse Prepared Statements:** Prepare once and execute repeatedly for better performance. 3. **Use batch ingestion:** Use `appendBatch` or `appendOpen` for bulk loading. 4. **Handle errors:** Wrap database operations in `try...catch` and log appropriately. 5. **Use connection pools:** Introduce pooling in production to handle concurrent requests reliably. 6. **Parameterize queries:** Use binding (`?` placeholders) instead of concatenation to prevent SQL injection. --- title: "11.8 .NET Connector" url: https://docs.machbase.com/dbms/development-tools-integration/net-connector/ language: en kind: section --- # 11.8 .NET Connector ## Contents {#index} * [Overview](#overview) * [Installation](#install) * [NuGet (Unified 8.0.55)](#nuget-unified-connector) * [Connection String Reference](#connection-string-reference) * [API Reference](#api-reference) * [Usage and Examples](#usage-and-examples) * [Protocol 4.0-full APIs](#full-provider-apis-protocol-40-full) ## Overview {#overview} Machbase provides **UniMachNetConnector**, a universal ADO.NET provider supporting wire protocols 2.1–4.0. The current unified package is `UniMachNetConnector` 8.0.55, with `net452`, `net5.0`, `net6.0`, `net7.0`, and `net8.0` builds. Automatic negotiation runs only when the connection string specifies `PROTOCOL=auto` or `auto-full`. ## Installation {#install} Machbase server/client installations distribute the universal .NET provider under `$MACHBASE_HOME/lib/`. A standard Linux package may include protocol-specific assemblies such as `UniMachNetConnector-net50-8.0.55.dll` and `machNetConnector-40-net50-3.2.2.dll`. The source project can build additional target framework variants when the required .NET SDK is available. - **UniMachNetConnector:** Framework-independent entry point. Source builds use `UniMachNetConnector-net{452|50|60|70|80}-.dll`; choose the file matching the deployment framework. - **Legacy protocol connectors:** Protocol-specific assemblies such as `machNetConnector-XX-net{40|50|60|70|80}-.dll`, loaded by UniMachNetConnector as needed. Reference the DLL matching the application target framework, or deploy it beside the executable. ## Multiple Databases MachConnector 4.0 can select the initial database with `DATABASE` or `DB_NAME` in the connection string. ```text SERVER=127.0.0.1;PORT_NO=5656;UID=APP_A;PWD=secret;DATABASE=FACTORY_A ``` The standard `Database` property and `ChangeDatabase()` are not guaranteed current catalog switching APIs; use SQL `USE` and `CURRENT_DATABASE()`. Do not assume automatic catalog reset on return to a connection pool. See the [Multi-Database Operations Guide](/dbms/operations-configuration-recovery/multi-database/#97-net) for limitations. ## Install with NuGet (Unified Connector, 8.0.55) {#nuget-unified-connector} The unified connector package ID is `UniMachNetConnector`. Prefer a NuGet package reference over copying DLLs for new projects. - Supported TFMs: net452, net5.0, net6.0, net7.0, net8.0 - net5.0 and later builds are self-contained. The net452 source build restores `System.ValueTuple` 4.5.0. ### Command-Line Quick Start ```bash # Run in the project directory dotnet add package UniMachNetConnector --version 8.0.55 dotnet build ``` To control the source feed explicitly, add the reference first and restore separately. ```bash dotnet add package UniMachNetConnector --version 8.0.55 --no-restore # Force a refresh of nuget.org metadata dotnet nuget locals http-cache --clear dotnet restore --no-cache --source https://api.nuget.org/v3/index.json ``` ### Visual Studio - Right-click the project → Manage NuGet Packages → Browse → search for “UniMachNetConnector” → select 8.0.55 → Install. ### Project File Example ```xml ``` ### Use a Local or Internal Feed (Optional) For an internal registry or folder feed, add the source and restore as follows. For a folder feed, place `UniMachNetConnector.8.0.55.nupkg` in that directory. ```bash # One-time setup dotnet nuget add source /path/to/local-nuget -n mach-local # Restore using both the local feed and nuget.org dotnet restore --no-cache \ --source /path/to/local-nuget \ --source https://api.nuget.org/v3/index.json ``` In environments with restricted permissions, set an absolute package cache path. ```bash PKG_DIR="$(pwd)/.nuget-packages"; mkdir -p "$PKG_DIR" NUGET_PACKAGES="$PKG_DIR" dotnet restore --no-cache --source /path/to/local-nuget NUGET_PACKAGES="$PKG_DIR" dotnet run --no-restore ``` > Tip: Immediately after publication, NU1102 (version not found) or “incompatible with > 'all' frameworks” usually indicates indexing or cache issues. Run > `dotnet nuget locals http-cache --clear`, then restore with `--no-cache`. The package > supports net452 and net5.0–net8.0. ### Minimal Example ```csharp using System; using Mach.Data.MachClient; var password = Environment.GetEnvironmentVariable("MACHBASE_PASSWORD") ?? throw new InvalidOperationException("MACHBASE_PASSWORD is required"); var cs = $"SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD={password};PROTOCOL=4.0-full"; using var conn = new MachConnection(cs); conn.Open(); using var cmd = new MachCommand("SELECT COUNT(*) FROM V$TABLES", conn); var count = Convert.ToInt64(cmd.ExecuteScalar()); Console.WriteLine($"Tables: {count}"); ``` ## Connection String Reference {#connection-string-reference} Separate entries with semicolons (`;`). Keywords listed in the same table row are equivalent. | Keywords | Description | Example | Default | |---|---|---|---| | `DSN`, `SERVER`, `HOST` | Host name or IP address | `SERVER=127.0.0.1` | None | | `PORT`, `PORT_NO` | Listener port | `PORT=5656` | `5656` | | `USERID`, `USERNAME`, `USER`, `UID` | User name | `UID=SYS` | `SYS` | | `PASSWORD`, `PWD` | Password | `PWD=manager` | None | | `CONNECT_TIMEOUT`, `ConnectionTimeout`, `connectTimeout` | Connection timeout (ms) | `CONNECT_TIMEOUT=10000` | `60000` | | `COMMAND_TIMEOUT`, `CommandTimeout`, `commandTimeout` | Per-command timeout (ms) | `COMMAND_TIMEOUT=50000` | `60000` | | `PROTOCOL`, `ProtocolVersion`, `MachProtocol` | Preferred wire protocol (`2.1`, `3.0`, `4.0`, `4.0-full`, `auto`, `auto-full`, etc.); omitted values use `4.0` | `PROTOCOL=auto` | `4.0` | Example: ```csharp var connectionString = string.Format( "SERVER={0};PORT_NO={1};UID=SYS;PWD=MANAGER;COMMAND_TIMEOUT=50000;PROTOCOL=4.0-full", host, port); ``` ### Automatic Protocol Detection (`PROTOCOL=auto`) With mixed server versions, set `PROTOCOL=auto` to let UniMachNetConnector negotiate a suitable legacy protocol at runtime: - `PROTOCOL=auto` attempts handshakes in order: 4.0 → 3.0 → 2.2 → 2.1. It uses the host, port, user, password, database, and `CONNECT_TIMEOUT` from the connection string. - `PROTOCOL=auto-full` selects the registered `4.0-full` descriptor when the server major version is 4. Only builds without that descriptor select limited 4.0. A failed full connection does not automatically retry with limited. - Multiple hosts, such as `SERVER=hostA:5700,hostB:6000`, are tried sequentially. Failure messages include each host/protocol combination to aid diagnosis. - Credentials are uppercased as in legacy drivers. Specify `DATABASE=` when not using the default database (`data`). - `CONNECT_TIMEOUT` applies to each detection round trip. If the exception says `Protocol probe received an invalid response`, check the port, firewall, and TLS configuration. If the server version is known, specify `PROTOCOL=2.1`, `3.0`, `4.0`, or `4.0-full` to skip automatic detection. ## API Reference {#api-reference} {{< callout type="warning" >}} Features not listed below may be unimplemented or may not work correctly.
Even declared APIs may throw `NotImplementedException` or `NotSupportedException` for unimplemented or unsupported features. Check that the installed provider supports the APIs you require. {{< /callout >}} ### MachConnection ```cs public sealed class MachConnection : DbConnection ``` Manages Machbase connections. Like `DbConnection`, it implements `IDisposable`; release it safely with `Dispose()` or a `using` statement. #### Constructor ``` MachConnection(string aConnectionString) ``` Creates a `MachConnection` from a connection string. #### Open ```cs void Open() ``` Establishes the connection using the connection string. #### Close ```cs void Close() ``` Closes the open connection. #### SetConnectAppendFlush ```cs void SetConnectAppendFlush(bool activeFlush) ``` Sets whether Append flushes automatically. #### Fields | Name | Description | |--|--| | `State` | `System.Data.ConnectionState` value | | `StatusString` | State string of the `MachCommand` used by this connection; intended for internal logging, not query status checks | ### MachCommand ```cs public sealed class MachCommand : DbCommand ``` Executes SQL or Append operations through a `MachConnection`. Like `DbCommand`, it implements `IDisposable`. #### Constructors ```cs MachCommand(string aQueryString, MachConnection aConn) ``` Creates an instance with the SQL to execute and a connection. ```cs MachCommand(MachConnection aConn) ``` Creates an Append-only command without a query. #### CreateParameter ```cs MachParameter CreateParameter() ``` Creates a new `MachParameter`. #### AppendOpen ```cs MachAppendWriter AppendOpen( string aTableName, int aErrorCheckCount = 0, MachAppendOption option = MachAppendOption.None) ``` Opens an Append session and returns a `MachAppendWriter`. * `aTableName`: Target table name * `aErrorCheckCount`: Sends data and checks failures after the specified record count; sets an automatic `APPEND-FLUSH` point. * `option`: `None` or `MicroSecTruncated`. #### AppendData ```cs void AppendData(MachAppendWriter writer, List dataList) ``` Loads list values into the Append buffer in order. Types must match the table columns; too few or too many values raise an exception. > **Note:** When specifying `_arrival_time` as `ulong`, use nanoseconds since > 1970-01-01 UTC, as required by Machbase. ```cs void AppendDataWithTime( MachAppendWriter writer, List dataList, DateTime arrivalTime) ``` Specifies `_arrival_time` explicitly as `DateTime`. ```cs void AppendDataWithTime( MachAppendWriter writer, List dataList, ulong arrivalTime) ``` Specifies `_arrival_time` as `ulong` nanoseconds. #### AppendFlush ```cs void AppendFlush(MachAppendWriter writer) ``` Sends buffered data to the server. More frequent calls reduce client-buffered data and transmission delay but may increase communication overhead. A successful call alone does not establish disk durability; also check server processing results and the target table durability policy. #### AppendClose ```cs void AppendClose(MachAppendWriter writer) ``` Closes the Append session. Internally calls `AppendFlush()` before completing the protocol. #### ExecuteNonQuery ```cs int ExecuteNonQuery() ``` Executes a query and returns the affected-record count. Mainly used for `INSERT`, `UPDATE`, `DELETE`, and DDL. #### RowId ```cs UInt64? RowId ``` After a successful single `INSERT ... VALUES` in Standard Edition, retrieve the inserted row's ROWID after `ExecuteNonQuery()` in MachConnector 4.0/4.0-full and Universal .NET. ```cs using (var command = new MachCommand( "INSERT INTO orders(item) VALUES('pump')", connection)) { command.ExecuteNonQuery(); ulong? rowId = command.RowId; } ``` Returns `null` if no ROWID is available. Read the 64-bit `RowId`, not the legacy 32-bit `LastInsertedId`. See [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/) for differences in batches and Append. #### ExecuteScalar ```cs object ExecuteScalar() ``` Executes a query and returns the first column value. #### ExecuteDbDataReader ```cs DbDataReader ExecuteDbDataReader(CommandBehavior behavior) ``` Executes a query and returns a `DbDataReader` for sequential result access. #### Fields | Name | Description | |--|--| | `Connection` / `DbConnection` | Current `MachConnection` | | `ParameterCollection` / `DbParameterCollection` | Parameter collection for binding | | `CommandText` | SQL string to execute | | `CommandTimeout` | Maximum server response wait (ms); inherited from `MachConnection` and read-only here | | `FetchSize` | Records fetched per server request; default 3000 | | `IsAppendOpened` | Whether an Append session is open | | `RowId` | 64-bit ROWID of a successful single INSERT; `null` when absent | ### MachDataReader ```cs public sealed class MachDataReader : DbDataReader ``` Reads fetched results sequentially. Use only objects obtained from `MachCommand.ExecuteDbDataReader()`. #### GetName ```cs string GetName(int ordinal) ``` Returns the column name at the specified index. #### GetDataTypeName ```cs string GetDataTypeName(int ordinal) ``` Returns the Machbase column type name. #### GetFieldType ```cs Type GetFieldType(int ordinal) ``` Returns the mapped .NET type. #### GetOrdinal ```cs int GetOrdinal(string name) ``` Returns the index for a column name. #### GetValue ```cs object GetValue(int ordinal) ``` Returns the current record value as `object`. #### IsDBNull ```cs bool IsDBNull(int ordinal) ``` Checks whether the column value is `NULL`. #### GetValues ```cs int GetValues(object[] values) ``` Fills an array with current record values and returns the number of entries written. #### GetSchemaTable ```cs DataTable GetSchemaTable() ``` Returns schema metadata for SELECT result columns. Check `AllowDBNull` for nullability. This behavior applies to both MachConnector40 and MachConnector40-full-API. ```csharp using var reader = command.ExecuteReader(); DataTable schema = reader.GetSchemaTable(); foreach (DataRow row in schema.Rows) { string columnName = Convert.ToString(row["ColumnName"]); object allowDBNull = row["AllowDBNull"]; if (allowDBNull is bool value && !value) { Console.WriteLine($"{columnName}: NO_NULLS"); } else { // true or DBNull.Value: NULL handling required Console.WriteLine($"{columnName}: NULL handling required"); } } ``` | `AllowDBNull` | Meaning | |---------------|------| | `false` | Cannot be NULL | | `true` | Can be NULL | | `DBNull.Value` | Unknown | `DBNull.Value` does not mean `NOT NULL`; handle it as potentially nullable. See [Nullable Metadata Support](/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-nullable-metadata) for SQL result rules. In Machbase SQL, `''` is SQL `NULL`: `AllowDBNull` in `GetSchemaTable()` is `true`, and `IsDBNull()` is `true` for the row. The literal `''''` is one single quote character, a non-NULL string result with `AllowDBNull=false`. `GetSchemaTable()` provides `ColumnName`, `ColumnOrdinal`, `ColumnSize`, `NumericPrecision`, `NumericScale`, `DataType`, `ProviderType`, `IsLong`, `AllowDBNull`, and `IsKey`. `IsKey=true` identifies a direct SELECT result column that is a PRIMARY KEY. Expressions and aggregates report `false`. Older servers or SDKs may return `false` for `IsKey`. Nullable metadata does not change DECIMAL precision `1–65`, scale `0–30`, or actual values. .NET returns DECIMAL as `System.Decimal` when precision is at most 29 and scale is at most 28. Values beyond that range return `System.String` to prevent precision loss. In that case, `GetSchemaTable().DataType`, `GetFieldType()`, and the actual row value CLR type are all `System.String`. #### Get*XXXX* ```cs bool GetBoolean(int ordinal) byte GetByte(int ordinal) char GetChar(int ordinal) short GetInt16(int ordinal) int GetInt32(int ordinal) long GetInt64(int ordinal) DateTime GetDateTime(int ordinal) string GetString(int ordinal) decimal GetDecimal(int ordinal) double GetDouble(int ordinal) float GetFloat(int ordinal) ``` Returns the column value as the specified type. #### Read ```cs bool Read() ``` Reads the next record. Returns `false` when there are no more results. #### Fields | Name | Description | |--|--| | `FetchSize` | Records fetched per request; default 3000 and read-only here | | `FieldCount` | Number of result columns | | `this[int ordinal]` | Equivalent to `GetValue(int ordinal)` | | `this[string name]` | Equivalent to `GetValue(GetOrdinal(name))` | | `HasRows` | Whether results exist | | `RecordsAffected` | Number of fetched records | ### MachParameterCollection ```cs public sealed class MachParameterCollection : DbParameterCollection, IEnumerable ``` Manages parameters bound to a `MachCommand`. Set parameters before execution to send their values with the command. > `MachParameter` binding does not provide a Prepared Statement execution-plan cache. > Measure repeated execution with actual queries and server cache conditions. > > The current provider renders parameters as typed SQL literals and executes through > ExecDirect. `MachParameterCollection` therefore does not use the server Prepared > Named Bind protocol or parameter metadata. #### Add ```cs MachParameter Add(string parameterName, DbType dbType) ``` Adds a `MachParameter` with the specified name and type, and returns it. ```cs int Add(object value) ``` Adds a value and returns its index. ```cs void AddRange(Array values) ``` Adds an array of plain values in one call. ```cs MachParameter AddWithValue(string parameterName, object value) ``` Adds a parameter name and value, and returns the created `MachParameter`. #### Contains ```cs bool Contains(object value) ``` Checks whether the value has already been added. ```cs bool Contains(string parameterName) ``` Checks whether the specified parameter name exists. #### Clear ```cs void Clear() ``` Removes all parameters. #### IndexOf ```cs int IndexOf(object value) ``` Returns the index of the value. ```cs int IndexOf(string parameterName) ``` Returns the index of the parameter name. #### Insert ```cs void Insert(int index, object value) ``` Inserts a value at the specified position. #### Remove ```cs void Remove(object value) ``` Removes the parameter containing the value. ```cs void RemoveAt(int index) ``` Removes the parameter at the index. ```cs void RemoveAt(string parameterName) ``` Removes the parameter with the specified name. #### Fields | Name | Description | |--|--| | `Count` | Parameter count | | `this[int index]` | `MachParameter` at the index | | `this[string name]` | `MachParameter` matching the name | ### MachParameter ```cs public sealed class MachParameter : DbParameter ``` Stores binding information for one parameter. #### Fields | Name | Description | |--|--| | `ParameterName` | Parameter name | | `Value` | Value to send | | `Size` | Value length | | `Direction` | `ParameterDirection`; default `Input` | | `DbType` | .NET database type | | `MachDbType` | Machbase-specific type | | `IsNullable` | Whether `NULL` is allowed | | `HasSetDbType` | Whether `DbType` is set | ### MachException ```cs public class MachException : DbException ``` Exception class for Machbase errors. #### Fields | Name | Description | |--|--| | `MachErrorCode` | Machbase error code when available; may be `0` when the Universal provider translates legacy exceptions | ### MachAppendWriter ```cs public sealed class MachAppendWriter ``` Helper class for the Append protocol. Obtain an instance by calling `MachCommand.AppendOpen()`. #### SetErrorDelegator ```cs void SetErrorDelegator(ErrorDelegateFuncType callback) void ErrorDelegateFuncType(MachAppendException e); ``` Registers a delegate called on Append errors. #### Fields | Name | Description | |--|--| | `SuccessCount` | Successfully stored record count; available after `AppendClose()` | | `FailureCount` | Failed record count; set after `AppendClose()` | | `Option` | `MachAppendOption` supplied to `AppendOpen()` | ### MachAppendException ```cs public sealed class MachAppendException : MachException ``` Exception with additional Append error information. Preserves the server error message and exposes the failed record as a string. #### GetRowBuffer ```cs string GetRowBuffer() ``` Returns the original failed record as a string. ## Usage and Examples {#usage-and-examples} ### Connect This example connects with an environment-variable password, creates a LOG table, inserts and queries data, then drops the table. ```csharp using System; using Mach.Data.MachClient; var password = Environment.GetEnvironmentVariable("MACHBASE_PASSWORD") ?? throw new InvalidOperationException("MACHBASE_PASSWORD is required"); var connString = $"SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD={password};PROTOCOL=4.0-full"; using var connection = new MachConnection(connString); connection.Open(); const string tableName = "NET_QUERY_DEMO"; using (var create = new MachCommand( $"CREATE LOG TABLE {tableName} (id INTEGER, name VARCHAR(40))", connection)) { create.ExecuteNonQuery(); } try { using (var insert = new MachCommand( $"INSERT INTO {tableName} VALUES (1, 'pump')", connection)) { insert.ExecuteNonQuery(); } using var query = new MachCommand($"SELECT id, name FROM {tableName}", connection); using var reader = query.ExecuteReader(); while (reader.Read()) { for (var column = 0; column < reader.FieldCount; column++) { Console.WriteLine($"{reader.GetName(column)} : {reader.GetValue(column)}"); } } } finally { using var drop = new MachCommand($"DROP TABLE {tableName}", connection); drop.ExecuteNonQuery(); } ``` ### Parameter Binding `MachParameterCollection` supports `:name`, `@name`, and `?name` placeholders. Prefer `:name`, which matches common SQL syntax. Name lookup is case-insensitive; a repeated name applies one value to all matching positions. Use `:name` with Machbase 8.7.0 servers. Older servers raise `MachException`. `@name` and `?name` are legacy provider compatibility formats. ```csharp var password = Environment.GetEnvironmentVariable("MACHBASE_PASSWORD") ?? throw new InvalidOperationException("MACHBASE_PASSWORD is required"); var connString = $"SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD={password};PROTOCOL=4.0-full"; using var connection = new MachConnection(connString); connection.Open(); const string sql = @" SELECT NAME FROM V$TABLES WHERE NAME = :table_name OR NAME = :table_name"; using var command = new MachCommand(sql, connection); command.Parameters.AddWithValue(":table_name", "V$TABLES"); using var reader = command.ExecuteReader(); while (reader.Read()) { Console.WriteLine($"{reader.GetName(0)} : {reader.GetValue(0)}"); } ``` Pass NULL as `DBNull.Value`. See [Named Bind Parameter Syntax](../../reference/sql/syntax/named-bind-parameter-syntax/) for shared name syntax. ### Append Use the Append protocol to load large volumes of time-series data quickly. ```csharp using System; using System.Collections.Generic; using Mach.Data.MachClient; var password = Environment.GetEnvironmentVariable("MACHBASE_PASSWORD") ?? throw new InvalidOperationException("MACHBASE_PASSWORD is required"); var connString = $"SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD={password};PROTOCOL=4.0-full"; using var connection = new MachConnection(connString); connection.Open(); const string tableName = "NET_APPEND_DEMO"; using (var create = new MachCommand( $"CREATE LOG TABLE {tableName} (ID INTEGER, NAME VARCHAR(40))", connection)) { create.ExecuteNonQuery(); } try { using var appendCommand = new MachCommand(connection); var writer = appendCommand.AppendOpen(tableName); writer.SetErrorDelegator(error => Console.Error.WriteLine($"Append row error: {error.Message}\n{error.GetRowBuffer()}")); try { for (var i = 1; i <= 100000; i++) { appendCommand.AppendData(writer, new List { i, $"NAME_{i % 100}" }); if (i % 1000 == 0) appendCommand.AppendFlush(writer); } } finally { if (appendCommand.IsAppendOpened) appendCommand.AppendClose(writer); } Console.WriteLine($"Success Count : {writer.SuccessCount}"); Console.WriteLine($"Failure Count : {writer.FailureCount}"); if (writer.FailureCount != 0) throw new InvalidOperationException($"Append failed rows: {writer.FailureCount}"); } finally { if (connection.State == System.Data.ConnectionState.Open) { try { using var drop = new MachCommand($"DROP TABLE {tableName}", connection); drop.ExecuteNonQuery(); } catch (Exception cleanupError) { Console.Error.WriteLine($"cleanup failed: {cleanupError.Message}"); } } } ``` ### ARRAY and Selected-Column Append Machbase DBMS 8.7.0 full/legacy providers return ARRAY as `object[]`. Element NULL is `null` within the array; use `IsDBNull()` to identify whole-array NULL. Standard `AppendOpen(table)` can also accept `MachSparseArray` as an ARRAY column value. ```csharp var writer = append.AppendOpen("ARRAY_APPEND_FULL_EXAMPLE"); ``` Input rows follow table column order. The [standard Open example](../data-input-load-export/array-append/#dotnet-full-open) inserts sparse values, empty sparse arrays, and whole NULL into `ID LONG, A INT32[4]`, covering `AppendData()`, Close, and result checks. The `IList` overload of `AppendOpen()` accepts ordinary columns or `ARRAY_COLUMN[position]`. To vary positions by row, pass `MachSparseArray` to a whole-array target. Element targets and `MachSparseArray.Set()` positions are 0-based. ```csharp using var append = new MachCommand(connection); var writer = append.AppendOpen( "ARRAY_APPEND_EXAMPLE", new List { "ID", "A" }); var sparse = new MachSparseArray(MachDBType.INT32_ARRAY, 4) .Set(1, 200) .Set(3, 400); try { append.AppendData(writer, new List { 2L, sparse }); } finally { if (append.IsAppendOpened) append.AppendClose(writer); } ``` An empty `MachSparseArray` means an ARRAY with all NULL elements; `DBNull.Value` means whole-array NULL. See [Sparse ARRAY and Selected-Column Append API](../data-input-load-export/array-append/) for overloads and complete validation examples. ### Configure the Error Delegate Register the delegate immediately after opening the writer to receive row errors as in the example above. Check success/failure counts after close. ### Configure Automatic AppendFlush AppendOpen starts an automatic flush thread. To disable it, call `connection.SetConnectAppendFlush(false)` on an already open writer. Automatic thread errors may not immediately surface as public exceptions; retain explicit flush/close and callback/count checks. ## Protocol 4.0-full APIs {#full-provider-apis-protocol-40-full} `PROTOCOL=4.0-full` enables expanded ADO.NET APIs. In the 8.0.55 source package, the 4.0 limited connector is 3.1.3 and 4.0-full is 3.2.2. Linux installations may include only the net50 variant under `$MACHBASE_HOME/lib/`; use source builds or NuGet restore artifacts for other target frameworks. - `UniMachNetConnector-net50-8.0.55.dll` – Universal entry point commonly installed with the DBMS Standard Linux package - `machNetConnector-40-net50-3.1.3.dll` – Protocol 4.0 limited connector - `machNetConnector-40-net50-3.2.2.dll` – Protocol 4.0-full connector ### Main Types Added in 4.0-full - `MachDbProviderFactory`: Registers/creates the provider with invariant name `Mach.Data`. - `MachConnectionStringBuilder`: Constructs connection strings without keyword typos. - `MachDataAdapter`, `MachRowUpdating`, `MachRowUpdated`: Support `DataTable`/`DataSet` workflows. - `MachCommandBuilder`: Generates INSERT/DELETE (and UPDATE under certain conditions) from SELECT. Before execution, check that generated SQL complies with the target table DML restrictions. ### Enable the Full API ```csharp var password = Environment.GetEnvironmentVariable("MACHBASE_PASSWORD") ?? throw new InvalidOperationException("MACHBASE_PASSWORD is required"); var connString = $"SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD={password};PROTOCOL=4.0-full"; using var connection = new MachConnection(connString); connection.Open(); ``` For UPDATE/DELETE, check both table-specific requirements and driver SQL generation capabilities. LOG does not support UPDATE. TAG UPDATE in Machbase DBMS 8.7.0 Standard Edition requires NAME and BASETIME predicates. Use commands and bindings that follow [TAG UPDATE Syntax](/dbms/reference/sql/syntax/dml-syntax/tag-data-update-syntax/) instead of relying on generic CommandBuilder output. ### Use the Connection String Builder ```csharp var builder = new MachConnectionStringBuilder { Server = "127.0.0.1", Port = 5656, UserID = "SYS", Password = Environment.GetEnvironmentVariable("MACHBASE_PASSWORD") ?? throw new InvalidOperationException("MACHBASE_PASSWORD is required") }; builder["PROTOCOL"] = "4.0-full"; using var connection = new MachConnection(builder.ConnectionString); connection.Open(); ``` ### Example: SQL INSERT with MachDataAdapter Load a LOOKUP table into a `DataTable` and add a row; the command builder executes an ordinary SQL INSERT. This path does not use the Append protocol. ```csharp using Mach.Data.MachClient; using System; using System.Data; var password = Environment.GetEnvironmentVariable("MACHBASE_PASSWORD") ?? throw new InvalidOperationException("MACHBASE_PASSWORD is required"); var connString = $"SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD={password};PROTOCOL=4.0-full"; using var connection = new MachConnection(connString); connection.Open(); using (var create = new MachCommand( "CREATE LOOKUP TABLE dotnet_lookup_demo (id INTEGER PRIMARY KEY, name VARCHAR(80))", connection)) { create.ExecuteNonQuery(); } var adapter = new MachDataAdapter( "SELECT id, name FROM dotnet_lookup_demo ORDER BY id", connection); var builder = new MachCommandBuilder(adapter); var table = new DataTable(); adapter.Fill(table); var newRow = table.NewRow(); newRow["id"] = 2001; newRow["name"] = "Inserted from MachDataAdapter"; table.Rows.Add(newRow); adapter.MachRowUpdating += (sender, args) => { Console.WriteLine( $"About to run {args.StatementType} with SQL: {args.Command?.CommandText}"); }; adapter.Update(table); using var drop = new MachCommand("DROP TABLE dotnet_lookup_demo", connection); drop.ExecuteNonQuery(); ``` > **Tip:** To inspect SQL before transmission, subscribe to events before `Update()`, as above. ### Example: Use DbProviderFactory `MachDbProviderFactory.Instance` connects Machbase to provider-neutral configurations such as `DbProviderFactories` and Dapper. ```csharp using System; using System.Data.Common; using Mach.Data.MachClient; DbProviderFactory factory = MachDbProviderFactory.Instance; using DbConnection connection = factory.CreateConnection()!; var password = Environment.GetEnvironmentVariable("MACHBASE_PASSWORD") ?? throw new InvalidOperationException("MACHBASE_PASSWORD is required"); connection.ConnectionString = $"SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD={password};PROTOCOL=4.0-full"; connection.Open(); using DbCommand command = connection.CreateCommand(); command.CommandText = "SELECT COUNT(*) FROM V$TABLES"; var count = (long)command.ExecuteScalar(); Console.WriteLine($"Visible tables: {count}"); ``` For automatic factory discovery in configuration-based applications, call `MachDbProviderFactory.Register()` once at startup so that `DbProviderFactories.GetFactory("Mach.Data")` returns the same instance. Protocol `4.0-full` requires Machbase 7.x or later. For older servers, use `PROTOCOL=4.0` (limited features) or protocols 2.x/3.x. --- title: "11.9 Go" url: https://docs.machbase.com/dbms/development-tools-integration/go/ language: en kind: section --- # 11.9 Go ## neo-client Overview `neo-client` is the Go client module for Machbase Neo. Version 2 centers on the standard `database/sql` driver and no longer provides the native `machgo` package from v1. Code written for v1 is incompatible with v2. Migrate existing `machgo.Config` or `mdb.Connect()` code to `database/sql` as described below. `neo-client` provides these packages: - `client` (module root, import `github.com/machbase/neo-client/v2`): Standard `database/sql` driver, `Appender`, struct scanning, and named parameter helpers - `api`: Machbase-specific data types and options - `machnet`: Low-level protocol/transport implementation used internally by `client`; application code rarely needs to import it directly ### Prerequisites - **Machbase server:** A running DBMS or Neo server reachable on its native port (default `5656`) - **Go 1.22 or later** - **Credentials:** A valid Machbase account (for example, `sys` / `manager` for local development) ## Getting Started ### Installation ```sh go get github.com/machbase/neo-client/v2 ``` ### Import Import the driver package with the blank identifier. It registers automatically as `machbase`; no explicit `sql.Register()` call is needed. ```go import ( "context" "database/sql" "fmt" _ "github.com/machbase/neo-client/v2" ) ``` ## Connections ### DSN Formats `neo-client` supports these DSN formats: - Server only: `host` or `host:port` - URL: `tcp://user:password@host:port/database?as=proxy&fetch_rows=100` - Semicolon-separated `key=value` pairs: `key=value;key=value;...` (for example, `user=sys;password=manager;server=127.0.0.1:5656`) Rules for `key=value` DSNs: - Values may be quoted with `"..."` or `'...'`. - Semicolons inside quoted values are literal characters. - Quoted values support backslash escapes: `\"` in double-quoted values, `\'` in single-quoted values, and `\\`. - Unclosed or mismatched quotes cause a parse error. Example: ```text user="sys as demo";password="12;34";server=127.0.0.1:5656; password="a\"b";server=127.0.0.1:5656; ``` Supported DSN keys: | Key | Description | |----|------| | `server` | Server URL such as `tcp://user:password@127.0.0.1:5656` | | `host`, `port` | Separate server host and port (default port: `5656`) | | `user`, `uid` | Login user | | `password`, `pwd` | Login password | | `database`, `db` | Initial database | | `auth_mode` | Authentication mode: `password` or `challenge` | | `auth_key_file`, `auth_key_pem` | Private key file path or inline PEM for `auth_mode=challenge` | | `auth_sig_scheme` | Challenge authentication signature scheme | | `fetch_rows`, `fetchrows` | Maximum rows per fetch (default `1000`) | | `statement_cache`, `statementcache` | Statement cache mode: `auto`, `on`, `off` (default `auto`) | | `io_metrics`, `iometrics` | Enable I/O metrics: `true`, `false` | | `alternative_servers` | Comma-separated alternatives such as `127.0.0.2:5656,backup.example.com:5657` | If `auth_key_file` or `auth_key_pem` is set without `auth_mode`, challenge authentication is selected. URL query parameters use the same option names. ```text tcp://sys:manager@127.0.0.1:5656/DATABASE_A?statement_cache=on&io_metrics=true ``` Unknown keys cause errors in `key=value` DSNs but are ignored in URL query strings. The URL path also selects the initial database (`tcp://sys:manager@127.0.0.1:5656/DATABASE_A`). Every physical connection selects the configured database. If application code executes `USE`, the connection is restored to that database before pool reuse. ## Query Example This example queries the `M$SYS_TABLES` system table through standard `database/sql`. ```go package main import ( "context" "database/sql" "fmt" _ "github.com/machbase/neo-client/v2" ) func main() { db, err := sql.Open("machbase", "server=tcp://sys:manager@127.0.0.1:5656") if err != nil { panic(err) } defer db.Close() ctx := context.Background() rows, err := db.QueryContext(ctx, `SELECT NAME, ID, TYPE FROM M$SYS_TABLES ORDER BY NAME`) if err != nil { panic(err) } defer rows.Close() for rows.Next() { var ( name string id int64 typ int ) if err := rows.Scan(&name, &id, &typ); err != nil { panic(err) } fmt.Println(name, id, typ) } if err := rows.Err(); err != nil { panic(err) } } ``` ## Create a Table and Insert Data This example creates a TAG table through `database/sql` and inserts rows with `ExecContext`. ```sql CREATE TAG TABLE IF NOT EXISTS example ( name VARCHAR(100) PRIMARY KEY, time DATETIME BASE TIME, value DOUBLE ); ``` ```go package main import ( "context" "database/sql" "fmt" "time" _ "github.com/machbase/neo-client/v2" ) func main() { dsn := "server=tcp://sys:manager@127.0.0.1:5656" db, err := sql.Open("machbase", dsn) if err != nil { panic(err) } defer db.Close() ctx := context.Background() _, err = db.ExecContext(ctx, `CREATE TAG TABLE IF NOT EXISTS EXAMPLE ( NAME VARCHAR(100) PRIMARY KEY, TIME DATETIME BASE TIME, VALUE DOUBLE )`) if err != nil { panic(err) } ts := time.Now() for i := 0; i < 10; i++ { rec := []any{ "example-client", ts.Add(time.Duration(i) * time.Second), 3.14 * float64(i), } result, err := db.ExecContext(ctx, `INSERT INTO EXAMPLE VALUES (?, ?, ?)`, rec...) if err != nil { panic(err) } affected, err := result.RowsAffected() if err != nil { panic(err) } fmt.Println("Rows affected:", affected) } } ``` After a successful single `INSERT ... VALUES` on Standard Edition with ROWID support, `Result.LastInsertId()` returns the inserted row's ROWID. Its type is `int64`; convert to `uint64` to preserve the ROWID's 64-bit value. Batches, Appender, `INSERT ... SELECT`, and UPSERT do not return ROWIDs. See [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/) for detailed conditions. ## Transactions Machbase supports `BEGIN`/`COMMIT`/`ROLLBACK` on ordinary tables (TRANSACTION tables) created with `CREATE TABLE`. TAG/LOG tables do not support transactions; DML on TAG/LOG tables inside a transaction raises `MACHCLI-ERR-2362`. Use the standard `database/sql` transaction API: ```go tx, err := db.BeginTx(ctx, nil) if err != nil { panic(err) } if _, err := tx.ExecContext(ctx, `INSERT INTO EXAMPLE_TX VALUES (?, ?, ?)`, name, ts, value); err != nil { tx.Rollback() panic(err) } if err := tx.Commit(); err != nil { panic(err) } ``` Use the `client.Tx`/`client.TxConn` closure helpers to reduce setup code. A `nil` return commits. An error rolls back and is returned unchanged. A panic rolls back and then panics again. ```go import client "github.com/machbase/neo-client/v2" err := client.Tx(ctx, db, func(tx *sql.Tx) error { if _, err := tx.ExecContext(ctx, `INSERT INTO EXAMPLE_TX VALUES (?, ?, ?)`, name, ts, value); err != nil { return err // Automatic ROLLBACK } return nil // Automatic COMMIT }) // TxConn runs a transaction on a specific connection obtained with db.Conn(ctx). conn, _ := db.Conn(ctx) defer conn.Close() err = client.TxConn(ctx, conn, func(tx *sql.Tx) error { // ... return nil }) ``` Errors returned by the closure remain unchanged, so `errors.Is`/`errors.As` still work. Returning a sentinel error is the idiomatic way to force rollback. Machbase does not support transaction options (isolation level or read-only), so the driver rejects them. ## High-Performance Bulk Ingestion (`Appender`) Use `client.Appender` for bulk time-series ingestion instead of individual `INSERT` statements. The appender buffers records on the client and streams them through a dedicated channel, making it much faster than individual INSERTs. ```go import client "github.com/machbase/neo-client/v2" appender := &client.Appender{} // Select columns: Append() sends these three values; remaining columns receive NULL. if err := appender.Connect(ctx, dsn, "EXAMPLE", "NAME", "TIME", "VALUE"); err != nil { panic(err) } defer func() { successCount, failCount, err := appender.Close() // Flush remaining buffers if err != nil { panic(err) } fmt.Println("Append finished. Success:", successCount, "Fail:", failCount) }() for _, rec := range records { // Pass individual values in the column order supplied to Connect. if err := appender.Append(rec.Name, rec.Time, rec.Value); err != nil { panic(err) } } ``` Key points: - **Column selection:** The columns passed to `Connect` (or `WithInputColumns`) define exactly which values each `Append` must supply and in what order. Unlisted columns receive NULL. - **Omitting the column list** (for example, `appender.Connect(ctx, dsn, "EXAMPLE")`) targets **all** table columns. Each `Append` must supply every value, including `nil`; otherwise, a value-count error occurs. - `Append` buffers rows. Call `Flush()` to send immediately. `Close()` flushes and returns session success/failure counts. - Configure buffering with `WithBatchMaxRows`, `WithBatchMaxBytes`, and `WithBatchMaxDelay`. - `WithBatchMaxRows(rows)`: Default `512`, minimum `1` - `WithBatchMaxBytes(bytes)`: Default `512KB`, minimum `4KB` - `WithBatchMaxDelay(duration)`: Default `5ms`, minimum `1ms`; `0` disables the time threshold - The appender works with TAG, LOG, and TRANSACTION tables, but bypasses SQL, so append is never part of a transaction. ```go appender := &client.Appender{} if err := appender.Connect(ctx, dsn, "EXAMPLE", "NAME", "TIME", "VALUE"); err != nil { panic(err) } defer appender.Close() appender. WithBatchMaxBytes(1024 * 1024). // 1 MB threshold WithBatchMaxRows(2000). // Row-count threshold WithBatchMaxDelay(500 * time.Millisecond) // Maximum delay threshold ``` {{< callout type="warning" >}} Do not run ordinary queries on a connection with an active appender. Use a separate connection for append workloads. {{< /callout >}} ### ARRAY and Selected-Column Append Omit column arguments from standard `appender.Connect(ctx, dsn, table)` and pass an object created by `api.NewSparseArray()` as the ARRAY column value. This differs from selecting fixed elements. ```go if err := appender.Connect(ctx, dsn, "ARRAY_APPEND_FULL_EXAMPLE"); err != nil { return err } ``` See the [standard Connect example](../data-input-load-export/array-append/#go-full-open) for the input order of `ID LONG, A INT32[4]`, sparse values, Close on errors, and query checks. ```go func appendSelected(ctx context.Context, dsn string) error { appender := &client.Appender{} if err := appender.Connect( ctx, dsn, "ARRAY_APPEND_EXAMPLE", "ID", "A[0]", "A[3]", ); err != nil { return err } if err := appender.Append(int64(1), int32(10), int32(40)); err != nil { _, _, _ = appender.Close() return err } success, failed, err := appender.Close() if err != nil { return err } if failed != 0 { return fmt.Errorf( "append result: success=%d failed=%d", success, failed, ) } return nil } ``` This example assumes imports of `context`, `fmt`, and `client "github.com/machbase/neo-client/v2"`. Use `api.NewSparseArray()` when positions vary by row. `Array.Set()`, `Get()`, `Entries()`, and element-position Append targets use 0-based positions. See [Sparse ARRAY and Selected-Column Append API](../data-input-load-export/array-append/) for APIs and version restrictions. ## Scan Results into Structs Map columns to struct fields with `db` tags instead of listing destinations in column order. Helpers accept an existing `*sql.Rows`, so they work with standard `database/sql` APIs. ```go import client "github.com/machbase/neo-client/v2" type TagRecord struct { Name string `db:"NAME"` Time time.Time `db:"TIME"` Value float64 `db:"VALUE"` cached string // Unexported or untagged fields are ignored } records, err := client.Select[TagRecord](ctx, db, `SELECT NAME, TIME, VALUE FROM EXAMPLE WHERE NAME = ? ORDER BY TIME LIMIT 100`, "sensor-1") ``` Available helpers: | Function | Purpose | | --- | --- | | `Select[T](ctx, q, query, args...)` | Executes a query and scans all rows into `[]T` | | `Get[T](ctx, q, query, args...)` | Executes a query and scans the first row; returns `sql.ErrNoRows` if empty | | `ScanAll[T](rows)` / `ScanOne[T](rows)` | Equivalent operations on rows opened by the caller | | `ScanEach[T](rows, fn)` | Streams one row at a time with constant memory | | `NewCursor[T](rows)` | Explicit `Next`/`Value`/`Err` iterator | | `ScanStruct(rows, &dest)` | Scans the current row without calling `rows.Next()` | | `ScanRow(rows, &dest)` / `ScanRows(rows, &slice)` | Non-generic variants | `T` can be a struct, pointer to a struct, scalar for a single-column query, or `map[string]any`. Mapping rules: - The tag key is `db`, with `json` as a fallback for existing DTOs. - Column names match case-insensitively; `db:"id"` matches `ID`. - `db:"-"` excludes a field; **untagged fields are also excluded**. To map untagged fields by name, call `WithNameMapper(client.NameMapperIdentity())`. - Embedded structs are flattened; named nested structs use `parent.child`. - NULL columns can be scanned into `*T` fields that become `nil`, or into `sql.Null[T]`. Mapping is strict by default: columns without matching fields and fields without matching columns are errors. This prevents changed `SELECT *` results from silently omitting values. Relax each call with `WithLaxColumns()` or `WithLaxFields()`. When scanning DATETIME into `string`, `int64`, or `time.Time` fields, additional `db` tag options use the same names as the machbase-neo HTTP API `timeformat`/`tz` query parameters. ```go type Row struct { Time string `db:"TIME,timeformat=2006-01-02 15:04:05,tz=Local"` // Custom layout and display time zone Epoch int64 `db:"TIME,timeformat=ms"` // Epoch milliseconds At time.Time `db:"TIME,tz=UTC"` // Per-field time zone override } ``` - `timeformat=`: Go time layout for `string`/`*string` fields (or `ns`/`us`/`ms`/`s` for an epoch represented as a numeric string) - `timeformat=ns|us|ms|s`: Epoch unit for `int64`/`*int64` fields - `tz=|Local|UTC`: Time zone for `string`/`time.Time` fields and their pointer variants These options also apply without tags. Fields of type `string`, `int64`, or `time.Time` matching DATETIME columns use `WithDateTime(timeformat, tz)` as the default. Without `WithDateTime`, defaults are `timeformat="2006-01-02 15:04:05.999"` and `tz="Local"`. Field tags always override `WithDateTime`. `Select`, `ScanAll`, and `ScanRows` load all results into memory and stop with `ErrScanTooManyRows` if `WithMaxRows` (default 1000) is exceeded. Raise it with `WithMaxRows(n)` or remove it with `WithMaxRows(0)`. Alternatively, stream with unlimited `ScanEach` or `NewCursor`. ```go rows, err := db.QueryContext(ctx, `SELECT NAME, TIME, VALUE FROM EXAMPLE`) if err != nil { panic(err) } defer rows.Close() // Helpers do not close supplied rows var total float64 err = client.ScanEach(rows, func(rec TagRecord) error { total += rec.Value return nil }) ``` ## Named Parameters `NamedArgs` converts a struct or `map[string]any` into `sql.Named` arguments using the same `db` tags. It does not inspect or rewrite SQL text; the server parses `:name` placeholders. ```go type condition struct { Name string `db:"name"` From time.Time `db:"from"` To time.Time `db:"to"` } args, err := client.NamedArgs(condition{Name: "sensor-1", From: begin, To: end}) if err != nil { panic(err) } records, err := client.Select[TagRecord](ctx, db, ` SELECT NAME, TIME, VALUE FROM EXAMPLE WHERE NAME = :name AND TIME BETWEEN :from AND :to`, args...) ``` Named parameters require a server that reports parameter-name metadata (Machbase v8.7.0 or later). Check `client.SupportsNamedParameters(ctx, db)`. Unsupported queries fail with `client.ErrNamedParamsUnsupported`; use positional `?` placeholders instead. See [Named Bind Parameter Syntax](../../reference/sql/syntax/named-bind-parameter-syntax/) for shared SQL behavior and SDK differences. ## Machbase 8.7: DECIMAL and Named Parameters Machbase 8.7 provides exact DECIMAL values, column nullability metadata, and named parameters. ```go import "database/sql" import client "github.com/machbase/neo-client/v2" amount, err := client.ParseDecimal("1234567890.125", 30, 3) if err != nil { panic(err) } result, err := conn.ExecContext(ctx, "INSERT INTO payments(id, amount) VALUES (:id, :amount)", sql.Named("id", int32(1)), sql.Named("amount", amount), ) if err != nil { panic(err) } ``` The `database/sql` driver accepts `sql.Named` and returns DECIMAL values as exact strings. Parameter names match case-insensitively; one supplied value binds all repeated occurrences. Do not mix named and positional arguments. `client.NamedArgs` creates `sql.Named` lists from structs or maps. When connecting to Machbase 8.5.x, use positional `?` parameters with table and data types supported by that server. Named parameters and Machbase 8.7 data types are unavailable. Column nullability may be unknown (`ColumnType.Nullable()` returns `ok=false`). ### Prepared Statements and Statement Cache Statements created with `db.PrepareContext` can run repeatedly. The driver caches statements per connection, configured by DSN `statement_cache=auto|on|off`. Reprepare after dropping and recreating a table or changing result column types to refresh cached metadata. After changing the session database with `USE`, prepare new statements or open new cursors for the other database instead of reusing existing ones. ## Run the Included Examples Runnable examples are included under `_example/` in the neo-client repository. ```sh go run ./_example/query.go -s 127.0.0.1:5656 -u sys -p manager go run ./_example/append.go -s 127.0.0.1:5656 -u sys -p manager go run ./_example/insert.go -s 127.0.0.1:5656 -u sys -p manager go run ./_example/scanbytag.go -s 127.0.0.1:5656 -u sys -p manager ``` ## Notes and Limitations - Both positional and named placeholders are supported, but cannot be mixed in one statement. Use `sql.Named()` for named input. See [Named Bind Parameter Syntax](../../reference/sql/syntax/named-bind-parameter-syntax/) for shared SQL behavior and SDK differences. - Pooling follows ordinary `sql.DB` behavior. With `database`/`db` in the DSN, every physical connection selects that database. Sessions changed with explicit `USE` are restored to the configured database before returning to the pool. - On Standard Edition with ROWID support, call `Result.LastInsertId()` after a single INSERT. Convert the returned `int64` to `uint64` to preserve its bit pattern. See [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/). - Always close `Rows`, `Stmt`, `sql.Conn`, and `sql.DB` after use. Struct scanning helpers do not close caller-supplied rows. - `Appender.Close()` returns append session success/failure counts. - Parameter types follow the driver implementation. Common SQL types, `time.Time`, `[]byte`, `net.IP`, and `api.Decimal` are supported; `bool` parameters are not. --- title: "11.10 Data Ingestion and Export" url: https://docs.machbase.com/dbms/development-tools-integration/data-input-load-export/ language: en kind: section --- # 11.10 Data Ingestion and Export Choose SQL, Append APIs, or file tools according to data volume and operational needs. This page covers selection and verification; see tool and SQL references for full options. ## Choose an Input Method | Method | Suitable for | Main checks | |------|-------------|-------------| | Single INSERT | Small inputs, immediate error checks | Affected rows, generated ID | | Prepared batch | Repeated execution of one SQL statement | Per-item results, failure position | | Append API | Continuous bulk TAG/LOG collection | Server responses, success/failure counts | | `LOAD DATA INFILE` | Loading server-accessible files | Server file permissions, input count | | `machloader`/`csvimport` | Loading client files | Logs, error-row files, input/failure counts | ### Compare Paths and Tools | Path/tool | Execution location and purpose | |---|---| | SDK Append | Application continuously sends multiple TAG/LOG rows | | SQL INSERT | Small inputs and ordinary SQL integration | | `LOAD DATA INFILE` | SQL loads a file accessible to the server | | `machloader` | Detailed control of client file mapping, logs, and error-row files | | `csvimport`/`csvexport` | Simple CSV input/output wrappers | | `tagmetaimport` | Bulk registration and updates of TAG metadata | `tagmetaimport` does not ingest TAG measurements. See [Command-Line Tools](/dbms/reference/command-line-tools/) for exact options. Use TAG or LOG for time-series/events requiring preservation of original data. Use TRANSACTION for relational changes, LOOKUP for small reference data, and VOLATILE for rebuildable in-memory caches. After choosing a table, select the input method based on expected counts, latency tolerance, retry scope, and duplicate policy. ## SQL INSERT Run this example in order, from creation through cleanup: ```sql CREATE LOG TABLE integration_insert_demo ( event_time DATETIME, sensor_id VARCHAR(32), value DOUBLE ); INSERT INTO integration_insert_demo VALUES (TO_DATE('2026-01-01 00:00:00'), 'TEMP-01', 25.3); SELECT sensor_id, value FROM integration_insert_demo; DROP TABLE integration_insert_demo; ``` In applications, bind values as prepared parameters and check returned affected-row counts. ## Append API Append opens a table through an SDK-specific API, sends multiple rows, then flushes and closes. Match column order and types to the schema, and use a separate connection from ordinary queries. See SDK pages for complete language-specific examples. Machbase DBMS 8.7.0 can select input columns or `ARRAY` elements at Append Open. Use SDK sparse ARRAY objects when positions vary by row. See [Sparse ARRAY and Selected-Column Append API](array-append/) for selection criteria, APIs, and validation examples. ## LOAD DATA INFILE `LOAD DATA INFILE` loads server-accessible files through SQL. Paths are interpreted from the server process, so check: - The file exists on the server host. - The server process account can read it. - Delimiters, quoting, encoding, and date format match the source. - Log/error-row file locations are defined for identifying failed rows. See [LOAD DATA INFILE](/dbms/reference/sql/syntax/load-data-infile-syntax/) for syntax and supported options. ## Prepare CSV Files Decide whether the first row is a header, and keep column count and order consistent. Test NULLs, empty strings, strings with delimiters, line breaks, and DATETIME formats using sample files. Validate schemas and conversion rules on a small sample before loading a large file. ## Import with machloader Basic syntax: ```bash "$MACHBASE_HOME/bin/machloader" -s 127.0.0.1 -P 5656 -u APP_USER -p "$MACH_SAMPLE_PASSWORD" -i -t SENSOR_LOG -d /data/sensor.csv -l /data/sensor.log -b /data/sensor.bad ``` Use `-H` for headers, `-D` for a non-comma delimiter, and `-F` for a different date format. See [machloader](/dbms/reference/command-line-tools/machloader/) for all options. ## Import with csvimport `csvimport` simplifies commonly used machloader CSV options. ```bash "$MACHBASE_HOME/bin/csvimport" -s 127.0.0.1 -P 5656 -u APP_USER -p "$MACH_SAMPLE_PASSWORD" -t SENSOR_LOG -d /data/sensor.csv -H -l /data/sensor.log -b /data/sensor.bad ``` Automatic creation with `-C` may not assign the intended business type to every column. For production loads, create the table explicitly and verify its schema first. ## Choose an Export Method | Method | Suitable for | |------|-------------| | `SAVE DATA INTO` | Create server files with SQL filters and selected columns | | `machloader -o` | Table exports with detailed options | | `csvexport` | Simple CSV export | | SDK SELECT | Application transforms or transmits rows | ## File Ownership and Paths `SAVE DATA INTO` paths and permissions are relative to the server process. Files from machloader and csvexport use the OS account running the tool. Avoid relative paths, and check overwrite policy and available disk space first. ## SAVE DATA INTO Use this to export filtered SQL results. Before running against a production path, verify file creation, encoding, and headers with small results in a separate test location. See [SAVE DATA INTO](/dbms/reference/sql/syntax/save-data-into-syntax/) for full syntax. ## Export with machloader ```bash "$MACHBASE_HOME/bin/machloader" -s 127.0.0.1 -P 5656 -u APP_USER -p "$MACH_SAMPLE_PASSWORD" -o -t SENSOR_LOG -d /data/sensor-export.csv -H -l /data/sensor-export.log ``` ## Export with csvexport ```bash "$MACHBASE_HOME/bin/csvexport" -s 127.0.0.1 -P 5656 -u APP_USER -p "$MACH_SAMPLE_PASSWORD" -t SENSOR_LOG -d /data/sensor-export.csv -H -l /data/sensor-export.log ``` ## Batch Processing - Load-test batch sizes against row size and latency requirements. - Record each batch's source offset and successful target count. - On partial failure, isolate and retry failed rows instead of the whole batch. - Define business keys and duplicate policies for safe row retransmission. ## Handle Bulk Ingestion Errors 1. Check the tool exit code and summary counts. 2. Find the server error code and first failure cause in logs. 3. Compare error-row column counts, types, NULLs, date formats, and encoding with the source. 4. Retest a small corrected file, then reload only failed rows. 5. Verify final table counts, time ranges, and sample rows. Logs and error-row files may contain credentials or raw sensitive data. Set access permissions and retention periods. --- title: "11.10.1 Sparse ARRAY and Selected-Column Append API" url: https://docs.machbase.com/dbms/development-tools-integration/data-input-load-export/array-append/ language: en kind: page --- # 11.10.1 Sparse ARRAY and Selected-Column Append API Machbase DBMS 8.7.0 supports populating selected positions in a fixed-length `ARRAY`. Use a sparse ARRAY when positions vary by row. When multiple Append rows populate the same positions, specify selected columns during Append Open. A sparse ARRAY represents **a value for one column**. Column selection specifies **which columns or elements a row supplies**. A full-row append using standard Open can also pass a sparse object to an ARRAY column. Node.js requires column definitions in `appendOpen()`, so list all columns to perform the equivalent full-row operation. For `ARRAY` declarations, ordinary input, queries, and SDK-specific dense ARRAY handling, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/). ## Choose an Input Method | Requirement | Recommended method | |---|---| | Specify only populated positions in one SQL row | `ARRAY_SPARSE(position => value, ...)` | | Populate the same positions in multiple Append rows | `A[0]`, `A[3]` targets in Append Open | | Append full rows with standard Open and varying ARRAY positions | Pass an SDK sparse object as the ARRAY value in each full row | | Populate selected columns with varying ARRAY positions | A whole `A` target in the selection list and an SDK sparse object | | A non-NULL ARRAY with all NULL elements | Empty sparse object | | A NULL ARRAY | SQL `NULL` or the SDK whole-NULL value | Positions are 0-based in SQL and all Machbase-specific SDK APIs. ## SQL Sparse Input ### ARRAY_SPARSE In INSERT or UPDATE contexts with a target column, specify only positions and values. ```sql CREATE LOG TABLE ARRAY_APPEND_EXAMPLE ( ID LONG, A INT32[4] ); INSERT INTO ARRAY_APPEND_EXAMPLE (ID, A) VALUES (1, ARRAY_SPARSE(0 => 10, 3 => 40)); ``` Where the target type cannot be inferred, such as SELECT, specify the element type and element count first. ```sql SELECT ARRAY_SPARSE(INT32[4], 0 => 10, 3 => 40); SELECT ARRAY_SPARSE(DECIMAL(12,4)[4], 1 => 1.2500); ``` - Positions must be integer literals in `0..cardinality-1`. - Pairs can appear in any order, but positions must be unique. - Omitted positions and `position => NULL` produce NULL elements. - `ARRAY_SPARSE()` or `ARRAY_SPARSE(INT32[4])` produces an ARRAY with all NULL elements. - Use SQL `NULL`, not `ARRAY_SPARSE()`, for a NULL array. - An invalid position or element conversion fails the entire statement. ### Direct sparse shorthand Position/value pairs can appear directly inside brackets without the `ARRAY_SPARSE` wrapper. ```sql INSERT INTO ARRAY_APPEND_EXAMPLE (ID, A) VALUES (2, [0 => 10, 3 => 40]); SELECT [1 => 12, 33 => 23]; ``` With a target ARRAY, its type and element count apply. Standalone expressions infer the common numeric type as dense ARRAYs do and set the element count to `largest position + 1`. The second example therefore has type `INT32[34]`. A standalone all-NULL sparse expression fails because the element type is unknown. Use `ARRAY_SPARSE(TYPE[N], ...)` in this case. `[]` remains the existing dense empty constructor; `ARRAY[0 => 1]` is not supported. ### Specify Positions in INSERT Targets When multiple rows populate the same positions, specify element targets in the column list. ```sql INSERT INTO ARRAY_APPEND_EXAMPLE (ID, A[0], A[3]) VALUES (2, 10, 40); -- A exists, but all elements are NULL. INSERT INTO ARRAY_APPEND_EXAMPLE (ID, A[0], A[3]) VALUES (3, NULL, NULL); -- A itself is NULL. INSERT INTO ARRAY_APPEND_EXAMPLE (ID) VALUES (4); ``` A statement cannot target both `A` and `A[0]`, or target the same element twice. Targeting an element of a scalar column or an out-of-range position raises an error. Element-position targets are supported in `INSERT ... VALUES` and Append selection lists. They are not supported in `INSERT ... SELECT` or `UPDATE ... SET A[0] = ...`. ## Common Append Rules ### Full-Row and Selected Input Standard Open uses the table input column order. Selected Open uses the specified target list order. The standard Open examples below pass two values, `ID` then `A`, without an extra `_arrival_time`. Each API in these examples handles the automatic LOG timestamp. Use the SDK timestamp API to provide an explicit arrival time. Node.js does not have separate standard and selected Open methods. Full-row input also requires column definitions with `name` and `type`; these examples list `ID` and `A` in table order. Calling only `appendOpen(table)` or passing an empty column list is unsupported. ### Prepare and Rerun the Examples The standard and selected examples use separate tables so they can run independently. Before each example, run the following setup SQL in the database you will connect to. ```sql CREATE LOG TABLE ARRAY_APPEND_FULL_EXAMPLE (ID LONG, A INT32[4]); ``` Standard example filenames include `full`. Selected examples use `ARRAY_APPEND_EXAMPLE` created above. The selected C example recreates this table itself; ensure the name is reserved for this exercise. Before running selected examples for other SDKs, prepare an empty `ARRAY_APPEND_EXAMPLE` with the same schema. Run each SDK example **independently**. Running multiple SDKs consecutively against one table creates duplicate IDs. To rerun, inspect the results, perform [Cleanup](#sparse-append-cleanup), and recreate the relevant table. Adjust the server address, port, and credentials to your environment. ### Common Results Both methods create the following four rows. The standard example uses a sparse object for ID=1; the selected example uses fixed element targets for ID=1. ```text ID=1 A=[10,null,null,40] Sparse object or fixed element targets ID=2 A=[null,200,null,400] Sparse object in the ARRAY column ID=3 A=[null,null,null,null] Empty sparse object ID=4 A=NULL whole NULL ``` ARRAY elements omitted from a sparse object become NULL. `entry_count == 0` or an empty sparse object produces an array of the declared length with all NULL elements, not a zero-length array. Whole NULL means the array value itself is absent; `ARRAY_LENGTH` is also NULL. ### Selected Open Rules These rules apply to **the target list of a selected Open**. Omitting column arguments from standard Open is not an empty selection list. Ordinary columns omitted from the selection list follow existing Append rules: - Nullable columns use NULL. - Columns with DEFAULT use their default value. - If a required-value column is missing, Append Open or row input fails. The target list must be nonempty and unique, ignoring case. It cannot include both a whole ARRAY and an element of that ARRAY. After Append Open, each row must supply exactly the number and order of values in the target list. Close an open Append handle even when row input fails. If Append Open itself fails, the SDK cleans up internal state and the connection can be reused. ## C SQLCLI Use the following public types for ARRAY input and retrieval: | Type or constant | Purpose | |---|---| | `SQL_MACHBASE_ARRAY` | Identifies the SQL ARRAY type | | `SQL_C_MACHBASE_ARRAY` | Dense ARRAY retrieval and binding descriptor | | `SQL_C_MACHBASE_SPARSE_ARRAY` | Prepared sparse ARRAY input | | `SQL_APPEND_SPARSE_ARRAY_DESC_LENGTH` | Identifies an Append sparse descriptor | ### Append a Sparse ARRAY with Standard Open Open with `SQLAppendOpen()` and pass `ID` and `A` in a `SQL_APPEND_PARAM` array. For `A`, set `mVar.mData` to the address of `SQL_MACHBASE_SPARSE_ARRAY_DESC` and `mVar.mLength` to `SQL_APPEND_SPARSE_ARRAY_DESC_LENGTH`. No columns are selected. Use `SQLAppendDataV3(..., row, 2)` to specify the value count. This example does not pass the descriptor directly to the legacy `SQLAppendData(void *[])` API. Use the empty `ARRAY_APPEND_FULL_EXAMPLE` created by the setup SQL. The descriptor and position, value, and indicator buffers must remain valid until the Append call returns. The same open handle sends different positions in the first two rows, then an empty sparse array and a whole NULL. ```c /* sparse_append_full.c */ #include #include #include #include static int ok(SQLRETURN rc) { return rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO; } static void fail(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt, const char *where) { SQLCHAR state[6] = {0}; SQLCHAR message[1024] = {0}; SQLINTEGER native = 0; SQLSMALLINT length = 0; SQLError(env, dbc, stmt, state, &native, message, (SQLSMALLINT)sizeof(message), &length); fprintf(stderr, "%s: %s %d %s\n", where, state, (int)native, message); exit(EXIT_FAILURE); } int main(void) { SQLHENV env = SQL_NULL_HENV; SQLHDBC dbc = SQL_NULL_HDBC; SQLHSTMT sql = SQL_NULL_HSTMT; SQLHSTMT append = SQL_NULL_HSTMT; SQLCHAR conn[] = "SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD=MANAGER;CONNTYPE=1"; SQL_APPEND_PARAM row[2]; SQLUSMALLINT positions[2] = {0, 3}; SQLINTEGER values[2] = {10, 40}; SQLLEN indicators[2] = {0, 0}; SQL_MACHBASE_SPARSE_ARRAY_DESC sparse; SQLBIGINT success = 0; SQLBIGINT failure = 0; SQLINTEGER id; SQLLEN idInd; SQLLEN textInd; SQLCHAR text[128]; if (!ok(SQLAllocEnv(&env)) || !ok(SQLAllocConnect(env, &dbc)) || !ok(SQLDriverConnect(dbc, NULL, conn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT)) || !ok(SQLAllocStmt(dbc, &sql)) || !ok(SQLAllocStmt(dbc, &append))) fail(env, dbc, SQL_NULL_HSTMT, "connect"); memset(&sparse, 0, sizeof(sparse)); sparse.struct_size = sizeof(sparse); sparse.element_c_type = SQL_C_SLONG; sparse.cardinality = 4; sparse.entry_count = 2; sparse.positions = positions; sparse.values = values; sparse.value_stride = sizeof(values[0]); sparse.element_indicators = indicators; memset(row, 0, sizeof(row)); if (!ok(SQLAppendOpen(append, (SQLCHAR*)"ARRAY_APPEND_FULL_EXAMPLE", 0))) fail(env, dbc, append, "sparse open"); row[0].mLong = 1; row[1].mVar.mData = &sparse; row[1].mVar.mLength = SQL_APPEND_SPARSE_ARRAY_DESC_LENGTH; if (!ok(SQLAppendDataV3(append, row, 2))) { SQLAppendClose(append, &success, &failure); fail(env, dbc, append, "first sparse row"); } positions[0] = 1; values[0] = 200; values[1] = 400; row[0].mLong = 2; if (!ok(SQLAppendDataV3(append, row, 2))) { SQLAppendClose(append, &success, &failure); fail(env, dbc, append, "sparse row"); } row[0].mLong = 3; sparse.entry_count = 0; if (!ok(SQLAppendDataV3(append, row, 2))) { SQLAppendClose(append, &success, &failure); fail(env, dbc, append, "empty sparse row"); } row[0].mLong = 4; row[1].mVar.mData = NULL; row[1].mVar.mLength = 0; if (!ok(SQLAppendDataV3(append, row, 2))) { SQLAppendClose(append, &success, &failure); fail(env, dbc, append, "whole NULL row"); } success = 0; failure = 0; if (!ok(SQLAppendClose(append, &success, &failure)) || success != 4 || failure != 0) fail(env, dbc, append, "sparse close"); if (!ok(SQLExecDirect(sql, (SQLCHAR*)"SELECT ID,A FROM ARRAY_APPEND_FULL_EXAMPLE ORDER BY ID", SQL_NTS))) fail(env, dbc, sql, "select"); if (!ok(SQLBindCol(sql, 1, SQL_C_SLONG, &id, sizeof(id), &idInd)) || !ok(SQLBindCol(sql, 2, SQL_C_CHAR, text, sizeof(text), &textInd))) fail(env, dbc, sql, "bind verify"); for (;;) { SQLRETURN fetch = SQLFetch(sql); if (fetch == SQL_NO_DATA) break; if (!ok(fetch)) fail(env, dbc, sql, "fetch verify"); printf("%d %s\n", (int)id, textInd == SQL_NULL_DATA ? "NULL" : (char*)text); } SQLFreeStmt(append, SQL_DROP); SQLFreeStmt(sql, SQL_DROP); SQLDisconnect(dbc); SQLFreeConnect(dbc); SQLFreeEnv(env); return EXIT_SUCCESS; } ``` ```bash cc -I"$MACHBASE_HOME/include" sparse_append_full.c \ -L"$MACHBASE_HOME/lib" -lmachbasecli -lm -ldl -lrt -pthread \ -o sparse_append_full LD_LIBRARY_PATH="$MACHBASE_HOME/lib" ./sparse_append_full ``` The program checks Close for 4 successes and 0 failures, then prints the retrieved IDs and arrays. Compare them with [Verify Results](#결과-확인). On an input error, it closes Append before exiting. Check which rows were actually stored before retrying. ### Append with Selected-Column Open `SQLAppendOpenColumns()` and its wide-character variant accept an array of column-name pointers terminated by `NULL`. There is no separate column-count argument. ```c SQLRETURN SQL_API SQLAppendOpenColumns( SQLHSTMT aStmtHandle, SQLCHAR *aTableName, SQLCHAR **aColumnNames, SQLINTEGER aErrorCheckCount); SQLRETURN SQL_API SQLAppendOpenColumnsW( SQLHSTMT aStmtHandle, SQLWCHAR *aTableName, SQLWCHAR **aColumnNames, SQLINTEGER aErrorCheckCount); ``` `aColumnNames == NULL` or a `NULL` first element raises an error. C pointers do not carry array lengths, so the caller must provide a valid array through the final `NULL`. Omitting the terminator can cause an out-of-bounds read; do not assume it can be diagnosed safely. The following `sparse_append.c` creates the table, appends four rows, and prints the results. ```c /* sparse_append.c */ #include #include #include #include static int ok(SQLRETURN rc) { return rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO; } static void fail(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt, const char *where) { SQLCHAR state[6] = {0}; SQLCHAR message[1024] = {0}; SQLINTEGER native = 0; SQLSMALLINT length = 0; SQLError(env, dbc, stmt, state, &native, message, (SQLSMALLINT)sizeof(message), &length); fprintf(stderr, "%s: %s %d %s\n", where, state, (int)native, message); exit(EXIT_FAILURE); } int main(void) { SQLHENV env = SQL_NULL_HENV; SQLHDBC dbc = SQL_NULL_HDBC; SQLHSTMT sql = SQL_NULL_HSTMT; SQLHSTMT append = SQL_NULL_HSTMT; SQLCHAR conn[] = "SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD=MANAGER;CONNTYPE=1"; SQLCHAR *fixed[] = {(SQLCHAR*)"ID", (SQLCHAR*)"A[0]", (SQLCHAR*)"A[3]", NULL}; SQLCHAR *whole[] = {(SQLCHAR*)"ID", (SQLCHAR*)"A", NULL}; SQL_APPEND_PARAM row[3]; SQLUSMALLINT positions[2] = {1, 3}; SQLINTEGER values[2] = {200, 400}; SQLLEN indicators[2] = {0, 0}; SQL_MACHBASE_SPARSE_ARRAY_DESC sparse; SQLBIGINT success = 0; SQLBIGINT failure = 0; SQLINTEGER id; SQLLEN idInd; SQLLEN textInd; SQLCHAR text[128]; if (!ok(SQLAllocEnv(&env)) || !ok(SQLAllocConnect(env, &dbc)) || !ok(SQLDriverConnect(dbc, NULL, conn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT)) || !ok(SQLAllocStmt(dbc, &sql)) || !ok(SQLAllocStmt(dbc, &append))) fail(env, dbc, SQL_NULL_HSTMT, "connect"); SQLExecDirect(sql, (SQLCHAR*)"DROP TABLE ARRAY_APPEND_EXAMPLE", SQL_NTS); if (!ok(SQLExecDirect(sql, (SQLCHAR*)"CREATE LOG TABLE ARRAY_APPEND_EXAMPLE(ID LONG,A INT32[4])", SQL_NTS))) fail(env, dbc, sql, "create"); memset(row, 0, sizeof(row)); row[0].mLong = 1; row[1].mInteger = 10; row[2].mInteger = 40; if (!ok(SQLAppendOpenColumns(append, (SQLCHAR*)"ARRAY_APPEND_EXAMPLE", fixed, 0))) fail(env, dbc, append, "fixed open"); if (!ok(SQLAppendDataV3(append, row, 3))) { SQLAppendClose(append, &success, &failure); fail(env, dbc, append, "fixed row"); } if (!ok(SQLAppendClose(append, &success, &failure)) || success != 1 || failure != 0) fail(env, dbc, append, "fixed close"); memset(&sparse, 0, sizeof(sparse)); sparse.struct_size = sizeof(sparse); sparse.element_c_type = SQL_C_SLONG; sparse.cardinality = 4; sparse.entry_count = 2; sparse.positions = positions; sparse.values = values; sparse.value_stride = sizeof(values[0]); sparse.element_indicators = indicators; memset(row, 0, sizeof(row)); if (!ok(SQLAppendOpenColumns(append, (SQLCHAR*)"ARRAY_APPEND_EXAMPLE", whole, 0))) fail(env, dbc, append, "sparse open"); row[0].mLong = 2; row[1].mVar.mData = &sparse; row[1].mVar.mLength = SQL_APPEND_SPARSE_ARRAY_DESC_LENGTH; if (!ok(SQLAppendDataV3(append, row, 2))) { SQLAppendClose(append, &success, &failure); fail(env, dbc, append, "sparse row"); } row[0].mLong = 3; sparse.entry_count = 0; if (!ok(SQLAppendDataV3(append, row, 2))) { SQLAppendClose(append, &success, &failure); fail(env, dbc, append, "empty sparse row"); } row[0].mLong = 4; row[1].mVar.mData = NULL; row[1].mVar.mLength = 0; if (!ok(SQLAppendDataV3(append, row, 2))) { SQLAppendClose(append, &success, &failure); fail(env, dbc, append, "whole NULL row"); } success = 0; failure = 0; if (!ok(SQLAppendClose(append, &success, &failure)) || success != 3 || failure != 0) fail(env, dbc, append, "sparse close"); if (!ok(SQLExecDirect(sql, (SQLCHAR*)"SELECT ID,A FROM ARRAY_APPEND_EXAMPLE ORDER BY ID", SQL_NTS))) fail(env, dbc, sql, "select"); if (!ok(SQLBindCol(sql, 1, SQL_C_SLONG, &id, sizeof(id), &idInd)) || !ok(SQLBindCol(sql, 2, SQL_C_CHAR, text, sizeof(text), &textInd))) fail(env, dbc, sql, "bind verify"); for (;;) { SQLRETURN fetch = SQLFetch(sql); if (fetch == SQL_NO_DATA) break; if (!ok(fetch)) fail(env, dbc, sql, "fetch verify"); printf("%d %s\n", (int)id, textInd == SQL_NULL_DATA ? "NULL" : (char*)text); } SQLFreeStmt(append, SQL_DROP); SQLFreeStmt(sql, SQL_DROP); SQLDisconnect(dbc); SQLFreeConnect(dbc); SQLFreeEnv(env); return EXIT_SUCCESS; } ``` Build and run as follows: ```bash cc -I"$MACHBASE_HOME/include" sparse_append.c \ -L"$MACHBASE_HOME/lib" -lmachbasecli -lm -ldl -lrt -pthread \ -o sparse_append LD_LIBRARY_PATH="$MACHBASE_HOME/lib" ./sparse_append ``` Descriptor positions are 0-based. They need not be sorted, but must be unique. An entry indicator of `SQL_NULL_DATA` makes that element NULL. `entry_count == 0` represents an empty sparse ARRAY. For a whole NULL, set `mVar.mData = NULL` and `mVar.mLength = 0`. ## C++ SQLCLI ### Append a Sparse ARRAY with Standard Open Use the same descriptors and `SQLAppendOpen()` as C. Keep position/value buffers in `std::array` and close Append on both success and exception paths. Prepare the standard example table first. ```cpp /* sparse_append_full.cpp */ #include #include #include #include static bool ok(SQLRETURN rc) { return rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO; } struct Handles { SQLHENV env{SQL_NULL_HENV}; SQLHDBC dbc{SQL_NULL_HDBC}; SQLHSTMT stmt{SQL_NULL_HSTMT}; ~Handles() { if (stmt != SQL_NULL_HSTMT) SQLFreeStmt(stmt, SQL_DROP); if (dbc != SQL_NULL_HDBC) { SQLDisconnect(dbc); SQLFreeConnect(dbc); } if (env != SQL_NULL_HENV) SQLFreeEnv(env); } }; int main() { Handles h; SQLCHAR conn[] = "SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD=MANAGER;CONNTYPE=1"; if (!ok(SQLAllocEnv(&h.env)) || !ok(SQLAllocConnect(h.env, &h.dbc)) || !ok(SQLDriverConnect(h.dbc, nullptr, conn, SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_NOPROMPT)) || !ok(SQLAllocStmt(h.dbc, &h.stmt))) throw std::runtime_error("connect"); std::array positions{0, 3}; std::array values{10, 40}; std::array indicators{0, 0}; SQL_MACHBASE_SPARSE_ARRAY_DESC sparse{}; sparse.struct_size = sizeof(sparse); sparse.element_c_type = SQL_C_SLONG; sparse.cardinality = 4; sparse.entry_count = 2; sparse.positions = positions.data(); sparse.values = values.data(); sparse.value_stride = sizeof(values[0]); sparse.element_indicators = indicators.data(); std::array row{}; row[1].mVar.mData = &sparse; row[1].mVar.mLength = SQL_APPEND_SPARSE_ARRAY_DESC_LENGTH; SQLBIGINT success = 0, failure = 0; if (!ok(SQLAppendOpen(h.stmt, (SQLCHAR*)"ARRAY_APPEND_FULL_EXAMPLE", 0))) throw std::runtime_error("SQLAppendOpen"); try { for (int id = 1; id <= 4; ++id) { row[0].mLong = id; if (id == 2) { positions[0] = 1; values[0] = 200; values[1] = 400; } else if (id == 3) { sparse.entry_count = 0; } else if (id == 4) { row[1].mVar.mData = nullptr; row[1].mVar.mLength = 0; } if (!ok(SQLAppendDataV3(h.stmt, row.data(), 2))) throw std::runtime_error("SQLAppendDataV3"); } } catch (...) { SQLAppendClose(h.stmt, &success, &failure); throw; } if (!ok(SQLAppendClose(h.stmt, &success, &failure)) || success != 4 || failure != 0) throw std::runtime_error("SQLAppendClose"); if (!ok(SQLExecDirect(h.stmt, (SQLCHAR*)"SELECT ID,A FROM ARRAY_APPEND_FULL_EXAMPLE ORDER BY ID", SQL_NTS))) throw std::runtime_error("verify query"); SQLINTEGER id{}; SQLLEN idInd{}, arrayInd{}; SQLCHAR value[128]{}; if (!ok(SQLBindCol(h.stmt, 1, SQL_C_SLONG, &id, sizeof(id), &idInd)) || !ok(SQLBindCol(h.stmt, 2, SQL_C_CHAR, value, sizeof(value), &arrayInd))) throw std::runtime_error("bind verify"); for (;;) { SQLRETURN fetch = SQLFetch(h.stmt); if (fetch == SQL_NO_DATA) break; if (!ok(fetch)) throw std::runtime_error("fetch verify"); std::cout << id << ' ' << (arrayInd == SQL_NULL_DATA ? "NULL" : (char*)value) << '\n'; } } ``` ```bash c++ -std=c++11 -I"$MACHBASE_HOME/include" sparse_append_full.cpp \ -L"$MACHBASE_HOME/lib" -lmachbasecli -lm -ldl -lrt -pthread \ -o sparse_append_full_cpp LD_LIBRARY_PATH="$MACHBASE_HOME/lib" ./sparse_append_full_cpp ``` ### Append with Selected-Column Open Use SQLCLI descriptors without creating a C++-specific transport object. This example uses an RAII wrapper to ensure close and sends descriptors while the C++ containers remain alive. ```cpp /* sparse_append.cpp */ #include #include #include #include static bool ok(SQLRETURN rc) { return rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO; } struct Handles { SQLHENV env{SQL_NULL_HENV}; SQLHDBC dbc{SQL_NULL_HDBC}; SQLHSTMT stmt{SQL_NULL_HSTMT}; ~Handles() { if (stmt != SQL_NULL_HSTMT) SQLFreeStmt(stmt, SQL_DROP); if (dbc != SQL_NULL_HDBC) { SQLDisconnect(dbc); SQLFreeConnect(dbc); } if (env != SQL_NULL_HENV) SQLFreeEnv(env); } }; static void append(Handles& h, SQLCHAR **columns, SQL_APPEND_PARAM *row, SQLINTEGER count) { SQLBIGINT success = 0, failure = 0; if (!ok(SQLAppendOpenColumns(h.stmt, (SQLCHAR*)"ARRAY_APPEND_EXAMPLE", columns, 0))) throw std::runtime_error("SQLAppendOpenColumns"); try { if (!ok(SQLAppendDataV3(h.stmt, row, count))) throw std::runtime_error("SQLAppendDataV3"); } catch (...) { SQLAppendClose(h.stmt, &success, &failure); throw; } if (!ok(SQLAppendClose(h.stmt, &success, &failure)) || failure != 0) throw std::runtime_error("SQLAppendClose"); } int main() { Handles h; SQLCHAR conn[] = "SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD=MANAGER;CONNTYPE=1"; if (!ok(SQLAllocEnv(&h.env)) || !ok(SQLAllocConnect(h.env, &h.dbc)) || !ok(SQLDriverConnect(h.dbc, nullptr, conn, SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_NOPROMPT)) || !ok(SQLAllocStmt(h.dbc, &h.stmt))) throw std::runtime_error("connect"); SQLCHAR *fixed[] = {(SQLCHAR*)"ID", (SQLCHAR*)"A[0]", (SQLCHAR*)"A[3]", nullptr}; std::array row{}; row[0].mLong = 1; row[1].mInteger = 10; row[2].mInteger = 40; append(h, fixed, row.data(), 3); std::array pos{1, 3}; std::array val{200, 400}; std::array ind{0, 0}; SQL_MACHBASE_SPARSE_ARRAY_DESC sparse{}; sparse.struct_size = sizeof(sparse); sparse.element_c_type = SQL_C_SLONG; sparse.cardinality = 4; sparse.entry_count = 2; sparse.positions = pos.data(); sparse.values = val.data(); sparse.value_stride = sizeof(val[0]); sparse.element_indicators = ind.data(); SQLCHAR *whole[] = {(SQLCHAR*)"ID", (SQLCHAR*)"A", nullptr}; std::array sparseRow{}; sparseRow[0].mLong = 2; sparseRow[1].mVar.mData = &sparse; sparseRow[1].mVar.mLength = SQL_APPEND_SPARSE_ARRAY_DESC_LENGTH; append(h, whole, sparseRow.data(), 2); sparse.entry_count = 0; sparseRow[0].mLong = 3; append(h, whole, sparseRow.data(), 2); sparseRow[0].mLong = 4; sparseRow[1].mVar.mData = nullptr; sparseRow[1].mVar.mLength = 0; append(h, whole, sparseRow.data(), 2); if (!ok(SQLExecDirect(h.stmt, (SQLCHAR*)"SELECT ID,A FROM ARRAY_APPEND_EXAMPLE ORDER BY ID", SQL_NTS))) throw std::runtime_error("verify query"); SQLINTEGER id{}; SQLLEN idInd{}, arrayInd{}; SQLCHAR value[128]{}; if (!ok(SQLBindCol(h.stmt, 1, SQL_C_SLONG, &id, sizeof(id), &idInd)) || !ok(SQLBindCol(h.stmt, 2, SQL_C_CHAR, value, sizeof(value), &arrayInd))) throw std::runtime_error("bind verify"); for (;;) { SQLRETURN fetch = SQLFetch(h.stmt); if (fetch == SQL_NO_DATA) break; if (!ok(fetch)) throw std::runtime_error("fetch verify"); std::cout << id << ' ' << (arrayInd == SQL_NULL_DATA ? "NULL" : (char*)value) << '\n'; } } ``` ```bash c++ -std=c++11 -I"$MACHBASE_HOME/include" sparse_append.cpp \ -L"$MACHBASE_HOME/lib" -lmachbasecli -lm -ldl -lrt -pthread \ -o sparse_append_cpp ``` ## Machbase ODBC extension ### Append a Sparse ARRAY with Standard Open A C program linked directly to the Machbase driver can use `sparse_append_full.c` from the [standard C Open example](#c-full-open) unchanged. It sends sparse descriptors with `SQLAppendDataV3()` after `SQLAppendOpen()` and does not call `OpenColumns`. Build with matching versions of the headers and ODBC extension library. ```bash cc -I"$MACHBASE_HOME/include" sparse_append_full.c \ -L"$MACHBASE_HOME/lib" -lmachbasecli_dll -lm -ldl -lrt -pthread \ -o sparse_append_full_odbc LD_LIBRARY_PATH="$MACHBASE_HOME/lib" ./sparse_append_full_odbc ``` Prepare the standard example table before running. These handles are created directly by the Machbase driver; do not mix them with generic ODBC Driver Manager handles. ### Append with Selected-Column Open ODBC C applications linked directly to the Machbase driver library and using `machbase_sqlcli.h` can use the same extension functions. This example inserts four rows through the direct Machbase driver API. Create the table first using the preceding DDL. ```c /* sparse_odbc.c */ #include #include #include static int ok(SQLRETURN rc) { return rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO; } int main(void) { SQLHENV env = SQL_NULL_HENV; SQLHDBC dbc = SQL_NULL_HDBC; SQLHSTMT stmt = SQL_NULL_HSTMT; SQLBIGINT success = 0, failure = 0; SQLCHAR connection[] = "SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD=MANAGER;CONNTYPE=1"; if (!ok(SQLAllocEnv(&env)) || !ok(SQLAllocConnect(env, &dbc)) || !ok(SQLDriverConnect(dbc, NULL, connection, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT)) || !ok(SQLAllocStmt(dbc, &stmt))) return 1; SQLCHAR *fixed[] = {(SQLCHAR*)"ID", (SQLCHAR*)"A[0]", (SQLCHAR*)"A[3]", NULL}; SQL_APPEND_PARAM row[3] = {0}; row[0].mLong = 1; row[1].mInteger = 10; row[2].mInteger = 40; if (!ok(SQLAppendOpenColumns(stmt, (SQLCHAR*)"ARRAY_APPEND_EXAMPLE", fixed, 0))) return 2; if (!ok(SQLAppendDataV3(stmt, row, 3))) { SQLAppendClose(stmt, &success, &failure); return 2; } if (!ok(SQLAppendClose(stmt, &success, &failure)) || success != 1 || failure != 0) return 2; SQLUSMALLINT positions[2] = {1, 3}; SQLINTEGER values[2] = {200, 400}; SQLLEN indicators[2] = {0, 0}; SQL_MACHBASE_SPARSE_ARRAY_DESC sparse = {0}; sparse.struct_size = sizeof(sparse); sparse.element_c_type = SQL_C_SLONG; sparse.cardinality = 4; sparse.entry_count = 2; sparse.positions = positions; sparse.values = values; sparse.value_stride = sizeof(values[0]); sparse.element_indicators = indicators; SQLCHAR *whole[] = {(SQLCHAR*)"ID", (SQLCHAR*)"A", NULL}; memset(row, 0, sizeof(row)); row[0].mLong = 2; row[1].mVar.mData = &sparse; row[1].mVar.mLength = SQL_APPEND_SPARSE_ARRAY_DESC_LENGTH; if (!ok(SQLAppendOpenColumns(stmt, (SQLCHAR*)"ARRAY_APPEND_EXAMPLE", whole, 0))) return 3; if (!ok(SQLAppendDataV3(stmt, row, 2))) { SQLAppendClose(stmt, &success, &failure); return 3; } sparse.entry_count = 0; row[0].mLong = 3; if (!ok(SQLAppendDataV3(stmt, row, 2))) { SQLAppendClose(stmt, &success, &failure); return 3; } row[0].mLong = 4; row[1].mVar.mData = NULL; row[1].mVar.mLength = 0; if (!ok(SQLAppendDataV3(stmt, row, 2))) { SQLAppendClose(stmt, &success, &failure); return 3; } success = 0; failure = 0; if (!ok(SQLAppendClose(stmt, &success, &failure)) || success != 3 || failure != 0) return 3; SQLFreeStmt(stmt, SQL_DROP); SQLDisconnect(dbc); SQLFreeConnect(dbc); SQLFreeEnv(env); puts("ODBC sparse append OK"); return 0; } ``` ```bash cc sparse_odbc.c -I/opt/machbase/include -L/opt/machbase/lib \ -lmachbasecli_dll -lm -ldl -lrt -pthread -o sparse_odbc LD_LIBRARY_PATH=/opt/machbase/lib ./sparse_odbc ``` {{< callout type="warning" >}} Do not pass a statement handle created by a generic ODBC Driver Manager to a direct SQLCLI extension: their handle ABIs differ. Selected-column Append requires the Machbase driver extension and direct driver handles. Generic ODBC APIs do not provide Append Open selection targets. {{< /callout >}} ## JDBC ### Append a Sparse ARRAY with Standard Open Use the `executeAppendOpen(table, errorCheckCount)` overload. Pass `ID` and `MachSparseArray` according to the returned metadata, without manually adding the standard example table's automatic timestamp. `null` means whole NULL; an empty `MachSparseArray` means an array with all NULL elements. Save as `SparseAppendFull.java` and run with a JDBC JAR that includes ARRAY support. ```java import com.machbase.jdbc.MachConnection; import com.machbase.jdbc.MachSparseArray; import com.machbase.jdbc.MachStatement; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class SparseAppendFull { public static void main(String[] args) throws Exception { try (MachConnection con = (MachConnection)DriverManager.getConnection( "jdbc:machbase://127.0.0.1:5656/machbasedb", "SYS", "MANAGER"); MachStatement st = (MachStatement)con.createStatement()) { Map entries = new HashMap(); entries.put(0, 10); entries.put(3, 40); MachSparseArray sparse = con.createSparseArrayOf("INT32", 4, entries); try (ResultSet opened = st.executeAppendOpen("ARRAY_APPEND_FULL_EXAMPLE", 0)) { try { ResultSetMetaData meta = opened.getMetaData(); for (int id = 1; id <= 4; id++) { if (id == 2) sparse.clear().set(1, 200).set(3, 400); if (id == 3) sparse.clear(); ArrayList row = new ArrayList(); row.add(Long.valueOf(id)); row.add(id == 4 ? null : sparse); st.executeAppendData(meta, row); } } finally { st.executeAppendClose(); } } try (ResultSet rs = st.executeQuery( "SELECT ID,A,ARRAY_LENGTH(A) " + "FROM ARRAY_APPEND_FULL_EXAMPLE ORDER BY ID")) { int count = 0; while (rs.next()) { System.out.println(rs.getLong(1) + " " + rs.getString(2)); count++; } if (count != 4) throw new IllegalStateException("Expected 4 rows"); } } } } ``` ```bash javac -cp "$MACHBASE_JDBC_JAR" SparseAppendFull.java java -cp ".:$MACHBASE_JDBC_JAR" SparseAppendFull ``` Set `MACHBASE_JDBC_JAR` to the actual JDBC JAR path. The classpath separator above is for Linux. Confirm that four rows are retrieved without errors, then compare with the [common expected results](#결과-확인). ### Append with Selected-Column Open The existing `executeAppendOpen(String, int)` remains the full-row API. Specify selected targets with the following overload: ```java ResultSet executeAppendOpen(String tableName, String[] inputColumns, int errorCheckCount) ``` ```java import com.machbase.jdbc.MachConnection; import com.machbase.jdbc.MachSparseArray; import com.machbase.jdbc.MachStatement; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class SparseAppend { static void append(MachStatement st, String[] columns, Object[][] values) throws Exception { try (ResultSet metaResult = st.executeAppendOpen( "ARRAY_APPEND_EXAMPLE", columns, 0)) { ResultSetMetaData meta = metaResult.getMetaData(); try { for (Object[] value : values) { ArrayList row = new ArrayList(); for (Object item : value) row.add(item); st.executeAppendData(meta, row); } } finally { st.executeAppendClose(); } } } public static void main(String[] args) throws Exception { Class.forName("com.machbase.jdbc.MachDriver"); MachConnection con = (MachConnection)DriverManager.getConnection( "jdbc:machbase://127.0.0.1:5656/machbasedb", "SYS", "MANAGER"); try { try (MachStatement st = (MachStatement)con.createStatement()) { append(st, new String[] {"ID", "A[0]", "A[3]"}, new Object[][] {{1L, 10, 40}}); Map entries = new HashMap(); entries.put(1, 200); entries.put(3, 400); MachSparseArray sparse = con.createSparseArrayOf( "INT32", 4, entries); MachSparseArray empty = con.createSparseArrayOf( "INT32", 4, new HashMap()); append(st, new String[] {"ID", "A"}, new Object[][] { {2L, sparse}, {3L, empty}, {4L, null} }); try (ResultSet rs = st.executeQuery( "SELECT ID,A,ARRAY_LENGTH(A) " + "FROM ARRAY_APPEND_EXAMPLE ORDER BY ID")) { while (rs.next()) System.out.println( rs.getLong(1) + " " + rs.getString(2)); } } } finally { con.close(); } } } ``` Map keys passed to `createSparseArrayOf()` are 0-based element positions. Reuse an object with `MachSparseArray.clear()` and `set()`. An empty map means an ARRAY with all NULL elements; Java `null` means whole NULL. ## Python DB-API ### Append a Sparse ARRAY Without a Column List The DB-API `append()` handles Open, input, and Close internally. Omit `columns=` and pass `ID` and `SparseArray` in each row. Prepare the standard example table first, then save and run the following as `sparse_append_full.py`. ```python from machbaseAPI import SparseArray, connect conn = connect(host="127.0.0.1", port=5656, user="SYS", password="MANAGER") try: first = SparseArray(4).set(0, 10).set(3, 40) second = SparseArray(4).set(1, 200).set(3, 400) empty = SparseArray(4) conn.append("ARRAY_APPEND_FULL_EXAMPLE", [ [1, first], [2, second], [3, empty], [4, None], ]) rows = conn.cursor(dictionary=False).execute( "SELECT ID,A,ARRAY_LENGTH(A) " "FROM ARRAY_APPEND_FULL_EXAMPLE ORDER BY ID" ).fetchall() expected = [ (1, [10, None, None, 40], 4), (2, [None, 200, None, 400], 4), (3, [None, None, None, None], 4), (4, None, None), ] assert rows == expected, rows print("Python full-row sparse append OK") finally: conn.close() ``` ```bash python3 sparse_append_full.py ``` If the query results match expectations, it prints `Python full-row sparse append OK`. ### Append with Selected Columns The existing `append(table, rows)` is unchanged. Use the `columns=` keyword for selected targets. ```python from machbaseAPI import SparseArray, connect def main(): conn = connect(host="127.0.0.1", port=5656, user="SYS", password="MANAGER", database="MACHBASEDB") try: conn.append( "ARRAY_APPEND_EXAMPLE", [[1, 10, 40]], columns=["ID", "A[0]", "A[3]"], ) sparse = SparseArray(4).set(1, 200).set(3, 400) empty = SparseArray(4) conn.append( "ARRAY_APPEND_EXAMPLE", [[2, sparse], [3, empty], [4, None]], columns=["ID", "A"], ) rows = conn.cursor(dictionary=False).execute( "SELECT ID,A,ARRAY_LENGTH(A) " "FROM ARRAY_APPEND_EXAMPLE ORDER BY ID" ).fetchall() expected = [ (1, [10, None, None, 40], 4), (2, [None, 200, None, 400], 4), (3, [None, None, None, None], 4), (4, None, None), ] assert rows == expected, rows print("Python sparse append OK") finally: conn.close() if __name__ == "__main__": main() ``` `SparseArray.clear()` resets all elements to NULL while preserving the element count. ### Python legacy wrapper #### Append with Standard appendOpen Open with `appendOpen(table)`, then use `appendData()`. A sparse array does not require `appendOpenColumns()`. Prepare the standard example table, then save and run as `sparse_append_full_legacy.py`. ```python from machbaseAPI import SparseArray, machbase db = machbase() if db.open("127.0.0.1", "SYS", "MANAGER", 5656) != 1: raise RuntimeError(db.result()) try: if db.appendOpen("ARRAY_APPEND_FULL_EXAMPLE") != 1: raise RuntimeError(db.result()) try: sparse = SparseArray(4).set(0, 10).set(3, 40) for row_id in range(1, 5): if row_id == 2: sparse.clear().set(1, 200).set(3, 400) if row_id == 3: sparse.clear() row = [row_id, None if row_id == 4 else sparse] if db.appendData("ARRAY_APPEND_FULL_EXAMPLE", None, row) != 1: raise RuntimeError(db.result()) finally: if db.appendClose() != 1: raise RuntimeError(db.result()) if db.select( "SELECT ID,A,ARRAY_LENGTH(A) " "FROM ARRAY_APPEND_FULL_EXAMPLE ORDER BY ID" ) != 1: raise RuntimeError(db.result()) print(db.result()) finally: db.close() ``` ```bash python3 sparse_append_full_legacy.py ``` Compare the query output from `db.result()` with the [common expected results](#결과-확인). #### Append with Selected-Column Open The existing `appendOpen(table, types=None)` remains the full-row API. Use `appendOpenColumns(table, columns, types=None)` for selected targets. ```python from machbaseAPI import SparseArray, machbase db = machbase() if db.open("127.0.0.1", "SYS", "MANAGER", 5656) != 1: raise RuntimeError(db.result()) try: if db.appendOpenColumns( "ARRAY_APPEND_EXAMPLE", ["ID", "A[0]", "A[3]"] ) != 1: raise RuntimeError(db.result()) try: if db.appendData( "ARRAY_APPEND_EXAMPLE", None, [1, 10, 40] ) != 1: raise RuntimeError(db.result()) finally: if db.appendClose() != 1: raise RuntimeError(db.result()) sparse = SparseArray(4).set(1, 200).set(3, 400) empty = SparseArray(4) if db.appendOpenColumns( "ARRAY_APPEND_EXAMPLE", ["ID", "A"] ) != 1: raise RuntimeError(db.result()) try: for row in ([2, sparse], [3, empty], [4, None]): if db.appendData("ARRAY_APPEND_EXAMPLE", None, row) != 1: raise RuntimeError(db.result()) finally: if db.appendClose() != 1: raise RuntimeError(db.result()) finally: db.close() ``` The value count and order in `appendData()` follow the open target list. For new code, prefer the more concise DB-API `append(..., columns=...)`. ## Node.js ### Append a Sparse ARRAY with All Column Definitions Node.js also uses `appendOpen()` for sparse arrays. However, the current `@machbase/ts-client` requires `columns` in `appendOpen(table, columns, options?)`. There is no separate `OpenColumns` method; full and selected input use the same method. The example defines both input columns, `ID` then `A`, for the standard example table. It does not specify element targets such as `A[0]` in Open; each row's `SparseArray` chooses the positions. Save as `sparse_append_full.js` and run in a project using a package with ARRAY support. ```javascript 'use strict'; const { createConnection, SparseArray } = require('@machbase/ts-client'); (async () => { const conn = createConnection({ host: '127.0.0.1', port: 5656, user: 'SYS', password: 'MANAGER', }); await conn.connect(); try { const stream = await conn.appendOpen('ARRAY_APPEND_FULL_EXAMPLE', [ { name: 'ID', type: 'int64' }, { name: 'A', type: 'int32-array' }, ]); try { await stream.append([ [1n, new SparseArray(4).set(0, 10).set(3, 40)], [2n, new SparseArray(4).set(1, 200).set(3, 400)], [3n, new SparseArray(4)], [4n, null], ]); } finally { await stream.close(); } const [rows] = await conn.query( 'SELECT ID,A,ARRAY_LENGTH(A) LEN ' + 'FROM ARRAY_APPEND_FULL_EXAMPLE ORDER BY ID', ); if (rows.length !== 4) throw new Error('Expected 4 rows'); console.log(rows); } finally { await conn.end(); } })().catch(error => { console.error(error); process.exitCode = 1; }); ``` ```bash node sparse_append_full.js ``` Check that four rows are retrieved and compare with the [common expected results](#결과-확인). Calling `appendOpen(table)` without column definitions or passing `[]` for automatic inference is not supported. ### Append with Selected Column and Element Definitions Set `AppendColumnDefinition.name` to a whole-column target or an element-position target. ```javascript 'use strict'; const { createConnection, SparseArray } = require('@machbase/ts-client'); async function appendRows(connection, columns, rows) { const appender = await connection.appendOpen('ARRAY_APPEND_EXAMPLE', columns); try { await appender.append(rows); } finally { await appender.close(); } } (async () => { const connection = createConnection({ host: '127.0.0.1', port: 5656, user: 'SYS', password: 'MANAGER', }); await connection.connect(); try { await appendRows(connection, [ { name: 'ID', type: 'int64' }, { name: 'A[0]', type: 'int32' }, { name: 'A[3]', type: 'int32' }, ], [[1n, 10, 40]]); const sparse = new SparseArray(4).set(1, 200).set(3, 400); const empty = new SparseArray(4); await appendRows(connection, [ { name: 'ID', type: 'int64' }, { name: 'A', type: 'int32-array' }, ], [[2n, sparse], [3n, empty], [4n, null]]); const [rows] = await connection.query( 'SELECT ID,A,ARRAY_LENGTH(A) LEN ' + 'FROM ARRAY_APPEND_EXAMPLE ORDER BY ID', ); console.log(rows); } finally { await connection.end(); } })().catch((error) => { console.error(error.stack || error); process.exitCode = 1; }); ``` `SparseArray` is also treated as an ARRAY-compatible value when `MACHBASE_NATIVE_APPEND=0` selects the prepared fallback path. ## .NET full/legacy provider ### Append a Sparse ARRAY with Standard AppendOpen Open with `AppendOpen(table)` and pass `MachSparseArray` to `AppendData()`. Prepare the standard example table first. Use this code as `Program.cs` in a C# project referencing a full/legacy provider with ARRAY support. ```csharp using System; using System.Collections.Generic; using Mach.Data.MachClient; public class SparseAppendFull { public static void Main() { using var conn = new MachConnection( "SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD=MANAGER"); conn.Open(); using var command = new MachCommand(conn); var writer = command.AppendOpen("ARRAY_APPEND_FULL_EXAMPLE"); try { var first = new MachSparseArray(MachDBType.INT32_ARRAY, 4) .Set(0, 10).Set(3, 40); var second = new MachSparseArray(MachDBType.INT32_ARRAY, 4) .Set(1, 200).Set(3, 400); var empty = new MachSparseArray(MachDBType.INT32_ARRAY, 4); var rows = new List> { new List { 1L, first }, new List { 2L, second }, new List { 3L, empty }, new List { 4L, DBNull.Value }, }; foreach (var row in rows) command.AppendData(writer, row); } finally { if (command.IsAppendOpened) command.AppendClose(writer); } if (writer.FailureCount != 0) throw new InvalidOperationException("APPEND row failure"); using var verify = new MachCommand( "SELECT ID,A,ARRAY_LENGTH(A) FROM ARRAY_APPEND_FULL_EXAMPLE ORDER BY ID", conn); using var reader = verify.ExecuteReader(); int count = 0; while (reader.Read()) { Console.WriteLine(reader.IsDBNull(1) ? $"{reader.GetInt64(0)} NULL" : $"{reader.GetInt64(0)} " + string.Join(",", (object[])reader.GetValue(1))); count++; } if (count != 4) throw new InvalidOperationException("Expected 4 rows"); } } ``` Save the following project file as `SparseAppendFull.csproj` beside `Program.cs`. The example uses a .NET 8 provider. ```xml Exe net8.0 false $(MachbaseProviderDll) ``` Replace the path below with the actual path to the .NET 8 provider DLL with ARRAY support. ```bash dotnet build SparseAppendFull.csproj -p:MachbaseProviderDll=/absolute/path/to/provider.dll dotnet bin/Debug/net8.0/SparseAppendFull.dll ``` Check that Close reports 0 failures and the query returns four rows, then compare with the [common expected results](#결과-확인). ### Append with Selected-Column Open The full API and legacy-compatible MachConnector40 provide overloads accepting selected targets. The existing `AppendOpen(string)` and error-check overloads are unchanged. ```csharp MachAppendWriter AppendOpen(string tableName, IList inputColumns); MachAppendWriter AppendOpen(string tableName, IList inputColumns, int errorCheckCount, MachAppendOption option); ``` ```csharp using System; using System.Collections.Generic; using Mach.Data.MachClient; static void Append(MachConnection connection, IList columns, IList> rows) { using var command = new MachCommand(connection); var writer = command.AppendOpen("ARRAY_APPEND_EXAMPLE", columns); try { foreach (var row in rows) command.AppendData(writer, row); } finally { if (command.IsAppendOpened) command.AppendClose(writer); } if (writer.FailureCount != 0) throw new InvalidOperationException("APPEND row failure"); } using var connection = new MachConnection( "SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD=MANAGER"); connection.Open(); Append(connection, new List { "ID", "A[0]", "A[3]" }, new List> { new List { 1L, 10, 40 } }); var sparse = new MachSparseArray(MachDBType.INT32_ARRAY, 4) .Set(1, 200).Set(3, 400); var empty = new MachSparseArray(MachDBType.INT32_ARRAY, 4); Append(connection, new List { "ID", "A" }, new List> { new List { 2L, sparse }, new List { 3L, empty }, new List { 4L, DBNull.Value }, }); using var verify = new MachCommand( "SELECT ID,A,ARRAY_LENGTH(A) FROM ARRAY_APPEND_EXAMPLE ORDER BY ID", connection); using var reader = verify.ExecuteReader(); while (reader.Read()) Console.WriteLine(reader.IsDBNull(1) ? $"{reader.GetInt64(0)} NULL" : $"{reader.GetInt64(0)} " + string.Join(",", (object[])reader.GetValue(1))); ``` `MachSparseArray.Clear()` resets the object to a reusable state with all NULL elements. Whole NULL is `DBNull.Value`. If metadata processing fails after Append Open succeeds, the provider cleans up the open handle and the connection remains reusable. ## Go neo-client ### Append with Connect Without Column Arguments Omit column arguments from `Appender.Connect(ctx, dsn, table)` and send rows with `Append(id, sparse)`. This LOG example does not pass `_arrival_time` explicitly. A nil `*api.Array` means whole NULL and is distinct from an empty sparse object. The code requires `neo-client/v2` source with ARRAY support using 0-based element positions. Save it as `sparse_append_full.go` in a Go module linked to that source through `go.work` or `replace`. The source must meet the same version requirements as the selected example below. ```go package main import ( "context" "database/sql" "errors" "fmt" client "github.com/machbase/neo-client/v2" "github.com/machbase/neo-client/v2/api" ) func appendFull(ctx context.Context, dsn string) error { first, err := api.NewSparseArray(api.SqlTypeInt32, 4) if err != nil { return err } if err = first.Set(0, int32(10)); err != nil { return err } if err = first.Set(3, int32(40)); err != nil { return err } second, err := api.NewSparseArray(api.SqlTypeInt32, 4) if err != nil { return err } if err = second.Set(1, int32(200)); err != nil { return err } if err = second.Set(3, int32(400)); err != nil { return err } empty, err := api.NewSparseArray(api.SqlTypeInt32, 4) if err != nil { return err } var wholeNull *api.Array appender := &client.Appender{} if err = appender.Connect(ctx, dsn, "ARRAY_APPEND_FULL_EXAMPLE"); err != nil { return err } for _, row := range [][]any{ {int64(1), first}, {int64(2), second}, {int64(3), empty}, {int64(4), wholeNull}, } { if err = appender.Append(row...); err != nil { _, _, closeErr := appender.Close() return errors.Join(err, closeErr) } } success, failure, err := appender.Close() if err != nil { return err } if success != 4 || failure != 0 { return fmt.Errorf("success=%d failure=%d", success, failure) } return nil } func main() { ctx := context.Background() dsn := "server=tcp://sys:manager@127.0.0.1:5656" if err := appendFull(ctx, dsn); err != nil { panic(err) } db, err := sql.Open(client.DefaultDriverName, dsn) if err != nil { panic(err) } defer db.Close() rows, err := db.QueryContext(ctx, "SELECT ID,A,ARRAY_LENGTH(A) FROM ARRAY_APPEND_FULL_EXAMPLE ORDER BY ID") if err != nil { panic(err) } defer rows.Close() count := 0 for rows.Next() { var id int64 var value sql.NullString var length sql.NullInt64 if err = rows.Scan(&id, &value, &length); err != nil { panic(err) } if value.Valid { fmt.Println(id, value.String, length.Int64) } else { fmt.Println(id, "NULL") } count++ } if err = rows.Err(); err != nil { panic(err) } if count != 4 { panic("Expected 4 rows") } } ``` ```bash go run sparse_append_full.go ``` Check that Close reports 4 successes and 0 failures, and verify the query results. ### Append with Selected-Column Connect This example connects `neo-client` directly to Machbase DBMS, not to a Machbase Neo server. The 0-based ARRAY and selected-column Append APIs are in v2 module source after [`neo-client` PR #17](https://github.com/machbase/neo-client/pull/17). Until a public v2 release is specified, do not assume published module versions include these features. ```go package main import ( "context" "database/sql" "errors" "fmt" client "github.com/machbase/neo-client/v2" "github.com/machbase/neo-client/v2/api" ) func appendRows(ctx context.Context, dsn, table string, columns []string, rows [][]any) error { appender := &client.Appender{} if err := appender.Connect(ctx, dsn, table, columns...); err != nil { return err } for _, row := range rows { if err := appender.Append(row...); err != nil { _, _, closeErr := appender.Close() return errors.Join(err, closeErr) } } success, failure, err := appender.Close() if err != nil { return err } if failure != 0 { return fmt.Errorf("append success=%d failure=%d", success, failure) } return nil } func main() { ctx := context.Background() dsn := "server=tcp://sys:manager@127.0.0.1:5656" db, err := sql.Open(client.DefaultDriverName, dsn) if err != nil { panic(err) } defer db.Close() if err := db.PingContext(ctx); err != nil { panic(err) } if err := appendRows(ctx, dsn, "ARRAY_APPEND_EXAMPLE", []string{"ID", "A[0]", "A[3]"}, [][]any{{int64(1), int32(10), int32(40)}}); err != nil { panic(err) } sparse, err := api.NewSparseArray(api.SqlTypeInt32, 4) if err != nil { panic(err) } if err := sparse.Set(1, int32(200)); err != nil { panic(err) } if err := sparse.Set(3, int32(400)); err != nil { panic(err) } empty, err := api.NewSparseArray(api.SqlTypeInt32, 4) if err != nil { panic(err) } var wholeNull *api.Array if err := appendRows(ctx, dsn, "ARRAY_APPEND_EXAMPLE", []string{"ID", "A"}, [][]any{ {int64(2), sparse}, {int64(3), empty}, {int64(4), wholeNull}, }); err != nil { panic(err) } rows, err := db.QueryContext(ctx, "SELECT ID,A,ARRAY_LENGTH(A) FROM ARRAY_APPEND_EXAMPLE ORDER BY ID") if err != nil { panic(err) } defer rows.Close() for rows.Next() { var id int64 var value sql.NullString var length sql.NullInt64 if err := rows.Scan(&id, &value, &length); err != nil { panic(err) } if !value.Valid { fmt.Println(id, "NULL"); continue } fmt.Println(id, value.String, length.Int64) } if err := rows.Err(); err != nil { panic(err) } } ``` The variadic arguments to `Appender.Connect(ctx, dsn, table, columns...)` specify selected targets. Apply `WithInputColumns(columns...)` before `Connect()`. Do not call `Append`, `Flush`, and `Close` concurrently on one `Appender`. ## Verify Results After running a standard example, use this query to check values, whole NULL, and NULL elements. ```sql SELECT ID, A, ARRAY_LENGTH(A), A[0], A[1], A[2], A[3] FROM ARRAY_APPEND_FULL_EXAMPLE ORDER BY ID; ``` After a selected example, use this query. Both tables have the same expected results. ```sql SELECT ID, A, ARRAY_LENGTH(A), A[0], A[1], A[2], A[3] FROM ARRAY_APPEND_EXAMPLE ORDER BY ID; ``` | ID | A | `ARRAY_LENGTH(A)` | |---:|---|---:| | 1 | `[10,null,null,40]` | 4 | | 2 | `[null,200,null,400]` | 4 | | 3 | `[null,null,null,null]` | 4 | | 4 | `NULL` | `NULL` | Running SDK examples consecutively against one table creates duplicate IDs. For validation, empty the table between examples or use different ID ranges. ## Clean Up the Examples After checking results, drop only the tables created for this exercise. Use both statements if you ran both examples; otherwise, drop only the relevant table. ```sql DROP TABLE ARRAY_APPEND_FULL_EXAMPLE; DROP TABLE ARRAY_APPEND_EXAMPLE; ``` Each statement deletes the table and its data. Do not run it against an existing business table with the same name. To rerun, start with the setup SQL. ## Versions and Limitations - `ARRAY` and selected-column Append are Machbase DBMS 8.7.0 features. - Public ARRAY element positions are 0-based. Subtract 1 from sparse ARRAY and selected-target positions used by earlier development versions with 1-based positions. Do not change separately defined 1-based standard APIs such as JDBC parameter positions. - Use a Machbase DBMS 8.7.0 server with an SDK build that includes ARRAY support. - Existing full-row Append Open function and method signatures and semantics are unchanged. - C API column-name lists are NULL-terminated arrays without a separate count. - Invalid element counts, duplicate or out-of-range positions, duplicate targets, whole/element target conflicts, and mismatched value counts are errors. - Until an official module release, the Go ARRAY API requires linking development source that includes the feature. - SDKs must not include failed rows in success counts. --- title: "12. Performance Tuning" url: https://docs.machbase.com/dbms/performance-tuning/ language: en kind: section --- # 12. Performance Tuning Diagnose and tune performance in this order: data model, ingestion path, query execution plan, memory, and storage. Identify the bottleneck and reproduction conditions before changing settings, then measure before and after with the same workload. ## Recommended diagnostic order 1. Record latency, throughput, and error rates for the target queries and ingestion operations. 2. Check that the table type matches the data characteristics. 3. Inspect execution state with `EXPLAIN`, `V$STMT`, and `V$SESSION`. 4. Adjust indexes, batch sizes, caches, and storage settings one at a time. 5. Remeasure the effect with the same data and workload. ## Chapter contents | Order | Section | Content | |-----:|------|------| | 12.1 | [Performance Diagnosis](./performance-approach/) | Baselines, bottleneck classification, execution plans, and system views | | 12.2 | [Data Modeling for Performance](./performance-tuning-modeling/) | Table type and schema design checks | | 12.3 | [Index Tuning](./index-tuning/) | Index selection by table type and write costs | | 12.5 | [Query and Analysis Tuning](./performance-query-tuning/) | Time predicates, execution plans, ROLLUP, and window functions | | 12.6 | [Cache and Memory Tuning](./cache-tuning-memory/) | PVO Cache, Min-Max Cache, and memory usage | | 12.7 | [Storage and Cluster Tuning](./tuning-storage-cluster/) | Disk I/O, checkpoints, and Cluster configuration | Throughput and response time depend on hardware, data distribution, schemas, indexes, and concurrent users. Use sample settings as starting points and validate them with production workloads. --- title: "12.1 Performance Diagnosis" url: https://docs.machbase.com/dbms/performance-tuning/performance-approach/ language: en kind: page --- # 12.1 Performance Diagnosis Establish reproduction conditions and baselines before narrowing down a performance bottleneck. Changing several properties or indexes at once without evidence makes causes and effects hard to distinguish. ## 1. Record reproduction conditions - Slow SQL or ingestion path - Start and end times, database, and user - Target table, time range, row count, and result count - Concurrent sessions, queries, and Appenders - Latency and throughput during normal operation and the incident - Recent deployment, schema, configuration, or data distribution changes ## 2. Check resource bottlenecks ```bash iostat -x 1 5 top -b -n 1 free -h ``` Compare CPU, I/O, and memory metrics with normal baselines rather than fixed thresholds. Distinguish brief spikes from sustained saturation, and align OS metric timestamps with server traces and query times. ## 3. Inspect active operations ```sql SELECT sess_id, id AS stmt_id, state, record_size, query FROM V$STMT ORDER BY sess_id, id; SELECT id, user_name, user_ip, login_time, client_type FROM V$SESSION ORDER BY login_time DESC; ``` Look for long-running statements, abnormal session growth, and concurrent copies of the same query. Use `DESC` to check system view columns in the deployed version. ## 4. Check execution plans and query ranges For a slow SELECT, use `EXPLAIN` to inspect tables, scan types, key ranges, filters, and joins. Check that TAG and LOG queries include a time range and that functions or casts do not prevent predicates from using index ranges. For details, see [Query and Analysis Tuning](../performance-query-tuning/). ## 5. Change one item and remeasure Narrow candidates in this order: query, index, batch size, concurrency, then caches and configuration. Change one item at a time and compare the following under the same conditions. | Area | Compare | |------|--------| | Queries | Response time distribution, result rows, execution plans | | Ingestion | Rows/s, server processing response latency, failure counts | | Server | CPU, I/O, memory, sessions | | Side effects | Other query latency, reduced ingestion, restart impact | Revert to the recorded previous value if a change provides no benefit or causes substantial side effects. Consider schema or storage structure changes last, after preparing a test environment and recovery procedure. ## Final diagnostic checklist - Have you compared current operations and sessions with normal baselines? - Have you checked the execution plan using the actual SQL and time range? - Have you assessed the ingestion cost of index and ROLLUP changes? - Have you aligned OS and server metrics with the same operation? - Have you applied configuration and schema changes one at a time? - Have you recorded rollback values and remeasurement results? --- title: "12.2 Data Modeling for Performance" url: https://docs.machbase.com/dbms/performance-tuning/performance-tuning-modeling/ language: en kind: page --- # 12.2 Data Modeling for Performance Choose table types and schemas that fit the data lifecycle, query keys, and update patterns. Do not try to compensate for an unsuitable table type through configuration or indexes alone. ## Choose a table type | Data | Consider first | |--------|-----------| | Time series centered on names, timestamps, and numeric values | TAG | | Append-oriented events and logs | LOG | | Relational changes and transactions | TRANSACTION | | Small persistent reference datasets | LOOKUP | | Rebuildable in-memory caches | VOLATILE | ## Schema design criteria - Include only columns needed for queries and ingestion. - Set string lengths based on observed maxima and possible growth. - Use the appropriate SQL types for timestamps, numbers, and IP addresses instead of strings. - Store relatively stable tag attributes in TAG metadata. - Align nullability and defaults with business meaning. - Compare the lifecycle and mutability of natural and surrogate relational keys. Do not apply a uniform spare-capacity ratio to string lengths. Measure current distributions, limits, and truncation impact, and prepare a schema change procedure. ## Indexes and aggregates Choose index candidates from query predicates and join keys. When adding an index, measure ingestion latency, storage, and memory as well as read improvements. Consider ROLLUP for repeated TAG time aggregates, and avoid creating aggregation intervals that are rarely queried. ## Validation procedure 1. Prepare representative data and queries. 2. Measure a baseline with the chosen table type and a minimal schema. 3. Add one index or ROLLUP. 4. Remeasure reads, writes, memory, and storage. 5. Remove structures that are not worth maintaining. For detailed design by table type, see [Table Type Concepts and Selection](/dbms/data-modeling-table-design/). --- title: "12.3 Index Tuning" url: https://docs.machbase.com/dbms/performance-tuning/index-tuning/ language: en kind: page --- # 12.3 Index Tuning Add indexes only when they reduce read costs for actual predicates and join keys. Measure query latency, ingestion throughput, memory, and storage before and after creation. ## Checks by table type | Table type | Primary key or access path | Additional indexes | |------------|--------------------|------------| | TAG | Name and BASETIME access | Supported value and metadata indexes | | LOG | `_ARRIVAL_TIME` range | LSM, BITMAP, KEYWORD | | LOOKUP | PRIMARY KEY | Supported secondary indexes | | VOLATILE | Optional PRIMARY KEY | REDBLACK secondary indexes | | TRANSACTION | PRIMARY KEY | Relational secondary indexes | For supported index types and syntax, see each table type's chapter and [Index Syntax](/dbms/reference/sql/syntax/index-syntax/). ## Procedure 1. Record `EXPLAIN` and the result count for the slow SQL. 2. Check predicate selectivity and value distribution. 3. Check for an existing index with the same leading column. 4. Create one candidate index and verify that its build completes. 5. Remeasure queries and ingestion under the same conditions. 6. Remove indexes that provide no benefit or impose excessive write costs. ```sql SHOW INDEXES; SHOW INDEXGAP; ``` Do not assume a fixed throughput reduction per index. Results depend on row size, key distribution, concurrency, and storage. Measure with data representative of production. ## Considerations - Compare against a scan before indexing a column with low selectivity. - Check whether functions or casts around indexed columns prevent key-range access. - Design composite indexes around frequent predicate combinations and leading columns. - During index creation, monitor ingestion and query load and `SHOW INDEXGAP`. - Before removing an unused index, verify that peak and batch workloads do not need it. For details, see the index and performance pages in the TAG, LOG, LOOKUP, VOLATILE, and TRANSACTION chapters. --- title: "12.4 Ingestion Performance Tuning" url: https://docs.machbase.com/dbms/performance-tuning/performance-tuning/ language: en kind: page --- # 12.4 Ingestion Performance Tuning Ingestion performance depends on the ingestion path, row size, batching, concurrency, indexes, and storage. Tune using representative data and measurements of end-to-end throughput and server processing response latency. ## Choose an ingestion path Use [Data Input and Export](/dbms/development-tools-integration/data-input-load-export/) to choose a path and check SDK and table-type support. This page focuses on throughput and latency for the selected path. ## Measurement procedure 1. Prepare a representative schema, row size, and indexes. 2. Measure a baseline with one connection and small batches. 3. Increase batch size incrementally, recording rows/s and flush and server processing response latency. 4. Observe client CPU and memory alongside server CPU, I/O, and memory. 5. Increase connections and compare total throughput and p95/p99 response times. The p99 latency is the time within which 99% of requests complete; it reveals the impact of slow requests. 6. Test failures, reconnections, and duplicate handling. Do not use a universal recommended batch size or thread count. Oversized batches increase memory use and error reprocessing scope; undersized batches increase network round-trip overhead. ## Append operations Follow the Append lifecycle, error handling, and duplicate handling contracts in [Common Integration Concepts](/dbms/development-tools-integration/concepts-common/#append-api-batch) and the [SDK Append Matrix](/dbms/development-tools-integration/sdk-support-scope/#append-table-type-matrix). As you vary batch size and connections, record rows/s, p95/p99 latency, server processing responses, and failure counts together. ## File loading For file format validation, rejected-row files, exit codes, and final row verification, see [Data Input and Export](/dbms/development-tools-integration/data-input-load-export/). Compare performance only after applying the same validation to the workload. ## Classify bottlenecks | Observation | Check next | |------|-----------| | Client CPU saturation | Serialization, conversion, logging | | Increasing network waits | Batches, round trips, packet loss | | Server CPU saturation | Index count, SQL parsing, concurrency | | Increasing storage latency | Checkpoints, device queues, retention jobs | | Increasing memory usage | Batch buffers, connection count, caches | | Only some nodes are slow | Key distribution, routing, per-node resources | ## Before and after changes Judge throughput improvements only after verifying successful and failed row counts. Also measure latency from ingestion start to server application, and check the impact on query performance and recovery time. --- title: "12.5 Query and Analysis Tuning" url: https://docs.machbase.com/dbms/performance-tuning/performance-query-tuning/ language: en kind: page --- # 12.5 Query and Analysis Tuning Improve query performance by reducing rows and partitions read and sorting and aggregation work while preserving correct results. Compare execution time and result counts before and after changes using the same data, predicates, and concurrency. ## Key principles 1. First restrict TAG and LOG queries to the required time range. 2. Select only the needed columns and avoid unbounded `SELECT *`. 3. Consider indexes for frequent equality and range predicates and JOIN keys. 4. Use ROLLUP for repeated long-range TAG aggregates. 5. Inspect the plan with `EXPLAIN` before changing hints or configuration. 6. Record latency distributions, rows read, CPU, I/O, and concurrent query effects, not just averages. ## Reproducible example This example creates a LOG table and index, checks the execution plan and results, then cleans up. ```sql CREATE LOG TABLE perf_event_demo ( device_id VARCHAR(32), level VARCHAR(16), code INTEGER, message VARCHAR(100) ); CREATE INDEX idx_perf_event_code ON perf_event_demo(code) INDEX_TYPE LSM; INSERT INTO perf_event_demo VALUES ('DEV-01', 'WARN', 1001, 'temperature high'); INSERT INTO perf_event_demo VALUES ('DEV-02', 'INFO', 1000, 'started'); EXEC TABLE_FLUSH(perf_event_demo); EXPLAIN SELECT device_id, level, message FROM perf_event_demo WHERE code = 1001 AND _ARRIVAL_TIME >= NOW - 60000000000; SELECT device_id, level, message FROM perf_event_demo WHERE code = 1001 AND _ARRIVAL_TIME >= NOW - 60000000000; DROP TABLE perf_event_demo; ``` Do not conclude from a small sample that an index scan is always faster. Compare before and after index creation with production-like data distribution and predicate selectivity. ## SELECT and JOIN - First reduce large source tables with time and key predicates. - Match data types and lengths on both sides of JOIN predicates. - Check whether functions around WHERE columns prevent index-range access. - Before replacing an outer JOIN with an inner JOIN, check whether NULL-extended rows disappear. - Specify `ORDER BY` when result order matters. - For pagination, consider keyset pagination using business keys and timestamps instead of large OFFSETs. Do not assume the optimizer follows table order as written in SQL. Hints that force join order can become counterproductive as statistics and data distribution change. Verify both the execution plan and results. ## Use EXPLAIN `EXPLAIN` shows the execution plan without running the query. `EXPLAIN FULL` may execute the query, so use it only in a controlled environment without production load. Check these plan elements: | Element | Question | |------|------| | Target tables | Are the intended tables and views selected? | | Scan type | Does the access path match the predicates and indexes? | | Time range | Is the TAG or LOG partition range restricted? | | JOIN | Are unnecessary joins processing large inputs? | | Sorting and aggregation | Are large intermediate results sorted or materialized? | Do not hardcode internal object IDs or complete plan strings in automated checks; they can change across versions. Check stable semantic elements such as table names, scan types, and key predicates. ## CTE CTEs improve readability but do not automatically improve performance. Inspect the plan for repeated CTE evaluation, filter pushdown into the CTE, and large intermediate results. Machbase 8.7.0 Standard Edition supports non-recursive SELECT CTEs. Recursive CTEs are not supported. For syntax and examples, see [CTE](/dbms/reference/sql/syntax/cte-syntax/). ## Search operators | Predicate | Check | |------|------| | Equality and range comparisons | Column type and index type compatibility | | `LIKE 'prefix%'` | Prefix search support and string index usage | | Leading wildcard | Whether a full scan is affordable | | `SEARCH` and `ESEARCH` | KEYWORD index and syntax compatibility | | `REGEXP` | Whether time and other indexed predicates first reduce candidate rows | | JSON path | Supported table types and JSON indexes | | IP range | IPV4/IPV6 types and index support | For exact predicate semantics and index requirements, see [SEARCH, ESEARCH, and REGEXP](/dbms/reference/sql/syntax/search-esearch-regexp-syntax/) and [JSON Operators](/dbms/reference/sql/functions/operators-json/). ## Window functions and PIVOT Large window partitions or wide ordering keys can increase sorting and memory costs. First reduce input with time and business-key predicates, and check for duplicate window calculations. For PIVOT, limit output categories and define how unexpected categories are handled. For syntax, see [Window Functions](/dbms/reference/sql/syntax/window-function-over-syntax/) and [PIVOT](/dbms/reference/sql/syntax/pivot-syntax/). ## Before-and-after checklist - Are result row counts and NULL distributions unchanged? - Are the time range and time zone the same? - Have cold and warm caches been measured separately? - Have you compared concurrent queries as well as individual executions? - Are there adverse effects on ingestion throughput or memory usage? - Have you recorded rollback DDL, configuration values, and baseline measurements? ## Related SQL documentation | Topic | Details | |---|---| | SELECT and time predicates | [SELECT Syntax](/dbms/reference/sql/syntax/select-syntax/) | | VIEW, CTE, and set operations | [SQL Syntax Reference](/dbms/reference/sql/syntax/) | | Hints | [SELECT Hints](/dbms/reference/sql/syntax/select-hint-syntax/) | | Functions and aggregates | [Function Reference](/dbms/reference/sql/functions/) | --- title: "12.6 PVO Cache and Memory Tuning" url: https://docs.machbase.com/dbms/performance-tuning/cache-tuning-memory/ language: en kind: page --- # 12.6 PVO Cache and Memory Tuning ## PVO Cache operations PVO Cache reuses SQL execution plans. It does not cache query result rows. ## Memory configuration tuning Plan PVO Cache, Min-Max Cache, process limits, and transient query memory within the available physical memory budget. --- title: "12.7 Storage and Cluster Tuning" url: https://docs.machbase.com/dbms/performance-tuning/tuning-storage-cluster/ language: en kind: page --- # 12.7 Storage and Cluster Tuning Base storage and Cluster tuning on workload measurements, recovery objectives, and per-node resource usage. Do not apply fixed hardware specifications or arbitrary configuration values to every environment. ## Storage and checkpoints Compare the following over the same time range: - Ingestion rows/s and server processing response latency - Query response time and read volume - Per-device IOPS, throughput, queue depth, and latency - Checkpoint start and end times and duration - Changes in memory usage and swap - Acceptable recovery time after a failure ```bash iostat -x 1 5 df -h ``` Check current checkpoint interval and I/O settings in the [Configuration Reference](/dbms/reference/configuration/configuration/). Change one property at a time and record restart requirements and rollback values. ## Paths and capacity - Check ownership and free space for data, backup, and export paths. - Separate paths on the same physical device do not necessarily distribute I/O. - Do not manually move data files while the server runs. - Account for retention policies and backup space growth together. - Verify support and recovery procedures before changing file system or mount options. Do not locate and delete internal partition tables to remove old data. Use public SQL and operational features, such as table-specific `DELETE ... BEFORE`, retention policies, and backup policies. ## Cluster measurements Inspect client, Broker, Warehouse, and Coordinator metrics separately. | Segment | Check | |------|------| | Client → Broker | Connections, round trips, batch size | | Broker | Sessions, routing, CPU, network | | Warehouse | Per-node ingestion, query, and disk imbalance | | Inter-node communication | Bandwidth, packet loss, latency | | Coordinator | Node state and disk-full policy | If load concentrates on a node, inspect tag and key distribution, routing, Warehouse groups, and per-node storage and network together. Do not use `TAG_PARTITION_COUNT` to control distribution across Cluster nodes. ## Configuration change principles - Check names, allowed ranges, and defaults in the installed version's configuration reference. - Record the current baseline and target instead of choosing arbitrary recommended numbers. - When increasing buffers, measure memory and tail latency as well as throughput. - Before changing replication settings, compare recovery time in both normal and failure scenarios. - Use hysteresis between disk-full upper and lower thresholds, linked to actual expansion and cleanup procedures. - Check edition-specific exclusions in [Support Scope](/dbms/reference/support-scope-constraints/). ## Change checklist 1. Is there evidence of a bottleneck by node and segment? 2. Have you recorded current settings and their sources? 3. Have you measured normal and failure scenarios in a test environment? 4. Have you checked deployment order and restart requirements by node? 5. Do you have rollback values and procedures if results worsen? 6. Have you verified backup and recovery after the change? --- title: "13. Operations, Configuration, and Recovery" url: https://docs.machbase.com/dbms/operations-configuration-recovery/ language: en kind: section --- # 13. Operations, Configuration, and Recovery This chapter covers starting and stopping Machbase servers, configuration changes, observability, backup and restore, and Cluster operations. Establish routine procedures first, then perform changes and recovery according to a plan. ## Chapter contents | Order | Section | Content | |-----:|------|------| | 13.1 | [Server and Database Operations](./server-database/) | Server startup and shutdown, database creation and deletion, licenses | | 13.2 | [Multiple Databases](./multi-database/) | Logical databases, privileges, backup and restore, client integration | | 13.3 | [Configuration Management](./configuration/) | Configuration files, memory, network, storage, time zones | | 13.4 | [ALTER SYSTEM Operations](./alter-system/) | Runtime configuration changes and system control | | 13.5 | [Data Retention Policies](./policy-data-retention/) | Create, attach, inspect, and detach retention policies | | 13.6 | [Observability and Diagnostics](./diagnosis-observability/) | System views, logs, sessions, capacity, and signs of failure | | 13.7 | [Schema Change Checklist](./checklist-schema-alter/) | Impact analysis and validation before and after DDL | | 13.8 | [Backup, Restore, and Mount](./backup-restore-mount/) | Online backup, offline restore, read-only mounts | | 13.9 | [Cluster Operations](./cluster/) | Topology, adding and removing nodes, state management | For routine checks, use [Server and Database Operations](./server-database/), [Configuration Management](./configuration/), and [Observability and Diagnostics](./diagnosis-observability/). Before introducing multiple databases, read [Multiple Databases](./multi-database/). For schema or configuration changes, use [ALTER SYSTEM Operations](./alter-system/) and the [Schema Change Checklist](./checklist-schema-alter/). For failure recovery and backup validation, see [Backup, Restore, and Mount](./backup-restore-mount/). --- title: "13.1 Server and Database Operations" url: https://docs.machbase.com/dbms/operations-configuration-recovery/server-database/ language: en kind: page --- # 13.1 Server and Database Operations `machadmin` starts and stops server instances, creates and drops physical databases, installs licenses, and performs offline restores. Distinguish logical databases created with SQL `CREATE DATABASE` from the physical instance database created with `machadmin -c`. ## Check the main options ```bash "$MACHBASE_HOME/bin/machadmin" -h ``` Use the help for the installed release to check options and their effects. ## Start and stop the server You can safely run the status check. ```bash "$MACHBASE_HOME/bin/machadmin" -e ``` Use one consistent method to start and stop the server: a service manager or your operations runbook. - Before startup, check the configuration, license, data paths, and free space. - After startup, check `machadmin -e`, a connection on port 5656, a lightweight SQL query, and server logs. - Before a normal shutdown, block new connections and ingestion, and check active transactions, backups, and Appenders. - Use a forced shutdown only after normal shutdown repeatedly fails and you have assessed the recovery impact. - Do not force a recovery mode arbitrarily. Check the error and documented recovery procedure. Command output can vary by release. Do not make automation depend on a complete success message. Check both the process exit code and an actual connection. ## Physical instance database `machadmin -c` and `machadmin -d` create and delete physical instance data in `DBS_PATH`. For logical databases, use the SQL described in [Multiple Databases](../multi-database/). Deleting or initializing a physical database is destructive and can lose all instance data. Do not delete and recreate a database to resolve a server startup error. Diagnose the error first, then choose a recovery method that preserves the existing data. Before execution, verify: 1. The absolute paths of the target `MACHBASE_HOME` and `DBS_PATH`. 2. That the service and processes have fully stopped. 3. A recent backup and a verified restore in an isolated environment. 4. The configuration, licenses, and logs to preserve. 5. Whether rollback is possible and the expected recovery time. 6. That two operators have cross-checked the instance and paths. Do not manually create, move, or delete internal files or metadata in the data directory. ## Install and verify a license Treat license files as secrets. Do not copy their contents or actual keys into documentation, support requests, or logs. | State | Method | |------|------| | Install with the server stopped | The `machadmin` license option for the current release | | Install with the server running | `ALTER SYSTEM INSTALL LICENSE` | | Verify installation | `machadmin` license information and `V$LICENSE_INFO` | ```sql SELECT * FROM V$LICENSE_INFO; ``` Before installation, check the target instance, edition, validity period, and file permissions. For online installation, the server process must be able to read the path. After renewal, verify a new connection and the required edition features, and apply your retention policy to the original license file. ## Information needed to diagnose failures - `machadmin -e` output and exit code - Release, edition, and `MACHBASE_HOME` - Actual configuration and data paths - Server startup and shutdown times - Server logs around the first error - File system free space and permissions - Recent configuration, license, or storage changes Do not delete the physical database or start with an initialization-based recovery merely because the server will not start. Preserve backups while diagnosing the cause. --- title: "13.2 Multiple Databases" url: https://docs.machbase.com/dbms/operations-configuration-recovery/multi-database/ language: en kind: page --- # 13.2 Multiple Databases Standard Edition lets you create multiple logical databases in one server to separate objects and access privileges. This page covers adoption and operations. Use the linked references for SQL syntax, privileges, SDK options, and backup procedures. ## Scope - Multiple databases are a Standard Edition feature. - A logical database does not create a separate server process or resource quota. - Object names have up to three parts: `object`, `owner.object`, or `database.owner.object`. - Include the owner when specifying another database. - Mounted databases provide read-only access to backups, separate from active databases. ## Decisions before adoption 1. Define owners and application users for each database. 2. Define `CONNECT` and minimum object privileges. 3. Check how connection pools initialize and reset the current database. 4. Define backup units, recovery order, and naming rules for mounted databases. 5. Establish monitoring that distinguishes usage and failures by database. ## Quick verification The following example verifies that two databases are separate, then removes both. ```sql CREATE DATABASE IF NOT EXISTS manual_multidb_a; CREATE DATABASE IF NOT EXISTS manual_multidb_b; USE manual_multidb_a; CREATE LOG TABLE sensor_event ( event_time DATETIME, message VARCHAR(100) ); INSERT INTO sensor_event VALUES (SYSDATE, 'from-a'); USE manual_multidb_b; CREATE LOG TABLE sensor_event ( event_time DATETIME, message VARCHAR(100) ); INSERT INTO sensor_event VALUES (SYSDATE, 'from-b'); SELECT message FROM manual_multidb_a.SYS.sensor_event; SELECT message FROM manual_multidb_b.SYS.sensor_event; USE MACHBASEDB; DROP DATABASE manual_multidb_a CASCADE FORCE; DROP DATABASE manual_multidb_b CASCADE FORCE; ``` `USE database_name` changes the current connection's database. Do not switch with an active transaction, open cursor, prepared statement, or Appender. Address objects in another database as `database.owner.object`. ## Privilege boundaries Users need both `CONNECT` on the target database and the privileges required for the actual object operation. For SQL to create or drop databases and manage privileges, see [Accounts and Privileges](/dbms/security-access-control/privileges/). Do not grant blanket administrator privileges to production accounts. ## Application connections SDKs differ in the option name for the initial database and in connection pool initialization behavior. Check support in each SDK's connection documentation, and verify the following immediately after borrowing a connection. ```sql SELECT CURRENT_DATABASE(); ``` For language-specific settings, see [Development and Application Integration](/dbms/development-tools-integration/). For version requirements, see [Server and SDK Compatibility](/dbms/reference/support-scope-constraints/compatibility-xma-protocol/). ## Backup and recovery Before backup, record the active databases to include and their recovery order. You can `USE` a mounted database, but it is read-only and permits only `SELECT`. For exact commands and validation steps, use [Backup, Restore, and Mount](../backup-restore-mount/). ## Operations checklist - Does `CURRENT_DATABASE()` return the expected value after connecting and after pool reuse? - Do SQL and monitoring distinguish same-named objects in different databases? - Does each user have only the required database and object privileges? - Have backup and recovery drills verified every target database? - Before dropping a database, have you checked open connections, objects, and backup retention requirements? For exact `CREATE/DROP/USE DATABASE` syntax, see [DATABASE Syntax](/dbms/reference/sql/syntax/database-syntax/). --- title: "13.3 Configuration Management" url: https://docs.machbase.com/dbms/operations-configuration-recovery/configuration/ language: en kind: page --- # 13.3 Configuration Management Change one setting at a time. Record its current value, the reason for the change, how to apply it, validation results, and rollback steps. For the full list of properties and defaults, see the [Configuration Reference](/dbms/reference/configuration/configuration/) for your release. ## Configuration file The default configuration file is `$MACHBASE_HOME/conf/machbase.conf`. A package or service configuration may use another file, so check the startup command and actual environment. Before changing a setting, record: - File path, owner, and permissions - The property's current value in the file and in `V$PROPERTY` - Units and allowed range - Whether it can change at runtime and whether a restart is required - Affected nodes and instances - Rollback value and validation SQL Do not include passwords, AUTH KEYs, or license contents in ordinary configuration backups or work logs. ## Runtime changes and restarts `ALTER SYSTEM SET` changes only supported runtime properties. Do not attempt to change an arbitrary property just because a sample command appears in the documentation. ```sql SELECT NAME, VALUE FROM V$PROPERTY ORDER BY NAME; ``` 1. Check the configuration reference for dynamic change support. 2. Define the maintenance scope and affected connections and queries. 3. Save the current value. 4. Change one property in a test environment or under a limited workload. 5. Compare response time, throughput, memory, I/O, and errors. 6. Write the chosen value to the configuration file so it persists after a restart. 7. After restarting, verify the setting with `V$PROPERTY` and a functional test. ## Find a configuration property ```sql SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME LIKE 'PVO_CACHE%' ORDER BY NAME; ``` If you know the exact name, query with `NAME = '...'`. Do not configure a property by guessing from a similar name. ## Memory configuration Budget together for process limits, table space and caches, ingestion buffers, and temporary query and session memory. Leave memory for the OS and other processes on the same host. - Resident and available memory under normal and peak workloads - Whether swapping occurs and when it increases - Concurrent queries, Appenders, and sessions - Cache usage, including PVO, Min-Max, LOOKUP, and VOLATILE - Temporary operations such as index creation, sorting, and aggregation Do not apply a fixed ratio or sample byte value without validating it for your workload. ## Network and sessions Set listener addresses and ports, maximum sessions, and connection and query timeouts according to application connection counts and failure isolation requirements. Verify firewall rules and binding separately. Check for connection leaks and review pool settings before increasing the session limit. ```sql SELECT ID, USER_NAME, USER_IP, LOGIN_TIME, CLIENT_TYPE FROM V$SESSION ORDER BY LOGIN_TIME DESC; ``` ## Storage and checkpoints Settings for `DBS_PATH`, checkpoints, direct I/O, and I/O threads directly affect data location and recovery time. Do not move production data files manually or guess alternative paths. - Verify the actual data and backup paths and file systems. - Compare checkpoint duration and device latency over the same period. - Prepare outage and recovery procedures for settings that require a restart. - After a change, verify normal restart, backup, and restore operations. ## Time zones Configure consistent time zones for parsing and displaying time strings in the server, command-line tools, and SDKs. Check epoch units and `DATETIME` precision separately, and test writing and reading the same value. ## Server and session time zones Distinguish the server's default time zone from the session time zone selected by the client. Specify the time zone for application string input and output through supported connection options. Verify it in a new connection with `SHOW TIMEZONE` and a sample `DATETIME` query. See [Time Zone Configuration](/dbms/reference/configuration/configuration-timezone/) for setup. Existing connections do not automatically change their session settings. ## machsql `-z` ```bash "$MACHBASE_HOME/bin/machsql" -s 127.0.0.1 -P 5656 -u APP_USER -p "$MACH_SAMPLE_PASSWORD" -z +0900 ``` Use sample values to verify that input and output strings are interpreted and displayed with the specified offset. ## machloader `-z` ```bash "$MACHBASE_HOME/bin/machloader" -s 127.0.0.1 -P 5656 -u APP_USER -p "$MACH_SAMPLE_PASSWORD" -z +0900 -i -t SENSOR_LOG -d /data/sensor.csv ``` Document both the time zone and date format of the source CSV. ## SDK connection time zones Option names differ by SDK. Check the driver's connection options in [Chapter 11: Development and Application Integration](/dbms/development-tools-integration/). Verify that the same time zone applies during writes, reads, and connection pool reuse. ## Change record | Item | Record | |------|------| | Target | Host, instance, node, database | | Change | Property, old value, and new value | | Rationale | Baseline and target | | Application | At runtime or after a restart | | Validation | SQL, workload, and OS metrics | | Rollback | Values, execution order, and responsible operator | Do not treat unverified recommendations or defaults from older releases as current settings. --- title: "13.4 ALTER SYSTEM Operations" url: https://docs.machbase.com/dbms/operations-configuration-recovery/alter-system/ language: en kind: page --- # 13.4 ALTER SYSTEM Operations `ALTER SYSTEM` is an administrative command that can affect the entire instance. Before execution, check the target instance, privileges, active operations, and rollback or release commands. For full syntax, see [System and Session ALTER Syntax](/dbms/reference/sql/syntax/system-session-alter-syntax/). ## Common procedure 1. Verify the current server, database, and release. 2. Record relevant session, statement, backup, and checkpoint states. 3. Check the command's blocking, I/O, and memory impact. 4. Define the maintenance window and failure response. 5. Immediately afterward, check the result, relevant virtual tables, and logs. ## CHECKPOINT ```text ALTER SYSTEM CHECKPOINT; ``` A checkpoint can increase storage I/O. Assess whether one is needed before backup or shutdown, and observe its effect on concurrent bulk ingestion and queries. Do not run it repeatedly just because the system is slow. ## CHECK DISK_USAGE ```text ALTER SYSTEM CHECK DISK_USAGE; ``` Use this command when file system state and database storage metadata need inspection. Check free space and mount status beforehand, then review the result logs. Do not edit internal files to make the figures match. ## INSTALL LICENSE ```text ALTER SYSTEM INSTALL LICENSE; ALTER SYSTEM INSTALL LICENSE = '/absolute/path/license.dat'; ``` Verify the license file's source, target instance, edition, and expiration date. Restrict its permissions and do not copy its contents into documentation or logs. After installation, verify it through `V$LICENSE_INFO` and a new connection. ## KILL and CANCEL SESSION ```text ALTER SYSTEM CANCEL SESSION session_id; ALTER SYSTEM KILL SESSION session_id; ``` First check the user, client IP, SQL, and state in `V$SESSION` and `V$STMT`. Consider `CANCEL` when first attempting to stop a running statement, and `KILL` when the connection itself must end. Check rollback effects and possible duplicates from transactions, Appenders, and application retries. ## FREEZE and UNFREEZE ```text ALTER SYSTEM FREEZE; ALTER SYSTEM UNFREEZE; ``` Consider freeze only for file system snapshot procedures that cannot use the public backup features instead. Define permitted reads and writes and the maximum freeze duration in advance. Assign an operator and verification steps for `UNFREEZE` on every error path. Do not leave the session in a frozen state. ## FLUSH AGER ```text ALTER SYSTEM FLUSH AGER; ``` Consider this command when investigating delayed reclamation of deleted space. First check retention policies, DELETE status, and available storage. Do not repeatedly force normal background work. ## FLUSH PVO_CACHE ```text ALTER SYSTEM FLUSH PVO_CACHE; ``` Clearing cached execution plans causes subsequent queries to be parsed and optimized again. Use this command only to isolate schema or plan issues, and watch for temporary latency spikes in concurrent queries. Do not use cache flushing as a remedy for persistent performance problems. ## FLUSH SYS_STAT ```text ALTER SYSTEM FLUSH SYS_STAT; ``` Save any required baselines before resetting cumulative statistics. Record the reset time in monitoring so rate calculations and failure analysis remain accurate. ## FLUSH PAGE_CACHE ```text ALTER SYSTEM FLUSH PAGE_CACHE; ``` Flushing the page cache can significantly change I/O and latency for subsequent queries. Use it only for cold-cache comparisons or limited diagnostics, never at peak production load. ## Privileges and auditing Use an administrative account with only the required privileges. Audit the command, target, time, operator, reason, and result. Replace sample session IDs, paths, and configuration values with the intended production values. --- title: "13.5 Data Retention Policies" url: https://docs.machbase.com/dbms/operations-configuration-recovery/policy-data-retention/ language: en kind: page --- # 13.5 Data Retention Policies A retention policy periodically deletes data older than a cutoff time from TAG, KV, and LOG tables. `DURATION` specifies the retention period; `INTERVAL` specifies the deletion job frequency. Retention policies cannot be applied to TRANSACTION, VOLATILE, or LOOKUP tables. ```text Create policy → Attach to table → Check job status → Detach from table → Drop policy ``` ## Retention Policy Before defining a production policy, review legal retention obligations, recovery requirements, hourly ingestion volume, and deletion load together. Do not choose `INTERVAL` using a fixed ratio. Use an interval sufficiently longer than the deletion time measured in production. Check policies and their attachment state in these views: ```sql SELECT * FROM M$RETENTION; SELECT USER_NAME, TABLE_NAME, POLICY_NAME, STATE, LAST_DELETED_TIME FROM V$RETENTION_JOB; ``` ### Create a retention policy ```sql CREATE RETENTION policy_name DURATION duration_value {MONTH|DAY|HOUR|MIN|SEC} INTERVAL interval_value {DAY|HOUR|MIN|SEC}; ``` `DURATION` accepts units from months to seconds; `INTERVAL` accepts `DAY` through `SEC`. `MONTH` means a fixed 30 days, not a calendar month. For policies where calendar boundaries matter, such as legal retention, convert the period to `DAY` and verify the actual deletion cutoff. For exact parser syntax and supported table types, see [RETENTION Syntax](/dbms/reference/sql/syntax/retention-syntax/). For example, this policy retains 30 days of data and processes eligible deletions once a day. ```sql CREATE RETENTION policy_30d DURATION 30 DAY INTERVAL 1 DAY; SELECT * FROM M$RETENTION WHERE POLICY_NAME = 'POLICY_30D'; ``` Creating and dropping policies requires the appropriate administrative privileges. Check privileges and the approved change scope before using a production account. ### Attach a policy to a table ```sql ALTER TABLE sensor_tag ADD RETENTION policy_30d; SELECT USER_NAME, TABLE_NAME, POLICY_NAME, STATE FROM V$RETENTION_JOB WHERE TABLE_NAME = 'SENSOR_TAG'; ``` A table can have only one policy. TAG tables determine data age using `BASETIME`; LOG tables use `_ARRIVAL_TIME`. Deletion runs at the configured interval, not immediately upon attachment. ### Detach a policy from a table ```sql ALTER TABLE sensor_tag DROP RETENTION; ``` Detaching stops automatic deletion but does not recover data already deleted. After detaching, verify that the target table no longer appears in `V$RETENTION_JOB`. ### Drop a retention policy First detach the policy from every table that uses it, then drop the policy object. ```sql SELECT USER_NAME, TABLE_NAME FROM V$RETENTION_JOB WHERE POLICY_NAME = 'POLICY_30D'; -- Run after detaching the policy from each returned table DROP RETENTION policy_30d; ``` `ALTER TABLE ... DROP RETENTION` detaches the policy from a table; `DROP RETENTION` deletes the policy object. A policy still in use cannot be dropped. ### Scope and privileges | Table type | Supported | |---|---| | TAG, KV, LOG | Yes | | TRANSACTION, VOLATILE, LOOKUP | No | If the policy administrator and table owner are different accounts, validate the actual privilege configuration before production use. For another owner's table, explicitly grant only the required privileges. ### Check job status ```sql SELECT USER_NAME, TABLE_NAME, POLICY_NAME, STATE, LAST_DELETED_TIME FROM V$RETENTION_JOB ORDER BY USER_NAME, TABLE_NAME; ``` `STATE` is the job's current state. `LAST_DELETED_TIME` is the cutoff used by the last deletion job, not its wall-clock completion time. To verify actual deletion, check both the oldest timestamp in the target table and the row count trend. --- title: "13.6 Observability and Diagnostics" url: https://docs.machbase.com/dbms/operations-configuration-recovery/diagnosis-observability/ language: en kind: page --- # 13.6 Observability and Diagnostics Record the reproduction time and symptoms, then examine server state, sessions and statements, storage and memory, and relevant logs on the same timeline. `M$` metadata tables describe schemas; `V$` virtual tables expose current state. ## Diagnostics and logs 1. Record when the problem started and ended, along with client information. 2. Check server responsiveness with `machadmin -e`. 3. Find relevant operations in `V$SESSION` and `V$STMT`. 4. Inspect virtual tables for the affected area, such as storage, memory, or ROLLUP. 5. Compare server, client, and loader logs from the same time. 6. Save current configuration properties and baselines before making changes. ## Trace log configuration Adjust trace levels, file sizes, and retention only as needed for diagnosis. Check property names, allowed values, and restart requirements for the current release in the [Configuration Reference](/dbms/reference/configuration/configuration/). Logs may contain sensitive SQL and data, so set access permissions and retention periods. ## Server logs The default trace directory is `$MACHBASE_HOME/trc`. Inspect the actual directory and settings instead of assuming fixed filenames. ```bash ls -lh "$MACHBASE_HOME/trc" tail -n 200 "$MACHBASE_HOME/trc/machbase.trc" ``` Review the first error, preceding warnings, server startup and shutdown, and checkpoint and storage events chronologically, rather than merely counting error strings. Do not manually bulk-delete log files. ## machsql logs `machsql.history` may contain credentials or sensitive SQL. Restrict history file permissions for production accounts and review the contents before sharing diagnostics. Preserve reproduction SQL together with the target database, execution time, results, and errors. ## machloader logs For bulk loading, check the process exit code, summary, logs, and rejected-row file together. - Schema and input column count and order - Delimiters, quote characters, and encoding - NULL and DATETIME formats - First failed row and recurring error codes - Final successful and failed row counts Do not blindly replay the entire rejected-row file. Fix the cause, validate a sample, then reprocess only the failed rows. ## Metadata tables Inspect the current database schema through `M$SYS_TABLES`, `M$SYS_COLUMNS`, `M$SYS_INDEXES`, and related tables. Include database, owner, and object IDs in joins instead of joining by name alone. Avoid application dependencies on reserved object names or internal table structures. ## Virtual tables First check the actual columns in the current release. ```sql SELECT * FROM V$SESSION LIMIT 1; SELECT * FROM V$STMT LIMIT 1; SELECT * FROM V$PROPERTY LIMIT 1; SELECT * FROM V$STORAGE_USAGE LIMIT 1; SELECT * FROM V$SYSMEM LIMIT 1; SELECT * FROM V$ROLLUP LIMIT 1; SELECT * FROM V$LICENSE_INFO LIMIT 1; ``` For the complete list and column definitions, see the [System Catalog](/dbms/reference/system-catalog/virtual-table-full/). ## Monitoring and capacity management Base alerts on normal baselines, growth rates, peak workloads, and recovery headroom rather than fixed thresholds. Review file system and database storage usage together, including separate space used by backups and exports. ## Server state ```bash "$MACHBASE_HOME/bin/machadmin" -e ``` A running process alone does not prove server health. Also check a native connection, a lightweight SQL query, and recent server logs. ## Sessions and running SQL ```sql SELECT id, user_name, user_ip, login_time, client_type FROM V$SESSION ORDER BY login_time DESC; SELECT sess_id, id AS stmt_id, state, record_size, query FROM V$STMT ORDER BY sess_id, id; ``` A long-running operation is not necessarily an error. Check the workload type, processed rows, client timeouts, and I/O and CPU state before deciding to cancel or kill it. ## Disk capacity ```bash df -h "$MACHBASE_HOME" du -sh "$MACHBASE_HOME/dbs" ``` If a separate `DBS_PATH` is configured, check the actual path. Do not directly edit or delete internal partition files. ## Memory Compare OS available memory and swap with `V$SYSMEM`, cache usage, and query concurrency. Do not make automation depend on internal manager names. ## Backup validation Do more than check backup command success. Record the path, size, and completion status, then mount or restore in an isolated environment and verify key tables, row counts, time ranges, and sample queries. ## Collect diagnostic information - Release and edition - Incident time and time zone - Reproduction commands, database, and user - Server, client, and loader logs - Relevant virtual table results - OS CPU, I/O, memory, and disk metrics - Recent schema, configuration, or deployment changes - Actions already attempted and their results Remove credentials, AUTH KEYs, personal information, and sensitive raw data from support materials. --- title: "13.7 Schema Change Checklist" url: https://docs.machbase.com/dbms/operations-configuration-recovery/checklist-schema-alter/ language: en kind: page --- # 13.7 Schema Change Checklist Before changing a production schema, check the following items in order. ## Pre-change checks ### 1. Check the table type ```sql SELECT NAME AS TABLE_NAME, TYPE AS TABLE_TYPE FROM M$SYS_TABLES WHERE NAME = 'TARGET_TABLE'; ``` ALTER TABLE support differs by table type. First check [Management Support by Table Type](/dbms/reference/support-scope-constraints/table-types-type/). ### 2. Inspect the current schema ```sql -- Inspect columns DESC target_table; -- Inspect indexes SELECT i.NAME AS INDEX_NAME, i.TYPE AS INDEX_TYPE FROM M$SYS_INDEXES i JOIN M$SYS_TABLES t ON i.DATABASE_ID = t.DATABASE_ID AND i.TABLE_ID = t.ID WHERE t.NAME = 'TARGET_TABLE'; ``` ### 3. Check data volume ```sql SELECT COUNT(*) FROM target_table; ``` Schema changes on large tables can take time. Measure duration and locking effects in a test environment, then execute during the service's maintenance window. ### 4. Check retention policy activity ```sql SELECT * FROM V$RETENTION_JOB WHERE TABLE_NAME = 'TARGET_TABLE'; ``` If a retention job is running, wait for it to finish before changing the schema. ### 5. Configure the DDL conflict policy Standard Edition can execute DDL concurrently on different objects. DDL on the same or directly related objects conflicts, so first set the permitted wait time for the production deployment session. ```sql -- Wait up to 10 seconds for a conflicting DDL lock ALTER SESSION SET DDL_LOCK_TIMEOUT = 10; -- Check each session's setting SELECT id, user_name, ddl_lock_timeout FROM v$session WHERE closed = 0 ORDER BY id; ``` | Concurrent targets | Result | |----------------|------| | Independent tables with different names | Can run concurrently | | Same object or same name | Conflict | | Table ALTER/DROP DDL and index DDL for that table | Conflict | | View DDL and ALTER/DROP DDL on its source table | Conflict | | TAG table ALTER/DROP DDL and its ROLLUP or retention DDL | Conflict | Cluster Edition does not provide `DDL_LOCK_TIMEOUT` and uses the existing serialized DDL policy. See [DDL Concurrency and Locking](/dbms/reference/sql/syntax/ddl-syntax/#ddl-concurrency) for details. --- ## Checklist for adding columns - [ ] Is the new column's data type supported by this table type? - [ ] For LOG/TRANSACTION tables, are you aware that the new column is NULL in existing rows? - [ ] Check for duplicate column names. ```sql ALTER TABLE sensor_log ADD COLUMN (new_col DOUBLE); ``` --- ## Checklist for dropping columns - [ ] Is the column included in an index? Drop the index first. - [ ] Do application queries reference the column? - [ ] Data in a dropped column cannot be recovered. ```sql ALTER TABLE sensor_log DROP COLUMN (old_col); ``` --- ## Checklist for index changes - [ ] Creating or dropping an index directly affects query performance. - [ ] Index creation also indexes existing data and can take time on large tables. - [ ] Consider dropping unused indexes because they slow INSERT operations. - [ ] With `IF NOT EXISTS`, separately verify the existing index definition for the same name. ```sql -- Create conditionally during repeat deployments CREATE INDEX IF NOT EXISTS idx_new ON sensor_log (sensor_id); -- Verify the actual mapping; a name match may cause a no-op SHOW INDEX idx_new; -- Drop an unnecessary index DROP INDEX idx_old; ``` `IF NOT EXISTS` checks only the index name within the same database and owner. Separately verify that the existing table, columns, index type, and properties match the intended deployment, following [INDEX Syntax](/dbms/reference/sql/syntax/index-syntax/#create-index-if-not-exists). --- ## Checklist for retention policy changes - [ ] To change a policy: detach the existing policy, then create and attach the new policy. - [ ] Shortening retention can increase the next deletion job's scope. Assess possible data loss. ```sql -- Detach the existing policy ALTER TABLE sensor_tag DROP RETENTION; -- Attach the new policy ALTER TABLE sensor_tag ADD RETENTION new_policy; ``` --- ## Handle DDL conflicts With the default `DDL_LOCK_TIMEOUT=0`, a conflict immediately returns `ERR-02031: Resource busy ()`. 1. Retry only `ERR-02031`, with a bounded retry count and wait intervals. 2. Before retrying, query the current state of the target and dependent objects again. 3. After waiting, `already exists` or `table not found` may be returned depending on the preceding DDL. 4. Do not repeatedly retry the same SQL for syntax errors, privilege errors, `already exists`, or `table not found`. 5. Automation using `machsql` must check output for `ERR-` as well as the process exit code. You can execute DDL again after a lock wait expires or an operation is canceled, but first check whether the preceding operation took effect. --- ## Post-change validation ```sql -- Verify the schema change DESC target_table; -- Check data consistency SELECT COUNT(*) FROM target_table; -- Inspect index state SELECT i.NAME AS INDEX_NAME, i.TYPE AS INDEX_TYPE FROM M$SYS_INDEXES i JOIN M$SYS_TABLES t ON i.DATABASE_ID = t.DATABASE_ID AND i.TABLE_ID = t.ID WHERE t.NAME = 'TARGET_TABLE'; ``` --- **Read next:** - [Data Retention Policies](/dbms/operations-configuration-recovery/policy-data-retention/) - [Operations and Configuration](/dbms/operations-configuration-recovery/) --- title: "13.8 Backup, Restore, and Mount" url: https://docs.machbase.com/dbms/operations-configuration-recovery/backup-restore-mount/ language: en kind: page --- # 13.8 Backup, Restore, and Mount Verify backups by mounting or restoring them in an isolated environment and running sample queries, as well as checking successful creation. Manage paths, permissions, storage, retention, encryption, and access control together. For complete SQL and options, see [Backup, Restore, and Mount Syntax](/dbms/reference/sql/syntax/backup-restore-mount-syntax/). ## Choose a backup method | Purpose | Method | |------|------| | Full recovery baseline for an instance | Full database backup | | Move or preserve a specific table | Table backup | | Changes since a previous backup | Incremental backup | | Archive a specific time range | Period backup | | Query a backup while the server runs | Read-only mount | | Replace instance data | Offline restore | Before choosing a backup type, check support in the current release for the edition, table types, incremental chains, mounting, and restoration. ## Full backup Keep a full backup as an independent recovery baseline. - The server process accesses the backup path. - Check free space and quotas on the destination file system. - Record start and end times, errors, and output size. - Do not keep the only backup in the same failure domain as the source data. - Regularly restore to an isolated server and verify key tables. ## Table backup Check supported table types and which indexes and metadata a table backup includes. To recover one table, preferably validate it in a new database or mount, then transfer it through an explicit INSERT or export/import procedure. Do not immediately replace an existing production table. ## Incremental backup and AFTER An incremental backup stores changes since a previous backup. Manage the baseline and all required incremental backups as one recovery chain. - Record each backup's baseline and creation order. - Check recoverability if an intermediate file is missing. - Do not retain only the final incremental backup. - Create a new full backup baseline when the chain becomes long. - For offline restore, pass the final incremental backup path to `machadmin -r` once. Do not apply each backup separately starting with the full backup. Preserve the entire required chain and verify that the data is restored to the final backup point. ## Period backup A period backup specifies start and end times with `BACKUP DATABASE FROM ... TO ...`. Do not confuse this syntax with a query's `WHERE` clause. Compare minimum and maximum timestamps and row counts with the source, including the selected time zone and boundary records. ## SQL BACKUP The account running BACKUP needs the required database and table privileges and access to the server path. In production automation, do not hardcode passwords on the command line. Check both exit codes and job status. Checks before and after execution: 1. Verify the target database or table and backup type. 2. Confirm that the destination is a unique path that does not yet exist. 3. Check free space and expected growth. 4. Check backup completion and errors. 5. Verify output files, sizes, and checksums or storage integrity. 6. Validate samples through a mount or restore. ## Offline restore An offline restore with `machadmin -r` replaces the current instance data. Restoration is rejected if a database already exists. First preserve the current data and verify the recovery target, then stop the server and remove the existing database using a validated procedure. Online restoration of a logical database in 8.7.0 Standard Edition uses the separate SQL statement `RESTORE DATABASE`. Distinguish the targets and prerequisites of the two methods. - Plan to stop the service and all clients and Collectors. - Secure a separate backup of current data and a rollback path. - Verify the exact backup and chain to restore. - Check compatibility of the release, edition, and configuration. - Have two recovery operators cross-check the target instance and paths. - Use production runbooks only after successful isolated recovery drills. - After restoration, verify schemas, row counts, time ranges, and application queries. ## Mount a database Mounting attaches a backup as a read-only database for investigation and selective recovery. ```text MOUNT DATABASE '/absolute/backup/path' TO mount_name; UMOUNT DATABASE mount_name; ``` Use a mount name that does not conflict with an active production database. Mount paths and permissions are evaluated for the server process. ## Query a mounted database ```text SELECT * FROM mount_name.SYS.table_name WHERE _ARRIVAL_TIME >= TO_DATE('2026-01-01', 'YYYY-MM-DD'); ``` First inspect the table list and schemas, then verify time ranges, row counts, and sample values. Before selectively transferring data, check the current schema and duplicate handling policy. ## Read-only access and mounts in use Do not execute DDL or DML on a mounted database. Open cursors or statements may prevent unmounting; close all references before retrying. First check for name conflicts with active databases or other mounts. ## Unsupported paths Do not depend on `MOUNT TABLE` or `UMOUNT TABLE`, which are not public operational APIs, even if internal syntax appears to succeed. Use the public `MOUNT DATABASE` and `UMOUNT DATABASE` commands. ## Scope by table type and edition Backup and mount behavior differs among LOG, TAG, TRANSACTION, LOOKUP, and VOLATILE tables. VOLATILE is an in-memory table whose data does not survive a server restart. Check [Backup and Mount Support](/dbms/reference/support-scope-constraints/backup-mount/) for table and edition restrictions. ## Recovery validation checklist - Database, owner, and table counts - Key table schemas and indexes - Row counts and minimum and maximum timestamps - Sample NULL, string, and numeric values - Users, privileges, and application connections - ROLLUP, retention policies, and job status - Handling of data received after the backup point - Rollback feasibility and actual recovery duration --- title: "13.9 Cluster Operations" url: https://docs.machbase.com/dbms/operations-configuration-recovery/cluster/ language: en kind: page --- # 13.9 Cluster Operations Perform Cluster operations with a verified runbook after checking node configuration, roles, replication, and data state. Use the checks on this page to assess change impact and recovery paths, then include commands from the installed management tool version in the runbook. ## Components | Role | Check | |------|------| | Coordinator | Node configuration and status | | Deployer | Package and node deployment | | Broker | Client connections and query routing | | Warehouse | Data storage and query processing | | Lookup | Reference data service | Design node counts and placement around availability, throughput, and failure domain requirements. Do not apply a fixed node count or hardware specification to every environment. ## Check status Before and after a change, check the full node configuration from the Coordinator and each node's processes and resources. Use the installed tool's help for status strings and options. ```bash machcoordinatoradmin --help machclusterctl --help ``` - Are all expected nodes registered? - Do node roles, hosts, ports, and groups match deployment records? - Are service, replication, and scrap states normal? - Are CPU, memory, disk, or network resources unevenly used across nodes? - Do actual connections and queries through the Broker succeed? ## Connect and export configuration When using `machclusterctl connect`, specify the target Broker and native port, then verify `CURRENT_DATABASE()` and a sample query. Configuration exports may contain hosts, ports, paths, and operational information. Restrict access and review the diff before importing. ## Start and stop nodes Before controlling a node, check: 1. Target node name, alias, host, and role. 2. Client connections and active queries and Appenders. 3. Warehouse group redundancy and data state. 4. Remaining capacity while the node is stopped. 5. Startup and shutdown order and rollback steps. 6. Acceptance criteria after maintenance. Use a forced shutdown only after normal shutdown repeatedly fails and you have assessed its data and recovery impact. Do not immediately kill a process on a timeout. ## Control the entire Cluster and use destroy For full startup and shutdown, check the dependency order of Coordinator, Deployer, Broker, Warehouse, and Lookup in the runbook for the current release. `destroy` is destructive and may remove node configuration and data. - Confirm that the target is not another cluster with a similar name. - Verify a recent backup and a successful restore. - Obtain service owner approval and block clients. - Check the deletion scope, including external `DBS_PATH` locations. - Identify changes that cannot be rolled back. - After execution, check each host for remaining processes and paths. Do not use `destroy` for routine state recovery. ## Add and remove nodes Before adding a node, check the package, version, ports, paths, file systems, and network. Before removal, verify data redundancy and completed migration, along with aliases, groups, and monitoring that reference the node. Removing a node may delete its home and data paths; check the command's help and validate the exact scope in a test environment. ## Change state Disabling a Broker, making a Warehouse group read-only, and scrapping a node serve different purposes. Do not change state arbitrarily to hide a failing node. | Purpose | Check first | |------|-----------| | Block new connections | Broker draining and existing connections | | Stop writes | Warehouse group and active Append operations | | Isolate a node | Evidence of replication problems or data corruption | | Return to service | Health, data synchronization, and sample queries | ## Recover a Warehouse 1. Preserve the failure time and first error. 2. Check processes, disks, network, and replication state. 3. Assess redundancy on remaining nodes and the service impact. 4. Choose a supported recovery path: restart, reattach, or rebuild. 5. Monitor progress and errors. 6. After recovery, compare row counts, time ranges, and query results across nodes. Do not force a node to normal state without checking for data corruption. ## Constraints and checklist For edition-specific support for SQL, ROLLUP, backups, and ALTER SYSTEM, see [Support Scope](/dbms/reference/support-scope-constraints/). - Are all node and client SDK releases compatible? - Are permitted reads and writes during maintenance defined? - Have backup, restore, and node recovery drills been completed? - Have two operators cross-checked hosts, ports, and paths? - Do monitoring and alerts reflect the new node configuration? - Have Broker connections, queries, Append, and metadata been verified after the change? --- title: "14. Accounts, Privileges, and Access Control" url: https://docs.machbase.com/dbms/security-access-control/ language: en kind: section --- # 14. Accounts, Privileges, and Access Control Protecting production data requires systematic account, privilege, and access control configuration. This chapter explains the security model and practical configuration procedures. ## Chapter contents | Order | Section | Description | |-----:|------|------| | 14.1 | [Security Model Overview](./security-model/) | Security architecture, default account, privilege types, AUTH KEY authentication | | 14.2 | [Account Management](./account/) | Create and drop users, change passwords, password policies (NONE/LOW/HIGH) | | 14.3 | [Privilege Management](./privileges/) | GRANT/REVOKE, table privileges, database privileges | | 14.4 | [AUTH KEY Authentication](./authentication-auth-key/) | Public-key challenge authentication, key generation, registration, and management | | 14.5 | [Access Control](./access-control/) | Remote access and bind IP settings | | 14.6 | [Security Configuration Checklist](./checklist-configuration/) | Pre-deployment checks for production | ## Four areas of security **1. Security model** — Understand how accounts, privileges, and authentication work together. Reserve SYS for administration and give each user only the required privileges. **2. Account management** — Manage identities that access the database. Create and drop users, and apply password policies (NONE/LOW/HIGH) and public-key AUTH KEY authentication. **3. Privilege management** — Restrict the operations an account can perform. Apply least privilege using table-level DML privileges (SELECT, INSERT, DELETE, UPDATE) and database-level DDL and operational privileges (CREATE, DROP, ALTER, BACKUP, MOUNT). **4. Access control** — Control which network paths permit connections. `GRANT_REMOTE_ACCESS` controls remote access, while `BIND_IP_ADDRESS` selects the listener's network interface. --- title: "14.1 Security Model Overview" url: https://docs.machbase.com/dbms/security-access-control/security-model/ language: en kind: page --- # 14.1 Security Model Overview Machbase's security model combines three layers: **user accounts**, **privileges (GRANT/REVOKE)**, and **access control (IP/authentication)**. ## Machbase security architecture ```text Client connection request │ ▼ ┌──────────────────────────┐ │ Access control │ BIND_IP_ADDRESS, GRANT_REMOTE_ACCESS │ (network layer) │ └────────┬─────────────────┘ │ Allowed ▼ ┌──────────────────────────┐ │ Authentication │ Password or AUTH KEY (public-key) authentication │ (user identification) │ └────────┬─────────────────┘ │ Authenticated ▼ ┌──────────────────────────┐ │ Privilege check │ Check privileges assigned by GRANT/REVOKE │ (operation authorization)│ Table privileges + database privileges └──────────────────────────┘ ``` A connection request first passes network access control, then user authentication. Finally, the system checks that the user has the privileges required for the operation. ## Default account: SYS Machbase automatically creates the `SYS` account during installation. SYS is a superuser that can perform all database operations, create other users, and grant privileges. | Item | Value | |------|------| | Account name | `SYS` | | Default password | `MANAGER` | | Privileges | All privileges (superuser) | | Can be dropped | No | > **Required for production:** Change the SYS account's default password (`MANAGER`) immediately > after installation. > > ```sql > ALTER USER SYS IDENTIFIED BY 'new_password'; > ``` ## Related documentation - User lifecycle and password policies: [Account Management](../account/) - Database/table privileges and GRANT/REVOKE: [Privilege Management](../privileges/) - Public-key registration and rotation: [AUTH KEY Authentication](../authentication-auth-key/) - Remote access and listeners: [Access Control](../access-control/) Account creation, privilege grants, and authentication configuration are separate tasks. Prepare the accounts and tables in the following example, then reconnect as each account to verify both allowed and restricted operations. ## Principle of least privilege Apply these principles in production: - **Reserve SYS for administration:** Do not use SYS for routine reads or ingestion. - **Separate accounts by purpose:** Use separate read-only, ingestion, deployment (DDL), and backup accounts. - **Restrict privileges by table:** Grant only the required DML privileges on tables the account must access. - **Review regularly:** Remove unnecessary accounts and identify accounts with excessive privileges. ```sql -- Read-only account CREATE USER reader IDENTIFIED BY 'Reader#Strong123'; GRANT SELECT ON sys.sensor_log TO reader; -- Dedicated ingestion account CREATE USER writer IDENTIFIED BY 'Writer#Strong123'; GRANT SELECT, INSERT ON sys.sensor_log TO writer; -- Dedicated DDL account (table creation and deletion) CREATE USER deploy IDENTIFIED BY 'Deploy#Strong123'; GRANT CONNECT ON DATABASE factory_a TO deploy; GRANT DDL ON DATABASE factory_a TO deploy; ``` --- title: "14.2 Account Management" url: https://docs.machbase.com/dbms/security-access-control/account/ language: en kind: page --- # 14.2 Account Management Use separate accounts for applications and operations. Reserve `SYS` for user and privilege administration. For routine queries and loading, use accounts with only the required privileges. ## Create and drop users ```sql CREATE USER app_user IDENTIFIED BY 'App#Strong123' PASSWORD POLICY HIGH; SELECT USER_ID, NAME, PWD_POLICY_LEVEL, VALID_BEFORE FROM M$SYS_USERS WHERE NAME = 'APP_USER'; ``` Usernames are stored in uppercase. After creating an account, separately grant `CONNECT` on the target logical database. ```sql GRANT CONNECT ON DATABASE factory_a TO app_user; GRANT SELECT, INSERT ON TABLE factory_a.sys.sensor_log TO app_user; ``` When changing a password, you can specify the new password and its policy together. ```sql ALTER USER app_user IDENTIFIED BY 'App#Changed456' PASSWORD POLICY HIGH; ``` Before dropping a user, check active sessions, granted privileges, and owned objects. A user that owns objects cannot be dropped. ```sql DROP USER app_user; ``` You cannot drop `SYS` or the account used by your current connection. To continue as another account in `machsql`, authenticate a new session with `CONNECT user/password;` or reconnect the client. ### Drop a user with active sessions Dropping a user from another administrative session does not immediately terminate sessions already authenticated as that user. Existing sessions retain the username and internal ID saved at login, but the deleted user cannot establish new connections and no longer appears in `M$SYS_USERS`. Check active sessions and close application connections before dropping the user. From Machbase 8.7.0, use [CURRENT_USER and SESSION_USER](../../reference/sql/functions/functions-full/#current-session-user) to inspect the user context of existing sessions. ## Password policies | Policy | Main behavior | |---|---| | `NONE` | Default compatibility policy; no strength or expiration restrictions | | `LOW` | Checks length and character composition | | `HIGH` | LOW checks plus restrictions on recent password reuse and an expiration period | LOW and HIGH require at least 10 characters. `ENABLE_CASE_SENSITIVE_PASSWORD` affects case validation. HIGH sets `VALID_BEFORE` to 90 days after the password is set. ```sql CREATE USER reader_user IDENTIFIED BY 'Reader#Strong123' PASSWORD POLICY HIGH; ALTER USER reader_user IDENTIFIED BY 'Reader#Changed456' PASSWORD POLICY LOW; ``` Specify a new password together with the policy rather than changing the policy alone. Check the current policy and expiration date as follows. ```sql SELECT USER_ID, NAME, PWD_POLICY_LEVEL, VALID_BEFORE FROM M$SYS_USERS ORDER BY USER_ID; ``` `PWD_POLICY_LEVEL` is `0=NONE`, `1=LOW`, or `2=HIGH`. Use your production secret management mechanism instead of embedding passwords in applications. For full syntax, see [USER/AUTH Syntax](/dbms/reference/sql/syntax/user-auth-syntax/#create-drop-alter-user). --- title: "14.3 Privilege Management" url: https://docs.machbase.com/dbms/security-access-control/privileges/ language: en kind: page --- # 14.3 Privilege Management Machbase separates administrative privileges scoped to active databases from DML privileges on specific tables. Users need both `CONNECT` on the database and the privileges required for the target operation. ```sql GRANT CONNECT ON DATABASE factory_a TO app_user; GRANT SELECT, INSERT ON TABLE factory_a.sys.sensor_log TO app_user; ``` ## Privilege model | Scope | Privilege | Purpose | |---|---|---| | Active database | `CONNECT` | Connect and `USE` | | Active database | `CREATE`, `DROP`, `ALTER` | Create, drop, and alter objects | | Active database | `BACKUP` | Back up the database | | Active database | `DDL` | Combined `CREATE` and `DROP` | | Active database | `ALL` | `CONNECT`, `CREATE`, `DROP`, `ALTER`, `BACKUP` | | Mounted database | `USAGE` | Browse a mounted database | | Administrative database | `MOUNT` | `MOUNT DATABASE`, `UMOUNT DATABASE` | | Table | `SELECT`, `INSERT`, `DELETE`, `UPDATE` | DML on a specific table | | Table | `ALL` | All four table DML privileges | Database `ALL` does not include table DML or `MOUNT`. Table `ALL` does not include database administration. A privilege does not enable DML unsupported by the table type; for example, LOG tables do not support `UPDATE`. ## GRANT / REVOKE ```sql GRANT privilege_list ON target TO user_name; REVOKE privilege_list ON target FROM user_name; ``` The following example grants database access and read/write access to one table. ```sql GRANT CONNECT ON DATABASE factory_a TO app_user; GRANT SELECT, INSERT ON TABLE factory_a.sys.sensor_log TO app_user; REVOKE INSERT ON TABLE factory_a.sys.sensor_log FROM app_user; REVOKE CONNECT ON DATABASE factory_a FROM app_user; ``` Specify a table as `owner.table` in the current database or as `database.owner.table`. Database-wide grants of DML privileges such as `SELECT` are not supported. Inspect current privilege records in `M$SYS_USER_ACCESS`. ```sql SELECT DB_NAME, USER_NAME, OWNER_NAME, TABLE_NAME, PRIV FROM M$SYS_USER_ACCESS WHERE USER_NAME = 'APP_USER' ORDER BY DB_NAME, OWNER_NAME, TABLE_NAME; ``` A record is database-scoped when `OWNER_NAME` and `TABLE_NAME` are `NULL`, and table-scoped when they have values. `PRIV` is a bitmask representing multiple privileges. Do not interpret a displayed number as a single privilege name or hardcode it in operational scripts. ## Database privileges Creating a user alone does not grant access to a logical database. Explicitly grant `CONNECT` on the target database, then add only the required administrative privileges. ```sql GRANT CONNECT ON DATABASE factory_a TO deploy_user; GRANT DDL ON DATABASE factory_a TO deploy_user; GRANT ALTER ON DATABASE factory_a TO deploy_user; ``` Default compatibility privilege records for new users are scoped to the default database, `MACHBASEDB`. They do not automatically extend to other logical databases. ### SELECT / INSERT / DELETE / UPDATE Grant DML privileges on specific tables. ```sql GRANT SELECT ON sys.sensor_log TO reader_user; GRANT INSERT ON sys.sensor_log TO writer_user; GRANT DELETE ON sys.device_config TO maint_user; GRANT UPDATE ON sys.device_config TO maint_user; ``` Before granting `DELETE` or `UPDATE`, check the target table type's predicate restrictions. TAG data changes require tag and time predicates; VOLATILE changes require primary-key predicates. ### CREATE / DROP ```sql GRANT CREATE ON DATABASE factory_a TO deploy_user; GRANT DROP ON DATABASE factory_a TO deploy_user; ``` `DROP` permits changes that can be difficult to recover from. Do not grant it to accounts used only for loading or querying. Object ownership alone does not grant access to another database. ### ALTER ```sql GRANT ALTER ON DATABASE factory_a TO deploy_user; ``` `ALTER` can affect table structures and operational settings. Grant it only to deployment or operations accounts separate from application accounts. After a change, query the current settings and schema again. ### BACKUP ```sql GRANT BACKUP ON DATABASE factory_a TO backup_user; ``` The Machbase server process's OS account also needs write access to the backup path and sufficient free space, separately from SQL privileges. Prefer a backup database user without additional DML or DDL privileges. ### MOUNT ```sql GRANT MOUNT ON DATABASE MACHBASEDB TO recovery_user; ``` MOUNT/UMOUNT are administrative operations. `USAGE` to browse a mounted database and `SELECT` to read its tables are separate privileges. Follow [Backup, Restore, and Mount](/dbms/operations-configuration-recovery/backup-restore-mount/) for actual recovery procedures. ### Combined DDL / ALL privileges ```sql -- CREATE + DROP GRANT DDL ON DATABASE factory_a TO deploy_user; -- CONNECT, CREATE, DROP, ALTER, and BACKUP on an active database GRANT ALL ON DATABASE factory_a TO database_admin; -- SELECT, INSERT, DELETE, and UPDATE on one table GRANT ALL ON TABLE factory_a.sys.sensor_log TO table_admin; ``` Combined privileges are convenient but can make least-privilege review harder. Grant individual privileges to automation accounts where possible. ## Default grants and exclusions A user created with `CREATE USER` has default compatibility privilege records for `MACHBASEDB`. For logical databases, explicitly define the required scope as follows. ```sql GRANT CONNECT ON DATABASE factory_a TO app_user; GRANT SELECT, INSERT ON TABLE factory_a.sys.sensor_log TO app_user; ``` Grant `ALTER`, `BACKUP`, `MOUNT`, `USAGE`, and privileges on other logical databases separately after reviewing the account's role. ## Table privileges Always manage table privileges together with their target objects. ```sql GRANT SELECT ON TABLE factory_a.sys.sensor_log TO reader_user; GRANT SELECT, INSERT ON TABLE factory_a.sys.sensor_log TO ingest_user; REVOKE INSERT ON TABLE factory_a.sys.sensor_log FROM ingest_user; ``` Dropping a table removes its existing grants. A new object with the same name does not inherit them. Regrant the required privileges and verify them in `M$SYS_USER_ACCESS`. ## Privilege diagnostic checklist Review users and privileges in the following order. ```sql SELECT USER_ID, NAME, PWD_POLICY_LEVEL, VALID_BEFORE FROM M$SYS_USERS ORDER BY USER_ID; SELECT DB_NAME, USER_NAME, OWNER_NAME, TABLE_NAME, PRIV FROM M$SYS_USER_ACCESS ORDER BY USER_NAME, DB_NAME, OWNER_NAME, TABLE_NAME; ``` - Check for unused accounts. - Ensure read-only accounts have no write, DDL, or administrative privileges. - `REVOKE` temporary privileges when the approved period ends, then query the results again. - Before dropping a user, check owned objects and active sessions. - Validate audit tools that decode numeric `PRIV` values against the privilege definitions for the deployed version. --- title: "14.4 AUTH KEY Authentication" url: https://docs.machbase.com/dbms/security-access-control/authentication-auth-key/ language: en kind: page --- # 14.4 AUTH KEY Authentication AUTH KEY authentication registers a public key on the server and uses the client's private key to sign a server challenge. It can replace password authentication, but private-key protection and rotation require separate procedures. Select `AUTH_MODE=PASSWORD` or `AUTH_MODE=CHALLENGE` for each connection. ## Preparation 1. Create a dedicated application user. 2. Generate a key pair on the client host. 3. Register only the public key on the server. 4. Store the private-key file in the client's secret store. 5. Verify a CHALLENGE connection, then record key expiration and rotation dates. For supported keys and complete AUTH KEY SQL syntax, see [USER/AUTH Syntax](/dbms/reference/sql/syntax/user-auth-syntax/#auth-key). ## Manage user AUTH KEYs Check registration state in `V$USER_AUTH_KEYS`. ```sql SELECT KEY_ID, USER_NAME, KEY_ALGO, KEY_PARAM, ACTIVATED, VALID_AFTER, VALID_BEFORE, COMMENT FROM V$USER_AUTH_KEYS WHERE USER_NAME = 'APP_USER' ORDER BY KEY_ID; ``` `PUBKEY` contains the public-key body; preferably omit it from routine operational reports. ### CREATE USER ... WITH AUTH KEY You can register a public key while creating a user. Replace the sample public-key string with the actual PEM contents, representing line breaks as `\n`. ```sql CREATE USER app_user IDENTIFIED BY 'App#Strong123' WITH AUTH KEY ( key='-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n', valid_before='2047-12-31', comment='initial application key' ); ``` A password may remain an emergency recovery path. Use a separate strong password and policy. ### ALTER USER ... ADD AUTH KEY Add a new public key to an existing user as follows. ```sql ALTER USER app_user ADD AUTH KEY ( key='-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n', valid_before='2047-12-31', comment='replacement key' ); ``` After registration, query the new `KEY_ID`, algorithm, active state, and expiration date. ### Enable and disable AUTH KEYs ```sql ALTER USER app_user DEACTIVATE AUTH KEY ID 3; ALTER USER app_user ACTIVATE AUTH KEY ID 3; ``` Disabling a key blocks authentication while preserving its metadata. Before disabling a production key, verify that another authentication path actually works. ### Change AUTH KEY expiration ```sql ALTER USER app_user ALTER AUTH KEY ID 3 VALID_BEFORE='2048-06-30'; ``` Before extending expiration, recheck who uses the key and how it is stored. Extending validity does not change the key itself, so manage rotation intervals separately. ### Drop an AUTH KEY ```sql ALTER USER app_user DROP AUTH KEY ID 3; ``` Deletion cannot be undone. Verify successful access with the new key and disabled status for the old key before deleting it. Dropping a user also removes that user's AUTH KEYs. ## Key rotation 1. Generate a new key pair. 2. Register the new public key with `ADD AUTH KEY`. 3. Verify a CHALLENGE connection using the new private key. 4. Disable the old key and verify that connections using it fail. 5. Delete the old key after the observation period. Keeping the old key during the transition lets you validate rotation without interrupting service. ## AUTH KEY challenge authentication The client must be able to read the private-key file paired with the registered public key. Do not register the private key on the server. CHALLENGE authentication fails if the file is missing, the private key does not match the registered public key, or the registered key is disabled or expired. It does not automatically fall back to PASSWORD; explicitly establish a separate PASSWORD connection if needed. ## SYS AS USER authentication restrictions To use CHALLENGE authentication as `SYS`, register an AUTH KEY for `SYS`. For application connections, avoid `SYS` and use a dedicated account with minimum privileges and its own key instead. Change `SYS` keys during a maintenance window with another verified administrative access path. ## AUTH_MODE=CHALLENGE In `machsql`, specify both the connection string and private-key option. ```bash machsql -s 127.0.0.1 -P 5656 -u app_user \ -c "AUTH_MODE=CHALLENGE" \ -K /secure/path/app_user.key ``` The following example uses JDBC connection properties. ```text jdbc:machbase://127.0.0.1:5656/machbasedb?AUTH_MODE=CHALLENGE&AUTH_KEY_FILE=/secure/path/app_user.key ``` Do not log private-key file contents, passwords, or secrets from connection strings in logs or error reports. ## AUTH_KEY_FILE Generate the private key on the client host and use only the public key for SQL registration. For example, generate an ECDSA P-256 key pair as follows. ```bash openssl ecparam -name prime256v1 -genkey -noout -out app_user.key openssl ec -in app_user.key -pubout -out app_user.pub chmod 600 app_user.key ``` `chmod 600` is an operational recommendation to reduce private-key exposure. Also verify that the actual process account can read the file and access its parent directories. When converting a public key to an inline SQL string, represent line breaks as `\n` as follows. ```bash awk '{printf "%s\\n", $0}' app_user.pub ``` Validate the private-key formats actually supported, including PKCS#8, with your client and deployed version. ## AUTH_SIG_SCHEME | Public key | Available signature schemes | |---|---| | ECDSA P-256, P-384, P-521 | `ECDSA` | | RSA 2048, 3072, 4096 | `RSA_PKCS1_V15`, `RSA_PSS` | You can use the key's default scheme. To explicitly select RSA-PSS, also set the client option. ```bash machsql -s 127.0.0.1 -P 5656 -u app_user \ -c "AUTH_MODE=CHALLENGE" \ -K /secure/path/app_user_rsa.key \ --auth-sig-scheme=RSA_PSS ``` Authentication fails if the registered public-key type does not match the signature scheme. ## RSA / ECDSA / RSA_PSS support Choose algorithms based on security policy, client support, and compatibility with the key management system. Do not make universal claims about an algorithm's speed or security. Before registration, verify the full generation, connection, rotation, and revocation lifecycle with the actual client. --- title: "14.5 Access Control" url: https://docs.machbase.com/dbms/security-access-control/access-control/ language: en kind: page --- # 14.5 Access Control Restrict network access with `GRANT_REMOTE_ACCESS`, `BIND_IP_ADDRESS`, and OS or cloud firewalls together. Check current values as follows. ```sql SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME IN ('GRANT_REMOTE_ACCESS', 'BIND_IP_ADDRESS'); ``` Listener settings take effect at server startup. Do not assume a running listener automatically rebinds. Change `machbase.conf`, then follow the approved restart procedure. ## Configure remote access `GRANT_REMOTE_ACCESS` controls whether remote clients can connect. ```ini # Allow remote access GRANT_REMOTE_ACCESS = 1 # Block remote access GRANT_REMOTE_ACCESS = 0 ``` Before changing the value, check: 1. Connection origins for application, monitoring, and backup clients. 2. How to retain local administrative access. 3. The procedure for testing remote and emergency access after restart. Configure a firewall allowlist alongside `GRANT_REMOTE_ACCESS=1` so enabling remote access does not admit every remote address. ## BIND_IP_ADDRESS and network exposure `BIND_IP_ADDRESS` specifies the address for the IPv4 listener. ```ini # All IPv4 interfaces BIND_IP_ADDRESS = 0.0.0.0 # Local IPv4 interface BIND_IP_ADDRESS = 127.0.0.1 # Specified internal IPv4 interface BIND_IP_ADDRESS = 10.0.0.5 ``` An address that does not exist on the server can prevent startup. Check current interface addresses before changing the setting. After restart, use OS tools to verify the actual listening address and port. If `0.0.0.0` is required, restrict allowed source addresses and ports in the firewall or security group. Firewall commands depend on the deployed OS and network policy; do not blindly apply fixed commands from this manual. --- title: "14.6 Security Configuration Checklist" url: https://docs.machbase.com/dbms/security-access-control/checklist-configuration/ language: en kind: page --- # 14.6 Security Configuration Checklist Check the following before production deployment and during periodic audits. ## Accounts and authentication - Change the initial `SYS` password immediately after installation using your organization's secret management procedure. - Create dedicated accounts for each application; do not use `SYS` for routine connections. - Do not store passwords in source code, documentation, or command history. - Review unused accounts and accounts nearing expiration. - For AUTH KEY, assign responsibility for private-key storage, rotation, and revocation. ```sql SELECT USER_ID, NAME, PWD_POLICY_LEVEL, VALID_BEFORE FROM M$SYS_USERS ORDER BY USER_ID; SELECT USER_NAME, KEY_ID, KEY_ALGO, KEY_PARAM, ACTIVATED, VALID_BEFORE FROM V$USER_AUTH_KEYS ORDER BY USER_NAME, KEY_ID; ``` ## Privileges - Grant only the required `CONNECT` privileges on each logical database. - Verify that read-only accounts have no write, DDL, or backup privileges. - Record expiration dates and owners responsible for revoking temporary privileges. - Recheck privileges after recreating a user or table. ```sql SELECT DB_NAME, USER_NAME, OWNER_NAME, TABLE_NAME, PRIV FROM M$SYS_USER_ACCESS ORDER BY USER_NAME, DB_NAME, OWNER_NAME, TABLE_NAME; ``` `PRIV` is a bitmask. Validate custom tools that display numeric values as privilege names against the definitions for the deployed version. For grant and revoke procedures, see [Privilege Management](../privileges/). ## Network access - First determine whether remote access is required. - Restrict `BIND_IP_ADDRESS` to the required IPv4 interface. - Review source address allowlists in firewalls or security groups. - Apply configuration changes through maintenance procedures that include restart and connection validation. ```sql SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME IN ('GRANT_REMOTE_ACCESS', 'BIND_IP_ADDRESS'); ``` ## Post-change evidence After a security change, record these results: 1. User and expiration date query results. 2. Target user and database/table privilege query results. 3. Successful access from allowed addresses and blocked access from disallowed addresses. 4. For AUTH KEY changes, successful access with the new key and rejected access with the old key. Do not change the `SYS` password, listener, or firewall on a shared production server for testing. Verify the recovery path in a separate test environment before approving production changes. --- title: "15. Troubleshooting" url: https://docs.machbase.com/dbms/troubleshooting/ language: en kind: section --- # 15. Troubleshooting This chapter addresses operational problems in Machbase through symptom identification, diagnosis, resolution, and prevention. {{< callout type="info" >}} Before classifying a problem, check server status with `machadmin -e`. Record recent errors from `$MACHBASE_HOME/trc/machbase.trc` and the client's `ERR-XXXXX` code. {{< /callout >}} ## Chapter contents | Order | Section | Content | |-----:|------|------| | 15.1 | [Troubleshooting Approach](./troubleshooting/) | Symptom collection, diagnostic commands, log and error code analysis | | 15.2 | [Server and Connection Problems](./server-connection/) | Server startup, remote access, authentication errors | | 15.3 | [Ingestion and Loading Problems](./item/) | Append and CSV import errors | | 15.4 | [Query and Performance Problems](./performance/) | Slow queries, empty results, memory, transaction conflicts | | 15.5 | [Backup and Recovery Problems](./recovery-backup/) | BACKUP, RESTORE, MOUNT, and UMOUNT errors | | 15.6 | [Cluster Problems](./cluster/) | Node state and Cluster Edition errors | | 15.7 | [ROLLUP Problems](./rollup/) | Aggregation lag, result differences, and rebuild decisions | For TAG and LOOKUP UPDATE/DELETE predicate errors, see the constraints and troubleshooting page in the relevant table chapter. After resolving a problem, record the cause, corrective action, verification queries, and prevention measures in the operations log. --- title: "15.1 Troubleshooting Approach" url: https://docs.machbase.com/dbms/troubleshooting/troubleshooting/ language: en kind: page --- # 15.1 Troubleshooting Approach Preserve state and evidence before reproducing a problem, then narrow the cause from the smallest possible scope. ## Five-step troubleshooting procedure 1. Record the failure time, executed command, complete error message, and `ERR-` code. 2. Use `machadmin -e` and a connection test to distinguish server, network, and authentication failures. 3. Inspect server logs and session/statement state from the same time. 4. Correct one cause at a time and verify again with the same input. 5. Record the cause, action, validation results, and prevention measures. ## Identify symptoms | Symptom | First checks | |---|---| | No server response | `machadmin -e`, process and port, server logs | | Connection refused | Server state, listening address, firewall, port | | Authentication failure | User, authentication mode, expiration, AUTH KEY state | | SQL failure | Full SQL, target database and object, exact error code | | Slow query | Execution plan, time range, rows scanned, concurrent load | | Loading stopped | Successful/failed row counts, bad/log files, last successful position | Restarting the server or changing settings before diagnosis can destroy evidence of the original cause. ## Diagnostic commands ```bash machadmin -e tail -100 "$MACHBASE_HOME/trc/machbase.trc" ``` ```sql SELECT * FROM V$VERSION; SELECT ID, USER_NAME, CLOSED FROM V$SESSION ORDER BY ID; SELECT ID, SESS_ID, STATE, QUERY FROM V$STMT ORDER BY ID; SELECT * FROM V$STORAGE_USAGE; SELECT NAME, VALUE FROM V$PROPERTY ORDER BY NAME; ``` Production results may contain sensitive information such as SQL text, usernames, and paths. Review them before sharing. ## Inspect logs The default server log is `$MACHBASE_HOME/trc/machbase.trc`. Verify the actual path and rotation settings against `V$PROPERTY` and the installation configuration. ```bash tail -100 "$MACHBASE_HOME/trc/machbase.trc" rg -n 'ERR-|ERROR|WARN' "$MACHBASE_HOME/trc/machbase.trc" ``` Before changing log levels or file counts, query the current `TRACE_LOG_LEVEL`, `TRACE_LOGFILE_SIZE`, `TRACE_LOGFILE_COUNT`, and `TRACE_LOGFILE_PATH`. Excessive diagnostic logging during an incident can affect disk usage and performance. ## Diagnose by error code Record the exact error code and check its current definition in the [Error Code Reference](/dbms/reference/error-codes/). If it is absent, collect the full message, server build, reproduction SQL, and log timestamp. --- title: "15.2 Server and Connection Problems" url: https://docs.machbase.com/dbms/troubleshooting/server-connection/ language: en kind: page --- # 15.2 Server and Connection Problems Isolate connection problems in this order: server startup, TCP connection, then user authentication. ## The server does not start ```bash machadmin -e tail -100 "$MACHBASE_HOME/trc/machbase.trc" ``` Check these items in order: 1. Whether another process uses the configured port. 2. Whether the Machbase server's OS account can read and write installation, data, and log paths. 3. Whether the file system has sufficient space and inodes. 4. Whether a valid license is installed (`machadmin -f`). 5. Why an earlier process or lock file remains. Avoid forced termination or lock-file deletion without understanding the cause. If normal shutdown is impossible, preserve logs and process state, then follow an approved recovery procedure. ## A connection cannot be established First test a local connection on the server host. ```bash machadmin -e machsql -s 127.0.0.1 -P 5656 -u app_user ``` If local access succeeds but remote access fails, check: - The address and port used by the client - Current `GRANT_REMOTE_ACCESS` and `BIND_IP_ADDRESS` values - OS and cloud firewalls and the intermediate network path - Whether `MAX_SESSION_COUNT` has been reached and sessions remain unclosed ```sql SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME IN ('GRANT_REMOTE_ACCESS', 'BIND_IP_ADDRESS', 'MAX_SESSION_COUNT'); SELECT ID, USER_NAME, CLOSED FROM V$SESSION ORDER BY ID; ``` Listener settings apply at server startup. After changing the configuration file, perform a maintenance restart and verify both local and remote access. Follow the deployed OS's official documentation for firewall commands. ## Authentication fails First check the authentication mode selected for the connection. `AUTH_MODE` is a client connection option, not a server `V$PROPERTY` setting. For password authentication, check the username, password policy, and expiration date. ```sql SELECT USER_ID, NAME, PWD_POLICY_LEVEL, VALID_BEFORE FROM M$SYS_USERS WHERE NAME = 'APP_USER'; ``` For AUTH KEY authentication, inspect registered keys and client options. ```sql SELECT KEY_ID, USER_NAME, KEY_ALGO, KEY_PARAM, ACTIVATED, VALID_BEFORE FROM V$USER_AUTH_KEYS WHERE USER_NAME = 'APP_USER' ORDER BY KEY_ID; ``` ```bash machsql -s 127.0.0.1 -P 5656 -u app_user \ -c "AUTH_MODE=CHALLENGE" \ -K /secure/path/app_user.key ``` Verify that the private-key file exists, is readable by the client process, matches the server's public key, and is active and valid. Do not use unsupported syntax such as account unlocking or `CREATE AUTH KEY`. Follow [AUTH KEY Authentication](/dbms/security-access-control/authentication-auth-key/) for registration and rotation. --- title: "15.3 Ingestion and Loading Problems" url: https://docs.machbase.com/dbms/troubleshooting/item/ language: en kind: page --- # 15.3 Ingestion and Loading Problems ## Ingestion fails First record the full client error, target database and table, ingestion method, and last successful row. Check error meanings in the [Error Code Reference](/dbms/reference/error-codes/) instead of relying on a fixed code table on this page. ```sql DESC target_table; SELECT NAME, TYPE, COLCOUNT FROM M$SYS_TABLES WHERE NAME = 'TARGET_TABLE'; ``` Check the following: - Input column count, order, types, and nullability - Current database and table owner - User `CONNECT` and table `INSERT` privileges - Time string format and connection time zone - File system space and `V$STORAGE_USAGE` - Append API return values, failed rows, and flush results Support for out-of-order timestamps and UPDATE/DELETE predicates differs by table type. Check the constraints in the relevant table usage chapter. ## CSV import fails Check the current distribution's options with `machloader -h`. ```bash machloader -h machloader -s 127.0.0.1 -P 5656 -u app_user \ -t target_table -i /data/input.csv \ -b /data/input.bad -l /data/input.log ``` Reproduce the failure with a small file, in this order: 1. Check absolute paths and file permissions on the loader host, not the server host. 2. Compare the column count of one CSV row with `DESC target_table`. 3. Check encoding names against the current help. Available names include `UTF8`, `MS949`, `KSC5601`, and `EUCJP`. 4. Match delimiter and quote options to the actual file. 5. Specify both the target column name and format in date format options. 6. Correct the first rejected row in the bad file, then load it into a separate validation table. For exact `-F` syntax and loader options, use the [machloader Command and Option Reference](/dbms/reference/command-line-tools/machloader/). When retrying after partial success, check the already ingested range to prevent duplicates. --- title: "15.4 Query and Performance Problems" url: https://docs.machbase.com/dbms/troubleshooting/performance/ language: en kind: page --- # 15.4 Query and Performance Problems ## A query is slow Record the affected SQL, bind value ranges, start and end times, and expected and actual row counts. ```sql SELECT ID, SESS_ID, STATE, QUERY FROM V$STMT ORDER BY ID; EXPLAIN SELECT ...; ``` Check the execution plan for the following: - Are time and tag predicates applied early enough? - Are large tables scanned repeatedly without need? - Do join key types and value formats match? - Is the required index or ROLLUP actually used? - Are unnecessary columns or rows being read? The current MINMAX cache property is `DISK_COLUMNAR_TABLE_COLUMN_MINMAX_CACHE_SIZE`. Record the current value and execution plan before changing it, then compare in an isolated environment. Follow [Performance Tuning](/dbms/performance-tuning/) for the detailed procedure. ## Query results differ from expectations ```sql SELECT COUNT(*), MIN(_ARRIVAL_TIME), MAX(_ARRIVAL_TIME) FROM target_log; ``` 1. Verify the target database, owner, and table name. 2. Read a small sample without filters to check data presence and actual timestamps. 3. Check the connection time zone and how input string time zones are interpreted. 4. Check tag names, case, and boundary operators (`>`, `>=`, `<`, `<=`). 5. For ROLLUP results, check the gap and update state. Do not look for a server property named `DEFAULT_TIMEZONE`. Specify the time zone through client connections and sessions, and record the source data's reference time zone. ```sql SHOW ROLLUPGAP; SELECT * FROM V$ROLLUP; ``` ## Insufficient memory ```sql SELECT * FROM V$SYSMEM; SELECT ID, SESS_ID, STATE, QUERY FROM V$STMT ORDER BY ID; ``` Check OS memory, swap, and OOM records alongside Machbase logs from the same time. Separately reproduce queries fetching large results at once, large joins and sorts, excessive concurrency, and large client fetch or Append buffers. Query current settings in `V$PROPERTY`. Check allowed ranges and change procedures in the [Configuration Reference](/dbms/reference/configuration/configuration/), then load-test each change individually before applying it. --- title: "15.5 Backup and Recovery Problems" url: https://docs.machbase.com/dbms/troubleshooting/recovery-backup/ language: en kind: page --- # 15.5 Backup and Recovery Problems ## Backup or restore fails For backup failures, check path permissions for the server process's OS account, available space, existing backups at the same path, and server logs. ```sql SELECT * FROM V$STORAGE_USAGE; ``` ```bash machadmin -e tail -100 "$MACHBASE_HOME/trc/machbase.trc" ``` Restoration is destructive: it replaces the existing physical database. Stopping the running server alone is insufficient; restoration is rejected if the current database still exists. The following is a conceptual checklist, not commands to copy into production. ```text 1. Verify the recovery target, backup path, version, and checksums. 2. Obtain approval for preserving the current database and defining rollback conditions. 3. Shut down the server normally. 4. Follow the approved procedure to remove the current physical database. 5. Run machadmin restore. 6. Start the server and run application validation queries. ``` `machadmin -d` destroys the current database. Do not run it without a backup and explicit approval. For exact restoration syntax and restrictions, see [BACKUP/RESTORE/MOUNT Syntax](/dbms/reference/sql/syntax/backup-restore-mount-syntax/). Checking a backup image or successfully mounting it is only preliminary validation and does not guarantee complete recoverability. Regularly restore and validate applications in a separate environment. ## Mounting fails Check current mounts, a unique alias, the backup path, and read permissions for the server process. ```sql SELECT * FROM V$STORAGE_MOUNT_DATABASES; ``` The current syntax places the alias after the backup path. ```sql MOUNT DATABASE '/backup/sc15_snapshot' TO backup_check; SELECT COUNT(*) FROM backup_check.sys.target_table; UMOUNT DATABASE backup_check; ``` Distinguish alias conflicts, unsupported editions, incompatible backups, and mounted databases in use. Do not forcibly delete files or modify server metadata. --- title: "15.6 Cluster Problems" url: https://docs.machbase.com/dbms/troubleshooting/cluster/ language: en kind: page --- # 15.6 Cluster Problems ## Abnormal Cluster node state Collect the overall state and first error before changing topology or restarting nodes. ```bash machcoordinatoradmin --cluster-status machclusterctl status ``` 1. Identify which role first became abnormal: Coordinator, Broker, or Warehouse. 2. Align and compare logs from that node and its upstream roles. 3. Check host, process, disk, network, and configuration file change history. 4. Record replication and redistribution state and the client impact. 5. Apply the approved recovery procedures in Chapter 13 one node at a time, then verify overall state again. Do not guess node names, service ports, or inter-node ports when running start/add/remove commands. Use the actual `cluster.yaml` and deployment tool help. For detailed operational restrictions, see [Cluster Operations](/dbms/operations-configuration-recovery/cluster/). ## Cluster Edition restriction errors ```sql SELECT * FROM V$VERSION; ``` To determine whether an error is an edition restriction, compare the current edition with [Support by Edition](/dbms/reference/support-scope-constraints/). Do not use unofficial workarounds for Standard-only features. Consider a supported Cluster feature that meets the same requirement or a separate Standard environment. --- title: "15.7 ROLLUP Problems" url: https://docs.machbase.com/dbms/troubleshooting/rollup/ language: en kind: page --- # 15.7 ROLLUP Problems When ROLLUP results lag or differ from raw data, first distinguish processing delay from differences in aggregation semantics. Replace sample names with the actual tables and jobs being diagnosed. Do not start by dropping and recreating them. ## 1. Check state and scope ```sql SELECT ROLLUP_NAME, ROLLUP_TABLE, ROOT_TABLE, EXT_TYPE, INTERVAL_TIME, WAKEUP_INTERVAL, ENABLED, RUN_STATE, LAST_ELAPSED_MSEC FROM V$ROLLUP ORDER BY ROLLUP_NAME; SHOW ROLLUPGAP; ``` SHOW ROLLUPGAP is a machsql command; do not send it through an SDK SQL API. The gap is a difference in processed RIDs, not a direct measure of time lag or completion of raw-data corrections. Record state across all levels and Cluster nodes, along with the server build, database, and owner. ## 2. Compare the same dataset | Symptom | Check | |---|---| | Some samples are missing | Whether a conditional ROLLUP candidate was selected and matches the raw-data filter | | FIRST/LAST error | Whether the selected candidate is EXTENSION | | No candidate for monthly/daily queries | Whether stored-interval selection rules were confused with query buckets | | Average differs | NULL handling, valid counts, reaggregation of partial averages, and tag grouping | | Values unchanged after raw-data correction | Whether FORCE was incorrectly used to revisit history and REBUILD is needed | | JSON counts differ | Distinction among source documents, SQL NULL, per-path counts, and document aggregate counts | Query raw data with DATE_TRUNC/DATE_BIN and GROUP BY, and stored aggregates with rollup(). Keep tags, timestamps, origin, end boundaries, and aggregate functions identical. Do not assume rollup() falls back to a raw-data scan when no applicable ROLLUP exists. ## 3. Catch up with new input Verify that the target job is active and specify the required job by name. ```sql ALTER ROLLUP rollup_name FORCE; SHOW ROLLUPGAP; ``` WAKEUP only wakes a job; FORCE waits for it to catch up to the processing range. After checking a stopped job's state, START it. Process multiple levels from the lowest upward. `ALTER SYSTEM FLUSH ROLLUP` is unsupported and must not be used as a diagnostic command. ## 4. Historical corrections and rebuilding Even in Standard Edition, not every ROLLUP configuration supports REBUILD. First check for a complete automatic hierarchy, supported Custom intervals and buckets, and retained raw data. Use supported constant strings or TO_DATE expressions for time arguments. The entire bucket containing the specified timestamp is recalculated. Account for stopping and restarting related jobs and for partial failures. After success or failure, verify results and actual active state. Follow the [REBUILD Tutorial](../../tag-rollup-usage/rollup-rebuild/) and [Argument Contract](../../reference/sql/syntax/rollup-rebuild-syntax/). ## 5. Information for support - Server build, edition, client, and connection target - TAG schema, ROLLUP definitions, predicates, and dependencies - State, gap, and observation time - Compared raw-data and ROLLUP SQL, time zone, origin, expected and actual results - First error and recent raw-data corrections, deletions, bulk ingestion, or configuration changes --- title: "16. Reference" url: https://docs.machbase.com/dbms/reference/ language: en kind: section --- # 16. Reference A comprehensive reference for precise definitions of syntax, functions, configuration, and system catalogs. For SDK/API documentation, see Chapter 11, Development and Application Integration. For concepts and examples, see the relevant feature chapter. ## Contents | Section | Description | |------|------| | [SQL Reference](./sql/) | SQL syntax, functions, data types, hints, and relative time expressions | | [Configuration Reference](./configuration/) | machbase.conf properties and dynamically configurable properties | | [Command-line Tools](./command-line-tools/) | Options for CLI tools such as machsql, machadmin, and machloader | | [Development Tool Integration](../development-tools-integration/) | Go, Python, Java, and C client SDK/APIs (Chapter 11) | | [System Catalog](./system-catalog/) | V$ and M$SYS views and column descriptions | | [Error Codes](./error-codes/) | Error numbers, messages, causes, and corrective actions | | [Support Scope and Constraints](./support-scope-constraints/) | Feature support by table type and known constraints | | [AI Agent Reference](./ai-agent-reference/) | AI/RAG navigation guides, canonical maps, and LLM outputs | ## Finding Information - **Check syntax** → [SQL Syntax Dictionary](./sql/syntax/) - **Function arguments and return values** → [SQL Function Dictionary](./sql/functions/) - **Data type ranges and defaults** → [Data Type Dictionary](./sql/types/) - **Setting meanings and allowed ranges** → [Configuration Reference](./configuration/) - **Diagnose error causes** → [Error Codes](./error-codes/) > For behavior, selection criteria, and operational guidance, see the relevant feature chapter. --- title: "16.1 SQL Reference" url: https://docs.machbase.com/dbms/reference/sql/ language: en kind: section --- # 16.1 SQL Reference Precise definitions of SQL syntax, functions, data types, query hints, and relative time expressions. ## Subsections | Section | Description | |------|------| | [SQL Syntax Dictionary](./syntax/) | BNF syntax and examples for CREATE, DROP, ALTER, SELECT, WITH/CTE, INSERT, DELETE, UPDATE, BACKUP, MOUNT, and other statements | | [Function Dictionary](./functions/) | Aggregate, mathematical, string, date/time, type conversion, and TAG-specific functions | | [Data Type Dictionary](./types/) | Sizes, ranges, defaults, and availability by table type | | [SELECT Hint Syntax](./syntax/select-hint-syntax/) | SELECT hint syntax, usage, and applicable targets | | [Relative Time Expressions](./relative-time/) | Relative time literals such as `now - 1h` and their suffixes | | [ROWID](./rowid/) | ROWID meaning, predicates, and INSERT results by table type | ## SQL Features Based on ANSI SQL, with extensions optimized for time-series processing. - **TAG time-series features**: BASETIME, METADATA, `FIRST`/`LAST`, `SERIES BY`, ROLLUP - **Time-range queries**: `DURATION`, `BEFORE`, `AFTER`, and `RANGE` clauses - **Common table expressions**: Nonrecursive `WITH`/CTE in Standard Edition - **Bulk ingestion integration**: Client SDK Append APIs (separate ingestion APIs, not SQL statements) - **Text search**: `SEARCH`, `ESEARCH`, and `REGEXP` operators - **Set operations**: `UNION ALL` (UNION, INTERSECT, and EXCEPT are not supported) --- title: "16.1.1 SQL Syntax Dictionary" url: https://docs.machbase.com/dbms/reference/sql/syntax/ language: en kind: section --- # 16.1.1 SQL Syntax Dictionary The SQL Syntax Dictionary provides BNF notation and minimal examples for all SQL statements supported by Machbase. ## Supported SQL Statements | Statement | Category | Description | |------|------|------| | [CREATE TABLE](./ddl-syntax/#create-table) | DDL | Create LOG/TAG/LOOKUP/VOLATILE/TRANSACTION tables | | [DROP TABLE](./ddl-syntax/#drop-table) | DDL | Drop tables | | [ALTER TABLE](./ddl-syntax/#alter-table) | DDL | Change schemas: add/drop/modify/rename columns | | [TRUNCATE TABLE](./ddl-syntax/#truncate-table) | DDL | Delete all table data | | [CREATE INDEX](./index-syntax/#create-index) | DDL | Conditional creation and index support by table type | | [DROP INDEX](./index-syntax/#drop-index) | DDL | Drop indexes | | [CREATE ROLLUP](./rollup-syntax/#create-rollup) | DDL | Create TAG ROLLUP definitions | | [DROP ROLLUP / ALTER ROLLUP](./rollup-syntax/#drop-rollup) | DDL | Delete and control ROLLUPs | | [CREATE RETENTION](./retention-syntax/#create-retention) | DDL | Create retention policies | | [CREATE VIEW / DROP VIEW](./view-syntax/) | DDL | Create and drop stored views | | [CREATE TABLESPACE](./ddl-syntax/#create-tablespace) | DDL | Create tablespaces | | [INSERT INTO](./dml-syntax/#insert-into) | DML | Insert single or multiple rows | | [INSERT SELECT](./dml-syntax/#insert-select) | DML | Insert query results into another table | | [UPDATE](./dml-syntax/#update) | DML | Modify TRANSACTION/LOOKUP/VOLATILE rows and correct TAG data with restricted predicates | | [DELETE](./dml-syntax/#delete) | DML | Delete table data | | [LOAD DATA INFILE](./load-data-infile-syntax/) | DML | Load CSV files directly | | [SELECT](./select-syntax/) | SELECT | Query data with JOIN, GROUP BY, ORDER BY, and LIMIT | | [WITH / CTE](./cte-syntax/) | SELECT | Nonrecursive common table expressions in Standard Edition | | [Named Bind Parameter](./named-bind-parameter-syntax/) | Common SQL | Value parameters in `:name` form | | [CAST](../functions/functions-full/#cast) | SQL expression | Explicitly convert values to a specified type | | [SAVE DATA INTO](./save-data-into-syntax/) | SELECT | Save query results to CSV | | [BACKUP](./backup-restore-mount-syntax/#backup) | Operations | Back up databases or tables | | [RESTORE](./backup-restore-mount-syntax/#restore) | Operations | Logical database restore and offline restore using `machadmin -r` | | [MOUNT / UMOUNT DATABASE](./backup-restore-mount-syntax/#mount-database) | Operations | Mount/unmount backup databases | | [CREATE USER / DROP USER / ALTER USER](./user-auth-syntax/#create-drop-alter-user) | Users | Create/drop users and change passwords | | [GRANT / REVOKE](./user-auth-syntax/#grant-revoke) | Users | Grant and revoke privileges | | [AUTH KEY Management](./user-auth-syntax/#auth-key) | Users | Register/manage public-key authentication keys | | [ALTER SYSTEM](./system-session-alter-syntax/#alter-system) | System | Session control, PVO Cache flush, license installation, and more | | [ALTER SESSION](./system-session-alter-syntax/#alter-session) | Session | Configure session parameters | | [PIVOT](./pivot-syntax/) | Analysis | Convert rows to columns | | [WINDOW FUNCTION (OVER)](./window-function-over-syntax/) | Analysis | Window functions and OVER | | [SERIES BY](./series-syntax/) | Analysis | Group consecutive records meeting conditions | | [SEARCH / ESEARCH / REGEXP](./search-esearch-regexp-syntax/) | Search | Keyword-index-based text search | | [ROLLUP REBUILD](./rollup-rebuild-syntax/) | Operations | Recalculate ROLLUP results | | [DATABASE](./database-syntax/) | DDL/session | Create/select/drop logical databases and check status | | [AUTO_INCREMENT](./auto-increment-syntax/) | DDL | Generate 64-bit PRIMARY KEY values automatically | | [EXEC procedure / SHOW ROLLUPGAP](./execute-procedure-syntax/) | Control | Table flush/refresh and ROLLUP control/status | ## BNF Conventions This dictionary uses the following Backus–Naur Form (BNF) conventions. | Notation | Meaning | |------|------| | `'keyword'` | SQL reserved word, case-insensitive | | `name` | User-defined name | | `( A \| B )` | Either A or B | | `[ ... ]` | Optional element | | `( ... )*` | Zero or more repetitions | | `( ... )+` | One or more repetitions | | `( ... )?` | Zero or one occurrence | --- title: "SELECT" url: https://docs.machbase.com/dbms/reference/sql/syntax/select-syntax/ language: en kind: page --- # SELECT `SELECT` retrieves, filters, and aggregates data from Machbase table types. ## Complete SELECT Syntax ```sql query_stmt ::= [ with_clause ] select_stmt select_stmt ::= 'SELECT' [ hint_clause ] target_list [ 'FROM' table_reference_list ] [ 'WHERE' condition_expr ] [ 'DURATION' duration_expr ] [ 'GROUP BY' expr_list [ 'HAVING' condition_expr ] ] [ 'ORDER BY' expr_list [ 'ASC' | 'DESC' ] ] [ 'SERIES BY' condition_expr ] [ 'LIMIT' [ offset ',' ] row_count ] -- Set operator select_stmt 'UNION ALL' select_stmt ``` Place `DURATION` after WHERE and before GROUP BY, HAVING, ORDER BY, SERIES BY, and LIMIT. The syntax above shows clause order, not internal execution order. `with_clause` declares nonrecursive CTEs in Standard Edition. See [WITH / CTE Syntax](../cte-syntax/) for complete syntax and restrictions. ### Target List (target_list) ```sql target_list ::= '*' | target_expr ( ',' target_expr )* target_expr ::= column_name [ 'AS' alias ] | expr [ 'AS' alias ] | '(' subquery ')' [ 'AS' alias ] ``` ### FROM Clause ```sql table_reference_list ::= table_reference ( ',' table_reference )* table_reference ::= table_name [ alias ] | '(' subquery ')' [ alias ] | table_name [ alias ] join_clause | view_name [ alias ] join_clause ::= [ 'INNER' | 'LEFT OUTER' | 'RIGHT OUTER' ] 'JOIN' table_reference 'ON' condition_expr | 'CROSS JOIN' table_reference ``` --- ## SELECT Without FROM Returns constants, arithmetic expressions, or simple function results as one row without querying a table. ```sql SELECT 1; SELECT 'alive'; SELECT 1 + 2; SELECT ABS(-7); SELECT SYSDATE; ``` --- ## WHERE Clause ```sql condition_expr ::= expr comparison_op expr | expr [ 'NOT' ] 'BETWEEN' expr 'AND' expr | column_name [ 'NOT' ] 'IN' '(' value_list | subquery ')' | column_name 'RANGE' duration_spec | column_name [ 'NOT' ] 'SEARCH' string_literal | column_name 'ESEARCH' pattern_literal | column_name [ 'NOT' ] 'REGEXP' pattern_literal | expr 'IS' [ 'NOT' ] 'NULL' | condition_expr ( 'AND' | 'OR' ) condition_expr | 'NOT' condition_expr | '(' condition_expr ')' | '(' subquery ')' ``` ### Main WHERE Operators | Operator | Description | |--------|------| | `=`, `<>`, `<`, `<=`, `>`, `>=` | Comparison | | `BETWEEN value1 AND value2` | Range condition | | `IN (value_list)` | Value-list condition | | `IN (subquery)` | Subquery IN | | `RANGE n unit` | Time range relative to now | | `SEARCH 'keyword'` | Keyword-index text search | | `ESEARCH 'pattern%'` | Extended text search (% wildcard) | | `REGEXP 'pattern'` | Regular expression search (no index) | | `IS NULL` / `IS NOT NULL` | NULL condition | ```sql -- BETWEEN SELECT * FROM sensor_log WHERE value BETWEEN 10.0 AND 20.0; -- IN SELECT * FROM sensor_log WHERE status IN ('OK', 'WARN'); -- RANGE (Last hour relative to now) SELECT * FROM sensor_log WHERE _arrival_time RANGE 1 HOUR; -- SEARCH (Uses the keyword index) SELECT * FROM log_table WHERE message SEARCH 'error'; -- ESEARCH (Wildcard pattern) SELECT * FROM log_table WHERE message ESEARCH 'timeout%'; -- REGEXP (Regular expression) SELECT * FROM log_table WHERE message REGEXP 'error[0-9]+'; ``` --- ## GROUP BY / HAVING ```sql 'GROUP BY' expr_list [ 'HAVING' condition_expr ] ``` ```sql SELECT name, AVG(value), MAX(value), COUNT(*) FROM sensor_log GROUP BY name HAVING AVG(value) > 50.0; ``` --- ## ORDER BY ```sql 'ORDER BY' expr_list [ 'ASC' | 'DESC' ] ``` ```sql SELECT name, value FROM sensor_log ORDER BY value DESC; SELECT name, value FROM sensor_log ORDER BY name ASC, value DESC; ``` --- ## LIMIT ```sql 'LIMIT' [ offset ',' ] row_count ``` ```sql -- Retrieve only the first 10 rows SELECT * FROM sensor_log LIMIT 10; -- Retrieve 10 rows starting with the 11th SELECT * FROM sensor_log LIMIT 10, 10; ``` --- ## DURATION Specifies a query time range based on `_arrival_time`. ```sql duration_expr ::= number time_unit [ ( 'BEFORE' | 'AFTER' ) number time_unit ] | 'FROM' datetime_expr 'TO' datetime_expr time_unit ::= 'YEAR' | 'MONTH' | 'WEEK' | 'DAY' | 'HOUR' | 'MINUTE' | 'SECOND' ``` ```sql -- Data from the last hour SELECT * FROM sensor_log DURATION 1 HOUR; -- One-hour range starting one day ago SELECT * FROM sensor_log DURATION 1 HOUR BEFORE 1 DAY; -- Explicit range SELECT * FROM sensor_log DURATION FROM TO_DATE('2024-01-01','YYYY-MM-DD') TO TO_DATE('2024-01-31','YYYY-MM-DD'); ``` --- ## JOIN ### INNER JOIN (Comma Syntax) ```sql SELECT t1.id, t2.name FROM sensor_log t1, devices t2 WHERE t1.id = t2.device_id AND t1.value > 50; ``` ### ANSI JOIN ```sql -- INNER JOIN SELECT t1.id, t2.name FROM sensor_log t1 INNER JOIN devices t2 ON (t1.id = t2.device_id) WHERE t1.value > 50; -- LEFT OUTER JOIN SELECT t1.id, t2.location FROM sensor_log t1 LEFT OUTER JOIN devices t2 ON (t1.name = t2.name); -- RIGHT OUTER JOIN SELECT t1.value, t2.name FROM sensor_log t1 RIGHT OUTER JOIN devices t2 ON (t1.name = t2.name); ``` > FULL OUTER JOIN is not supported. --- ## SERIES BY Extracts groups of consecutive records that satisfy a condition in sorted results. ```sql 'ORDER BY' expr 'SERIES BY' condition_expr ``` ```sql -- Retrieve consecutive record groups satisfying C2 > 1 SELECT c1, c2, SERIESNUM() AS grp FROM t1 ORDER BY c1 SERIES BY c2 > 1; ``` --- ## SUBQUERY ```sql -- FROM subquery (inline view) SELECT a.name, a.avg_val FROM (SELECT name, AVG(value) AS avg_val FROM sensor_log GROUP BY name) a WHERE a.avg_val > 50; -- WHERE subquery SELECT * FROM sensor_log WHERE value > (SELECT AVG(value) FROM sensor_log); -- IN subquery SELECT * FROM sensor_log WHERE name IN (SELECT name FROM devices WHERE status = 'ACTIVE'); ``` > Correlated subqueries (subqueries referencing outer-query columns) are not supported. --- ## CASE Expressions ```sql -- simple CASE CASE expr WHEN value1 THEN result1 [ WHEN value2 THEN result2 ... ] [ ELSE default_result ] END -- searched CASE CASE WHEN condition1 THEN result1 [ WHEN condition2 THEN result2 ... ] [ ELSE default_result ] END ``` ```sql SELECT name, value, CASE WHEN value >= 80 THEN 'HIGH' WHEN value >= 40 THEN 'MID' ELSE 'LOW' END AS level FROM sensor_log; ``` --- ## PIVOT Transforms aggregate results from an inline view from rows into columns. ```sql 'PIVOT' '(' aggregate_func '(' column ')' 'FOR' pivot_column 'IN' '(' value_list ')' ')' ``` ```sql SELECT * FROM (SELECT regtime, tagid, dvalue FROM result_d) PIVOT (SUM(dvalue) FOR tagid IN ('AXIS_X', 'AXIS_Y', 'AXIS_Z')); ``` --- ## UNION ALL ```sql select_stmt 'UNION ALL' select_stmt ``` Combines two SELECT results. Column counts and types must be compatible. `UNION` (deduplication), `INTERSECT`, and `EXCEPT` are unsupported. ```sql SELECT id, name FROM table_a UNION ALL SELECT id, name FROM table_b; ``` --- ## SAVE DATA INTO Saves SELECT results to a CSV file. ```sql 'SAVE DATA INTO' 'file_path' [ 'HEADER' ( 'ON' | 'OFF' ) ] [ ( 'FIELDS' | 'COLUMNS' ) [ 'TERMINATED BY' char ] [ 'ENCLOSED BY' char ] ] [ 'ENCODED BY' encoding ] 'AS' select_stmt ``` ```sql SAVE DATA INTO '/tmp/sensor_data.csv' HEADER ON AS SELECT * FROM sensor_log; ``` --- ## Related Documentation - [WITH / CTE Syntax](../cte-syntax/) – Nonrecursive common table expressions - [Hint Reference](../select-hint-syntax/) – SELECT optimization hints - [SERIES BY](../series-syntax/) – Consecutive-condition grouping - [PIVOT](../pivot-syntax/) – Row-to-column examples - [SEARCH/ESEARCH/REGEXP](../search-esearch-regexp-syntax/) – Text search - [DURATION Relative Time Expressions](../../relative-time/) – Complete time-range expressions --- title: "WITH / CTE" url: https://docs.machbase.com/dbms/reference/sql/syntax/cte-syntax/ language: en kind: page --- # WITH / CTE A Common Table Expression (CTE) names a `SELECT` result within one SQL statement. Use it to split complex inline views into stages or join aggregate results to other tables. Machbase 8.7.0 Standard Edition supports nonrecursive SELECT CTEs. A CTE exists only within its SQL statement and is not stored as a database object. ## Support Scope | Feature | Supported | Description | |---|:---:|---| | Single nonrecursive CTE | O | CTE body and main query are `SELECT` | | Multiple CTEs | O | Comma-separated; later CTEs can reference earlier ones | | Explicit result column names | O | Column list follows the CTE name | | Nested CTEs | O | Outer CTEs are visible to nested `SELECT` queries | | `INSERT SELECT` | O | Uses `INSERT INTO ... WITH ... SELECT` | | VIEW definitions | O | Uses `CREATE VIEW ... AS WITH ... SELECT` | | Prepared statements | O | `?` or `:name` in CTE bodies and the main `SELECT` | | EXPLAIN | O | `EXPLAIN`, `EXPLAIN FULL`, `EXPLAIN TRACE` | | `UNION ALL`, PIVOT | O | Existing `SELECT` scope and restrictions apply | | Table types | O | Queries LOG, TAG, LOOKUP, VOLATILE, and TRANSACTION | | Recursive CTEs | X | No `WITH RECURSIVE`, self-reference, or mutual recursion | | Materialization control | X | No `MATERIALIZED` or `NOT MATERIALIZED` | | Data-modifying CTEs | X | No DML or DDL in CTE bodies | CTE bodies support JOIN, aggregates, `GROUP BY`, `HAVING`, `ORDER BY`, `LIMIT`, `UNION ALL`, and PIVOT under existing SELECT rules. LOG `DURATION`, `SERIES BY`, window functions, and TAG ROLLUP also retain their existing rules. See [Named Bind Parameter Syntax](../named-bind-parameter-syntax/) for parameter name rules and SDK binding methods. ## Basic Syntax ### SELECT ```sql WITH cte_name [(column_name [, ...])] AS ( select_statement ) [, cte_name [(column_name [, ...])] AS (select_statement) ...] select_statement; ``` ### INSERT SELECT ```sql INSERT INTO target_table [(target_column [, ...])] WITH cte_name [(column_name [, ...])] AS ( select_statement ) [, cte_name [(column_name [, ...])] AS (select_statement) ...] select_statement; ``` For `INSERT SELECT`, place `WITH` after the target table and column list. The leading `WITH ... INSERT INTO ...` form used by other DBMSs is unsupported. ### VIEW ```sql CREATE [OR REPLACE] VIEW view_name AS WITH cte_name [(column_name [, ...])] AS ( select_statement ) [, cte_name [(column_name [, ...])] AS (select_statement) ...] select_statement; ``` ### EXPLAIN ```sql EXPLAIN [FULL | TRACE] WITH cte_name [(column_name [, ...])] AS ( select_statement ) [, cte_name [(column_name [, ...])] AS (select_statement) ...] select_statement; ``` ## Basic Usage The examples assume the current user owns these tables: | Table | Type | Columns used | |---|---|---| | `sensor_data` | LOG | `name`, `device_id`, `time`, `value` | | `device_info` | TRANSACTION | `device_id`, `device_name` | | `device_summary` | LOG | `device_id`, `sample_count`, `avg_value` | ### Name a Query Result ```sql WITH recent_data AS ( SELECT name, time, value FROM sensor_data WHERE time >= NOW - 10m ) SELECT name, time, value FROM recent_data ORDER BY time DESC; ``` Specify `ORDER BY` in the main SELECT to guarantee final ordering. An `ORDER BY` inside the CTE alone does not guarantee outer-result order. ### Join Aggregate Results ```sql WITH top_devices AS ( SELECT device_id, AVG(value) AS avg_value FROM sensor_data WHERE time >= NOW - 1h GROUP BY device_id ORDER BY avg_value DESC LIMIT 10 ) SELECT d.device_id, d.device_name, t.avg_value FROM device_info d JOIN top_devices t ON d.device_id = t.device_id ORDER BY t.avg_value DESC; ``` Use this to aggregate large time-series datasets and reduce result counts before joining reference data. ### Chain Multiple CTEs ```sql WITH recent_data AS ( SELECT device_id, value FROM sensor_data WHERE time >= NOW - 30m ), device_avg AS ( SELECT device_id, AVG(value) AS avg_value FROM recent_data GROUP BY device_id ) SELECT device_id, avg_value FROM device_avg WHERE avg_value >= 80; ``` `device_avg` can reference the earlier `recent_data`. An earlier CTE cannot reference a later one; forward references are unsupported. ### Specify Result Column Names ```sql WITH device_stat (id, sample_count, average_value) AS ( SELECT device_id, COUNT(*), AVG(value) FROM sensor_data GROUP BY device_id ) SELECT id, sample_count, average_value FROM device_stat; ``` The explicit column count must match the CTE result count, and names must be unique. Without a list, SELECT aliases and inline-view column naming rules apply. ## Supported SQL Contexts ### Nested SELECT ```sql WITH active_devices AS ( SELECT device_id FROM sensor_data WHERE time >= NOW - 1m ) SELECT d.device_id, d.device_name FROM device_info d WHERE d.device_id IN ( SELECT device_id FROM active_devices ); ``` A CTE declared in an outer SELECT is visible in scalar subqueries, `IN (subquery)`, inline views, and other nested SELECTs. Existing restrictions on scalar subqueries and `IN (subquery)` in JOIN ON conditions still apply. ### INSERT SELECT ```sql INSERT INTO device_summary WITH hourly_summary AS ( SELECT device_id, COUNT(*) AS sample_count, AVG(value) AS avg_value FROM sensor_data WHERE time >= NOW - 1h GROUP BY device_id ) SELECT device_id, sample_count, avg_value FROM hourly_summary; ``` A CTE produces result rows; target-table `INSERT SELECT` rules determine allowed input and duplicate-key handling. CTEs do not change target constraints or atomicity scope. ### VIEW Definitions ```sql CREATE VIEW active_device_summary AS WITH recent_data AS ( SELECT device_id, value FROM sensor_data WHERE time >= NOW - 10m ) SELECT device_id, COUNT(*) AS sample_count, AVG(value) AS avg_value FROM recent_data GROUP BY device_id; ``` A VIEW stores the SELECT definition, including the CTE, and interprets it again when queried. The same syntax applies to `CREATE OR REPLACE VIEW`. VIEW definitions cannot use bind parameters (`?`). Put conditions that vary per execution in the SELECT querying the VIEW. ### EXPLAIN ```sql EXPLAIN FULL WITH recent_data AS ( SELECT name, time, value FROM sensor_data WHERE time >= NOW - 5m ) SELECT * FROM recent_data WHERE name = 'sensor-01'; ``` Use `EXPLAIN`, `EXPLAIN FULL`, or `EXPLAIN TRACE` to inspect scans, filters, and joins on actual tables after CTE expansion. ### Prepared statement Bind parameters (`?`) are allowed in CTE bodies and the main SELECT. ```sql WITH selected_data AS ( SELECT device_id, time, value FROM sensor_data WHERE device_id = ? ) SELECT device_id, time, value FROM selected_data WHERE value >= ?; ``` Parameters in unreferenced CTEs are still registered and require values. Referencing a CTE multiple times does not multiply its original parameter count. ## Names and Scope ### Declaration Order Later CTEs can reference earlier CTEs. Forward references, self-references, and mutual references are unsupported. ### Names Shared with Real Tables When an unqualified name matches both a CTE and a real TABLE or VIEW, the CTE in the current scope takes precedence. ```sql WITH device_info AS ( SELECT device_id FROM sensor_data ) SELECT * FROM device_info; ``` Qualify a real table with its owner, such as `user_name.device_info`. Owner-qualified names resolve to actual TABLEs or VIEWs, not CTEs. ### Nested Scope Inner SELECTs can reference outer CTEs. An inner CTE is not visible outside its SELECT. If its name matches an outer CTE, the inner one takes precedence. ## Execution and Performance Machbase plans CTE references by expanding them into existing inline-view forms. It does not guarantee materialization into temporary tables or single evaluation. Multiple references to one CTE may be planned and executed independently. ```sql WITH recent_data AS ( SELECT device_id, time, value FROM sensor_data WHERE time >= NOW - 1d ) SELECT a.device_id, a.value, b.value FROM recent_data a JOIN recent_data b ON a.device_id = b.device_id AND a.time = b.time; ``` Use these performance guidelines: - Avoid repeated references to CTEs that read large tables. - Apply selective time, tag-name, and key predicates as early as possible in CTE bodies. - Do not predict performance assuming filter pushdown or automatic result reuse. - For repeated references, consider separate queries or persisted objects. - Inspect the actual plan for each reference with `EXPLAIN`. Because `MATERIALIZED` and `NOT MATERIALIZED` are unsupported, users cannot force a CTE evaluation strategy. ### CTE Expansion Limit CTE expansion can generate at most 1,024 SELECT units per SQL statement. This is the total after expanding repeated and chained references, not the number of declared CTE names. Exceeding the limit raises this error: ```text CTE expansion limit exceeded ``` Reduce repeated-reference chains or separate intermediate results into another table or VIEW. ## Limitations The following are unsupported: - `WITH RECURSIVE` and recursive CTEs - Self-reference or mutual recursion even without `RECURSIVE` - Forward references - `MATERIALIZED`, `NOT MATERIALIZED` - Recursive syntax `SEARCH DEPTH FIRST`, `SEARCH BREADTH FIRST`, `CYCLE` - Leading `WITH ... INSERT`, `WITH ... UPDATE`, `WITH ... DELETE`, `WITH ... MERGE` - INSERT, UPDATE, DELETE, MERGE, or DDL inside a CTE - `UNION`, `INTERSECT`, `EXCEPT` - `UNION ALL` between literal SELECTs without FROM - `EXISTS` expressions - `FREQUENCY` inside a CTE - CTEs in custom `CREATE ROLLUP ... AS (...)` queries CTEs do not expand table-type DML support. Queries and inserts on LOG, TAG, LOOKUP, VOLATILE, and TRANSACTION follow their existing rules. ## Diagnose Errors | Condition | Check | |---|---| | Duplicate CTE name | Declare each name once per WITH clause. | | Column-count mismatch | Match explicit columns to SELECT result columns. | | Duplicate column name | Remove duplicates from the explicit list. | | Forward reference | Declare the referenced CTE first. | | Self-reference | Remove recursion or use fixed-depth SQL/application iteration. | | Table not found | Check whether a qualified name resolves to a real TABLE/VIEW instead of a CTE. | | Expansion limit exceeded | Reduce reference chains or separate intermediate objects. | | VIEW bind error | Remove `?` from VIEW/CTE definitions and apply predicates when querying. | | Syntax error | Check for unsupported recursion, materialization, or leading WITH/DML forms. | ## Migrate from Other DBMSs | Source feature | Machbase approach | |---|---| | PostgreSQL/MySQL `WITH RECURSIVE` | Use fixed-depth SQL or application iteration. | | PostgreSQL/SQLite `MATERIALIZED` | Remove the keyword; do not assume single evaluation. | | PostgreSQL/SQLite `NOT MATERIALIZED` | Remove the keyword and inspect EXPLAIN. | | Oracle recursive subquery factoring | Migrate only nonrecursive CTEs without self-reference. | | SQL Server `WITH ... UPDATE/DELETE/MERGE` | Separate CTE and DML; follow table-specific rules. | | Recursive `SEARCH` or `CYCLE` | Handle paths and cycle detection in applications or stored columns. | ## Related Documentation - [SELECT Syntax](../select-syntax/) - [DML Syntax](../dml-syntax/) - [VIEW Syntax](../view-syntax/) - [Set Operators](../set-operator-syntax/) - [PIVOT Syntax](../pivot-syntax/) - [Window Functions and OVER](../window-function-over-syntax/) - [Query Analysis and EXPLAIN](/dbms/performance-tuning/performance-query-tuning/) --- title: "Named Bind Parameter" url: https://docs.machbase.com/dbms/reference/sql/syntax/named-bind-parameter-syntax/ language: en kind: page --- # Named Bind Parameter Named Bind Parameters use :name markers in SQL value positions and bind values at execution. Names express the meaning of repeated parameters and keep the SQL/application mapping clear. ```sql SELECT ID, NAME FROM SENSOR_DATA WHERE ID = :id; ``` ## Name Syntax Named markers use the following form. ```text :[A-Za-z_$][A-Za-z0-9_$]* ``` | Category | Examples | |---|---| | Valid names | :id, :sensor_id, :value2, :_from_time, :select | | Invalid names | :1id, :, ::id | For SQL shared across SDKs, prefer names matching `[A-Za-z][A-Za-z0-9_]*`. Parameter names are case-sensitive: :VALUE, :value, and :VaLuE are different names. .NET MachParameterCollection performs case-insensitive lookup for compatibility with the existing provider. ## Allowed Positions Use named markers where a value or expression is allowed. ```sql SELECT ID, NAME, VALUE FROM SENSOR_DATA WHERE CREATED_AT >= :from_time AND CREATED_AT < :to_time AND VALUE >= :minimum_value ORDER BY CREATED_AT LIMIT :row_count OFFSET :start_row; ``` Parameters cannot replace identifiers or SQL structure such as the following. ```sql SELECT * FROM :table_name; -- Unsupported SELECT :column_name FROM SENSOR_DATA; -- Does not replace a column identifier SELECT * FROM SENSOR_DATA ORDER BY ID :direction; -- Unsupported ``` For dynamic identifiers, validate against an application allowlist before constructing SQL. Colons inside strings and SQL comments are not recognized as parameters. ```sql SELECT ':not_a_parameter' FROM SENSOR_DATA WHERE ID = :id /* :ignored */; ``` ## Parameter Occurrence Order Parameters are counted by occurrences in SQL, not unique names. In the following SQL, target appears twice, so there are two parameters. ```sql SELECT ID, NAME FROM SENSOR_DATA WHERE ID = :target OR PARENT_ID = :target; ``` - SQLNumParams() returns 2. - Ordinal APIs bind the first and second positions separately. - Name-based APIs apply one target value to both matching positions. - Parameter metadata contains a separate entry for each position. A statement supports at most 256 parameter occurrences. ## Relationship to Positional Markers Low-level ordinal APIs can bind ? and :name in SQL occurrence order. Name-, object-, or mapping-based APIs reject mixed anonymous ? and named markers. Use one marker style per SQL statement. | Method | SQL marker | Binding | |---|---|---| | Positional | ? | 1-based ordinal in SQL occurrence order | | Named SQL with ordinal API | :name | 1-based ordinal in SQL occurrence order | | Named API | :name | Parameter name | ## DML Examples Named Bind Parameters use the existing prepared-statement type rules. ```sql INSERT INTO SENSOR_DATA (ID, PARENT_ID, NAME, VALUE, CREATED_AT) VALUES (:id, :parent_id, :name, :value, :created_at); ``` Named Bind Parameters do not change table-specific DML policies or Edition restrictions. For supported DML and predicates, see [DML Syntax](../dml-syntax/) and [Support Scope and Constraints](../../../support-scope-constraints/). Standard and Cluster Editions use the same :name syntax and ordinal rules. Executable SQL and table types remain subject to each Edition's existing support scope. ### TAG Data UPDATE Since Machbase 8.7.0, Standard Edition TAG data UPDATE supports named markers for NAME and BASETIME predicate values in WHERE. ```sql UPDATE sensor_tag SET value = :value, status = :status, note = :note WHERE name = :name AND time = :time; ``` Reexecuting the same prepared statement can bind new SET, NAME, and TIME values. No matching row succeeds with 0 affected rows. Tag selection and BASETIME predicates remain required regardless of binding, and SET column restrictions still apply. For supported predicate forms and parameter metadata, see [TAG Data UPDATE](../dml-syntax/tag-data-update-syntax/#tag-data-update-predicate-bind). ## Use in CTEs Standard Edition permits named parameters in CTE bodies and the main SELECT. ```sql WITH FILTERED AS ( SELECT ID, NAME, VALUE FROM SENSOR_DATA WHERE ID > :minimum_id AND NAME = :label ) SELECT ID, NAME, VALUE FROM FILTERED WHERE ID = :target_id ORDER BY ID; ``` Parameter ordinals above are minimum_id, label, and target_id in that order. For CTE scope and Standard Edition restrictions, see [WITH / CTE Syntax](../cte-syntax/). ## NULL and Data Types Pass NULL using the SDK's standard NULL value or indicator. | SDK | NULL value | |---|---| | Machbase SQLCLI | SQL_NULL_DATA indicator | | ODBC | SQL_NULL_DATA indicator | | JDBC | null | | Node.js/TypeScript | null | | Python | None | | .NET | DBNull.Value | Binding NULL to column = :value does not make it equivalent to column IS NULL. Use IS NULL according to SQL NULL comparison rules. Existing prepared-statement types such as INTEGER, VARCHAR, DOUBLE, DECIMAL, NUMERIC, and DATETIME are supported. Use an SDK decimal type or string representation to preserve DECIMAL/NUMERIC precision. ## Binding by SDK | SDK or tool | Name-based usage | |---|---| | Machbase SQLCLI | SQLBindParameterByName(), SQLBindParameterByNameW() | | ODBC | Bind :name SQL through SQLBindParameter() ordinals | | JDBC | MachPreparedStatement.setObject(String name, Object value) | | Node.js/TypeScript | Arrays for positional input; objects for named input | | Python DB-API | Pass a mapping; the 2.4 prepared cursor reuses :name and %(name)s across calls | | .NET | MachCommand.Parameters.AddWithValue(":name", value) | | Go native | api.Named("name", value) | | Go database/sql | sql.Named("name", value) | | machsql | :name in SQL; values assigned in $1, $2 order | For API details and error handling, see [Development Integration](../../../../development-tools-integration/) and [machsql Commands and Options](../../../command-line-tools/machsql/). ## Compatibility and Errors Machbase 8.7.0 name-based SDK APIs require both a client and server supporting the feature. Use ? with ordinal APIs for older-version compatibility. | Situation | Typical error | |---|---| | Required name missing | missing parameter | | Name absent from SQL supplied | unknown or extra parameter | | Named and positional styles mixed | sequence or mixed error | | Value type incompatible with SQL type | type or conversion error | | Name-based API used against an older server | unsupported | In production, prioritize SQLSTATE, error codes, and exception types over message text. For version combinations and SDK error codes, see [Client/Server Protocol Compatibility](../../../support-scope-constraints/compatibility-xma-protocol/). --- title: "SELECT hint" url: https://docs.machbase.com/dbms/reference/sql/syntax/select-hint-syntax/ language: en kind: section --- # SELECT hint SELECT hints use /*+ ... */ comment blocks to control optimizer behavior or specify processing such as sampling. ## Hint Syntax ```sql SELECT /*+ hint_clause */ ... SELECT /*+ hint1 hint2 */ ... ``` Place hints in a /*+ ... */ block immediately after SELECT. ## Main Hints ### Execution Plan Hints | Hint | Syntax | Description | |------|------|------| | `PARALLEL` | `/*+ PARALLEL(table, n) */` | Set parallelism factor | | `NOPARALLEL` | `/*+ NOPARALLEL(table) */` | Disable parallel processing | | `FULL` | `/*+ FULL(table) */` | Force a full scan instead of an index scan | | `NO_INDEX` | `/*+ NO_INDEX(table, index) */` | Disable a specific index | | `ROLLUP_TABLE` | `/*+ ROLLUP_TABLE(rollup_table) */` | Force a specific ROLLUP table | | `RID_RANGE` | `/*+ RID_RANGE(table, start, end) */` | Specify an RID range | | `SCAN_FORWARD` | `/*+ SCAN_FORWARD(table) */` | Scan oldest records first (LOG tables) | | `SCAN_BACKWARD` | `/*+ SCAN_BACKWARD(table) */` | Scan newest records first (LOG tables) | ### Data Processing Hints | Hint | Syntax | Description | |------|------|------| | `SAMPLING` | `/*+ SAMPLING(SamplingRate) */` | Sample using a floating-point rate | ## Examples ```sql -- Parallel processing with 8 threads SELECT /*+ PARALLEL(sensor_log, 8) */ sensor, AVG(value) FROM sensor_log WHERE ts BETWEEN TO_DATE('2024-01-01', 'YYYY-MM-DD') AND TO_DATE('2024-01-31', 'YYYY-MM-DD') GROUP BY sensor; -- Disable a specific index SELECT /*+ NO_INDEX(sensor_log, idx_ts) */ * FROM sensor_log WHERE ts > TO_DATE('2024-01-01', 'YYYY-MM-DD'); -- Force a ROLLUP table SELECT /*+ ROLLUP_TABLE(_rollup_tag_value_min) */ name, rollup('min', 5, time) AS t, AVG(value) FROM tag WHERE name = 'TEMP-01' GROUP BY name, t; -- Sample 1% from a range capped at 100,000 matching rows SELECT /*+ SAMPLING(0.01) */ t_name, time, value FROM tag WHERE t_name = 'TAG_99' LIMIT 100000; ``` ## Subsections - [SAMPLING Hint](./sampling-hint/) — Rate-based sampling details ## Related Documentation - [Query Performance Tuning](/dbms/performance-tuning/performance-query-tuning/) — Execution plans and hint selection --- title: "SAMPLING hint" url: https://docs.machbase.com/dbms/reference/sql/syntax/select-hint-syntax/sampling-hint/ language: en kind: page --- # SAMPLING hint The SAMPLING hint extracts data at a specified rate. SamplingRate is a floating-point value; 1 means 100% of the data. ## Syntax ```sql SELECT /*+ SAMPLING(SamplingRate) */ col1, col2, ... FROM table_name WHERE ...; ``` | Parameter | Description | |----------|------| | `SamplingRate` | Floating-point sampling fraction | Multiply SamplingRate by 100 to express it as a percentage. | SamplingRate | Sampling Percentage | |--------------|-----------| | `1` | 100% (all data) | | `0.01` | 1% | | `0.0001` | 0.01% | | `0.00001` | 0.001% | ## Examples ```sql -- Sample 1% from a range capped at 100,000 matching rows SELECT /*+ SAMPLING(0.01) */ t_name, time, value FROM tag WHERE t_name = 'TAG_99' LIMIT 100000; ``` ## Notes - SamplingRate is a sampling fraction, not a time interval or result row count. - Row counts may vary per execution; an exact count corresponding to the rate is not guaranteed. - Small datasets or low rates may return zero rows. - With LIMIT as above, sampling applies within the row range capped by LIMIT. For example, SAMPLING(0.5) with LIMIT 1000 samples about 50% of up to 1,000 rows when enough matching data exists. It does not fill the sampled result to 1,000 rows. ## Related Documentation - [SELECT Hint Syntax](../) — Complete hint list - [ROLLUP Syntax](../../rollup-syntax/) — Exact time-unit aggregation --- title: "SEARCH / ESEARCH / REGEXP" url: https://docs.machbase.com/dbms/reference/sql/syntax/search-esearch-regexp-syntax/ language: en kind: page --- # SEARCH / ESEARCH / REGEXP Search operators inspect different targets despite similar syntax. SEARCH and ESEARCH use KEYWORD index tokens; LIKE and REGEXP evaluate the original text. Before changing operators for performance, verify equivalent result semantics. ## SEARCH ```text column_name SEARCH 'search_term' column_name NOT SEARCH 'search_term' ``` LOG VARCHAR/TEXT columns require a KEYWORD index. Multiple words use AND semantics; this is not phrase search guaranteeing word order or adjacency. In default mode, ordinary ASCII words are normalized to lowercase and Korean text uses 2-grams. This does not guarantee morphological analysis or Unicode case handling for every language. The following standalone exercise table is used throughout this page. ```sql CREATE LOG TABLE ch7_ref_search ( event_id INTEGER, message VARCHAR(200), detail VARCHAR(200) ); CREATE INDEX ch7_ref_msg ON ch7_ref_search(message) INDEX_TYPE KEYWORD; CREATE INDEX ch7_ref_detail ON ch7_ref_search(detail) INDEX_TYPE KEYWORD; INSERT INTO ch7_ref_search VALUES (1, 'ERROR timeout occurred', 'connection reset'); INSERT INTO ch7_ref_search VALUES (2, 'pretimeout normal', 'port 8080'); INSERT INTO ch7_ref_search VALUES (3, NULL, NULL); EXEC TABLE_FLUSH(ch7_ref_search); EXEC INDEX_FLUSH(ch7_ref_search); SELECT event_id FROM ch7_ref_search WHERE message SEARCH 'timeout' ORDER BY event_id; SELECT event_id FROM ch7_ref_search WHERE message SEARCH 'error' AND detail SEARCH 'reset' ORDER BY event_id; SELECT event_id FROM ch7_ref_search WHERE message NOT SEARCH 'timeout' ORDER BY event_id; ``` The first two queries select row 1; the last selects row 2. NOT SEARCH excludes row 3, whose message is NULL. For searches across columns, create the required index on each target column. ## ESEARCH ```text column_name ESEARCH 'pattern%' column_name ESEARCH '%pattern%' ``` Applies patterns to indexed words. pattern% matches a word prefix; %pattern% matches a substring within a word. Do not interpret % as freely crossing word boundaries in the original text. The following examples use ASCII keyword patterns. ```sql SELECT event_id FROM ch7_ref_search WHERE message ESEARCH 'time%' ORDER BY event_id; SELECT event_id FROM ch7_ref_search WHERE message ESEARCH '%time%' ORDER BY event_id; ``` Results are row 1 and rows 1/2, respectively. Current ESEARCH ASCII pattern comparison is case-insensitive. It does not fully replace original-text LIKE; cost depends on the tokens and rows matching the pattern. NOT ESEARCH is unsupported. Replacing it with NOT SEARCH or NOT LIKE can change excluded rows; check results and NULL handling. ## Comparison with LIKE ```sql SELECT event_id FROM ch7_ref_search WHERE message LIKE '%TIMEOUT%' ORDER BY event_id; SELECT event_id FROM ch7_ref_search WHERE message NOT LIKE '%timeout%' ORDER BY event_id; ``` The first query returns rows 1/2; the second returns zero rows. NOT LIKE also excludes NULL rows. LIKE currently uses case-insensitive ASCII comparison. % represents zero or more characters; _ represents one. LIKE itself does not use KEYWORD indexes. This does not necessarily mean a full table scan. Time predicates or other index predicates may restrict target rows first. ## REGEXP ```text column_name REGEXP 'pattern' column_name NOT REGEXP 'pattern' ``` Tests for a substring matching the regular expression. Matching is case-sensitive by default. Use ^ and $ to anchor the start and end. ```sql SELECT event_id FROM ch7_ref_search WHERE message REGEXP '^ERROR.*timeout' ORDER BY event_id; SELECT event_id FROM ch7_ref_search WHERE message NOT REGEXP 'timeout' ORDER BY event_id; ``` The first query returns row 1; the second returns zero rows. REGEXP does not directly use KEYWORD indexes. Before using SEARCH to narrow candidates, verify that it does not omit required results. ### REGEXP as an Expression REGEXP results can also be used in scalar expressions. ```sql SELECT 'abcde' REGEXP 'a[bcd]{1,10}e' FROM dual; ``` The result is 1. The REGEXP_LIKE function also accepts matching options. Current function input must be VARCHAR; pattern and options must be constant VARCHAR. Do not assume its input constraints are identical to the REGEXP operator, which accepts TEXT columns. ```sql SELECT event_id, REGEXP_LIKE(message, 'error') AS case_sensitive, REGEXP_LIKE(message, 'error', 'i') AS case_insensitive FROM ch7_ref_search WHERE event_id IN (1, 3) ORDER BY event_id; ``` Row 1 returns 0/1; row 3 returns NULL/NULL. i is case-insensitive and c is case-sensitive; omitting the option uses case-sensitive matching. ## Performance Guidelines | Goal | Selection | |---|---| | Test for a word | SEARCH | | Prefix/substring patterns within indexed words | ESEARCH | | Substring patterns in original text | LIKE | | Original-text format, position, or complex patterns | REGEXP/REGEXP_LIKE | Distinguish index existence from completed index building. Compare on the same data and time range. Drop the exercise table when finished. ```sql DROP TABLE ch7_ref_search; ``` ## Related Documentation - [Text Search Exercise](/dbms/log-table-usage/text-search-keyword-index/) — Multiple words, Korean text, NULLs, and TEXT constraints - [INDEX Syntax](../index-syntax/) — KEYWORD index creation --- title: "set operator" url: https://docs.machbase.com/dbms/reference/sql/syntax/set-operator-syntax/ language: en kind: page --- # set operator Set operators combine results from two or more SELECT queries or calculate intersections/differences. > Machbase currently supports only UNION ALL. UNION (duplicate removal), > INTERSECT, and EXCEPT are not supported. ## UNION ALL Combines two query results without removing duplicates. ```sql select_stmt UNION ALL select_stmt ``` ```sql SELECT i1, i2 FROM table_1 UNION ALL SELECT c1, c2 FROM table_2; ``` ## Requirements Both SELECT statements must satisfy the following. 1. **Same column count**. 2. **Matching or compatible column types**. A violation returns an error. ### Type Compatibility | Combination | Compatible | Result Type | |------|-----------|-----------| | Signed ↔ unsigned integer | X | Error | | Integer ↔ floating-point | O | Floating-point | | Character types of different lengths | O | Accepted | | IPv6 ↔ IPv4 | X | Error | - Result column names come from the left query. ## Examples ```sql -- Combine data from two tables SELECT id, name FROM active_devices UNION ALL SELECT id, name FROM inactive_devices; -- Combine statistics from different periods SELECT 'Q1' AS quarter, SUM(value) AS total FROM sales WHERE month BETWEEN 1 AND 3 UNION ALL SELECT 'Q2' AS quarter, SUM(value) AS total FROM sales WHERE month BETWEEN 4 AND 6; -- Combine three queries SELECT name, time, value FROM sensor_a WHERE time > TO_DATE('2024-01-01', 'YYYY-MM-DD') UNION ALL SELECT name, time, value FROM sensor_b WHERE time > TO_DATE('2024-01-01', 'YYYY-MM-DD') UNION ALL SELECT name, time, value FROM sensor_c WHERE time > TO_DATE('2024-01-01', 'YYYY-MM-DD'); ``` ## Notes - UNION ALL retains duplicates. To remove them, wrap the result in a subquery and apply DISTINCT or GROUP BY. - UNION ALL between literal SELECT statements without FROM is unsupported. - Result order is not guaranteed. For sorting, wrap the entire operation in an inline view and apply ORDER BY outside it. ```sql -- When sorting is required SELECT * FROM ( SELECT id, name, time FROM log_a UNION ALL SELECT id, name, time FROM log_b ) ORDER BY time DESC; ``` ## Related Documentation - [SELECT Syntax](../select-syntax/) — Basic SELECT syntax - [WITH / CTE Syntax](../cte-syntax/) — UNION ALL in CTEs - [VIEW Syntax](../view-syntax/) — Views containing UNION ALL --- title: "PIVOT" url: https://docs.machbase.com/dbms/reference/sql/syntax/pivot-syntax/ language: en kind: page --- # PIVOT PIVOT converts row-oriented data into columns. Use it to rearrange GROUP BY aggregate results into readable reports. > PIVOT is supported from Machbase 5.6. ## Syntax ```sql SELECT * FROM (inline_view) PIVOT (aggregate_function(value_col) FOR category_col IN ('val1', 'val2', ...)) [WHERE ...] ``` - Groups columns in inline_view that are not referenced by PIVOT. - FOR category_col IN (...) specifies the pivot column and values to turn into output columns. - Result column names are the string values in IN. ## Examples ### Pivoting Sensor Aggregates into Columns ```sql -- PIVOT with an inline view SELECT * FROM ( SELECT regtime, tagid, dvalue FROM result_d WHERE regtime BETWEEN TO_DATE('2024-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2024-01-02 00:00:00', 'YYYY-MM-DD HH24:MI:SS') ) PIVOT ( SUM(dvalue) FOR tagid IN ('FRONT_AXIS_TORQUE', 'REAR_AXIS_TORQUE', 'HOIST_AXIS_TORQUE', 'SLIDE_AXIS_TORQUE') ) WHERE FRONT_AXIS_TORQUE >= 40 AND REAR_AXIS_TORQUE >= 20; ``` ### Concise Alternative to CASE ```sql -- CASE without PIVOT SELECT regtime, SUM(CASE WHEN tagid = 'SENSOR_A' THEN dvalue ELSE 0 END) AS sensor_a, SUM(CASE WHEN tagid = 'SENSOR_B' THEN dvalue ELSE 0 END) AS sensor_b FROM result_d GROUP BY regtime; -- Concise PIVOT form SELECT * FROM ( SELECT regtime, tagid, dvalue FROM result_d ) PIVOT (SUM(dvalue) FOR tagid IN ('SENSOR_A', 'SENSOR_B')); ``` ### PIVOT with TAG Tables ```sql SELECT * FROM ( SELECT name, time, value FROM sensor_tag WHERE time BETWEEN TO_DATE('2024-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2024-01-01 01:00:00', 'YYYY-MM-DD HH24:MI:SS') ) PIVOT ( AVG(value) FOR name IN ('sensor-01', 'sensor-02', 'sensor-03') ); ``` ## Constraints - PIVOT requires an inline view (subquery). - All inline-view columns except value_col and category_col are automatically grouped. - IN values must be literals known at compile time; dynamic column lists are unsupported. ## Related Documentation - [SELECT Hint Syntax](../select-hint-syntax/) — Syntax and examples for SELECT hints --- title: "window function / OVER" url: https://docs.machbase.com/dbms/reference/sql/syntax/window-function-over-syntax/ language: en kind: page --- # window function / OVER Machbase `LAG()` and `LEAD()` reference earlier or later row values in query results. For example, compare sensor measurements in time order to calculate changes from the previous reading. Unlike GROUP BY aggregates, they do not collapse multiple rows into one. ## Syntax ```sql LAG(value_expression, offset) OVER ( [PARTITION BY partition_expression] [ORDER BY order_expression] ) LEAD(value_expression, offset) OVER ( [PARTITION BY partition_expression] [ORDER BY order_expression] ) ``` | Element | Description | |------|------| | `value_expression` | Value from an earlier or later row | | `offset` | Row distance from the current row; integer at least 1 | | `PARTITION BY` | One expression grouping rows; omitted means one group for all results | | `ORDER BY` | One expression ordering comparisons within each group | OVER is required, but PARTITION BY and ORDER BY inside it are optional. Specify an order such as `ORDER BY time` for chronological comparisons. That expression alone does not order ties. To guarantee final output order, also put ORDER BY at the end of SELECT. ## Supported Window Functions | Function | Description | |------|------| | `LAG(value, n)` | Value n rows before the current row in the same group | | `LEAD(value, n)` | Value n rows after the current row in the same group | Returns NULL if the referenced row does not exist. `offset` counts rows, not elapsed time. With irregular samples, the previous row is not necessarily one second or one minute earlier. ### Differences from Other DBMS Window Syntax Do not confuse the following syntax with Machbase LAG/LEAD: - `ROW_NUMBER()`, `RANK()`, `DENSE_RANK()`, `FIRST_VALUE()`, and `LAST_VALUE()` are unsupported. - Aggregate windows such as `SUM(...) OVER (...)` and `AVG(...) OVER (...)` are unsupported. - ROWS/RANGE frames and boundaries such as UNBOUNDED PRECEDING and CURRENT ROW are unsupported. - PARTITION BY and ORDER BY within OVER each accept only one expression. ASC/DESC after ORDER BY is also unsupported. See [Window/Series Functions](../../functions/series/) for `ROWNUM()`, which numbers result rows, and `SERIESNUM()`, which numbers consecutive groups. ## Examples ### LAG / LEAD: Compare Previous and Next Values This example uses `sensor_tag` with `name`, `time`, and `value` columns. ```sql SELECT name, time, value, LAG(value, 1) OVER (PARTITION BY name ORDER BY time) AS prev_value, LEAD(value, 1) OVER (PARTITION BY name ORDER BY time) AS next_value, value - LAG(value, 1) OVER (PARTITION BY name ORDER BY time) AS delta FROM sensor_tag WHERE name = 'TEMP-01' AND time >= TO_DATE('2024-01-01', 'YYYY-MM-DD') ORDER BY name, time; ``` `prev_value` and `next_value` are previous/next values within the query range. The first prev_value and last next_value are NULL. Rows excluded by WHERE are not comparison candidates; extend the range earlier if you need the first row's change as well. ### Compare Previous Aggregate Values Aggregate tag time intervals first, then compare aggregate changes. This example assumes `sensor_tag` has an hourly ROLLUP available. ```sql SELECT name, bucket, avg_val, LAG(avg_val, 1) OVER (PARTITION BY name ORDER BY bucket) AS prev_avg FROM ( SELECT name, rollup('hour', 1, time) AS bucket, AVG(value) AS avg_val FROM sensor_tag WHERE time BETWEEN TO_DATE('2024-01-01', 'YYYY-MM-DD') AND TO_DATE('2024-07-01', 'YYYY-MM-DD') GROUP BY name, bucket ) t ORDER BY name, bucket; ``` This compares each interval average to the preceding interval average. It does not calculate a moving average or cumulative total. Empty intervals are not filled automatically. ## Performance Considerations Window calculations require grouping, sorting, and retaining previous/next values. Reduce target rows with time/tag predicates. For long-term trends, apply comparisons to aggregates to process fewer rows. Use LAG/LEAD in SELECT result expressions. Do not call them directly in WHERE, HAVING, GROUP BY, ORDER BY, or JOIN ON. To filter computed values, reference inline-view result columns from an outer SELECT. ## Related Documentation - [Window/Series Functions](../../functions/series/) — `ROWNUM()` and `SERIESNUM()` - [PIVOT Syntax](../pivot-syntax/) — Convert rows to columns - [SERIES BY Syntax](../series-syntax/) — Extract consecutive groups --- title: "SERIES BY" url: https://docs.machbase.com/dbms/reference/sql/syntax/series-syntax/ language: en kind: page --- # SERIES BY SERIES BY extracts contiguous sequences of rows satisfying a condition from an ordered result set. Use it to analyze interval start/end times and patterns. ## Syntax ```sql SELECT ... FROM table_name [WHERE ...] ORDER BY col [ASC | DESC] SERIES BY condition_expr ``` - Without ORDER BY, rows are ordered by _ARRIVAL_TIME. - Explicit ORDER BY is required with GROUP BY or on VOLATILE/LOOKUP tables without _ARRIVAL_TIME. - Rows in one contiguous interval satisfying SERIES BY share the same SERIESNUM() value. ## Examples ### Basic Usage ```sql CREATE LOG TABLE t1 (c1 INTEGER, c2 INTEGER); INSERT INTO t1 VALUES (0, 1); INSERT INTO t1 VALUES (1, 2); INSERT INTO t1 VALUES (2, 3); INSERT INTO t1 VALUES (3, 2); INSERT INTO t1 VALUES (4, 1); INSERT INTO t1 VALUES (5, 2); INSERT INTO t1 VALUES (6, 3); INSERT INTO t1 VALUES (7, 1); SELECT c1, c2 FROM t1 ORDER BY c1 SERIES BY c2 > 1; ``` Result: ``` C1 C2 --------------------------- 1 2 2 3 3 2 5 2 6 3 ``` ### Identifying Intervals with SERIESNUM() ```sql SELECT c1, c2, SERIESNUM() AS grp FROM t1 ORDER BY c1 SERIES BY c2 > 1; ``` Result: ``` C1 C2 GRP ----------------------------------- 1 2 1 2 3 1 3 2 1 5 2 2 6 3 2 ``` ### Contiguous Intervals in TAG Tables Generate interval numbers in an inner query, then aggregate by interval number in the outer query. ```sql -- Start/end timestamps and maximum for each contiguous interval above 100 SELECT MIN(time) AS start_time, MAX(time) AS end_time, MAX(value) AS peak_value, series_id FROM ( SELECT time, value, SERIESNUM() AS series_id FROM tag WHERE name = 'PRESSURE-01' AND time >= TO_DATE('2024-01-01', 'YYYY-MM-DD') ORDER BY time SERIES BY value > 100.0 ) GROUP BY series_id ORDER BY series_id; ``` ## Related Documentation - [SELECT Hint Syntax](../select-hint-syntax/) — Syntax and examples for SELECT hints - [Window Function / OVER Syntax](../window-function-over-syntax/) — Comparison with window-based analysis --- title: "SAVE DATA INTO" url: https://docs.machbase.com/dbms/reference/sql/syntax/save-data-into-syntax/ language: en kind: page --- # SAVE DATA INTO SAVE DATA INTO saves SELECT query results to CSV. ## Syntax ```sql SAVE DATA INTO 'file_path' [HEADER { ON | OFF }] [{ FIELDS | COLUMNS } [TERMINATED BY 'char'] [ENCLOSED BY 'char'] ] [ENCODED BY coding_name] AS select_query ``` ## Options | Option | Default | Description | |------|--------|------| | `HEADER { ON \| OFF }` | OFF | Whether to write column names in the first row | | `TERMINATED BY 'char'` | `,` | Field delimiter | | `ENCLOSED BY 'char'` | `"` | Field quoting character | | `ENCODED BY coding_name` | UTF8 | Output encoding | Supported encodings: UTF8, MS949, KSC5601, EUCJP, SHIFTJIS, BIG5, GB231280 ## Examples ```sql -- Basic CSV output SAVE DATA INTO '/tmp/result.csv' AS SELECT * FROM sensor_log; -- Include a header and use a semicolon delimiter SAVE DATA INTO '/tmp/output.csv' HEADER ON FIELDS TERMINATED BY ';' AS SELECT name, time, value FROM sensor_log WHERE time > TO_DATE('2024-01-01', 'YYYY-MM-DD'); -- Specify delimiter and quoting characters SAVE DATA INTO '/tmp/export.csv' HEADER ON FIELDS TERMINATED BY ';' ENCLOSED BY '\'' ENCODED BY MS949 AS SELECT * FROM t1 WHERE i1 > 100; -- Export TAG table data SAVE DATA INTO '/tmp/tag_export.csv' HEADER ON AS SELECT name, time, value FROM sensor_tag WHERE name = 'TEMP-01' AND time BETWEEN TO_DATE('2024-01-01', 'YYYY-MM-DD') AND TO_DATE('2024-01-02', 'YYYY-MM-DD') ORDER BY time; ``` ## Notes - The Machbase server process must be able to write to the path. - If the output file already exists, an error is returned and the existing file remains unchanged. Use another filename or move the existing file before retrying. - Empty SELECT results may produce an empty file or a header-only file. - Lack of permission to access the path returns an error. ## Related Documentation - [LOAD DATA INFILE Syntax](../load-data-infile-syntax/) — Load data from files into tables --- title: "DDL" url: https://docs.machbase.com/dbms/reference/sql/syntax/ddl-syntax/ language: en kind: page --- # DDL Data Definition Language (DDL) creates, modifies, and drops database objects such as tables, indexes, views, and ROLLUPs. > **Privileges**: Ordinary users need `GRANT DDL ON DATABASE database_name TO user_name;` or `GRANT CREATE ON DATABASE database_name TO user_name;` to execute DDL in an active database. See [GRANT/REVOKE](../user-auth-syntax/#grant-revoke). ## CREATE TABLE ```sql create_table_stmt ::= 'CREATE' table_type? 'TABLE' ['IF NOT EXISTS'] table_name '(' column_def ( ',' column_def )* ')' [ 'METADATA' '(' column_def ( ',' column_def )* ')' ] [ table_property_list ] [ 'TABLESPACE' tablespace_name ] [ 'WITH ROLLUP' rollup_interval_spec ] table_type ::= 'LOG' | 'TAG' | 'VOLATILE' | 'LOOKUP' | 'TRANSACTION' | 'TXN' -- Omitting table_type creates a TRANSACTION table. column_def ::= column_name column_type [ 'PRIMARY KEY' ] [ 'NOT NULL' ] [ column_axis ] [ 'SUMMARIZED' ] [ 'DEFAULT' value ] [ 'PROPERTY' '(' column_property_list ')' ] decimal_type ::= ( 'DECIMAL' | 'NUMERIC' | 'DEC' | 'FIXED' | 'NUMBER' ) [ '(' precision [ ',' scale ] ')' ] array_type ::= ( 'SHORT' | 'INT16' | 'USHORT' | 'UINT16' | 'INTEGER' | 'INT' | 'INT32' | 'UINTEGER' | 'UINT32' | 'LONG' | 'INT64' | 'ULONG' | 'UINT64' | 'FLOAT' | 'DOUBLE' | decimal_type ) '[' cardinality ']' column_axis ::= 'BASETIME' | 'BASE TIME' | 'BASE DISTANCE' | 'BASEDISTANCE' column_property_list ::= ( 'MINMAX_CACHE_SIZE' '=' number | 'PART_PAGE_COUNT' '=' number | 'PAGE_VALUE_COUNT' '=' number | 'MAX_CACHE_PART_COUNT' '=' number | 'SEQUENCE' '=' number ) ( ',' column_property_list )* table_property_list ::= ( 'TAG_PARTITION_COUNT' '=' number | 'TAG_DATA_PART_SIZE' '=' number | 'TAG_STAT_ENABLE' '=' ( '0' | '1' ) | 'TAG_DUPLICATE_CHECK_DURATION' '=' number | 'VARCHAR_FIXED_LENGTH_MAX' '=' number ) ( ',' table_property_list )* ``` ### Table Types | Keyword | Description | |--------|------| | (omitted) | **TRANSACTION** — Relational data and transactions | | `LOG` | **LOG** — Time-series logs; append-oriented, no general UPDATE | | `TAG` | **TAG** — Name/time/value time series; BASETIME required | | `LOOKUP` | **LOOKUP** — Memory-resident; PRIMARY KEY required; full DML support | | `VOLATILE` | **VOLATILE** — Memory-resident; data lost on restart; optional PRIMARY KEY | | `TRANSACTION`, `TXN` | **TRANSACTION** — Full and abbreviated names create the same type | CREATE TABLE without a type, CREATE TRANSACTION TABLE, and CREATE TXN TABLE all create TRANSACTION tables. Use CREATE LOG TABLE for LOG. Previous public names RDB and TRX are unsupported as table-type aliases. TRANSACTION is Standard Edition only; Cluster rejects all three creation forms. DECIMAL is available for every table type. Precision is 1–65, scale is 0–30, and scale cannot exceed precision. See [DECIMAL and NUMERIC Fixed-Point Types](/dbms/reference/sql/types/decimal-numeric-fixed-point/). Machbase DBMS 8.7.0 ARRAY specifies a cardinality from 1..1024 after a numeric element type. For supported types and table-specific restrictions, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/). ### Examples ```sql -- Create a LOG table with the explicit LOG keyword. CREATE LOG TABLE sensor_log ( id INTEGER, name VARCHAR(64), value DOUBLE, status VARCHAR(20) ); -- Create a TAG table: BASETIME required; SUMMARIZED marks the ROLLUP column. CREATE TAG TABLE tag ( name VARCHAR(40) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ); -- TAG table with metadata and properties CREATE TAG TABLE sensors ( name VARCHAR(40) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ) METADATA ( location VARCHAR(100), unit VARCHAR(20) ) TAG_PARTITION_COUNT = 4; -- LOOKUP table (PRIMARY KEY required) CREATE LOOKUP TABLE devices ( device_id VARCHAR(40) PRIMARY KEY, ip IPV4, status VARCHAR(20) ); -- VOLATILE table CREATE VOLATILE TABLE cache_data ( id INTEGER PRIMARY KEY, value DOUBLE ); -- Exact fixed-point columns in a TRANSACTION table CREATE TRANSACTION TABLE invoice ( id LONG PRIMARY KEY, amount DECIMAL(18,2), tax NUMERIC(18,4) ); -- Use IF NOT EXISTS CREATE TAG TABLE IF NOT EXISTS tag ( name VARCHAR(40) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ); -- NOT NULL constraint CREATE TABLE t1 ( c1 INTEGER NOT NULL, c2 VARCHAR(200) ); ``` ### Predefined System Columns The following system columns are provided. | Column | Type | Description | |------|------|------| | `_ARRIVAL_TIME` | DATETIME | LOG only; row insertion time and basis for DURATION queries | | `_RID` | LONG | LOG and internal TAG data tables; unique row identifier that users cannot assign directly | --- ## DROP TABLE ```sql drop_table_stmt ::= 'DROP TABLE' table_name ``` Drops the specified table and all its data and indexes. Returns an error if another session is querying the table. ```sql DROP TABLE sensor_log; ``` --- ## ALTER TABLE ALTER TABLE changes a table schema. Available subclauses depend on table type. TRANSACTION supports ADD COLUMN, DROP COLUMN, RENAME COLUMN, and RENAME TO. Use METADATA ADD COLUMN and METADATA DROP COLUMN for TAG metadata columns. ### ADD COLUMN ```sql alter_table_add_stmt ::= 'ALTER TABLE' table_name [ 'METADATA' ] 'ADD COLUMN' '(' column_name column_type [ 'DEFAULT' value ] ')' ``` ```sql -- Add a column ALTER TABLE sensor_log ADD COLUMN (quality FLOAT); -- Add a TRANSACTION column ALTER TABLE product_master ADD COLUMN (stock_qty INTEGER DEFAULT 0); -- Add columns with defaults ALTER TABLE sensor_log ADD COLUMN (flag INTEGER DEFAULT 0); ALTER TABLE sensor_log ADD COLUMN (tag_ip IPV4 DEFAULT '192.168.0.1'); -- Add an ARRAY column with DEFAULT ALTER TABLE sensor_log ADD COLUMN (channels INT32[3] DEFAULT [1, NULL, 3]); -- Add a TAG METADATA ARRAY column ALTER TABLE sensor_tag METADATA ADD COLUMN (limits DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]); ``` Omitting scale in DECIMAL(p)[n] ARRAY means scale 0. ARRAY DEFAULT must contain exactly the declared number of elements. Invalid element types, cardinality, precision, scale, nested/multidimensional declarations, or a DEFAULT of the wrong length fail the entire statement without partially creating columns. #### ARRAY ADD COLUMN Support | Edition | Table or column area | Supported | Explicit DEFAULT for existing rows | |---|---|:---:|---| | Standard | LOG | Yes | Applied | | Standard | VOLATILE | Yes | Not applied; whole-array NULL retained | | Standard | LOOKUP | Yes | Applied | | Standard | TRANSACTION | Yes | Applied | | Standard | TAG METADATA | Yes | Applied | | Standard | Ordinary TAG DATA columns | No | - | | Cluster | LOG | Yes | Applied | | Cluster | Other tables or TAG METADATA | No | - | Without DEFAULT, the new ARRAY column is a whole-array NULL in pre-ALTER rows for every supported table. Ordinary TAG DATA ARRAY columns can be declared in CREATE TABLE but cannot be added with ALTER. For types and NULL semantics, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/). ### DROP COLUMN ```sql alter_table_drop_stmt ::= 'ALTER TABLE' table_name [ 'METADATA' ] 'DROP COLUMN' '(' column_name ')' ``` ```sql ALTER TABLE sensor_log DROP COLUMN (quality); ALTER TABLE product_master DROP COLUMN (stock_qty); ALTER TABLE sensor_log DROP COLUMN (channels); ALTER TABLE sensor_tag METADATA DROP COLUMN (limits); ``` ### RENAME COLUMN ```sql alter_table_column_rename_stmt ::= 'ALTER TABLE' table_name 'RENAME COLUMN' old_column_name 'TO' new_column_name ``` ```sql ALTER TABLE sensor_log RENAME COLUMN status TO device_status; ALTER TABLE product_master RENAME COLUMN name TO product_name; ``` ### MODIFY COLUMN ```sql alter_table_modify_stmt ::= 'ALTER TABLE' table_name 'MODIFY COLUMN' ( '(' column_name 'VARCHAR' '(' new_size ')' ')' | column_name ( 'NOT NULL' [ 'NOCHECK' ] | 'NULL' | 'SET' 'MINMAX_CACHE_SIZE' '=' value ) ) ``` The length-extension and MINMAX examples below target LOG. Existing VARCHAR length can be increased, but not decreased, and other types cannot be converted to VARCHAR. The new LOG length cannot exceed 32,767 bytes. MINMAX_CACHE_SIZE applies to supported fixed-length LOG columns, not variable-length columns such as VARCHAR/TEXT. In LOG, NOT NULL without an option checks existing rows. NOCHECK only skips that check; it does not fill existing NULL values. NULL removes the constraint. Do not apply this entire scope to TAG; check [TAG Column Changes](/dbms/tag-table-usage/create-alter-drop/). TRANSACTION does not support MODIFY COLUMN. ```sql -- Increase VARCHAR length (decreasing is unsupported) ALTER TABLE sensor_log MODIFY COLUMN (name VARCHAR(128)); -- Add NOT NULL ALTER TABLE sensor_log MODIFY COLUMN id NOT NULL; -- Remove NOT NULL ALTER TABLE sensor_log MODIFY COLUMN id NULL; -- Change MINMAX_CACHE_SIZE ALTER TABLE sensor_log MODIFY COLUMN id SET MINMAX_CACHE_SIZE = 10240; ``` ### RENAME TO ```sql alter_table_rename_stmt ::= 'ALTER TABLE' table_name 'RENAME TO' new_name ``` ```sql -- Supported for TRANSACTION tables ALTER TABLE product_master RENAME TO product_catalog; ``` ### ADD / DROP RETENTION For retention assignment/detachment, see [RETENTION Syntax](../retention-syntax/). --- ## TRUNCATE TABLE ```sql truncate_table_stmt ::= 'TRUNCATE TABLE' table_name ``` Deletes all table data. Returns an error if another session is querying the table. ```sql TRUNCATE TABLE sensor_log; ``` --- ## CREATE INDEX For index types, table support, JSON paths, and properties, see [INDEX Syntax](../index-syntax/). --- ## DROP INDEX For drop syntax and restrictions, see [INDEX Syntax](../index-syntax/#drop-index). --- ## CREATE TABLESPACE ```sql create_tablespace_stmt ::= 'CREATE TABLESPACE' tablespace_name 'DATADISK' datadisk_list datadisk_list ::= data_disk ( ',' data_disk )* data_disk ::= disk_name '(' 'DISK_PATH' '=' '"' path '"' [ ',' 'PARALLEL_IO' '=' number ] ')' ``` ```sql -- Single-disk tablespace CREATE TABLESPACE tbs1 DATADISK disk1 (DISK_PATH="tbs1_disk1"); -- Configure parallel I/O CREATE TABLESPACE tbs2 DATADISK disk1 (DISK_PATH="tbs2_disk1", PARALLEL_IO = 5); -- Multiple disks CREATE TABLESPACE tbs3 DATADISK disk1 (DISK_PATH="tbs3_d1", PARALLEL_IO = 10), disk2 (DISK_PATH="tbs3_d2"), disk3 (DISK_PATH="tbs3_d3"); ``` --- ## DROP TABLESPACE ```sql drop_tablespace_stmt ::= 'DROP TABLESPACE' tablespace_name ``` ```sql DROP TABLESPACE tbs1; ``` A tablespace cannot be dropped while it contains objects. --- ## CREATE ROLLUP For basic, conditional, and Custom ROLLUP syntax, see [ROLLUP Syntax](../rollup-syntax/). --- ## DROP ROLLUP For deletion syntax, see [ROLLUP Syntax](../rollup-syntax/#drop-rollup). --- ## ALTER ROLLUP For start, stop, force, and interval changes, see [ROLLUP Syntax](../rollup-syntax/#alter-rollup). --- ## CREATE RETENTION For creation and table assignment, see [RETENTION Syntax](../retention-syntax/). --- ## DROP RETENTION For deletion syntax and detachment order, see [RETENTION Syntax](../retention-syntax/#drop-retention). --- ## DDL Concurrency and Locks {#ddl-concurrency} Machbase 8.7.0 Standard Edition coordinates DDL at object level for independent objects. DDL creating or changing differently named LOG, TAG, VOLATILE, LOOKUP, and TRANSACTION tables in the same database can therefore proceed concurrently. | Edition | DDL on independent objects | Conflict scope | Conflict wait setting | |---------|-----------------|-----------|-------------------| | Standard | Can proceed concurrently | Same object and directly related objects | DDL_LOCK_TIMEOUT | | Cluster | Serialized under existing policy | Catalog scope | DDL_LOCK_TIMEOUT unavailable | Even concurrently started DDL on independent objects can share work such as metadata processing and storage I/O. Throughput scaling with client count and simultaneous completion of all DDL are not guaranteed. ### Conflicting Objects | Concurrent operations | Behavior | |----------------|------| | Independent tables with different names | Can proceed concurrently regardless of table type | | Same object or same object name | One DDL proceeds; the other waits or errors | | Table alter/drop and its index DDL | Treated as related objects | | View DDL and alter/drop of its referenced table | Treated as related objects | | TAG alter/drop and its ROLLUP/RETENTION DDL | Treated as related objects | | DROP VIEW, CREATE OR REPLACE VIEW, system-wide DDL | Can serialize at broader scope | Table names share one namespace across table types. Concurrent LOG and TAG creation with the same name creates only one of them. ### DDL Lock Wait Time In Standard Edition, DDL_LOCK_TIMEOUT sets the wait for conflicting DDL locks in seconds. | Value | Behavior | |---:|------| | 0 | Immediately return `ERR-02031: Resource busy ()` without waiting | | Positive | Wait up to the specified time; return ERR-02031 if the lock is not acquired | The parentheses in the error identify a representative conflicting object. Broad-scope conflicts can show DDL instead of an object name. The default is 0 and the range is 0–1000000. Change the current session value as follows. ```sql ALTER SESSION SET DDL_LOCK_TIMEOUT = 10; ``` Wait time does not restart at each lock stage of one DDL statement. After locking, objects and dependencies are checked again, so preceding DDL can cause ordinary errors such as already exists or table not found. DDL_LOCK_TIMEOUT limits only lock waits, not total SQL execution time. Running DDL keeps its startup value; ALTER SESSION changes apply from the next DDL. DDL commit/recovery behavior remains the same as earlier versions; no new implicit commits are introduced. | Setting | Unit | Limit target | |------|------|-----------| | DDL_LOCK_TIMEOUT | Seconds | Standard Edition DDL lock waits | | SESSION_QUERY_TIMEOUT_SEC / QUERY_TIMEOUT | Seconds | Query execution and response waits | | TRANSACTION_BUSY_TIMEOUT_MS | Milliseconds | Concurrent TRANSACTION write conflicts | --- ## Related Documentation - [Table Types](/dbms/data-modeling-table-design/) — Characteristics and usage of LOG, TAG, LOOKUP, VOLATILE, and TRANSACTION - [TAG Table ROLLUP](/dbms/tag-table-usage/create-alter-drop/#original-85-creating-tag-tables) — ROLLUP creation and operation - [GRANT/REVOKE](../user-auth-syntax/#grant-revoke) — DDL privileges - [ALTER SESSION](../system-session-alter-syntax/#alter-session) — Current-session DDL lock wait settings - [Schema Change Checklist](/dbms/operations-configuration-recovery/checklist-schema-alter/) — Operational DDL and conflict handling --- title: "DML" url: https://docs.machbase.com/dbms/reference/sql/syntax/dml-syntax/ language: en kind: section --- # DML Data Manipulation Language (DML) inserts, updates, and deletes table data. ## DML Support by Table Type | Statement | LOG | TAG | LOOKUP | VOLATILE | TRANSACTION | |------|:---:|:---:|:------:|:--------:|:---:| | INSERT | Yes | Yes | Yes | Yes | Yes | | INSERT SELECT | Yes | Yes | Yes | Yes | Yes | | UPDATE | - | Yes (tag/axis predicates or metadata) | Yes (general predicates) | Yes (PK predicates) | Yes | | DELETE | Yes (retention/all) | Yes (time/name predicates) | Yes (general predicates/all) | Yes (PK predicates) | Yes | | DELETE WHERE | - | Yes (tag/axis predicates) | Yes (general predicates) | Yes (PK equality) | Yes | | TRUNCATE | Yes | - | - | - | Yes | > LOG does not support UPDATE. For mutable data, use LOOKUP, VOLATILE, or TRANSACTION. --- ## INSERT INTO ```sql insert_stmt ::= 'INSERT INTO' table_name [ 'METADATA' ] [ '(' insert_column_list ')' ] 'VALUES' '(' value_list ')' [ 'ON DUPLICATE KEY UPDATE' [ 'SET' set_list ] ] insert_column_list ::= insert_target ( ',' insert_target )* insert_target ::= column_name | array_column_name '[' position ']' value_list ::= value ( ',' value )* set_list ::= column_name '=' value ( ',' column_name '=' value )* ``` Omitted columns receive NULL. METADATA inserts into TAG metadata columns. ```sql -- Basic insert INSERT INTO sensor_log VALUES (1, 'sensor-01', 23.5, 'OK'); -- Insert into specified columns INSERT INTO sensor_log (name, value) VALUES ('sensor-01', 23.5); -- Insert TAG metadata INSERT INTO sensors METADATA (name, location, unit) VALUES ('sensor-01', 'building-A', 'celsius'); ``` ### ARRAY element target Machbase DBMS 8.7.0 permits fixed-length ARRAY positions in an INSERT ... VALUES column list. Positions start at 0. Unspecified elements are stored as element NULL. ```sql CREATE LOG TABLE array_input ( id INTEGER, channels INT32[4] ); INSERT INTO array_input (id, channels[0], channels[3]) VALUES (1, 10, 40); ``` A statement cannot mix a whole-ARRAY target with element targets or specify the same position twice. Scalar columns and out-of-range positions are invalid element targets. Indexed targets are unsupported in INSERT ... SELECT and UPDATE SET. For ARRAY construction, sparse input, and selected Append targets, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/) and [Sparse ARRAY and Selected-Column Append APIs](/dbms/development-tools-integration/data-input-load-export/array-append/). ### ON DUPLICATE KEY UPDATE Updates an existing row when INSERT ... VALUES encounters a duplicate key. It cannot be combined with INSERT ... SELECT. | Table type | Duplicate key | Support | |---|---|---| | TRANSACTION | PRIMARY KEY, single/composite UNIQUE INDEX | Standard Edition | | LOOKUP | PRIMARY KEY | Supported | | VOLATILE | PRIMARY KEY | Supported | | TAG METADATA | Tag-name PRIMARY KEY | Supported | | TAG data, LOG | - | Unsupported | Without SET, INSERT input values update existing non-key columns. With SET, right-hand expressions use the conflicting existing row. LOOKUP, VOLATILE, and TRANSACTION cannot update the PRIMARY KEY itself. TAG METADATA tag names and system-managed columns follow [TAG Metadata](/dbms/tag-table-usage/tag-metadata/) change rules. ```sql -- On a duplicate key, update only the value column INSERT INTO devices (device_id, ip, status) VALUES ('dev-001', '192.168.1.1', 'ONLINE') ON DUPLICATE KEY UPDATE SET status = 'ONLINE'; -- Without SET, update all columns with insert values INSERT INTO devices (device_id, ip, status) VALUES ('dev-001', '192.168.1.2', 'ONLINE') ON DUPLICATE KEY UPDATE; ``` UPSERT without a duplicate-detection key, key changes, and DBMS-specific expressions such as VALUES(col)/EXCLUDED.col cause errors. For TRANSACTION UNIQUE conflicts and transactions, see [TRANSACTION UPSERT](/dbms/rdb-table-usage/insert-on-duplicate-key-update/). --- ## INSERT SELECT ```sql insert_select_stmt ::= 'INSERT INTO' table_name [ '(' insert_column_list ')' ] [ with_clause ] select_stmt ``` Inserts SELECT results into a table. Standard Edition allows WITH after the target table and column list. Leading WITH ... INSERT INTO ... syntax is unsupported. ```sql -- Copy query results to another table INSERT INTO sensor_log_copy SELECT * FROM sensor_log; -- Insert explicit _arrival_time values in chronological order INSERT INTO sensor_log_copy (_arrival_time, id, name, value) SELECT _arrival_time, id, name, value FROM sensor_log ORDER BY _arrival_time; -- Insert CTE results INSERT INTO sensor_log_copy (id, name, value) WITH filtered AS ( SELECT id, name, value FROM sensor_log WHERE value >= 80 ) SELECT id, name, value FROM filtered; ``` Considerations: - Omitting _ARRIVAL_TIME automatically uses the INSERT execution time. - For explicit LOG timestamp copies, insert into an empty target in ascending order, separately from other ingestion. Existing newer timestamps make input out of order even when the source is sorted. The default DISK_COLUMNAR_TABLE_TIME_INVERSION_MODE=1 adjusts inverted timestamps to the previous stored time + 1 ns; 0 rejects them. Explicit input therefore does not unconditionally preserve source timestamps. - Values exceeding a VARCHAR maximum length are automatically truncated on insertion. - LOG/TAG ingestion is outside TRANSACTION table ROLLBACK. --- ## UPDATE ```sql update_stmt ::= 'UPDATE' table_name [ 'METADATA' ] 'SET' update_expr_list [ 'WHERE' predicate ] update_expr_list ::= column_name '=' value ( ',' column_name '=' value )* ``` TRANSACTION updates all rows if WHERE is omitted. LOOKUP uses primary key or general predicates; VOLATILE uses primary key equality. TAG data UPDATE combines a tag selector with a time-axis predicate. ```sql -- Update a LOOKUP row UPDATE devices SET status = 'OFFLINE' WHERE device_id = 'dev-001'; -- Update multiple columns UPDATE devices SET ip = '10.0.0.1', status = 'ONLINE' WHERE device_id = 'dev-002'; -- Update multiple LOOKUP rows with a general predicate UPDATE devices SET status = 'OFFLINE' WHERE site = 'SEOUL' AND status = 'READY'; ``` ### TAG data UPDATE Update actual TAG time-series data using both tag-selection and BASETIME predicates. ```sql UPDATE sensors SET value = 101, status = 1 WHERE name = 'sensor-01' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); ``` name (PRIMARY KEY), time (BASETIME), and metadata columns cannot be SET targets in data UPDATE. ### UPDATE METADATA (TAG Tables) Use the separate UPDATE ... METADATA form to modify TAG metadata columns. ```sql -- Update multiple rows with a metadata predicate UPDATE sensors METADATA SET status = 'DONE' WHERE status = 'READY'; -- Update by tag name UPDATE sensors METADATA SET location = 'building-B' WHERE name = 'sensor-01'; ``` --- ## DELETE ```sql -- LOG deletion by time or row count delete_stmt ::= 'DELETE FROM' table_name [ 'OLDEST' number 'ROWS' | 'EXCEPT' number ( 'ROWS' | time_unit ) | 'BEFORE' datetime_expression ] [ 'NO WAIT' ] time_unit ::= 'YEAR' | 'MONTH' | 'WEEK' | 'DAY' | 'HOUR' | 'MINUTE' | 'SECOND' ``` LOG does not support arbitrary-position deletion; it can delete only a continuous range starting from the oldest data. Current LOG BEFORE t deletes rows with _arrival_time <= t. Do not infer exclusive boundaries from its name; use the same comparison for preliminary queries. EXCEPT n DAY and similar periods use current server time, not the last ingestion timestamp. User-defined DATETIME values are not the deletion basis. See actual before/after results in [LOG Retention Deletion](/dbms/log-table-usage/operations-lifecycle/). ```sql -- Delete all data DELETE FROM sensor_log; -- Delete the oldest N rows DELETE FROM sensor_log OLDEST 1000 ROWS; -- Delete all but the latest N rows DELETE FROM sensor_log EXCEPT 10000 ROWS; -- Delete all but the latest N days DELETE FROM sensor_log EXCEPT 7 DAY; -- Delete through a timestamp, including the boundary DELETE FROM sensor_log BEFORE TO_DATE('2024-01-01', 'YYYY-MM-DD'); ``` ### DELETE WHERE (LOOKUP/VOLATILE Tables) ```sql delete_where_stmt ::= 'DELETE FROM' table_name 'WHERE' predicate ``` LOOKUP supports primary key or general predicates. VOLATILE uses primary key equality. LOOKUP also permits omitting WHERE to delete every row. ```sql DELETE FROM devices WHERE device_id = 'dev-001'; -- Delete multiple LOOKUP rows with a general predicate DELETE FROM devices WHERE status = 'EXPIRED' OR site = 'RETIRED'; -- Delete all LOOKUP rows DELETE FROM devices; ``` ### DELETE (TAG Tables) ```sql -- TAG: delete by name or time predicates delete_from_tag_where_stmt ::= 'DELETE FROM' table_name [ 'ROLLUP' ] 'WHERE' predicate -- predicate: tag_name, tag_time, or both combined with AND ``` Time predicates support =, <, <=, and BETWEEN. ```sql -- Delete by TAG name DELETE FROM tag WHERE name = 'sensor-01'; -- Delete by TAG name and time DELETE FROM tag WHERE name = 'sensor-01' AND time < TO_DATE('2024-01-01', 'YYYY-MM-DD'); -- Delete by time only DELETE FROM tag WHERE time <= TO_DATE('2024-01-01', 'YYYY-MM-DD'); -- Delete ROLLUP data DELETE FROM tag ROLLUP WHERE name = 'sensor-01'; DELETE FROM tag ROLLUP WHERE time BETWEEN TO_DATE('2024-01-01','YYYY-MM-DD') AND TO_DATE('2024-02-01','YYYY-MM-DD'); ``` ### DELETE FROM TAG METADATA ```sql DELETE FROM table_name METADATA [ WHERE predicate ] ``` Deletes TAG metadata rows. Omitting WHERE deletes all metadata. Metadata cannot be deleted for tags that still have actual data. ```sql DELETE FROM sensors METADATA WHERE name = 'sensor-01'; DELETE FROM sensors METADATA WHERE status = 'STOP'; DELETE FROM sensors METADATA; -- Delete all metadata (only tags without actual data) ``` --- ## UPDATE/DELETE Affected Rows Clients executing UPDATE/DELETE can obtain the statement affected row count. Direct execution and prepared statements use the same rules. UPDATE returns the number of rows matching WHERE, not the number whose values actually changed. Setting the same value still counts a matching row. Where omitting WHERE is supported, every target row counts as matched. DELETE returns the number of matching rows actually deleted. Repeating the same DELETE returns 0 after the first execution has removed them. ```sql CREATE LOOKUP TABLE device_state ( id INTEGER PRIMARY KEY, value INTEGER ); INSERT INTO device_state VALUES (1, 10); INSERT INTO device_state VALUES (2, 10); UPDATE device_state SET value = 20 WHERE id >= 1 AND id <= 2; -- 2 row(s) updated. UPDATE device_state SET value = 20 WHERE id >= 1 AND id <= 2; -- 2 row(s) updated. (Repeated UPDATE with identical values) UPDATE device_state SET value = 20 WHERE id = 999; -- No row updated. DELETE FROM device_state WHERE id = 1; -- 1 row(s) deleted. DELETE FROM device_state WHERE id = 1; -- No row deleted. ``` No row updated. or 0 affected rows means no row matched the predicate, not that assigned values equaled existing values. Affected counts within a transaction reflect each statement at execution time. A later ROLLBACK does not change the meaning of counts already returned. --- ## Related Documentation - [DDL Syntax Dictionary](../ddl-syntax/) — Table creation and schema changes - [SELECT Syntax Dictionary](../select-syntax/) — Data queries - [WITH / CTE Syntax](../cte-syntax/) — INSERT SELECT with CTEs - [LOOKUP Predicate UPDATE](./lookup-predicate-update-syntax/) — General-predicate updates - [LOOKUP Predicate DELETE](./lookup-predicate-delete-syntax/) — General-predicate deletion - [LOAD DATA INFILE](../load-data-infile-syntax/) — Bulk CSV loading --- title: "TAG data UPDATE" url: https://docs.machbase.com/dbms/reference/sql/syntax/dml-syntax/tag-data-update-syntax/ language: en kind: page --- # TAG data UPDATE Modify TAG time-series data with ordinary UPDATE. There is no separate UPDATE TAG TABLE keyword sequence. Supported since Machbase 8.7.0 TAG data UPDATE is supported only on logical TAG tables in Standard Edition. ## Syntax ```sql UPDATE table_name SET data_column = expression [, data_column = expression ...] WHERE tag_selector AND time_condition [AND data_predicate ...]; ``` tag_selector supports name = ..., name IN (...), and name LIKE ... predicates. time_condition supports BASETIME equality, BETWEEN, and bounded or one-sided ranges. ## Examples ### Single Tag and Time Range ```sql UPDATE sensor_tag SET value = 110, status = 1 WHERE name = 'TEMP-01' AND time >= TO_DATE('2026-07-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND time < TO_DATE('2026-07-02 00:00:00', 'YYYY-MM-DD HH24:MI:SS'); ``` ### Multiple Tags ```sql UPDATE sensor_tag SET note = 'corrected' WHERE name IN ('TEMP-01', 'TEMP-02') AND time BETWEEN TO_DATE('2026-07-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2026-07-01 23:59:59', 'YYYY-MM-DD HH24:MI:SS'); ``` ### LIKE and Data-Column Predicates ```sql UPDATE sensor_tag SET status = 7 WHERE name LIKE 'TEMP-%' AND time >= TO_DATE('2026-07-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND value > 100; ``` ### CASE Expressions ```sql UPDATE sensor_tag SET grade = CASE WHEN 1 = 1 THEN 'HIGH' ELSE 'LOW' END WHERE name = 'TEMP-01' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); ``` ### Bind Parameters in NAME and TIME Predicates Tag-name and BASETIME values in WHERE support positional ? or named :name markers. Do not mix marker styles in one statement. Positional markers bind SET values, tag names, and reference times in SQL occurrence order. ```sql UPDATE sensor_tag SET value = ?, status = ?, note = ? WHERE name = ? AND time = ?; ``` Named markers allow SDK name-based APIs to supply values independently of SQL order. ```sql UPDATE sensor_tag SET value = :value, status = :status, note = :note WHERE name = :name AND time = :time; ``` Reexecuting the same prepared statement selects targets using newly bound SET, NAME, and TIME values. NAME parameters retain VARCHAR metadata and TIME parameters DATETIME metadata. No matching rows returns 0 affected rows without an error. Reversed equality with the column on the right, such as ? = name, :name = name, ? = time, or :time = time, is also supported. Prefer columns on the left for readability. Markers can also replace values in existing supported BASETIME range predicates. For SDK name-based APIs and ordinal rules, see [Named Bind Parameters](../../named-bind-parameter-syntax/). ## Metadata UPDATE TAG metadata columns are not SET targets for TAG data UPDATE. Modify metadata with UPDATE ... METADATA. ```sql UPDATE sensor_tag METADATA SET location = 'zone-2', owner = 'ops' WHERE name = 'TEMP-01'; ``` ## Restrictions - WHERE requires one tag selector and at least one BASETIME predicate. Supported forms include name equality, IN, LIKE, and time equality, BETWEEN, bounded ranges, or one-sided ranges. Add data-column predicates with AND. - OR, subqueries, aggregates, and tag/axis expressions that are not bare columns are unsupported as target predicates. - name (PRIMARY KEY), time (BASETIME), metadata, and hidden/system columns cannot be data UPDATE SET targets. - SET right-hand sides allow constants, bind variables, functions/operations/CASE that do not reference existing row columns, and NULL. Existing-column expressions such as value = value + 1 are unsupported. - Bind parameters replace only values; tag-selector, BASETIME, and SET-target restrictions remain unchanged. - UPDATE does not automatically correct already materialized ROLLUP rows. Rebuild affected intervals with ROLLUP_REBUILD before querying those aggregates. ## Related - [TAG data UPDATE WHERE/SET constraints](../tag-data-update-where-set-constraints/) - [Named Bind Parameter](../../named-bind-parameter-syntax/) - [ROLLUP_REBUILD syntax](../../rollup-rebuild-syntax/) --- title: "TAG data UPDATE WHERE/SET constraints" url: https://docs.machbase.com/dbms/reference/sql/syntax/dml-syntax/tag-data-update-where-set-constraints/ language: en kind: page --- # TAG data UPDATE WHERE/SET constraints TAG data UPDATE requires an explicit target scope. WHERE must contain both tag selection and BASETIME predicates, and SET can target only actual data columns. Supported since Machbase 8.7.0 ## SET Restrictions | Column role | SET allowed | Description | |-----------|:------------:|------| | Data column | Yes | value and auxiliary numeric/string columns | | SUMMARIZED data column | Yes | Changes source TAG row values | | BASETIME column | No | Time-axis column cannot change | | PRIMARY KEY column (name) | No | Tag name cannot change | | Metadata column | No | Use UPDATE ... METADATA separately | | Hidden/system column | No | Internal columns are not SET targets | SET expressions allow constants, bind variables, arithmetic/string/CASE expressions without existing-row references, supported conversion functions, and NULL. Existing-row column references, subqueries, and aggregates are unsupported on the right-hand side. ## WHERE Restrictions ```sql UPDATE table_name SET col = expr WHERE name = 'tag-name' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); ``` | WHERE predicate | Supported | |-----------|:---------:| | `name = '...'` | Yes | | `name = ?`, `name = :tag_name` | Yes | | `? = name`, `:tag_name = name` | Yes | | `name IN ('...', '...')` | Yes | | `name LIKE '...'` | Yes | | `time = t1` | Yes | | `time = ?`, `time = :base_time` | Yes | | `? = time`, `:base_time = time` | Yes | | `time BETWEEN t1 AND t2` | Yes | | `time >= t1 AND time < t2` | Yes | | `time >= ? AND time < ?` | Yes | | One-sided time predicate | Yes | | Data-column predicate | Yes | | No tag selector | No | | No time predicate | No | | OR | No | | IN (SELECT ...) | No | | Tag/axis column wrapped in a function or expression | No | Use bind parameters only in predicate value positions. Markers cannot replace tag-name or BASETIME column identifiers, and both tag selection and time predicates remain mandatory. Reexecution selects targets using newly bound values; no match succeeds with 0 affected rows. For NAME/TIME parameter metadata and SDK APIs, see [Bind Parameters in TAG Data UPDATE](../tag-data-update-syntax/#tag-data-update-predicate-bind) and [Named Bind Parameters](../../named-bind-parameter-syntax/). ## Metadata UPDATE ```sql UPDATE table_name METADATA SET meta_col = value WHERE condition; ``` Metadata UPDATE modifies the tag-attribute area. Its syntax and targets differ from TAG data UPDATE, which modifies data columns in actual time-series rows. ## Checking Column Roles Use DESC to inspect column attributes. ```sql DESC sensor_tag; ``` Alternatively, query column FLAG values in system tables. ```sql SELECT NAME, TYPE, FLAG FROM M$SYS_COLUMNS WHERE TABLE_ID = ( SELECT ID FROM M$SYS_TABLES WHERE NAME = 'SENSOR_TAG' ); ``` | FLAG value | Meaning | |---------|------| | 134217728 | Tag Name | | 16777216 | Base Time / Base Distance | | 33554432 | Summarized | | 67108864 | Metadata | ## Error Examples ```sql -- Error: BASETIME column used as a SET target UPDATE sensor_tag SET time = TO_DATE('2026-07-01', 'YYYY-MM-DD') WHERE name = 'TEMP-01' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); -- Error: missing time predicate UPDATE sensor_tag SET value = 0.0 WHERE name = 'TEMP-01'; -- Error: OR predicate UPDATE sensor_tag SET value = 0.0 WHERE name = 'TEMP-01' OR name = 'TEMP-02'; ``` ## Related Documentation - [TAG data UPDATE syntax](../tag-data-update-syntax/) - [Named Bind Parameter](../../named-bind-parameter-syntax/) - [ROLLUP_REBUILD syntax](../../rollup-rebuild-syntax/) --- title: "LOOKUP predicate UPDATE" url: https://docs.machbase.com/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-update-syntax/ language: en kind: page --- # LOOKUP predicate UPDATE LOOKUP UPDATE supports general WHERE predicates as well as primary key equality. Every matching row is updated. ## Syntax ```sql UPDATE table_name SET column_name = expression [, column_name = expression ...] WHERE predicate; ``` ## Supported Predicate Examples ```sql -- Ordinary column predicate UPDATE device_lookup SET status = 'ACTIVE' WHERE site = 'SEOUL' AND status = 'READY'; -- Range and string predicates UPDATE device_lookup SET score = score + 10 WHERE score BETWEEN 10 AND 80 AND note LIKE 'sensor-%'; -- JSON path predicates UPDATE device_lookup SET meta = JSON_SET(meta, '$.state', 'active') WHERE meta->'$.region' = 'kr' AND JSON_EXTRACT_INTEGER(meta, '$.level') >= 3; ``` Right-hand SET expressions can reference the current row values. ```sql UPDATE device_lookup SET score = score + 1 WHERE group_name IN ('A', 'B'); ``` ## Supported Predicates | Predicate | Supported | |------|:---:| | `pk_col = value` | Yes | | `non_pk_col = value` | Yes | | `<`, `<=`, `>`, `>=`, `<>` | Yes | | BETWEEN | Yes | | IN, NOT IN | Yes | | LIKE, NOT LIKE | Yes | | AND, OR, NOT | Yes | | IS NULL, IS NOT NULL | Yes | | TO_DATE(...) date predicates | Yes | | JSON ->, JSON_EXTRACT_*, JSON_IS_VALID | Yes | ## Constraints - SET cannot change the primary key column itself. - Multiple matching rows result in multiple updates. - Use single quotes for JSON path strings, such as '$.key'. Double quotes denote SQL identifiers. - For numeric JSON comparison, use typed functions such as JSON_EXTRACT_INTEGER or JSON_EXTRACT_DOUBLE. ## Related Documentation - [LOOKUP Predicate DELETE Syntax](../lookup-predicate-delete-syntax/) - [LOOKUP SQL/JSON Support Matrix](../../../../support-scope-constraints/lookup-sql-json/) --- title: "LOOKUP predicate DELETE" url: https://docs.machbase.com/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-delete-syntax/ language: en kind: page --- # LOOKUP predicate DELETE LOOKUP DELETE supports general WHERE predicates as well as primary key equality. Every matching row is deleted. ## Syntax ```sql DELETE FROM table_name WHERE predicate; ``` Omitting WHERE deletes all rows in the LOOKUP table. ## Supported Predicate Examples ```sql -- Ordinary column predicate DELETE FROM device_lookup WHERE status = 'EXPIRED'; -- Date and range predicates DELETE FROM device_lookup WHERE updated_at < TO_DATE('2026-01-01 00:00:00') OR score < 10; -- JSON path predicates DELETE FROM device_lookup WHERE meta->'$.region' = 'kr' AND JSON_EXTRACT_INTEGER(meta, '$.level') < 2; ``` ## Supported Predicates | Predicate | Supported | |------|:---:| | `pk_col = value` | Yes | | `non_pk_col = value` | Yes | | `<`, `<=`, `>`, `>=`, `<>` | Yes | | BETWEEN | Yes | | IN, NOT IN | Yes | | LIKE, NOT LIKE | Yes | | AND, OR, NOT | Yes | | IS NULL, IS NOT NULL | Yes | | TO_DATE(...) date predicates | Yes | | JSON ->, JSON_EXTRACT_*, JSON_IS_VALID | Yes | | Delete all rows without WHERE | Yes | ## Operational Considerations General-predicate DELETE removes every matching row. For production data, verify the target scope with the same predicate before execution. ```sql SELECT COUNT(*) FROM device_lookup WHERE status = 'EXPIRED'; DELETE FROM device_lookup WHERE status = 'EXPIRED'; ``` ## Related Documentation - [LOOKUP Predicate UPDATE Syntax](../lookup-predicate-update-syntax/) - [LOOKUP SQL/JSON Support Matrix](../../../../support-scope-constraints/lookup-sql-json/) --- title: "LOAD DATA INFILE" url: https://docs.machbase.com/dbms/reference/sql/syntax/load-data-infile-syntax/ language: en kind: page --- # LOAD DATA INFILE LOAD DATA INFILE reads a CSV-format file directly on the server and inserts its data into a table. > For large loads, use machloader. It offers parallel processing and additional options for higher ingestion throughput. ## Syntax ```sql LOAD DATA INFILE 'file_path' INTO TABLE table_name [TABLESPACE tablespace_name] [AUTO { BULKLOAD | HEADUSE | HEADUSE_ESCAPE }] [{ FIELDS | COLUMNS } [TERMINATED BY 'char'] [ENCLOSED BY 'char']] [LINES TERMINATED BY 'char'] [TRIM { ON | OFF }] [IGNORE number LINES] [MAX_LINE_LENGTH number] [ENCODED BY coding_name] [ON ERROR { STOP | IGNORE }] ``` ## Options | Option | Description | |------|------| | AUTO BULKLOAD | Insert each entire line into one column | | AUTO HEADUSE | Create a table from first-row column names, then load data | | AUTO HEADUSE_ESCAPE | Like HEADUSE, but replace reserved words/special characters with _ | | TERMINATED BY 'char' | Field separator; default: , | | ENCLOSED BY 'char' | Field quote character; default: " | | LINES TERMINATED BY 'char' | Record separator | | TRIM { ON \| OFF } | Remove leading/trailing column whitespace; default: ON | | IGNORE number LINES | Skip the first N lines, for example a header | | MAX_LINE_LENGTH number | Maximum line length; default: 512 KB | | ENCODED BY coding_name | File encoding; default: UTF8 | | ON ERROR STOP\|IGNORE | Stop or ignore on errors; default: STOP | Supported encodings: UTF8, MS949, KSC5601, EUCJP, SHIFTJIS, BIG5, GB231280. ## Examples ```sql -- Load a default CSV file (separator: , quote: ") LOAD DATA INFILE '/tmp/sensor_data.csv' INTO TABLE sensor_log; -- Skip one header line and load semicolon-separated data LOAD DATA INFILE '/tmp/data.csv' INTO TABLE sample_data FIELDS TERMINATED BY ';' ENCLOSED BY '\'' IGNORE 1 LINES ON ERROR IGNORE; -- AUTO BULKLOAD: one column per line; create the table automatically LOAD DATA INFILE '/tmp/raw.txt' INTO TABLE raw_table AUTO BULKLOAD; -- AUTO HEADUSE: create columns from the first line, then load LOAD DATA INFILE '/tmp/data_with_header.csv' INTO TABLE auto_table AUTO HEADUSE; -- Specify encoding LOAD DATA INFILE '/tmp/korean_data.csv' INTO TABLE Korean_table ENCODED BY MS949; ``` ## Considerations - Without AUTO, every target column must be VARCHAR or TEXT. - The Machbase server process must be able to access the file path. - Rows already inserted are not rolled back after an ingestion error. - machloader offers better performance for large files. ## Comparison with machloader | Item | LOAD DATA INFILE | machloader | |------|-----------------|------------| | Parallel processing | Unsupported | Supported | | Interface | SQL statement | CLI utility | | Use | Small loads and scripts | Large bulk loads | ## Related Documentation - [SAVE DATA INTO Syntax](../save-data-into-syntax/) — Save SELECT results to files --- title: "VIEW" url: https://docs.machbase.com/dbms/reference/sql/syntax/view-syntax/ language: en kind: page --- # VIEW A VIEW stores a SELECT definition as a named logical object for reuse. It does not store data separately; queries expand and execute its stored SQL. ## CREATE VIEW ```sql CREATE VIEW view_name AS SELECT ... FROM ...; ``` ```sql CREATE VIEW view_name (col1, col2, ...) AS SELECT ... FROM ...; ``` ```sql CREATE OR REPLACE VIEW view_name AS SELECT ... FROM ...; ``` Standard Edition allows a nonrecursive CTE before the SELECT in a VIEW definition. ```sql CREATE VIEW view_name AS WITH cte_name AS ( SELECT ... FROM ... ) SELECT ... FROM cte_name; ``` - `CREATE OR REPLACE VIEW` replaces an existing VIEW definition. If the target is another object type, it raises an error. - An explicit column list defines the official VIEW column names; otherwise, aliases or source column names apply. - `view_name` can be schema-qualified as `db.user.view_name`. ### Basic Example ```sql CREATE LOOKUP TABLE customer ( id INTEGER PRIMARY KEY, name VARCHAR(20), city VARCHAR(20), amount INTEGER ); CREATE VIEW v_customer AS SELECT id, name, city, amount FROM customer; SELECT name, city FROM v_customer WHERE id = 100; ``` ### Explicit Column Names ```sql CREATE VIEW v_customer_short (cust_id, cust_name) AS SELECT id, name FROM customer; ``` ### Replace a VIEW Definition ```sql CREATE OR REPLACE VIEW v_customer_amount AS SELECT id, amount * 10 AS amount FROM customer WHERE id <= 10; ``` ### VIEW with a CTE ```sql CREATE VIEW v_customer_city_summary AS WITH city_summary AS ( SELECT city, COUNT(*) AS customer_count, SUM(amount) AS total_amount FROM customer GROUP BY city ) SELECT city, customer_count, total_amount FROM city_summary; ``` VIEW definitions cannot contain bind parameters (`?`). Put conditions that vary per execution in the SELECT querying the VIEW. ## VIEW User Context Since Machbase 8.7.0, `CURRENT_*` and `SESSION_*` functions inside VIEWs distinguish definers from callers. Here, `VIEW_OWNER` creates the VIEW and `VIEW_CALLER` queries it with granted privileges. ```sql CONNECT sys/manager; CREATE USER view_owner IDENTIFIED BY 'VIEW_OWNER'; CREATE USER view_caller IDENTIFIED BY 'VIEW_CALLER'; CONNECT view_owner/VIEW_OWNER; CREATE LOOKUP TABLE user_context_source (id INTEGER PRIMARY KEY); INSERT INTO user_context_source VALUES (1); CREATE VIEW v_user_context AS SELECT CURRENT_USER() AS current_name, SESSION_USER() AS session_name, CURRENT_USER_ID() AS current_id, SESSION_USER_ID() AS session_id FROM user_context_source; CONNECT sys/manager; GRANT SELECT ON view_owner.v_user_context TO view_caller; CONNECT view_caller/VIEW_CALLER; SELECT current_name, session_name, CASE WHEN current_id <> session_id THEN 'DIFF' ELSE 'SAME' END AS id_context FROM view_owner.v_user_context; ``` ```text CURRENT_NAME SESSION_NAME ID_CONTEXT VIEW_OWNER VIEW_CALLER DIFF ``` Inside a VIEW, `CURRENT_*` returns the VIEW owner and `SESSION_*` returns the connected caller. In ordinary SQL, both return the same user. See [User Context Functions](../../functions/functions-full/#current-session-user) for details. ```sql CONNECT view_owner/VIEW_OWNER; DROP VIEW v_user_context; DROP TABLE user_context_source; CONNECT sys/manager; DROP USER view_caller; DROP USER view_owner; ``` ## DROP VIEW ```sql DROP VIEW view_name; DROP VIEW IF EXISTS view_name; ``` - `DROP VIEW IF EXISTS` succeeds without error when the target does not exist. - Deletion is blocked if another VIEW references the target. - `DROP TABLE view_name` cannot delete a VIEW. ## Inspect Metadata ```sql SHOW VIEWS; DESC view_name; SELECT USER_NAME, DB_NAME, VIEW_NAME, VIEW_SQL FROM M$SYS_VIEWS WHERE VIEW_NAME = 'V_CUSTOMER'; ``` - VIEWs have `TYPE = 7` in `M$SYS_TABLES`. ## Supported VIEW Forms | Form | Supported | |------|-----------| | Simple projection and predicates | O | | Expressions, functions, constants, CASE | O | | JOIN | O | | Subqueries | O | | Nested VIEWs | O | | GROUP BY, HAVING | O | | DISTINCT | O | | UNION ALL | O | ## TAG / BINARY Column Example Use `extract_*()` functions to interpret TAG BINARY columns and expose logical columns. ```sql CREATE TAG TABLE dam ( name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, frame BINARY(16) ); CREATE VIEW damdata AS SELECT name, time, extract_bit(frame, 0) AS bit0, extract_ulong(frame, 0, 16) AS u16, extract_float(frame, 0) AS f32, extract_scaled_double(frame, 0, 12, 0, 0.5, 0.5) AS sd12 FROM dam; SELECT name, time, bit0, u16, f32, sd12 FROM damdata WHERE name = 'main' AND time >= TO_DATE('2024-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND time < TO_DATE('2024-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY time; ``` ## Limitations - VIEW definition SQL (the SELECT body) supports up to 256KB. - VIEWs do not store data; performance depends on source queries and optimizer decisions. - DISTINCT and predicates on computed columns may require full scans; check EXPLAIN. - Recursive VIEWs that reference themselves are unsupported. ## Related Documentation - [SELECT Syntax](../select-syntax/) — Use VIEWs in FROM - [WITH / CTE Syntax](../cte-syntax/) — Define VIEWs containing CTEs --- title: "INDEX" url: https://docs.machbase.com/dbms/reference/sql/syntax/index-syntax/ language: en kind: page --- # INDEX This reference explains index syntax and support by table type. Indexes reduce query cost but require maintenance during ingestion and changes. Add them after checking actual predicates and execution plans. ## CREATE INDEX Supported since Machbase 8.7.0 ```sql create_index_stmt ::= 'CREATE' index_modifier? 'INDEX' [ 'IF NOT EXISTS' ] index_name 'ON' index_target '(' index_column_list ')' [ 'INDEX_TYPE' ( 'LSM' | 'KEYWORD' | 'BITMAP' | 'REDBLACK' | 'TAG' ) ] [ 'TABLESPACE' tablespace_name ] [ index_property_list ] index_modifier ::= 'UNIQUE' | 'PRIMARY KEY' index_target ::= table_name | table_name 'METADATA' index_column_list ::= column_name ( ',' column_name )* | column_name json_path index_property_list ::= ( 'MAX_LEVEL' '=' number | 'PAGE_SIZE' '=' number | 'BITMAP_ENCODE' '=' ( 'EQUAL' | 'RANGE' ) | 'PART_VALUE_COUNT' '=' number ) ( ',' index_property_list )* ``` ### IF NOT EXISTS IF NOT EXISTS succeeds without error and retains the existing index if the same index name exists for the same database and owner. - If the name does not exist, validate table, column, index type, properties, and privileges as for ordinary CREATE INDEX, then create it. - If the name exists, do not compare or change table, column, index type, JSON path, or properties. - The duplicate namespace is database + owner + index name. The same name in another database or owner is a different index. - Without the option, CREATE INDEX returns the existing duplicate-name error. {{< callout type="warning" >}} IF NOT EXISTS does not reconcile index definitions. An existing name makes the statement a successful no-op even if its target table/column is absent or its definition differs. After repeated deployment, verify actual tables, columns, types, and properties with SHOW INDEX or the system catalog. {{< /callout >}} ```sql CREATE LOG TABLE sensor_log_ifne ( sensor_id INTEGER, value DOUBLE ); CREATE INDEX IF NOT EXISTS sensor_log_ifne_idx ON sensor_log_ifne(sensor_id); -- Existing name: succeeds and retains the original SENSOR_ID mapping. CREATE INDEX IF NOT EXISTS sensor_log_ifne_idx ON sensor_log_ifne(value); SHOW INDEX sensor_log_ifne_idx; DROP TABLE sensor_log_ifne; ``` ### Supported Conditional Creation Forms | Form | Support | |---|---| | Ordinary CREATE INDEX IF NOT EXISTS | Ordinary indexes supported by the table type | | CREATE UNIQUE INDEX IF NOT EXISTS | Standard Edition TRANSACTION | | CREATE PRIMARY KEY INDEX IF NOT EXISTS | Standard Edition TRANSACTION | | TAG data JSON path / TAG METADATA index | Standard and Cluster Editions | | INDEX_TYPE in ordinary syntax | Existing table/index-type support | Deprecated CREATE BITMAP INDEX, CREATE KEYWORD INDEX, and CREATE REDBLACK INDEX forms do not accept IF NOT EXISTS. Use ordinary syntax. ```sql CREATE INDEX IF NOT EXISTS idx_message ON app_log(message) INDEX_TYPE KEYWORD; ``` ## Support by Table Type | Table type | Indexes | Main uses | |------------|--------|-----------| | LOG | LSM, KEYWORD, BITMAP | Range queries, text search, analytical predicates | | TAG | TAG/KV secondary, JSON path | Value-column and JSON-member predicates | | TAG METADATA | Automatic column indexes, JSON path | Tag-attribute predicates | | TRANSACTION | PRIMARY KEY, UNIQUE, ordinary BTREE | Relational keys and composite predicates | | VOLATILE | REDBLACK | In-memory key/predicate queries | | LOOKUP | REDBLACK | In-memory key/predicate queries | The default internal index depends on table type. Specifying an index type from another table type does not necessarily create the same structure. ## LOG Indexes ```sql CREATE INDEX idx_ts ON sensor_log (ts); CREATE INDEX idx_msg ON app_log (message) INDEX_TYPE KEYWORD; CREATE INDEX idx_status ON sensor_log (status) INDEX_TYPE BITMAP BITMAP_ENCODE = RANGE; ``` | Type | Targets and characteristics | |------|-------------| | LSM | Default LOG range index | | KEYWORD | SEARCH/ESEARCH on VARCHAR/TEXT | | BITMAP | Repeated-value analysis; not for VARCHAR, TEXT, or BINARY | Choose properties such as LSM MAX_LEVEL/PAGE_SIZE and BITMAP BITMAP_ENCODE through measurements of data distribution and query predicates. ## TAG Indexes Default access structures for TAG names and the time axis are managed automatically. Consider TAG/KV secondary indexes when value columns are frequently used as standalone predicates. ```sql CREATE INDEX idx_value ON sensor_tag (value) INDEX_TYPE TAG; ``` JSON value columns support indexes by path. ```sql CREATE INDEX idx_sensor ON tag_json (value.sensor.name); CREATE INDEX idx_metric ON tag_json (value->'$.metric'); CREATE INDEX idx_item ON tag_json (value.items[0]."product-id"); ``` Ordinary TAG METADATA columns are indexed automatically. Use the following form to add a path from a METADATA JSON column. ```sql CREATE INDEX idx_ship_owner ON ships METADATA (info->'$.owner'); ``` For support scope and execution-plan examples, see [TAG Indexes and Performance](/dbms/tag-table-usage/index-performance/). ## TRANSACTION Indexes TRANSACTION supports PRIMARY KEY, UNIQUE INDEX, and ordinary single/composite indexes. ```sql CREATE PRIMARY KEY INDEX idx_pk_order ON orders (order_id); CREATE UNIQUE INDEX uidx_account_email ON account (email); CREATE UNIQUE INDEX uidx_tenant_login ON account (tenant_id, login_name); CREATE INDEX idx_category_name ON product (category, product_name); ``` A table permits one single-column PRIMARY KEY. CREATE UNIQUE INDEX supports composite columns; NULL-containing keys are not duplicates of other NULL-containing keys. See [TRANSACTION Indexes and Performance](/dbms/rdb-table-usage/index-performance/). ## VOLATILE and LOOKUP Indexes VOLATILE and LOOKUP use REDBLACK in-memory indexes. ```sql CREATE INDEX idx_status ON device_status (status) INDEX_TYPE REDBLACK; ``` For primary key and secondary-index design by type, see: - [VOLATILE Indexes and Performance](/dbms/volatile-table-usage/index-performance/) - [LOOKUP Indexes and Performance](/dbms/lookup-table-usage/index-performance/) ## DROP INDEX ```sql drop_index_stmt ::= 'DROP INDEX' index_name ``` ```sql DROP INDEX idx_status; ``` Deletion can fail while sessions use the target index. Check execution plans and production queries using it before dropping it. ## Related Documentation - [SEARCH / ESEARCH / REGEXP](../search-esearch-regexp-syntax/) - [Query Performance Tuning](/dbms/performance-tuning/performance-query-tuning/) --- title: "RETENTION syntax" url: https://docs.machbase.com/dbms/reference/sql/syntax/retention-syntax/ language: en kind: page --- # RETENTION syntax RETENTION policies periodically delete expired data from TAG, KV, and LOG tables. They do not apply to TRANSACTION, LOOKUP, or VOLATILE. ## Creating a RETENTION Policy ```sql create_retention_stmt ::= 'CREATE RETENTION' policy_name 'DURATION' positive_integer ( 'MONTH' | 'DAY' | 'HOUR' | 'MIN' | 'SEC' ) 'INTERVAL' positive_integer ( 'DAY' | 'HOUR' | 'MIN' | 'SEC' ) ``` | Parameter | Description | |----------|------| | `policy_name` | Policy name | | `DURATION duration MONTH\|DAY\|HOUR\|MIN\|SEC` | Data retention period (MONTH is a fixed 30 days) | | `INTERVAL interval DAY\|HOUR\|MIN\|SEC` | Deletion execution interval | ```sql -- Retain 1 day; delete every hour CREATE RETENTION policy_1d_1h DURATION 1 DAY INTERVAL 1 HOUR; -- Retain 30 days; delete daily CREATE RETENTION policy_30d_1d DURATION 30 DAY INTERVAL 1 DAY; -- Retain 3 months; delete daily CREATE RETENTION policy_3m_1d DURATION 3 MONTH INTERVAL 1 DAY; ``` ## Dropping a RETENTION Policy ```sql drop_retention_stmt ::= 'DROP RETENTION' policy_name ``` ```sql DROP RETENTION policy_1d_1h; ``` ## Assigning a RETENTION Policy to a Table ```sql alter_table_add_retention_stmt ::= 'ALTER TABLE' table_name 'ADD RETENTION' policy_name ``` ```sql ALTER TABLE sensor_tag ADD RETENTION policy_1d_1h; ``` ## Detaching a RETENTION Policy from a Table ```sql alter_table_drop_retention_stmt ::= 'ALTER TABLE' table_name 'DROP RETENTION' ``` ```sql ALTER TABLE sensor_tag DROP RETENTION; ``` ## Listing RETENTION Policies Query system tables for registered policies and their assignments. ```sql -- Query all RETENTION policies SELECT * FROM M$RETENTION; -- Check assigned jobs and the last deletion cutoff by table SELECT USER_NAME, TABLE_NAME, POLICY_NAME, STATE, LAST_DELETED_TIME FROM V$RETENTION_JOB ORDER BY USER_NAME, TABLE_NAME; ``` ## Complete Example ```sql -- 1. Create a policy: retain 1 day and delete hourly CREATE RETENTION ret_1d DURATION 1 DAY INTERVAL 1 HOUR; -- 2. Create a TAG table CREATE TAG TABLE sensor_tag ( name VARCHAR(40) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ); -- 3. Assign the policy to the table ALTER TABLE sensor_tag ADD RETENTION ret_1d; -- 4. Check policy assignment SELECT * FROM M$RETENTION; -- 5. Detach the policy ALTER TABLE sensor_tag DROP RETENTION; -- 6. Drop the policy DROP RETENTION ret_1d; ``` ## Considerations - RETENTION policies apply to LOG and TAG tables. - KV tables are also supported. - Only one policy can be assigned to a table. - MONTH means a fixed 30 days, not a calendar month. If calendar boundaries matter, convert to DAY units and verify actual deletion cutoffs. - Deleted rows cannot be recovered, so choose retention periods and execution intervals carefully. DROP RETENTION removes only the policy object after detachment from every table. - INTERVAL determines how often deletion runs; actual deletion can be slightly delayed. - Missing policies, unsupported table types, and duplicate policy assignments to one table cause errors. - Detach an in-use policy from every table before dropping it. ## Related Documentation - [Role of Retention Policy](/dbms/core-concepts/features-concepts/#role-retention-policy) — Automatic data deletion concepts --- title: "BACKUP / RESTORE / MOUNT syntax" url: https://docs.machbase.com/dbms/reference/sql/syntax/backup-restore-mount-syntax/ language: en kind: page --- # BACKUP / RESTORE / MOUNT syntax Machbase backup, restore, and mount statements protect data, recover it when needed, and query historical data. > **Privileges**: Ordinary users need separate privileges for backup and mount. > ```sql > GRANT BACKUP ON DATABASE database_name TO user_name; > GRANT MOUNT ON DATABASE MACHBASEDB TO user_name; > ``` --- ## BACKUP ### Logical Database Backup Standard Edition 8.7.0 supports logical backups with an explicit target catalog. ```sql backup_logical_database_stmt ::= 'BACKUP DATABASE' database_name [ 'AFTER' 'backup_path_or_lsn' ] 'INTO DISK' '=' 'backup_path' ``` ```sql BACKUP DATABASE factory_a INTO DISK = '/backup/factory_a_20260806'; BACKUP DATABASE factory_a AFTER '/backup/factory_a_20260806' INTO DISK = '/backup/factory_a_inc'; ``` A logical backup targets one active database catalog. A full-instance image containing multiple active databases cannot be input to logical MOUNT or RESTORE. ### Full Backup ```sql backup_database_stmt ::= 'BACKUP DATABASE INTO DISK' '=' 'backup_path' [ 'IMPORT MODE' ] ``` Saves the entire current database to the specified path. This is an online backup that does not stop the server. ```sql -- Full backup to an absolute path BACKUP DATABASE INTO DISK = '/backup/machbase_20240101'; -- Relative path (under $MACHBASE_HOME/dbs) BACKUP DATABASE INTO DISK = 'backup_20240101'; ``` - An existing backup_path causes an error. Use a unique name, for example including a date. - The command blocks until the backup completes. ### Incremental Backup ```sql backup_incremental_stmt ::= 'BACKUP DATABASE AFTER' 'backup_path_or_lsn' 'INTO DISK' '=' 'backup_path' ``` Backs up relative to the last full or incremental backup. Distinguish storage behavior by table type. TRANSACTION storage is included as a complete snapshot at the backup point even in incremental images, so do not estimate it as a changed-row delta or changed-data-sized increment. Compare backup and current data in [TRANSACTION Backup Validation](/dbms/rdb-table-usage/backup-restore-mount/). ```sql -- Incremental backup after the full backup BACKUP DATABASE AFTER '/backup/machbase_20240101' INTO DISK = '/backup/incr_20240102'; ``` ### Time-Range Backup ```sql backup_period_stmt ::= 'BACKUP DATABASE' 'FROM' datetime_expr 'TO' datetime_expr 'INTO DISK' '=' 'backup_path' ``` Backs up only data in the specified time range. ```sql BACKUP DATABASE FROM TO_DATE('2024-01-01','YYYY-MM-DD') TO TO_DATE('2024-02-01','YYYY-MM-DD') INTO DISK = '/backup/period_jan'; ``` ### Table Backup ```sql backup_table_stmt ::= 'BACKUP TABLE' table_name 'INTO DISK' '=' 'backup_path' ``` Selectively backs up a table instead of the entire database. ```sql BACKUP TABLE sensor_log INTO DISK = '/backup/sensor_log_20240101'; ``` --- ## RESTORE Existing machadmin -r recovery restores an instance offline with the server stopped. Standard Edition 8.7.0 also supports online RESTORE DATABASE to a new logical catalog or to replace a READ ONLY target. ```sql restore_database_stmt ::= 'RESTORE DATABASE' database_name 'FROM DISK' '=' 'backup_path' [ 'REMAP OWNER' old_owner 'TO' new_owner ] [ 'REPLACE' ] ``` ```sql RESTORE DATABASE factory_a_copy FROM DISK = '/backup/factory_a_20260806' REMAP OWNER APP_A TO APP_ARCHIVE; RESTORE DATABASE factory_a FROM DISK = '/backup/factory_a_20260806' REPLACE; ``` RESTORE DATABASE is SYS-only. A REPLACE target must be READ ONLY with no active references. Database/table privileges are not inherited automatically after restore and must be granted again. Unsupported objects or owner conflicts in the backup image can fail the entire restore. ### Offline Instance Restore (`machadmin -r`) Prepare and validate a backup SQL file before running the restore procedure. ```sql -- /secure/path/pre_restore_backup.sql BACKUP DATABASE INTO DISK = '/backup/before_restore'; ``` ```bash # 1. Back up current data before restore machsql -s 127.0.0.1 -P 5656 -u SYS \ -f /secure/path/pre_restore_backup.sql # 2. Stop the server machadmin -s # 3. Destroy the current database machadmin -d # 4. Restore from the backup machadmin -r /backup/machbase_20240101 # 5. Start the server machadmin -u ``` machadmin -d destroys the current database. Verify the recovery target, backup, and rollback plan, and execute only after explicit approval. Restore completely replaces the current database with its backup-time state. ### Restoring an Incremental Backup Specify the final incremental backup path once. Incremental backups contain chain information, so repeated application starting from the full backup is unnecessary. ```bash machadmin -s machadmin -d machadmin -r /backup/incr_20240103 machadmin -u ``` ### Main machadmin Options | Option | Description | |------|------| | `-s` (`--shutdown`) | Shut down the server normally | | `-k` (`--kill`) | Force server termination | | `-u` (`--startup`) | Start the server | | `-d` (`--destroydb`) | Destroy the current database | | `-r path` (`--restore`) | Restore from the specified backup path | --- ## MOUNT DATABASE ```sql mount_database_stmt ::= 'MOUNT DATABASE' 'backup_database_path' 'TO' mount_name ``` Attaches a single-catalog backup image as a mounted database without stopping the server or replacing an active database. Mounted databases are always READ ONLY and cannot become the current database through USE. - backup_database_path: backup directory created using DISK. - mount_name: database alias used to access the mounted database. ```sql -- Mount an absolute path MOUNT DATABASE '/backup/machbase_20240101' TO backup_db; -- Relative path (under $MACHBASE_HOME/dbs) MOUNT DATABASE 'machbase_20240101' TO backup_db; ``` ### Querying Mounted Databases Access mounted tables as mount_name.user_name.table_name. Queries require both USAGE on the mounted database and SELECT on the target table. ```sql -- Query a mounted database table SELECT * FROM backup_db.sys.sensor_log WHERE _arrival_time > TO_DATE('2024-01-01','YYYY-MM-DD'); -- Join current and mounted database tables SELECT a.name, a.value AS current_val, b.value AS backup_val FROM sensor_log a JOIN backup_db.sys.sensor_log b ON a.name = b.name; ``` --- ## UMOUNT DATABASE ```sql umount_database_stmt ::= 'UMOUNT DATABASE' mount_name ``` Detaches a mounted database. ```sql UMOUNT DATABASE backup_db; ``` Unmount fails if open cursors or running queries reference the mounted database. End the relevant sessions and retry. --- ## Limitations and Considerations | Item | Description | |------|------| | Writes to mounted databases | Unsupported; read-only | | Mounting IBFILE backups | Unsupported; only DISK backups can be mounted | | Version compatibility | Backup and current server metadata versions must be compatible | | Time-range restore for TAG tables | Unsupported; use full or incremental backups | | Cluster Edition | Multiple databases and MOUNT/UMOUNT unsupported | --- ## Related Documentation - [Backup, Restore, and Mount Operations](/dbms/operations-configuration-recovery/backup-restore-mount/) — Detailed procedures and automation examples - [GRANT/REVOKE](../user-auth-syntax/#grant-revoke) — Backup and mount privileges --- title: "ROLLUP" url: https://docs.machbase.com/dbms/reference/sql/syntax/rollup-syntax/ language: en kind: page --- # ROLLUP ROLLUP stores and queries recurring aggregates for time-axis TAG tables. Query ordinary, conditional, and extended ROLLUPs with the public rollup() function; reaggregate user target TAG tables for Custom rollups. ## Creation The following is syntax notation; do not execute brackets or braces literally. ```text CREATE ROLLUP [IF NOT EXISTS] name ON source_tag [(column_name | json_path_expression)] INTERVAL n { SEC | MIN | HOUR } [WAKEUP INTERVAL m { SEC | MIN | HOUR }] [EXTENSION] [WHERE predicate]; CREATE ROLLUP [IF NOT EXISTS] name FROM source_rollup INTERVAL n { SEC | MIN | HOUR } [WAKEUP INTERVAL m { SEC | MIN | HOUR }] [EXTENSION] [WHERE predicate]; CREATE ROLLUP [IF NOT EXISTS] name INTO (destination_tag) AS (SELECT ...) INTERVAL n { SEC | MIN | HOUR } [WAKEUP INTERVAL m { SEC | MIN | HOUR }]; ``` - EXTENSION is a standalone keyword; do not append an extension_name. - CREATE uses SEC/MIN/HOUR. Distinguish these from query units such as DAY. - Ordinary numeric columns can be specified without SUMMARIZED. JSON path aggregation differs from whole-document aggregation; whole-document and automatic WITH ROLLUP creation require SUMMARIZED. - FROM intervals must be larger integer multiples of the source interval, with matching extension attributes and aggregation modes. - WAKEUP must be positive, no greater than the aggregation interval, and divide it evenly. - Custom is Standard-only and requires one source TAG and a precreated target TAG. Put WHERE inside SELECT. Direct BASETIME predicates, JOIN, and FROM subqueries are disallowed. - IF NOT EXISTS skips creation for an existing name; it does not modify, compare, or reconcile definitions. It does not bypass all syntax and source validation. ## Deletion ```sql DROP ROLLUP rollup_name; ``` Drop higher-level ROLLUPs that reference others first. Dropping a Custom target TAG is rejected while related jobs remain. Before using CASCADE on the source TAG, check which related ROLLUPs will be removed. Manage user Custom target tables with their own lifecycle. ## Control ```sql ALTER ROLLUP rollup_name STOP; ALTER ROLLUP rollup_name START; ALTER ROLLUP rollup_name WAKEUP; ALTER ROLLUP rollup_name FORCE; ALTER ROLLUP rollup_name SET WAKEUP INTERVAL 10 SEC; ``` These commands require existing jobs and valid interval conditions. Jobs start automatically at creation. Repeating an already-started/stopped state may cause an error. WAKEUP returns without waiting for completion; FORCE waits for the target to catch up with its source processing range. For historical source corrections, check [REBUILD's separate support scope](../rollup-rebuild-syntax/). ## Queries and Candidate Selection ```text rollup(time_unit, period, basetime_column [, origin]) ``` Return type: DATETIME. period must be a positive integer literal. Do not assume an ordinary DATE_TRUNC + GROUP BY query switches automatically merely because a ROLLUP exists. Specify rollup() for ROLLUP queries; use a separate source-data query if no candidate applies. Automatic selection first looks for unconditional candidates matching column, path, and mode, then selects the largest usable interval. Equal intervals are affected by registration order. Do not infer priority from ordinary/extended status alone. Use ROLLUP_TABLE to fix the dataset. SEC/MIN candidate intervals are checked against period seconds/minutes. HOUR, DAY, WEEK, MONTH, and YEAR use period hours during candidate selection. This rule is separate from calendar calculation of result buckets. For month/year origins, check the first-day-of-month requirement. For per-tag aggregation returning name, also include name in GROUP BY. Match time range, origin, NULL handling, and candidate predicates before comparing source results. Ordinary numeric ROLLUP supports MIN/MAX/SUM/COUNT/AVG/SUMSQ; extended ROLLUP adds FIRST/LAST. Distinguish source-data FIRST/LAST usage from stored ROLLUP extension requirements. Whole-document JSON COUNT and per-path counts have separate contracts. For runnable creation, query, and error examples, see [Chapter 6: Using ROLLUP](/dbms/tag-rollup-usage/) and [Query Syntax](/dbms/tag-rollup-usage/query-syntax-rollup/). --- title: "ROLLUP_REBUILD" url: https://docs.machbase.com/dbms/reference/sql/syntax/rollup-rebuild-syntax/ language: en kind: page --- # ROLLUP_REBUILD ROLLUP_REBUILD is a Standard Edition procedure that recalculates historical buckets for supported TAG aggregates. It is unavailable in Cluster Edition. ## Syntax and Arguments ```text EXEC ROLLUP_REBUILD(source_tag, tag_name, begin_time, end_time); ``` | Argument | Current Input | |---|---| | source_tag | Source TAG identifier, owner-qualified if needed | | tag_name | String naming one tag to rebuild | | begin_time | Time string or TO_DATE with constant string arguments | | end_time | End timestamp in the same form; must be at least begin_time | Current time argument handling does not evaluate general DATETIME expressions. Do not use NOW, NOW-1h, columns, or bind parameters in examples. For relative ranges, resolve timestamps in an operational tool and pass supported constants. Specify date strings, formats, and timezones clearly. ## Time Range Includes the buckets containing both endpoints and recalculates entire buckets. At one-minute resolution, 00:00:30–00:01:00 covers [00:00:00, 00:02:00). Equal start/end rebuilds the containing bucket; start greater than end is an error. The HOUR level can expand the range further to whole hour buckets. Passing the upper bound of a half-open source WHERE range directly may include the next bucket. Determine impact from the actual corrected timestamps and each aggregate's bucket boundaries. ## Targets and Constraints - Use a complete automatic SEC→MIN→HOUR hierarchy as the basic exercise target. - Do not assume the same path handles manually named ordinary ROLLUPs or automatic hierarchies missing SEC. - Custom trees use a separate path. Current time-boundary generation supports 1 SEC, 1 MIN, and 1 HOUR. Other creatable intervals, such as 10 MIN, do not imply rebuild support. - Custom SELECT buckets and origin must match rebuild boundaries. - A nonexistent tag may be a no-op when a valid target exists. - If source data has been removed, statistics from before deletion cannot be restored. ## Example The following call assumes the ch6_rebuild exercise objects are prepared. ```sql EXEC ROLLUP_REBUILD(ch6_rebuild, 'S1', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS')); ``` Setup SQL, source corrections, ordinary/Custom result comparison, and cleanup are provided in [6.10 Complete Exercise](/dbms/tag-rollup-usage/rollup-rebuild/). ## Job State and Failures Related jobs pass through stop, recalculate, and restart stages. Normal aggregation is not guaranteed to continue unchanged during rebuilding. Test source-read stabilization and data regeneration impact in an isolated environment. A failure may leave some results changed. Do not assume complete rollback or automatic restoration of an originally stopped state. Check source data, target buckets, V$ROLLUP, gaps, and the first error. Do not repeat the command before excluding unsupported jobs or correcting the procedure. Also check [Creation/Query Syntax](../rollup-syntax/), [Support Scope](/dbms/reference/support-scope-constraints/rollup/), and [Troubleshooting](/dbms/troubleshooting/rollup/). --- title: "USER/AUTH" url: https://docs.machbase.com/dbms/reference/sql/syntax/user-auth-syntax/ language: en kind: page --- # USER/AUTH Syntax for creating/dropping users, changing passwords, granting/revoking privileges, and managing public-key AUTH KEY authentication. --- ## CREATE USER {#create-drop-alter-user} ```sql create_user_stmt ::= 'CREATE USER' user_name 'IDENTIFIED BY' password [ 'PASSWORD POLICY' ( 'NONE' | 'LOW' | 'HIGH' ) ] [ 'WITH AUTH KEY' '(' auth_key_spec ')' ] auth_key_spec ::= "key='" pem_public_key "'," "valid_before='" YYYY-MM-DD "'," "comment='" text "'" ``` User names are converted to uppercase when stored. ```sql -- Create a basic user CREATE USER app_user IDENTIFIED BY 'App#1234'; -- Specify password policy CREATE USER ops_user IDENTIFIED BY 'Ops@Strong1' PASSWORD POLICY HIGH; -- Create with AUTH KEY (public-key authentication) CREATE USER app_user IDENTIFIED BY 'App#1234' WITH AUTH KEY ( key='-----BEGIN PUBLIC KEY-----\nMFkw...(omitted)...==\n-----END PUBLIC KEY-----\n', valid_before='2047-12-31', comment='initial key' ); ``` ### Password Policies | Policy | Description | |------|------| | `NONE` | No strength restrictions or expiration | | `LOW` | At least 10 characters, uppercase/lowercase/special characters; no consecutive-number or keyboard patterns | | `HIGH` | LOW rules + no reuse of the last 24 passwords + automatic expiration after 90 days | --- ## DROP USER ```sql drop_user_stmt ::= 'DROP USER' user_name ``` The `SYS` user cannot be dropped. Dropping a user that still owns tables raises an error. Dropping a user from another administrator session does not immediately terminate existing sessions. New connections fail; existing sessions retain the user name and ID from login. See [Account Management](../../../../security-access-control/account/#drop-user-active-session) for procedures and [User Context Functions](../../functions/functions-full/#current-session-user) for verification functions. ```sql DROP USER old_user; ``` --- ## ALTER USER ```sql -- Change password alter_user_pwd_stmt ::= 'ALTER USER' user_name 'IDENTIFIED BY' new_password [ 'PASSWORD POLICY' ( 'NONE' | 'LOW' | 'HIGH' ) ] ``` Policy-only changes are not allowed. Always specify a new password when changing the policy. ```sql -- Change password ALTER USER app_user IDENTIFIED BY 'NewPass#456'; -- Change password and policy together ALTER USER app_user IDENTIFIED BY 'NewPass#456' PASSWORD POLICY HIGH; ``` --- ## CONNECT ```sql user_connect_stmt ::= 'CONNECT' user_name '/' password ``` Reconnects as another user without exiting the application. ```sql CONNECT app_user/App#1234; ``` --- ## GRANT / REVOKE {#grant-revoke} ```sql grant_stmt ::= 'GRANT' priv_list 'ON' object_ref 'TO' user_name revoke_stmt ::= 'REVOKE' priv_list 'ON' object_ref 'FROM' user_name priv_list ::= priv_value ( ',' priv_value )* object_ref ::= 'DATABASE' database_name | 'TABLE' ['database_name.'] owner_name '.' table_name | ['database_name.'] owner_name '.' table_name ``` ### Table Privileges ```sql -- Table DML privileges GRANT SELECT ON sensor_log TO reader; GRANT SELECT, INSERT ON sys.sensor_log TO writer; GRANT ALL ON sys.sensor_log TO app_user; -- Revoke privileges REVOKE INSERT ON sys.sensor_log FROM writer; REVOKE ALL ON sys.sensor_log FROM app_user; ``` Table privileges: `SELECT`, `INSERT`, `DELETE`, `UPDATE`, `ALL` ### Database Privileges (Machbase 8.5 and Later) ```sql -- DDL privileges (CREATE + DROP) GRANT DDL ON DATABASE factory_a TO deploy_user; -- Individual DDL privileges GRANT CONNECT ON DATABASE factory_a TO app_user; GRANT CREATE ON DATABASE factory_a TO create_user; GRANT DROP ON DATABASE factory_a TO drop_user; GRANT ALTER ON DATABASE factory_a TO ops_user; -- Operational privileges GRANT BACKUP ON DATABASE factory_a TO backup_user; GRANT MOUNT ON DATABASE MACHBASEDB TO mount_user; GRANT USAGE ON DATABASE factory_a_backup TO report_user; -- All database privileges GRANT ALL ON DATABASE factory_a TO admin_user; -- Revoke privileges REVOKE BACKUP ON DATABASE factory_a FROM backup_user; ``` Database privileges: `CONNECT`, `CREATE`, `DROP`, `ALTER`, `BACKUP`, `MOUNT`, `USAGE`, `DDL` (`CREATE+DROP`), `ALL` (`CONNECT+CREATE+DROP+ALTER+BACKUP`) ### Operations Requiring Database Privileges | Operation | Required privilege | |------|------------| | CREATE/DROP TABLE, VIEW, INDEX, ROLLUP, TABLESPACE, RETENTION | `CREATE`, `DROP`, or `DDL` | | ALTER SYSTEM | `ALTER` | | BACKUP DATABASE | `BACKUP` | | MOUNT/UMOUNT DATABASE | `MOUNT` | ### Default Privileges for New Users New users have `SELECT`, `INSERT`, `DELETE`, `UPDATE`, `CREATE`, and `DROP` by default. Grant `ALTER`, `MOUNT`, and `BACKUP` explicitly. --- ## AUTH KEY Management {#auth-key} An AUTH KEY is a public key registered in Machbase for challenge authentication instead of password authentication. ### Supported Algorithms | Algorithm | Supported parameters | Signature schemes | |---------|-------------|----------| | ECDSA | P-256, P-384, P-521 | ECDSA | | RSA | 2048, 3072, 4096 bits | RSA_PKCS1_V15, RSA_PSS | ### Generate Key Files (openssl) ```bash # Generate an ECDSA P-256 key openssl ecparam -name prime256v1 -genkey -noout -out app_user.key openssl ec -in app_user.key -pubout -out app_user.pub chmod 600 app_user.key # Generate an RSA 2048-bit key openssl genrsa -out app_user_rsa.key 2048 openssl rsa -in app_user_rsa.key -pubout -out app_user_rsa.pub chmod 600 app_user_rsa.key # Convert PEM to inline SQL (newlines to \n) awk '{printf "%s\\n", $0}' app_user.pub ``` ### Add an AUTH KEY ```sql alter_user_add_auth_key_stmt ::= 'ALTER USER' user_name 'ADD AUTH KEY' '(' auth_key_spec ')' auth_key_spec ::= "key='" pem_public_key "'," "valid_before='" YYYY-MM-DD "'," "comment='" text "'" ``` ```sql ALTER USER app_user ADD AUTH KEY ( key='-----BEGIN PUBLIC KEY-----\nMFkw...(omitted)...==\n-----END PUBLIC KEY-----\n', valid_before='2047-12-31', comment='primary key' ); ``` Added keys are immediately registered as active (`ACTIVATED=1`). ### Activate / Deactivate an AUTH KEY ```sql alter_user_activate_key_stmt ::= 'ALTER USER' user_name 'ACTIVATE AUTH KEY ID' key_id alter_user_deactivate_key_stmt ::= 'ALTER USER' user_name 'DEACTIVATE AUTH KEY ID' key_id ``` ```sql ALTER USER app_user DEACTIVATE AUTH KEY ID 3; ALTER USER app_user ACTIVATE AUTH KEY ID 3; ``` ### Change AUTH KEY Validity ```sql alter_user_alter_key_stmt ::= 'ALTER USER' user_name 'ALTER AUTH KEY ID' key_id "VALID_BEFORE='" YYYY-MM-DD "'" ``` ```sql ALTER USER app_user ALTER AUTH KEY ID 3 VALID_BEFORE='2048-06-30'; ``` ### Delete an AUTH KEY ```sql alter_user_drop_key_stmt ::= 'ALTER USER' user_name 'DROP AUTH KEY ID' key_id ``` ```sql ALTER USER app_user DROP AUTH KEY ID 3; ``` ### Query AUTH KEYs ```sql SELECT key_id, user_name, key_algo, key_param, activated, valid_before, comment FROM V$USER_AUTH_KEYS WHERE user_name = 'APP_USER' ORDER BY key_id; ``` Main `V$USER_AUTH_KEYS` columns: `KEY_ID`, `USER_NAME`, `KEY_ALGO`, `KEY_PARAM`, `ACTIVATED`, `VALID_AFTER`, `VALID_BEFORE`, `COMMENT`, `PUBKEY` --- ## Related Documentation - [User Management Guide](../../../../operations-configuration-recovery/) – Operational procedures and examples - [System/Session Management Syntax](../system-session-alter-syntax/) – ALTER SYSTEM and ALTER SESSION --- title: "SYSTEM/SESSION/ALTER SYSTEM" url: https://docs.machbase.com/dbms/reference/sql/syntax/system-session-alter-syntax/ language: en kind: page --- # SYSTEM/SESSION/ALTER SYSTEM `ALTER SYSTEM` manages server-wide resources. `ALTER SESSION` sets parameters for the current session only. > **Privileges:** `ALTER SYSTEM` requires the `SYS` account or privileges > granted with `GRANT ALTER ON DATABASE database_name TO user_name;`. --- ## ALTER SYSTEM {#alter-system} ### Command List | Command | Description | |--------|------| | `KILL SESSION n` | Forcibly terminates a session | | `CANCEL SESSION n` | Cancels the current query while retaining the session | | `CHECKPOINT` | Immediately synchronizes memory buffers to disk | | `FREEZE` | Pauses all DML for backup preparation | | `UNFREEZE` | Resumes DML paused by FREEZE | | `FLUSH AGER` | Immediately runs the Ager to clean expired data | | `FLUSH SYS_STAT` | Refreshes optimizer system statistics | | `FLUSH PVO_CACHE` | Clears the PVO Statement cache | | `FLUSH PAGE_CACHE` | Forcibly releases the OS page cache | | `FLUSH TAG_CACHE` | Clears the TAG metadata cache | | `INSTALL LICENSE` | Installs the license file from the default path | | `INSTALL LICENSE = 'path'` | Installs the license file from a specified path | | `CHECK DISK_USAGE` | Recalculates LOG table disk usage | | `SET property = value` | Changes system properties dynamically | --- ### KILL SESSION / CANCEL SESSION ```sql alter_system_kill_session_stmt ::= 'ALTER SYSTEM KILL SESSION' session_id alter_system_cancel_session_stmt ::= 'ALTER SYSTEM CANCEL SESSION' session_id ``` ```sql -- Inspect current sessions SELECT id, user_id, client_type FROM v$session; -- Force session termination (disconnect and transaction rollback) ALTER SYSTEM KILL SESSION 12; -- Cancel only the running query (retain connection) ALTER SYSTEM CANCEL SESSION 6; ``` - `KILL SESSION`: SYS only; terminates the target session immediately. - `CANCEL SESSION`: Same user or SYS only; retains the session and stops only its current SQL. --- ### CHECKPOINT ```sql alter_system_checkpoint_stmt ::= 'ALTER SYSTEM CHECKPOINT' ``` Immediately synchronizes memory-buffered data to disk. ```sql ALTER SYSTEM CHECKPOINT; ``` --- ### FREEZE / UNFREEZE ```sql alter_system_freeze_stmt ::= 'ALTER SYSTEM FREEZE' alter_system_unfreeze_stmt ::= 'ALTER SYSTEM UNFREEZE' ``` Pauses all DML when consistency is required, such as during backup preparation. ```sql ALTER SYSTEM FREEZE; -- (Perform backup or inspection) ALTER SYSTEM UNFREEZE; ``` --- ### FLUSH ```sql alter_system_flush_stmt ::= 'ALTER SYSTEM FLUSH' ( 'AGER' | 'SYS_STAT' | 'PVO_CACHE' | 'PAGE_CACHE' | 'TAG_CACHE' ) ``` ```sql -- Run Ager immediately (clean expired data) ALTER SYSTEM FLUSH AGER; -- Refresh optimizer statistics ALTER SYSTEM FLUSH SYS_STAT; -- Clear PVO Statement cache ALTER SYSTEM FLUSH PVO_CACHE; -- Force OS page-cache release ALTER SYSTEM FLUSH PAGE_CACHE; -- Clear TAG metadata cache ALTER SYSTEM FLUSH TAG_CACHE; ``` --- ### INSTALL LICENSE ```sql -- Default path ($MACHBASE_HOME/conf/license.dat) alter_system_install_license_stmt ::= 'ALTER SYSTEM INSTALL LICENSE' -- Specified path alter_system_install_license_path_stmt ::= 'ALTER SYSTEM INSTALL LICENSE' '=' "'" path "'" ``` ```sql -- Install from the default path ALTER SYSTEM INSTALL LICENSE; -- Install from a specified path ALTER SYSTEM INSTALL LICENSE = '/tmp/new_license.dat'; ``` --- ### CHECK DISK_USAGE ```sql alter_system_check_disk_stmt ::= 'ALTER SYSTEM CHECK DISK_USAGE' ``` Recalculates `DC_TABLE_FILE_SIZE` in `V$STORAGE` from the filesystem. Use when usage figures are inaccurate after a process failure or power outage. ```sql ALTER SYSTEM CHECK DISK_USAGE; ``` --- ### SET (Dynamic System Properties) ```sql alter_system_set_stmt ::= 'ALTER SYSTEM SET' property_name '=' value_expr value_expr ::= value | property_name '|' number -- Bitwise OR (add flags) | property_name '&' '~' number -- Bitwise AND NOT (remove flags) ``` Dynamically changeable properties: | Property | Description | |------|------| | `QUERY_PARALLEL_FACTOR` | Query parallelism thread count | | `DEFAULT_DATE_FORMAT` | Default date format, such as `'YYYY-MM-DD HH24:MI:SS'` | | `TRACE_LOG_LEVEL` | Trace log level (bit flags) | | `DISK_COLUMNAR_PAGE_CACHE_MAX_SIZE` | Maximum disk columnar page-cache size | | `MAX_SESSION_COUNT` | Maximum sessions | | `SESSION_IDLE_TIMEOUT_SEC` | Session idle timeout (seconds) | | `PROCESS_MAX_SIZE` | Maximum process memory size | | `TAG_CACHE_MAX_MEMORY_SIZE` | Maximum TAG cache memory | | `PVO_CACHE_ENABLE` | Enable PVO cache (0/1) | | `PVO_CACHE_MAX_MEMORY_SIZE` | Maximum PVO cache memory | ```sql -- Set values directly ALTER SYSTEM SET TRACE_LOG_LEVEL = 3; ALTER SYSTEM SET DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'; -- Check current values before changing SELECT NAME, VALUE, MIN, MAX FROM V$PROPERTY WHERE NAME = 'MAX_SESSION_COUNT'; -- Add bit flags (OR) ALTER SYSTEM SET TRACE_LOG_LEVEL = TRACE_LOG_LEVEL | 0x00000004; -- Remove bit flags (AND NOT) ALTER SYSTEM SET TRACE_LOG_LEVEL = TRACE_LOG_LEVEL & ~0x00000001; -- Set hexadecimal value ALTER SYSTEM SET TRACE_LOG_LEVEL = 0x00000003; ``` --- ## ALTER SESSION {#alter-session} Changes session-level parameters. ```sql alter_session_stmt ::= 'ALTER SESSION SET' session_property_name '=' value ``` ### SET SQL_LOGGING ```sql ALTER SESSION SET SQL_LOGGING = flag -- flag: Bitwise OR combination -- 0x1: Parsing, validation, and optimization logs -- 0x2: DDL execution result logs ``` ```sql ALTER SESSION SET SQL_LOGGING = 3; -- Parsing + DDL logs ALTER SESSION SET SQL_LOGGING = 0; -- Disable logging ``` ### SET DEFAULT_DATE_FORMAT ```sql ALTER SESSION SET DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'; ALTER SESSION SET DEFAULT_DATE_FORMAT = 'YYYYMMDD'; ``` ### SET SHOW_HIDDEN_COLS Controls whether `SELECT *` includes hidden columns (`_arrival_time`). ```sql ALTER SESSION SET SHOW_HIDDEN_COLS = 1; -- Show hidden columns ALTER SESSION SET SHOW_HIDDEN_COLS = 0; -- Hide hidden columns (default) ``` ### SET FEEDBACK_APPEND_ERROR Controls whether Append API error messages are sent to the client. ```sql ALTER SESSION SET FEEDBACK_APPEND_ERROR = 1; -- Send error messages ALTER SESSION SET FEEDBACK_APPEND_ERROR = 0; -- Do not send error messages (default) ``` ### SET MAX_QPX_MEM Maximum memory in bytes for GROUP BY, DISTINCT, and ORDER BY in one SQL statement. ```sql ALTER SESSION SET MAX_QPX_MEM = 1073741824; -- 1GB ``` ### SET DDL_LOCK_TIMEOUT In Standard Edition, sets DDL lock wait time in seconds. Default `0`; range `0`–`1000000`. At `0`, conflicting DDL returns `ERR-02031: Resource busy ()` immediately without waiting. ```sql ALTER SESSION SET DDL_LOCK_TIMEOUT = 10; -- Wait up to 10 seconds ``` Changing this setting does not alter a running DDL wait. The new value applies to subsequent DDL. Check per-session values in `V$SESSION.DDL_LOCK_TIMEOUT`. ```sql SELECT id, user_name, ddl_lock_timeout FROM v$session WHERE closed = 0 ORDER BY id; ``` See [DDL Concurrency and Locks](../ddl-syntax/#ddl-concurrency) for conflict scope and error handling. ### SET SESSION_IDLE_TIMEOUT_SEC Maximum idle-session connection lifetime in seconds. ```sql ALTER SESSION SET SESSION_IDLE_TIMEOUT_SEC = 300; -- 5 minutes ``` ### SET QUERY_TIMEOUT Maximum query execution wait in seconds. Queries are cancelled automatically when it expires. ```sql ALTER SESSION SET QUERY_TIMEOUT = 60; -- 60 seconds ``` --- ## Related Views | View | Description | |----|------| | `v$session` | Connected sessions and per-session parameters | | `v$storage` | Disk usage, including `DC_TABLE_FILE_SIZE` | | `v$license_info` | Installed license information | | `v$property` | System properties and current values | ```sql -- List sessions SELECT id, user_id, client_type, login_time FROM v$session; -- Check system properties SELECT name, value FROM v$property WHERE name = 'TRACE_LOG_LEVEL'; ``` --- ## Related Documentation - [ALTER SYSTEM Operations Guide](../../../../operations-configuration-recovery/alter-system/) – Procedures and command behavior - [GRANT/REVOKE](../user-auth-syntax/#grant-revoke) – ALTER SYSTEM privileges --- title: "DATABASE" url: https://docs.machbase.com/dbms/reference/sql/syntax/database-syntax/ language: en kind: page --- # DATABASE This reference covers logical database lifecycle and session-selection syntax in Machbase 8.7.0 Standard Edition. Database names identify catalogs, distinct from `machadmin -c` and `machadmin -d`, which manage physical server-instance storage. ## CREATE DATABASE ```sql create_database_stmt ::= 'CREATE DATABASE' ['IF NOT EXISTS'] database_name ``` CREATE DATABASE creates an active logical database in the current Machbase instance. The default access mode is READ WRITE. Users and authentication information are shared instance-wide; tables, views, indexes, and object privileges are managed per database. ```sql CREATE DATABASE factory_a; CREATE DATABASE IF NOT EXISTS factory_b; ``` ## ALTER DATABASE ```sql alter_database_stmt ::= 'ALTER DATABASE' database_name ( 'READ ONLY' | 'READ WRITE' ) ``` READ ONLY databases permit queries but reject write DML, Append, and modifying DDL. Finish active writes before changing the mode. ```sql ALTER DATABASE factory_a READ ONLY; ALTER DATABASE factory_a READ WRITE; ``` ## DROP DATABASE ```sql drop_database_stmt ::= 'DROP DATABASE' ['IF EXISTS'] database_name [ 'RESTRICT' | 'CASCADE' | 'FORCE' | 'CASCADE FORCE' | 'FORCE CASCADE' ] ``` - RESTRICT refuses deletion when objects or active references exist. - CASCADE removes the target database objects, metadata, and database-local grants. - FORCE clears terminable session, statement, cursor, and job references before deletion. - Use CASCADE FORCE to clear both objects and references. The default MACHBASEDB database cannot be dropped. The current session database cannot be dropped either; first execute USE MACHBASEDB or switch to another active database. ## USE ```sql use_database_stmt ::= 'USE' ['DATABASE'] database_name ``` USE and USE DATABASE are equivalent. They change only the current session database and do not affect other connections. They fail during an active transaction or when the target is a mounted database. ```sql USE factory_a; USE DATABASE factory_b; ``` ## Checking the Current Database ```sql SELECT CURRENT_DATABASE(); SELECT DATABASE(); SELECT CURRENT_CATALOG; SHOW CURRENT DATABASE; SHOW DATABASES; ``` CURRENT_DATABASE() is the recommended check. Even if client connection options specify an initial database, query it immediately after connection to verify the actual server catalog. ## Object Names Tables, views, and DML targets accept these forms. ```text table_name -- Current database, current user owner.table_name -- Current database, specified owner database_name.owner.table_name -- Specified database, specified owner ``` Two-part names always mean owner.table. Thus factory_a.sensor_log is not interpreted as database.table. To explicitly reference another database, use three parts, such as factory_a.sys.sensor_log. ```sql SELECT * FROM factory_a.sys.sensor_log; INSERT INTO factory_b.app.orders VALUES (1, 'ready'); ``` Direct cross-database access requires both CONNECT on the target database and the necessary DML privileges on the target table. Index names, LOAD DATA targets, and other statements follow their own qualifier restrictions. ## Privilege Syntax and Database Scope Database and table privileges are separate. The basic forms are: ```sql GRANT CONNECT ON DATABASE factory_a TO app_a; GRANT CREATE, ALTER ON DATABASE factory_a TO deployer; GRANT SELECT, INSERT ON TABLE factory_a.sys.sensor_log TO app_a; REVOKE CONNECT ON DATABASE factory_a FROM app_a; ``` Querying a mounted database requires both USAGE on that database and SELECT on the table. For operational MOUNT DATABASE/UMOUNT DATABASE privileges, see [USER/AUTH Syntax](../user-auth-syntax/#grant-revoke) and [Multidatabase Operations](/dbms/operations-configuration-recovery/multi-database/). ## Relationship to BACKUP/RESTORE Logical database backup/restore syntax is covered in [BACKUP / RESTORE / MOUNT](../backup-restore-mount-syntax/). Only a named backup of one active catalog can be input to logical MOUNT or RESTORE. A full-instance image containing multiple active databases cannot be mounted/restored as a logical catalog. --- title: "AUTO_INCREMENT" url: https://docs.machbase.com/dbms/reference/sql/syntax/auto-increment-syntax/ language: en kind: page --- # AUTO_INCREMENT `AUTO_INCREMENT` is a column property that instructs the server to generate values for a single 64-bit integer PRIMARY KEY. LOOKUP and VOLATILE supported since Machbase 8.7.0 ## Support Scope | Item | Support | |---|---| | Edition | Standard Edition | | Tables | TRANSACTION, LOOKUP, VOLATILE | | Column types | `LONG`, `INT64` | | Key | Single column-level `PRIMARY KEY` | Table-level and composite primary keys are unsupported. Do not combine `PROPERTY(SEQUENCE)` on the same LOOKUP column or use NEXTVAL(). ```sql CREATE TRANSACTION TABLE device_master ( id LONG PRIMARY KEY AUTO_INCREMENT, device_name VARCHAR(80), site_code VARCHAR(32) ); CREATE LOOKUP TABLE lookup_order ( id INT64 PRIMARY KEY AUTO_INCREMENT, item VARCHAR(100) ); CREATE VOLATILE TABLE volatile_order ( id LONG PRIMARY KEY AUTO_INCREMENT, item VARCHAR(100) ); ``` TRANSACTION table DDL cannot run during an explicit transaction. COMMIT or ROLLBACK before creating the table. ## Automatic Value Generation Omit the automatic column or insert NULL to have the server generate a value. ```sql INSERT INTO device_master(device_name, site_code) VALUES ('compressor-01', 'SEOUL-A'); INSERT INTO device_master(id, device_name, site_code) VALUES (NULL, 'pump-02', 'SEOUL-A'); ``` A non-NULL value can also be specified directly. If it is at least the next automatic value, numbering advances beyond it. Smaller values do not move numbering backward. 0 is valid. After INT64_MAX, no more values can be generated and automatic INSERT fails. Do not depend on number reuse after duplicate keys or failed INSERTs. These are row identifiers, not gap-free business sequence numbers. ## Differences by Table Type | Behavior | TRANSACTION | LOOKUP | VOLATILE | |---|:---:|:---:|:---:| | Rows and next automatic value survive restart | Yes | Yes | No | | Explicit transactions | Yes | No | No | | Automatic values in `INSERT ... SELECT` | Yes | No | No | | Single INSERT result ROWID | Yes | Yes | Yes | VOLATILE tables and values disappear on server restart. Only TRANSACTION data migration can use INSERT ... SELECT with the automatic column omitted. ```sql INSERT INTO device_master(device_name, site_code) SELECT device_name, site_code FROM staging_device ORDER BY device_name; ``` ## Checking INSERT Results Supported SDKs can return generated identifiers from successful single INSERT ... VALUES execution results. Batch, Append, loaders, INSERT ... SELECT, and UPSERT do not return a single value. For conditions, see [ROWID](../../rowid/); for language APIs, see [SDK Feature Support](/dbms/development-tools-integration/sdk-support-scope/). ## Related Documentation - [TRANSACTION Table Structure](/dbms/rdb-table-usage/table-structure-schema/) - [LOOKUP Table Structure](/dbms/lookup-table-usage/table-structure-schema/) - [VOLATILE Table Structure](/dbms/volatile-table-usage/table-structure-schema/) - [LOOKUP SEQUENCE](/dbms/lookup-table-usage/sequence-column/) --- title: "EXEC Procedures and ROLLUPGAP" url: https://docs.machbase.com/dbms/reference/sql/syntax/execute-procedure-syntax/ language: en kind: page --- # EXEC Procedures and ROLLUPGAP This reference covers public Machbase table/ROLLUP control procedures and machsql status commands. ## Common EXEC Form ```text execute_procedure_stmt ::= 'EXEC' procedure_name [ '(' argument_list ')' ] ``` Argument counts are fixed for each procedure. Missing names, incorrect argument counts/types, or nonexistent target objects return errors. ## TABLE_FLUSH ```sql EXEC TABLE_FLUSH(table_name); ``` | Item | Contract | |---|---| | Arguments | One table name | | Edition | Standard, Cluster | | Behavior | Explicitly flush pending table storage/input buffers | | Return | Statement success or error; no ResultSet | | Errors | Missing table, denied access, or flush failure | Use when validation or operations require an explicit storage flush. It does not guarantee transaction commit or query visibility. Do not call it for every input row, which increases flush cost. ## INDEX_FLUSH ```sql EXEC INDEX_FLUSH(table_name); EXEC INDEX_FLUSH(table_name, index_name); ``` With only a table name, waits for all index builds on that table to finish. With an index name, targets only that index; an index not belonging to the table causes an error. No ResultSet is returned. ## TABLE_REFRESH ```sql EXEC TABLE_REFRESH(lookup_table_name); ``` | Item | Contract | |---|---| | Arguments | One LOOKUP table name | | Edition | Standard, Cluster | | Behavior | Reload persistent LOOKUP content into the runtime memory table | | Name scope | Current database; owner.table allowed | | Privileges | Table owner or authorized administrative user | | Write restriction | Cannot run in a READ ONLY database | | Return | Statement success or error; no ResultSet | | Errors | Non-LOOKUP target, missing table, or write-admission failure | Before execution, check ongoing LOOKUP changes and query impact. Afterward, query row counts and representative keys again. ## FREEZE_TAG_INDEX and UNFREEZE_TAG_INDEX ```sql EXEC FREEZE_TAG_INDEX(tag_table_name); EXEC UNFREEZE_TAG_INDEX(tag_table_name); ``` These one-argument procedures freeze or unfreeze a TAG table's tag index. Other table types are unsupported. They directly control index-maintenance boundaries and should not be used routinely in ordinary ingestion. After failure, always check whether UNFREEZE_TAG_INDEX was executed. Both return statement success or error without a ResultSet. ## ROLLUP_START and ROLLUP_STOP ```sql EXEC ROLLUP_START; EXEC ROLLUP_START(rollup_name); EXEC ROLLUP_STOP; EXEC ROLLUP_STOP(rollup_name); ``` Both procedures accept zero arguments or one ROLLUP name. A name controls that ROLLUP; omission controls ROLLUPs within the current user scope. Unnamed SYS execution can affect all users, requiring target checks and change approval. A nonexistent ROLLUP, START on an already started target, or STOP on an already stopped target causes an error. Verify the change with V$ROLLUP.RUN_STATE. ## ROLLUP_FORCE ```sql EXEC ROLLUP_FORCE; EXEC ROLLUP_FORCE(rollup_name); ``` The zero-argument form processes the current user's default SEC→MIN→HOUR hierarchy. The named form synchronously waits to catch up to the named ROLLUP source's current END_RID. For a stopped ROLLUP, first ensure it has been started. After completion, check every relevant source-stage gap with V$ROLLUP and SHOW ROLLUPGAP. ## ROLLUP_REBUILD This Standard-only four-argument procedure accepts a tag and time range. Use [ROLLUP_REBUILD](../rollup-rebuild-syntax/) as the authoritative contract. ## SHOW ROLLUPGAP ```sql SHOW ROLLUPGAP; ``` SHOW ROLLUPGAP is a **machsql-only client command**, not server SQL. Do not send it to ordinary JDBC, ODBC, or SDK SQL execution APIs. Standard output includes source/ROLLUP tables, source END_RID, ROLLUP END_RID, GAP, state, and wakeup time. Cluster adds HOSTNAME for per-node state. `GAP = SRC_END_RID - ROLLUP_END_RID`. Every source→ROLLUP row in the hierarchy must be 0 before the entire hierarchy is considered caught up. ## Related Documentation - [ROLLUP Operations and Status](/dbms/tag-rollup-usage/ingestion-control-rollup/) - [V$ROLLUP Reference](/dbms/reference/system-catalog/vrollup/) - [machsql Commands](/dbms/reference/command-line-tools/machsql/) --- title: "16.1.2 Data Type Dictionary" url: https://docs.machbase.com/dbms/reference/sql/types/ language: en kind: section --- # 16.1.2 Data Type Dictionary SQL data types supported by Machbase. Choose a type for the required value range and precision. Values reserved for NULL, such as an integer type's minimum or maximum, cannot be ordinary data. The table's NULL Value column shows internal representations; use SQL NULL to insert and IS NULL to test. ## Data Type Summary | Type | Size | Value Range | NULL Value | |------|------|---------|---------| | `SHORT` | 2 bytes | -32,767 ~ 32,767 | -32,768 | | `USHORT` | 2 bytes | 0 ~ 65,534 | 65,535 | | `INTEGER` | 4 bytes | -2,147,483,647 ~ 2,147,483,647 | -2,147,483,648 | | `UINTEGER` | 4 bytes | 0 ~ 4,294,967,294 | 4,294,967,295 | | `LONG` | 8 bytes | -9,223,372,036,854,775,807 ~ 9,223,372,036,854,775,807 | -9,223,372,036,854,775,808 | | `ULONG` | 8 bytes | 0 ~ 18,446,744,073,709,551,614 | 18,446,744,073,709,551,615 | | `FLOAT` | 4 bytes | 32-bit single-precision floating-point | Maximum positive value | | `DOUBLE` | 8 bytes | 64-bit double-precision floating-point | Maximum positive value | | `DECIMAL(M,D)` | Varies with precision | Exact fixed-point, M: 1–65, D: 0–30 | - | | `ARRAY` | Varies with element type and cardinality | Fixed-length one-dimensional numeric array, cardinality 1–1024 | Whole-array and element NULLs are distinct | | `DATETIME` | 8 bytes | 1970-01-01 – 2262-04-11 (nanosecond precision) | - | | `VARCHAR(n)` | Variable | Up to n bytes (LOG declaration range: 1–32,767) | - | | `IPV4` | 4 bytes | 0.0.0.0 ~ 255.255.255.255 | - | | `IPV6` | 16 bytes | 0000:...:0000 ~ FFFF:...:FFFF | - | | `TEXT` | Variable | 0–64MB (full-text indexing supported) | - | | `BINARY` | Variable | LOG: 0–64MB / TAG: 1–32,767 bytes (fixed length) | - | | `JSON` | Variable | JSON document: 1–32,768 bytes / path: 1–512 bytes | - | --- ## Integer Types ### SHORT Signed 16-bit integer. Storage size matches C int16_t, but the minimum value (-32,768) is reserved for NULL. INT16 is also accepted in SQL. ```sql CREATE LOG TABLE t (c1 SHORT); INSERT INTO t VALUES (-32767); -- Valid minimum INSERT INTO t VALUES (-32768); -- Treated as NULL ``` ### USHORT Unsigned 16-bit integer (uint16_t). The maximum value (65,535) represents NULL. ### INTEGER Signed 32-bit integer. Storage size matches C int32_t, but the minimum is reserved for NULL. INT32 and INT are SQL aliases. ### UINTEGER Unsigned 32-bit integer (uint32_t). ### LONG Signed 64-bit integer. Storage size matches C int64_t, but the minimum is reserved for NULL. INT64 is a SQL alias. ### ULONG Unsigned 64-bit integer (uint64_t). --- ## Floating-point Types ### FLOAT Equivalent to C's 32-bit float. The maximum positive value represents NULL. ### DOUBLE Equivalent to C's 64-bit double. The maximum positive value represents NULL. --- ## Fixed-point Types ### DECIMAL / NUMERIC Exact decimal storage within declared precision and scale. Input with more fractional digits than the declared scale may be rounded. Determine required precision before storing amounts or rates. NUMERIC, DEC, FIXED, and NUMBER are aliases for DECIMAL. ```sql CREATE TRANSACTION TABLE invoice ( id LONG PRIMARY KEY, amount DECIMAL(18,2), rate NUMERIC(7,4) ); ``` DECIMAL means DECIMAL(10,0); DECIMAL(M) means DECIMAL(M,0). For declarations, rounding, indexes, aggregation, and client mappings, see [DECIMAL and NUMERIC Fixed-point Types](decimal-numeric-fixed-point/). --- ## ARRAY Types Machbase DBMS 8.7.0 supports fixed-length, one-dimensional numeric ARRAYs. Specify cardinality after the element type. ```sql CREATE LOG TABLE sensor_array ( id INTEGER, location DOUBLE[2], acceleration FLOAT[3] ); ``` For element types, NULL distinctions, ingestion/query syntax, and SDK representations, see [Numeric ARRAY Types](array/). --- ## Date/Time Types ### DATETIME Internally stores nanoseconds elapsed since midnight on January 1, 1970. Range: 1970-01-01 00:00:00 000:000:000 through 2262-04-11 23:47:16.854:775:807. - Supports nanosecond precision - Internal representation: 8-byte integer (nanoseconds since epoch) - String representation: `YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn` ```sql -- Convert string to DATETIME SELECT TO_DATE('2024-01-15 10:30:00 000:000:000'); -- Convert DATETIME to string SELECT TO_CHAR(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t; ``` --- ## String Types ### VARCHAR(n) Variable-length string. n is the storage limit in bytes, not characters. The LOG declaration range is 1–32,767. UTF-8 characters vary in byte length, so account for encoded size when storing Korean text, emoji, and other multibyte characters. ```sql CREATE LOG TABLE t (name VARCHAR(100), description VARCHAR(1000)); ``` ### TEXT Stores large text beyond VARCHAR capacity, up to 64MB. Distinguish text storage support from KEYWORD index support; index availability depends on table type. - Supported in LOG and Standard Edition TRANSACTION tables - LOG supports keyword search with KEYWORD indexes and SEARCH - Not supported in TAG, LOOKUP, or VOLATILE ORDER BY and GROUP BY cannot operate directly on LOG TEXT columns. This is a query validation constraint, not merely a performance recommendation. Store device IDs, error codes, severity, and other sort/group keys in separate VARCHAR or numeric columns. Using MODIFY COLUMN to change TEXT to VARCHAR is also unsupported. ```sql CREATE LOG TABLE log_table (ts DATETIME, message TEXT); -- Create a keyword index CREATE INDEX idx_msg ON log_table (message) INDEX_TYPE KEYWORD; ``` --- ## Binary Types ### BINARY Stores unstructured binary data such as images and documents. - **LOG**: Variable length, up to 64MB - **TRANSACTION**: Variable-length binary values (Standard Edition) - **TAG**: Fixed-length BINARY(n) variant, 1–32,767 bytes - Not supported in LOOKUP or VOLATILE TAG BINARY(n): - Supports X'...', B'...', and O'...' literals, including lowercase prefixes - Supports '0x...' for compatibility - Exceeding the declared length causes ERR-02233 --- ## Network Address Types ### IPV4 Stores IPv4 addresses in 4 bytes, ranging from 0.0.0.0 through 255.255.255.255. ```sql CREATE LOG TABLE access_log (ts DATETIME, src_ip IPV4, dst_ip IPV4); INSERT INTO access_log VALUES (NOW, '192.168.0.1', '10.0.0.1'); SELECT * FROM access_log WHERE src_ip = TO_IPV4('192.168.0.1'); ``` ### IPV6 Stores IPv6 addresses in 16 bytes. Abbreviated notation is supported. - `"::FFFF:1232"` — Omitted leading zeros - `"::FFFF:192.168.0.3"` — IPv4-compatible notation - `"::192.168.3.1"` — IPv4-compatible notation (deprecated) ```sql CREATE LOG TABLE v6_log (ts DATETIME, src_ip IPV6); INSERT INTO v6_log VALUES (NOW, '21DA:D3:0:2F3B:2AA:FF:FE28:9C5A'); ``` --- ## JSON Type Stores JSON documents as text containing key-value pairs. - Maximum data size: 32,768 bytes - Maximum JSON path length: 512 bytes - Supported in TAG, LOG, LOOKUP, and TRANSACTION - VOLATILE cannot create JSON columns - LOOKUP JSON columns cannot be primary keys ```sql CREATE LOG TABLE sensor_data ( ts DATETIME, data JSON ); INSERT INTO sensor_data VALUES (NOW, '{"temp":23.5,"hum":60}'); SELECT data -> 'temp' AS temperature FROM sensor_data; ``` For details by table type, see [JSON Support by Table Type](table-types-type-support-scope-json/). --- ## SQL Data Type Mappings Mappings between Machbase types, SQL standard types, and C types. | Machbase Type | Machbase CLI Type | SQL Type | C Type | Native C Type | |--------------|------------------|----------|--------|------------| | `short` | SQL_SMALLINT | SQL_SMALLINT | SQL_C_SSHORT | `int16_t` | | `ushort` | SQL_USMALLINT | SQL_SMALLINT | SQL_C_USHORT | `uint16_t` | | `integer` | SQL_INTEGER | SQL_INTEGER | SQL_C_SLONG | `int32_t` | | `uinteger` | SQL_UINTEGER | SQL_INTEGER | SQL_C_ULONG | `uint32_t` | | `long` | SQL_BIGINT | SQL_BIGINT | SQL_C_SBIGINT | `int64_t` | | `ulong` | SQL_UBIGINT | SQL_BIGINT | SQL_C_UBIGINT | `uint64_t` | | `float` | SQL_FLOAT | SQL_REAL | SQL_C_FLOAT | `float` | | `double` | SQL_DOUBLE | SQL_FLOAT, SQL_DOUBLE | SQL_C_DOUBLE | `double` | | `decimal` | SQL_DECIMAL | SQL_DECIMAL, SQL_NUMERIC | SQL_C_NUMERIC | decimal-preserving value | | `datetime` | SQL_TIMESTAMP | SQL_TYPE_TIMESTAMP | SQL_C_TYPE_TIMESTAMP | `char *` (YYYY-MM-DD ...) | | `varchar` | SQL_VARCHAR | SQL_VARCHAR | SQL_C_CHAR | `char *` | | `ipv4` | SQL_IPV4 | SQL_VARCHAR | SQL_C_CHAR | `char *` (IP string) | | `ipv6` | SQL_IPV6 | SQL_VARCHAR | SQL_C_CHAR | `char *` (IP string) | | `text` | SQL_TEXT | SQL_LONGVARCHAR | SQL_C_CHAR | `char *` | | `binary` | SQL_BINARY | SQL_BINARY | SQL_C_BINARY | `char *` | | `json` | SQL_JSON | SQL_JSON | SQL_C_CHAR | `json_t` | --- ## Supported Data Types by Table Type | Type | TAG | LOG | LOOKUP | VOLATILE | TRANSACTION | |------|:---:|:---:|:------:|:--------:|:---:| | SHORT | O | O | O | O | O | | USHORT | O | O | O | O | O | | INTEGER | O | O | O | O | O | | UINTEGER | O | O | O | O | O | | LONG | O | O | O | O | O | | ULONG | O | O | O | O | O | | FLOAT | O | O | O | O | O | | DOUBLE | O | O | O | O | O | | DECIMAL / NUMERIC | O | O | O | O | O | | DATETIME | O | O | O | O | O | | VARCHAR | O | O | O | O | O | | IPV4 | O | O | O | O | O | | IPV6 | O | O | O | O | O | | TEXT | X | O | X | X | O | | JSON | O | O | O | X | O | | BINARY | O (fixed length) | O | X | X | O | DECIMAL is supported in all public table types. TRANSACTION tables are available in Standard Edition. Cluster Edition supports DECIMAL columns in LOG/TAG tables and DDL propagation. --- title: "JSON Support by Table Type" url: https://docs.machbase.com/dbms/reference/sql/types/table-types-type-support-scope-json/ language: en kind: page --- # JSON Support by Table Type Support scope for JSON columns in each table type. ## Support Summary | Table Type | JSON Columns | JSON Path Queries | JSON PK | Notes | |------------|:-------------:|:---------------:|:-------:|------| | TAG | O | O | X | JSON columns and functions supported; PK not supported | | LOG | O | O | X | JSON columns and functions supported | | LOOKUP | O | O | X | Ordinary columns supported; JSON path indexes not supported | | VOLATILE | X | X | X | Cannot create JSON columns | | TRANSACTION | O | O | X | JSON columns and functions supported | ## LOOKUP Tables LOOKUP supports JSON as an ordinary column. ```sql CREATE LOOKUP TABLE config_lookup ( key VARCHAR(64) PRIMARY KEY, site VARCHAR(32), config JSON ); INSERT INTO config_lookup VALUES ( 'device-001', 'SEOUL', '{"region":"kr","level":3,"state":"ready"}' ); SELECT key FROM config_lookup WHERE config->'$.region' = 'kr' AND JSON_EXTRACT_INTEGER(config, '$.level') >= 3; ``` Update JSON columns with JSON_SET, JSON_SET_JSON, JSON_REMOVE, and other JSON functions. ```sql UPDATE config_lookup SET config = JSON_SET(config, '$.state', 'active') WHERE site = 'SEOUL'; ``` JSON columns cannot be declared as primary keys. ```sql -- Error CREATE LOOKUP TABLE invalid_lookup ( config JSON PRIMARY KEY ); ``` ## VOLATILE Tables VOLATILE does not support JSON column creation. ```sql CREATE VOLATILE TABLE session_data ( session_id VARCHAR(64) PRIMARY KEY, payload JSON ); ``` ## JSON Functions by Table Type | Function/Operator | TAG | LOG | LOOKUP | VOLATILE | TRANSACTION | |-------------|:---:|:---:|:------:|:--------:|:---:| | `->` operator | O | O | O | X | O | | `JSON_EXTRACT*` | O | O | O | X | O | | `JSON_TYPEOF` | O | O | O | X | O | | `JSON_IS_VALID` | O | O | O | O | O | | `JSON_SET` | O | O | O | X | O | | `JSON_SET_JSON` | O | O | O | X | O | | `JSON_REMOVE` | O | O | O | X | O | ## Usage Notes - Write JSON paths as single-quoted strings, such as '$.key'. - Use typed functions such as JSON_EXTRACT_INTEGER or JSON_EXTRACT_DOUBLE for numeric comparisons. - LOOKUP does not support dedicated JSON path indexes. Extract frequently searched values into separate columns. --- title: "DECIMAL and NUMERIC Fixed-point Types" url: https://docs.machbase.com/dbms/reference/sql/types/decimal-numeric-fixed-point/ language: en kind: page --- # DECIMAL and NUMERIC Fixed-point Types DECIMAL stores decimal values exactly. NUMERIC, DEC, FIXED, and NUMBER are aliases; DESC, SHOW, and result metadata display the canonical name DECIMAL. NUMBER is a Machbase compatibility extension, not a MySQL alias. ## Declaration Syntax ```sql DECIMAL DECIMAL(precision) DECIMAL(precision, scale) NUMERIC NUMERIC(precision) NUMERIC(precision, scale) ``` | Declaration | Interpretation | |------|------| | `DECIMAL` | `DECIMAL(10,0)` | | `DECIMAL(M)` | `DECIMAL(M,0)` | | `DECIMAL(M,D)` | precision `M`, scale `D` | - Precision is the total number of significant digits, from 1 through 65. - Scale is the number of fractional digits, from 0 through 30. - Scale cannot exceed precision. - UNSIGNED and ZEROFILL are not supported. ```sql CREATE TRANSACTION TABLE invoice ( invoice_id LONG PRIMARY KEY, amount DECIMAL(18,2), tax_rate NUMERIC(7,4) ); ``` ## Rounding and Overflow Input with more fractional digits than scale is rounded half away from zero. ```sql CREATE TRANSACTION TABLE decimal_rounding ( id INTEGER PRIMARY KEY, amount DECIMAL(5,2) ); INSERT INTO decimal_rounding VALUES (1, 1.235); -- 1.24 INSERT INTO decimal_rounding VALUES (2, -1.235); -- -1.24 ``` Values exceeding precision cause errors rather than truncation or floating-point conversion. DECIMAL NULL is managed separately from the value, without a numeric sentinel. ## Support by Table Type | Table Type | DECIMAL Columns | Main Uses | |------------|:------------:|----------------| | LOG | O | Monetary/settlement events and exact aggregation | | TAG | O | Exact measurements and aggregate data columns | | VOLATILE | O | State/cache values and primary keys | | LOOKUP | O | Reference amounts/rates, primary keys, and secondary indexes | | TRANSACTION | O | Relational business data and PK/UNIQUE/ordinary indexes | ```sql CREATE LOG TABLE payment_log ( occurred_at DATETIME, amount DECIMAL(18,2) ); CREATE TAG TABLE meter_value ( name VARCHAR(80) PRIMARY KEY, time DATETIME BASETIME, value DECIMAL(24,6) ); CREATE VOLATILE TABLE exchange_cache ( rate_key DECIMAL(12,6) PRIMARY KEY, label VARCHAR(32) ); CREATE LOOKUP TABLE price_rule ( rule_id LONG PRIMARY KEY, amount DECIMAL(18,2) ); ``` Cluster Edition supports DECIMAL columns in LOG/TAG tables and DDL propagation. TRANSACTION tables remain exclusive to Standard Edition regardless of DECIMAL support. ## Comparison and Indexes All table engines use the same DECIMAL comparison rules. Numerically equal values compare equal regardless of their represented scale. ```sql -- 1, 1.0, and 1.00 are equal in equality, PK, and UNIQUE comparisons. SELECT * FROM price_rule WHERE amount = 1.00; ``` DECIMAL is supported in VOLATILE/LOOKUP primary key memory indexes and TRANSACTION ordinary, UNIQUE, and PRIMARY KEY indexes. TRANSACTION indexes use the same numeric ordering for equality, ranges, and sorting. Derived VIEW columns preserve DECIMAL precision and scale. Check them separately through DESC, SHOW, M$SYS_COLUMNS, and client result metadata. ## Expressions and Aggregates DECIMAL values support +, -, *, /, ROUND, TRUNC, [CAST](../../functions/functions-full/#cast), and the following aggregate and ordering operations. - `SUM`, `AVG`, `MIN`, `MAX` - `GROUP BY`, `ORDER BY`, `DISTINCT` Advanced statistics, percentile functions, TOP_K, and other operations without an exact DECIMAL path convert to DOUBLE, so results may be approximate. ## Input/Output and Client Mappings machloader .fmt files, CSV import/export, and Append preserve sign, NULL, precision, and scale. Pass values as strings or language-native decimal types, without converting through floating-point types. | Interface | Recommended Mapping | |-----------|-----------| | ODBC | `SQL_DECIMAL` / `SQL_NUMERIC`, `SQL_C_NUMERIC` | | JDBC | `java.math.BigDecimal` | | Python | `decimal.Decimal` | | Node.js | Decimal-compatible string or connector decimal representation | | .NET | `decimal`, `DbType.Decimal` | For Go NUMERIC values, also use the connector's decimal-preserving value or string representation instead of converting to float64. ## Choosing a Type - Use DECIMAL for exact decimal currency, tax rates, and settlement amounts. - Use FLOAT or DOUBLE when approximation and a wide exponent range matter, such as sensor values. - Converting DECIMAL to DOUBLE during storage, comparison, or calculation loses exact fixed-point semantics. --- title: "Numeric ARRAY Types" url: https://docs.machbase.com/dbms/reference/sql/types/array/ language: en kind: page --- # Numeric ARRAY Types Machbase DBMS 8.7.0 supports fixed-length, one-dimensional ARRAYs containing a fixed number of values of the same numeric type. Use them to store multiple numeric values in one row, such as sensor coordinates or per-axis measurements, and query individual elements. For sparse input and selected-column Append APIs, see [Sparse ARRAY and Selected-column Append APIs](../../../../development-tools-integration/data-input-load-export/array-append/). ## Supported Types and Declaration Limits Append [cardinality] to the numeric element type when declaring a column. Cardinality is the fixed number of elements declared for the column, not the number of non-NULL elements in each row. A missing entire array (whole-array NULL) differs from a missing value at a particular position (element NULL). | Element Type | DDL Example | Description | |---|---|---| | `INT16` | `INT16[4]` | Signed 16-bit integer | | `UINT16` | `UINT16[4]` | Unsigned 16-bit integer | | `INT32` | `INT32[4]` | Signed 32-bit integer | | `UINT32` | `UINT32[4]` | Unsigned 32-bit integer | | `INT64` | `INT64[4]` | Signed 64-bit integer | | `UINT64` | `UINT64[4]` | Unsigned 64-bit integer | | `FLOAT` | `FLOAT[4]` | Single-precision floating-point | | `DOUBLE` | `DOUBLE[4]` | Double-precision floating-point | | `DECIMAL(p,s)` | `DECIMAL(12,4)[4]` | Fixed-point number | - Cardinality ranges from 1 through 1024. - DECIMAL precision ranges from 1 through 65. - DECIMAL scale ranges from 0 through 30 and cannot exceed precision. The following aliases map to their canonical element types. | Alias | Canonical Type | |---|---| | `SHORT` | `INT16` | | `USHORT` | `UINT16` | | `INT`, `INTEGER` | `INT32` | | `UINTEGER` | `UINT32` | | `LONG` | `INT64` | | `ULONG` | `UINT64` | | `NUMERIC`, `DEC`, `FIXED`, `NUMBER` | `DECIMAL` | ## Creating Tables and Adding Columns This example stores four channel values, three counters, and two fixed-point values. ```sql CREATE LOG TABLE SENSOR_ARRAY ( ID INTEGER, CHANNELS DOUBLE[4], COUNTERS UINT64[3], AMOUNTS DECIMAL(12,4)[2] ); ``` For tables that already support ADD COLUMN, add columns using the same ARRAY declaration and remove them with the existing DROP COLUMN syntax. ```sql ALTER TABLE SENSOR_ARRAY ADD COLUMN (STATUS_VALUES INT32[3]); ALTER TABLE SENSOR_ARRAY ADD COLUMN (LIMITS DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]); ALTER TABLE SENSOR_ARRAY DROP COLUMN (STATUS_VALUES); ALTER TABLE SENSOR_ARRAY DROP COLUMN (LIMITS); ``` Omitting scale, as in DECIMAL(12)[2], means DECIMAL(12,0)[2]. For TAG METADATA ARRAYs, use METADATA ADD COLUMN and METADATA DROP COLUMN. ```sql ALTER TABLE SENSOR_TAG METADATA ADD COLUMN (LIMITS DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]); ALTER TABLE SENSOR_TAG METADATA DROP COLUMN (LIMITS); ``` ARRAY is supported in ordinary data columns in the following locations. - LOG tables - Ordinary TAG DATA columns - Ordinary TAG METADATA columns - VOLATILE tables - LOOKUP tables - Standard Edition TRANSACTION tables Adding ARRAY does not expand a table's existing DML scope. LOG UPDATE remains unsupported, and TAG UPDATE is limited to the existing allowed DATA or METADATA paths. ### ADD COLUMN Support | Edition | Table or Column Area | ARRAY ADD/DROP | |---|---|:---:| | Standard | LOG | O | | Standard | VOLATILE | O | | Standard | LOOKUP | O | | Standard | TRANSACTION | O | | Standard | TAG METADATA | O | | Standard | Ordinary TAG DATA columns | X | | Cluster | LOG | O | | Cluster | Other tables or TAG METADATA | X | Ordinary TAG DATA ARRAY columns can be declared in CREATE TABLE, but cannot be added with ALTER. ### DEFAULT and Existing Rows - Without DEFAULT, the new ARRAY column is whole-array NULL for rows existing before ALTER. - LOG, LOOKUP, TRANSACTION, and TAG METADATA apply an explicit ARRAY DEFAULT to existing rows. - Like scalar ADD COLUMN, VOLATILE does not rewrite existing rows with DEFAULT, so the new ARRAY column is whole-array NULL. - Cluster LOG applies an explicit ARRAY DEFAULT to existing rows. - The DEFAULT constructor must contain exactly the declared number of elements. If a new tag is registered automatically by TAG DATA INSERT or Append after ALTER, the new metadata row does not receive the ADD COLUMN DEFAULT. Added ARRAY metadata columns are whole-array NULL. This DEFAULT applies only to metadata rows that existed before ALTER. ARRAY cannot be used for the following roles. - PRIMARY KEY, UNIQUE, or ordinary index keys - `AUTO_INCREMENT`, `SEQUENCE` - TAG NAME, BASETIME, BASE DISTANCE, or SUMMARIZED columns TAG METADATA ARRAY columns do not receive automatic indexes, and explicit indexes are not supported. The following declarations are not supported. ```sql INT32[] INT32[0] INT32[1025] VARCHAR[4] INT32[2][3] DECIMAL[4](12,4) ``` ## Inserting ARRAY Values Both ARRAY[...] and shorthand [...] are supported. ```sql INSERT INTO SENSOR_ARRAY VALUES (1, ARRAY[1.5, NULL, 3.5, 4.5], [1, NULL, 3], [12.3400, NULL]); INSERT INTO SENSOR_ARRAY VALUES (2, [10.0, 20.0, 30.0, 40.0], [4, 5, 6], [1.2500, 2.5000]); INSERT INTO SENSOR_ARRAY VALUES (3, NULL, NULL, NULL); ``` The constructor element count must exactly match the target column's cardinality. A mismatch fails the statement rather than padding or truncating. Empty [] and ARRAY[] cannot be stored as zero-cardinality values. Each element follows the target numeric type's conversion, sign, range, and DECIMAL precision/scale rules. If any element cannot be converted, the entire statement fails; no partial ARRAY is stored. ### Numeric Ranges Integer types cannot store internal NULL sentinel values as actual data. | Type | Storable Range | |---|---| | `INT16` | `-32767..32767` | | `UINT16` | `0..65534` | | `INT32` | `-2147483647..2147483647` | | `UINT32` | `0..4294967294` | | `INT64` | `-9223372036854775807..9223372036854775807` | | `UINT64` | `0..18446744073709551614` | The reserved maximum finite NULL sentinels of FLOAT and DOUBLE also cannot be actual elements. Infinity handling for larger inputs follows the corresponding scalar type. ### Type Inference Without a Target Without a target column, as in SELECT [1,2,3], a common type is inferred from all elements. - If all non-NULL elements have one type, preserve that type. - Promote signed/unsigned integers to the smallest integer type that holds all values. - Signed integers mixed with UINT64 use DECIMAL(20,0). - DECIMAL inputs combine required integer digits and scale. - FLOAT alone remains FLOAT; mixed with other numeric types, it promotes to DOUBLE. - Empty arrays, all-NULL arrays, nonnumeric elements, and nested arrays cause inference errors. With a target column, as in INSERT, UPDATE, or a prepared parameter, validate each element against the target's element type, cardinality, and DECIMAL metadata. ### Whole-array NULL and Element NULL A NULL ARRAY and an ARRAY containing NULL elements are distinct values. ```sql -- The entire ARRAY is NULL. INSERT INTO SENSOR_ARRAY (ID, CHANNELS) VALUES (10, NULL); -- The ARRAY exists and all four elements are NULL. INSERT INTO SENSOR_ARRAY (ID, CHANNELS) VALUES (11, [NULL, NULL, NULL, NULL]); ``` NOT NULL constrains only the entire ARRAY value. An ARRAY whose elements are all NULL can therefore be inserted into a NOT NULL column. ## Querying Elements Element positions start at 0. For cardinality 4, valid positions are 0 through 3. ```sql SELECT CHANNELS, CHANNELS[0] AS FIRST_CHANNEL, CHANNELS[3] AS LAST_CHANNEL, CHANNELS[4] AS OUT_OF_RANGE FROM SENSOR_ARRAY; ``` The following cases return SQL NULL rather than an error. - Negative index or index at least equal to cardinality - SQL NULL index expression - Whole-array NULL - NULL element at the position {{< callout type="warning" >}} An element [position] can follow only a simple, unquoted column name. A[0] is supported; T.A[0] and "A"[0] are not supported. {{< /callout >}} ## ARRAY_LENGTH ARRAY_LENGTH() returns the declared cardinality unless the entire array is NULL. ```sql SELECT ID, ARRAY_LENGTH(CHANNELS) FROM SENSOR_ARRAY; ``` It returns cardinality even if all elements are NULL. A whole-array NULL returns NULL. ARRAY_LENGTH(NULL) without type information causes an error because the argument type cannot be determined. ## Whole-array CAST Convert every element of a numeric ARRAY to another type with the same cardinality using CAST(array_expression AS TYPE[N]). ```sql SELECT CAST(CHANNELS AS INT32[4]) FROM SENSOR_ARRAY; SELECT CAST(AMOUNTS AS DECIMAL(10,2)[2]) FROM SENSOR_ARRAY; ``` - Input must be a numeric ARRAY or SQL NULL. - Targets can use the numeric element types and aliases in this document. - Input and target cardinalities must match exactly. - Whole-array NULL and each element NULL are preserved. - Each non-NULL element follows the corresponding scalar CAST numeric conversion rules. - DECIMAL[N] means DECIMAL(10,0)[N]; DECIMAL(p)[N] means DECIMAL(p,0)[N]. - If any element violates range or conversion rules, CAST and the containing statement fail. In prepared statements, the CAST target determines parameter and result element types, cardinality, and DECIMAL precision/scale. Rebind the same statement with ARRAY values, whole-array NULL, or sparse ARRAYs specifying selected positions. ```sql SELECT CAST(? AS INT32[3]); SELECT CAST(? AS DECIMAL(12,4)[3]); ``` To combine ARRAY results in CASE and UNION ALL, element type, cardinality, and DECIMAL precision/scale must all match. Otherwise, explicitly CAST to the same ARRAY type before combining. The following conversions are unsupported. - Scalar expansion to ARRAY - ARRAY reduction to scalar - Padding/truncation between different cardinalities - String, date, IP, BINARY, or JSON ARRAY targets For full syntax, numeric conversion, and error rules, see [CAST](../../functions/functions-full/#cast). ## Comparisons and Expressions Whole ARRAYs support `=`, `<>`, `IS NULL`, and `IS NOT NULL`. Element NULLs in corresponding positions match in whole-array equality comparisons. Whole-array NULL follows ordinary SQL NULL rules. ```sql SELECT ID FROM SENSOR_ARRAY WHERE CHANNELS = [1.5, NULL, 3.5, 4.5] OR CHANNELS[1] IS NULL; ``` Element expressions can appear in ordinary expressions and predicates of the corresponding numeric type. Whole ARRAYs are unsupported in the following locations. - `DISTINCT` - `GROUP BY` - `ORDER BY` - DISTINCT arguments to aggregate functions ## VIEW, INSERT SELECT, CASE, and Upsert VIEW and INSERT ... SELECT preserve element type, cardinality, and DECIMAL precision/scale. When inserting into a different numeric ARRAY type, each element converts to the target type; if any conversion fails, the entire statement fails. CASE results in INSERT and UPDATE also follow the target ARRAY contract. ```sql UPDATE SENSOR_LOOKUP SET AMOUNTS = CASE WHEN ID = 1 THEN [12345678.1234, NULL] ELSE AMOUNTS END WHERE ID = 1; ``` For LOOKUP/VOLATILE duplicate-key upserts, direct ARRAY values, constant CASE expressions, and prepared whole-array binds use the same conversion rules. Whether an upsert right-hand expression can reference existing row columns follows the table's existing policy. ## Metadata and Display Format DESC and SQL export display canonical declarations. ```sql DESC SENSOR_ARRAY; ``` System catalogs preserve ARRAY type code, cardinality, precision, and scale as separate fields. SQLColumns() in SQLCLI or ODBC returns the following. - `DATA_TYPE`: `SQL_MACHBASE_ARRAY` - TYPE_NAME: Canonical declaration such as INT32[3] or DECIMAL(12,4)[2] - `COLUMN_SIZE`: cardinality - DECIMAL_DIGITS: DECIMAL element scale Paths requiring textual results, such as machsql, generic ODBC text queries, and Go database/sql, use [value,null,value]. Lowercase null is an element NULL; SQL NULL for the column result is a whole-array NULL. ## Reading and Writing ARRAYs with SDKs The following examples share this table and data. ```sql CREATE LOG TABLE SDK_ARRAY_SAMPLE ( ID INTEGER, A_I32 INT32[3], A_U64 UINT64[3], A_DEC DECIMAL(12,4)[3] ); INSERT INTO SDK_ARRAY_SAMPLE VALUES (1, [1,NULL,-3], [1,NULL,18446744073709551614], [1.2500,NULL,-3.7500]); INSERT INTO SDK_ARRAY_SAMPLE (ID) VALUES (2); ``` SDKs represent whole-array NULL with their NULL value and element NULL with NULL inside the collection. Use SDK types that preserve UINT64 and DECIMAL precision. ### C SQLCLI Use SQL_C_MACHBASE_ARRAY and SQL_MACHBASE_ARRAY_DESC for typed fetch. ```c SQLINTEGER values[3] = {0}; SQLLEN elements[3] = {0}; SQLLEN outer = 0; SQL_MACHBASE_ARRAY_DESC array = {0}; array.struct_size = sizeof(array); array.element_c_type = SQL_C_SLONG; array.capacity = 3; array.values = values; array.element_indicators = elements; SQLExecDirect(stmt, (SQLCHAR*)"SELECT A_I32 FROM SDK_ARRAY_SAMPLE WHERE ID=1", SQL_NTS); SQLBindCol(stmt, 1, SQL_C_MACHBASE_ARRAY, &array, sizeof(array), &outer); SQLFetch(stmt); /* outer != SQL_NULL_DATA, array.count == 3, * values[0] == 1, elements[1] == SQL_NULL_DATA, values[2] == -3 */ ``` For whole-array NULL, outer == SQL_NULL_DATA and array.count == 0. Provide element_indicators to distinguish element NULLs. To fetch DECIMAL as strings, set element_c_type = SQL_C_CHAR and value_stride to the spacing between element buffers. For prepared INSERT, set capacity, count, and ColumnSize to the target cardinality. ```c array.count = 3; SQLPrepare(stmt, (SQLCHAR*)"INSERT INTO SDK_ARRAY_SAMPLE(ID,A_I32) VALUES(3,?)", SQL_NTS); SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_MACHBASE_ARRAY, SQL_MACHBASE_ARRAY, 3, 0, &array, sizeof(array), &outer); SQLExecute(stmt); ``` Set outer = SQL_NULL_DATA for whole-array NULL input. ARRAY parameter-set execution is currently unsupported and returns HYC00. Legacy SQLAppendBatch also lacks an ARRAY type code and does not support ARRAY, but does not guarantee the same SQLSTATE. ### C++ C++ uses the SQLCLI descriptor ABI directly. Keep vector size fixed so its address remains stable from bind until fetch completes. ```cpp std::vector values(3); std::vector indicators(3); SQLLEN outer = 0; SQL_MACHBASE_ARRAY_DESC array{}; array.struct_size = sizeof(array); array.element_c_type = SQL_C_SLONG; array.capacity = values.size(); array.values = values.data(); array.element_indicators = indicators.data(); SQLBindCol(stmt, 1, SQL_C_MACHBASE_ARRAY, &array, sizeof(array), &outer); ``` In the application model, represent whole-array NULL with the outer optional in `std::optional>>` and element NULL with an inner optional. ### Machbase ODBC and Generic ODBC ODBC C programs using Machbase headers use the same ARRAY descriptor as C SQLCLI. Generic tools that do not recognize the custom type can query canonical text or project individual elements. ```sql SELECT ID, A_I32, A_I32[1], A_I32[2], A_I32[3] FROM SDK_ARRAY_SAMPLE ORDER BY ID; ``` ### JDBC JDBC returns java.sql.Array. UINT64 uses BigInteger and DECIMAL uses BigDecimal to preserve precision. ```java try (Connection con = DriverManager.getConnection( "jdbc:machbase://127.0.0.1:5656/machbasedb", "SYS", "MANAGER"); Statement st = con.createStatement(); ResultSet rs = st.executeQuery( "SELECT A_I32 FROM SDK_ARRAY_SAMPLE ORDER BY ID")) { rs.next(); java.sql.Array sqlArray = rs.getArray(1); Object[] values = (Object[])sqlArray.getArray(); // [Integer(1), null, Integer(-3)] rs.next(); assert rs.getArray(1) == null && rs.wasNull(); } ``` JDBC metadata reports Types.ARRAY, precision as cardinality, and DECIMAL scale as the element scale. Pass values created with Connection.createArrayOf() to PreparedStatement.setArray(). ### Python Python returns ARRAY as list, element NULL as None inside the list, and whole-array NULL as None for the column. UINT64 uses arbitrary-precision int; DECIMAL uses Decimal. ```python from decimal import Decimal from machbaseAPI import connect conn = connect(host="127.0.0.1", port=5656, user="SYS", password="MANAGER") try: rows = conn.cursor(dictionary=True).execute( "SELECT A_I32,A_U64,A_DEC FROM SDK_ARRAY_SAMPLE ORDER BY ID" ).fetchall() assert rows[0]["A_I32"] == [1, None, -3] assert rows[0]["A_U64"][2] == 18446744073709551614 assert rows[0]["A_DEC"][0] == Decimal("1.2500") assert rows[1]["A_I32"] is None finally: conn.close() ``` Prepared execute() and executemany() encode list or tuple values as ARRAY. Check ARRAY type code, cardinality, and DECIMAL element metadata in cursor.column_metadata. ### Node.js Node.js returns ARRAY as JavaScript Array. INT64 and UINT64 use bigint; DECIMAL uses strings to preserve precision. ```javascript const { createConnection } = require('@machbase/ts-client'); const conn = createConnection({ host: '127.0.0.1', port: 5656, user: 'SYS', password: 'MANAGER', }); await conn.connect(); try { const [rows] = await conn.query( 'SELECT A_I32,A_U64,A_DEC FROM SDK_ARRAY_SAMPLE ORDER BY ID', ); console.log(rows[0].A_I32); // [1, null, -3] console.log(rows[0].A_U64); // [1n, null, 18446744073709551614n] console.log(rows[1].A_I32); // null: whole NULL } finally { await conn.end(); } ``` Convert bigint to strings before JSON.stringify(), and do not coerce DECIMAL strings to Number. A prepared statement's getColumns() exposes ARRAY cardinality and element precision/scale metadata. ### .NET full/legacy provider MachConnector40 full/legacy providers return ARRAY as object[]. Element NULL is null inside the array; use IsDBNull() to distinguish whole-array NULL. ```csharp using Mach.Data.MachClient; using var conn = new MachConnection( "SERVER=127.0.0.1;PORT_NO=5656;UID=SYS;PWD=MANAGER"); conn.Open(); using var cmd = new MachCommand( "SELECT A_I32 FROM SDK_ARRAY_SAMPLE ORDER BY ID", conn); using var reader = cmd.ExecuteReader(); reader.Read(); var values = (object[])reader.GetValue(0); Console.WriteLine((int)values[0]); Console.WriteLine(values[1] is null); reader.Read(); Console.WriteLine(reader.IsDBNull(0)); ``` Elements use short, ushort, int, uint, long, ulong, float, double, or decimal. Values outside CLR decimal range are returned as invariant strings. GetSchemaTable() provides provider type, cardinality, element scale, and object[] field type. ### Go neo-client This section covers the neo-client SDK connecting directly to Machbase DBMS, not a Machbase Neo server. The 0-based ARRAY API is in the v2 module source after [`neo-client` PR #17](https://github.com/machbase/neo-client/pull/17). Until a public v2 release is specified, use that source checkout with an explicit local module connection such as go.work or replace. Do not assume public v1 releases contain the feature. ```go import ( "context" "database/sql" "fmt" client "github.com/machbase/neo-client/v2" "github.com/machbase/neo-client/v2/api" ) db, err := sql.Open(client.DefaultDriverName, dsn) if err != nil { return err } defer db.Close() dense, err := api.NewArray(api.SqlTypeInt32, int32(10), nil, int32(30)) if err != nil { return err } if _, err = db.ExecContext(context.Background(), "INSERT INTO SDK_ARRAY_SAMPLE(ID,A_I32) VALUES(3,?)", dense); err != nil { return err } rows, err := db.QueryContext(context.Background(), "SELECT A_I32 FROM SDK_ARRAY_SAMPLE WHERE ID=3") if err != nil { return err } defer rows.Close() for rows.Next() { var raw sql.NullString if err := rows.Scan(&raw); err != nil { return err } fmt.Println(raw.String) // [10,null,30] } return rows.Err() ``` database/sql returns canonical strings. Use sql.NullString to check whole-array NULL, then parse valid values with array.Scan(raw.String), or whole-array NULL with array.Scan(nil). To preserve original narrow integer and FLOAT types, create the receiver from element metadata first. Set DECIMAL precision/scale with NewSparseArrayWithMeta(). ColumnTypes().DatabaseTypeName() provides the ARRAY type name; DecimalSize() provides DECIMAL element precision/scale. Length() currently reports encoded payload byte length, not cardinality, and must not be used as cardinality. Standard database/sql metadata does not directly provide cardinality. ## Command-line Tools and Data Movement ### machsql machsql prints canonical ARRAY strings. ```sql SELECT ID, CHANNELS, ARRAY_LENGTH(CHANNELS), CHANNELS[1] FROM SENSOR_ARRAY ORDER BY ID; ``` Save the SQL to a file and run it as follows. ```bash machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER -f array_query.sql ``` ### machloader machloader text input/output uses canonical [value,null,value] format. Because delimiters or quotes may occur within an ARRAY, enclose ARRAY fields in CSV. ```csv 1,"[1.5,null,3.5,4.5]" ``` Verify by round trip that whole-array NULL and all-element-NULL ARRAY remain distinct. CSV automatic table creation does not infer ARRAY, so create the table explicitly before importing. ### Backup, Restore, and Mount Backup and restore preserve element type, cardinality, DECIMAL precision/scale, and NULL information. Mounted queries provide the same results and metadata. Use Machbase DBMS 8.7.0 for backup, restore, and mount operations involving ARRAY data. ## Versions and Errors - ARRAY is supported in Machbase DBMS 8.7.0. - SQL ARRAY element positions and Machbase-specific SDK positions are 0-based. Decrement positions in legacy 1-based SQL and SDK calls by one. - Pair a Machbase DBMS 8.7.0 server with an SDK build containing ARRAY support. - Unsupported servers or SDKs return errors instead of automatically converting ARRAYs to other types. - Cardinality, position, or element conversion errors fail the entire statement; no partial ARRAY is stored. - Applications must treat whole-array NULL and all-element-NULL ARRAY as distinct values. - This document covers Machbase DBMS SQL and SDK features. Machbase Neo, HTTP, TQL, and ILP are outside its scope. --- title: "16.1.3 Function Dictionary" url: https://docs.machbase.com/dbms/reference/sql/functions/ language: en kind: section --- # 16.1.3 Function Dictionary Built-in functions organized by category. | Category | Description | |----------|------| | [Aggregate Functions](aggregation/) | Group aggregates such as COUNT, SUM, AVG, MIN, MAX, STDDEV, FIRST, and LAST | | [Window/Series Functions](series/) | Window and series analysis functions such as ROWNUM and SERIESNUM | | [Date/Time Functions](datetime/) | Date/time processing with TO_DATE, TO_CHAR, DATE_TRUNC, ADD_TIME, and others | | [JSON Functions and Dot Notation](operators-json/) | JSON extraction, modification, and member access | | [Regular Expression Functions](regex/) | Regex search and transformation with REGEXP_LIKE, REGEXP_SUBSTR, and others | | [NEXTVAL](nextval/) | Automatic sequence values for Lookup table sequence columns | | [User Context Functions](functions-full/#current-session-user) | CURRENT_USER, SESSION_USER, and internal user IDs | | [Complete Function Reference](functions-full/) | Complete reference, including existing functions and CAST | ## Common Rules - NULL input produces NULL output unless otherwise stated. - Argument type mismatches produce `ERR-02036` or `ERR-02037`. --- title: "Aggregate Functions" url: https://docs.machbase.com/dbms/reference/sql/functions/aggregation/ language: en kind: page --- # Aggregate Functions Aggregate functions combine values from multiple rows into one result. With GROUP BY, they return results per group. NULL values are ignored, except by COUNT(*). ## Quick Reference | Function | Syntax | Description | |------|------|------| | COUNT | `COUNT(*) / COUNT(col)` | All rows or non-NULL rows | | SUM | `SUM(col)` | Sum | | AVG | `AVG(col)` | Average | | MIN | `MIN(col)` | Minimum | | MAX | `MAX(col)` | Maximum | | STDDEV | `STDDEV(col)` | Sample standard deviation | | STDDEV_POP | `STDDEV_POP(col)` | Population standard deviation | | VARIANCE | `VARIANCE(col)` | Sample variance | | VAR_POP | `VAR_POP(col)` | Population variance | | FIRST | `FIRST(sort_expr, return_expr)` | Value from the first row by the sort expression | | LAST | `LAST(sort_expr, return_expr)` | Value from the last row by the sort expression | | SUMSQ | `SUMSQ(col)` | Sum of squares | | MEDIAN | `MEDIAN(col)` | Median | | MODE | `MODE(col)` | Most frequent value | | AREA | `AREA(y, x)` | Area under the curve (trapezoidal integration) | | SLOPE | `SLOPE(y, x)` | Linear regression slope | | GROUP_CONCAT | `GROUP_CONCAT(col ...)` | Concatenate values within a group | | TS_CHANGE_COUNT | `TS_CHANGE_COUNT(col)` | Number of value changes | | TOP_K | `TOP_K(col, k)` | k most frequent values | | PERCENTILE_CONT | `PERCENTILE_CONT(col, ratio)` | Continuous percentile | | PERCENTILE_DISC | `PERCENTILE_DISC(col, ratio)` | Discrete percentile | | APPROX_PERCENTILE | `APPROX_PERCENTILE(col, ratio)` | Approximate percentile | | CUME_DIST | `CUME_DIST(value, threshold)` | Cumulative distribution ratio | --- ## COUNT Counts records. `COUNT(*)` returns all rows, including NULLs; `COUNT(col)` returns the count of non-NULL rows. ```sql COUNT(*) COUNT(column_name) ``` ```sql Mach> CREATE LOG TABLE count_table (id1 INTEGER, id2 INTEGER); Mach> INSERT INTO count_table VALUES(1, 1); Mach> INSERT INTO count_table VALUES(2, 2); Mach> INSERT INTO count_table VALUES(null, 4); Mach> SELECT COUNT(*) FROM count_table; COUNT(*) --------- 3 Mach> SELECT COUNT(id1) FROM count_table; COUNT(id1) ----------- 2 ``` --- ## SUM Returns the sum of a numeric column. ```sql SUM(column_name) ``` ```sql Mach> SELECT c1, SUM(c2) FROM sum_table GROUP BY c1; c1 SUM(c2) -------------------- 1 6 2 6 3 4 ``` --- ## AVG Returns the average of a numeric column. ```sql AVG(column_name) ``` ```sql Mach> SELECT id1, AVG(id2) FROM avg_table GROUP BY id1; id1 AVG(id2) --------------------- 1 2 2 2 NULL 4 ``` --- ## MIN Returns the minimum of the specified numeric column. ```sql MIN(column_name) ``` ```sql Mach> SELECT MIN(c1) FROM min_table; MIN(c1) -------- 1 ``` --- ## MAX Returns the maximum of the specified numeric column. ```sql MAX(column_name) ``` ```sql Mach> SELECT MAX(c) FROM max_table; MAX(c) ------- 30 ``` --- ## STDDEV / STDDEV_POP Returns the sample standard deviation (STDDEV) or population standard deviation (STDDEV_POP) of a column. ```sql STDDEV(column) STDDEV_POP(column) ``` ```sql Mach> SELECT c2, STDDEV(c1) FROM stddev_table GROUP BY c2; c2 STDDEV(c1) ----------------------- 1 0.707107 2 0.707107 Mach> SELECT c2, STDDEV_POP(c1) FROM stddev_table GROUP BY c2; c2 STDDEV_POP(c1) --------------------------- 1 0.5 2 0.5 ``` --- ## VARIANCE / VAR_POP Returns sample variance (VARIANCE) or population variance (VAR_POP). ```sql VARIANCE(column_name) VAR_POP(column_name) ``` ```sql Mach> SELECT VARIANCE(c1) FROM var_table; VARIANCE(c1) -------------- 0.333333 Mach> SELECT VAR_POP(c1) FROM var_table; VAR_POP(c1) ------------- 0.25 ``` --- ## FIRST / LAST Returns `return_expr` from the first (FIRST) or last (LAST) row in each group ordered by `sort_expr`. Useful for retrieving values at specific points in a time series. ```sql FIRST(sort_expr, return_expr) LAST(sort_expr, return_expr) ``` ```sql Mach> SELECT group_no, FIRST(id, name) FROM firstlast_table GROUP BY group_no; group_no first(id, name) ---------------------------- 0 John 1 Grey Mach> SELECT group_no, LAST(id, name) FROM firstlast_table GROUP BY group_no; group_no last(id, name) --------------------------- 0 Ryan 1 Kyle ``` --- ## SUMSQ Returns the sum of squared numeric values. ```sql SUMSQ(value) ``` ```sql Mach> SELECT c1, SUMSQ(c2) FROM sumsq_table GROUP BY c1; c1 SUMSQ(c2) ---------------------- 1 14 2 41 ``` --- ## MEDIAN Returns the exact median of a numeric expression. ```sql MEDIAN(value) ``` ```sql SELECT MEDIAN(temp_c) FROM sensor_log; ``` --- ## MODE Returns the most frequent numeric value. If multiple values tie, returns the smallest. ```sql MODE(value) ``` ```sql SELECT MODE(alarm_code) FROM event_log; ``` --- ## AREA Calculates the area under a curve of numeric `(x, y)` points using trapezoidal integration. Returns NULL with fewer than two valid points. ```sql AREA(y, x) ``` ```sql SELECT AREA(power_kw, sample_sec) FROM power_log; ``` --- ## SLOPE Calculates the slope of the linear regression line for numeric `(x, y)` points. Returns NULL if x has zero variance or there are insufficient valid data. ```sql SLOPE(y, x) ``` ```sql SELECT SLOPE(temp_c, sample_sec) FROM sensor_log; ``` --- ## GROUP_CONCAT Concatenates column values within a group into a string. {{< callout type="warning" >}} Unavailable in Cluster Edition. {{< /callout >}} ```sql GROUP_CONCAT( [DISTINCT] column [ORDER BY column [ASC | DESC] [, ...]] [SEPARATOR str_val] ) ``` ```sql Mach> SELECT GROUP_CONCAT(name) FROM concat_table GROUP BY id2; G_NAMES --------- Jack,Jack,Ram Jill,Zara,John Mach> SELECT GROUP_CONCAT(DISTINCT name SEPARATOR '.') FROM concat_table GROUP BY id2; G_NAMES --------- Jack.Ram Jill.Zara.John ``` --- ## TS_CHANGE_COUNT Returns the number of changes in time-ordered column values. VARCHAR is not supported. {{< callout type="warning" >}} Unavailable in Cluster Edition. {{< /callout >}} ```sql TS_CHANGE_COUNT(column) ``` ```sql Mach> SELECT id, TS_CHANGE_COUNT(ip) FROM ipcount_table GROUP BY id; id TS_CHANGE_COUNT(ip) -------------------------------- 1 4 2 2 ``` --- ## TOP_K Returns the k most frequent numeric values as a `value:count` string, ordered by descending frequency and ascending value for ties. ```sql TOP_K(value, k) ``` ```sql SELECT TOP_K(alarm_code, 3) FROM event_log; -- Example result: 101:532,205:317,301:90 ``` --- ## PERCENTILE_CONT / PERCENTILE_DISC Aggregate functions that calculate exact percentiles. `ratio` must be a constant from 0.0 through 1.0. - `PERCENTILE_CONT`: Interpolates between adjacent sorted values. - `PERCENTILE_DISC`: Selects an observed value. ```sql PERCENTILE_CONT(value, ratio) PERCENTILE_DISC(value, ratio) ``` Shorthand functions `P05`, `P10`, `P90`, and `P95` are also available. ```sql SELECT PERCENTILE_CONT(latency_ms, 0.95) AS p95, PERCENTILE_DISC(latency_ms, 0.50) AS p50 FROM api_log; -- Shorthand SELECT P05(response_ms), P95(response_ms) FROM web_log; ``` --- ## APPROX_PERCENTILE Approximate percentile function, useful for very large datasets when a small error is acceptable. Shorthands include APPROX_MEDIAN, APPROX_P05, APPROX_P10, APPROX_P90, and APPROX_P95. ```sql APPROX_PERCENTILE(value, ratio) APPROX_MEDIAN(value) APPROX_P95(value) ``` ```sql SELECT APPROX_PERCENTILE(latency_ms, 0.95) AS ap95, APPROX_MEDIAN(latency_ms) AS amedian FROM api_log; ``` --- ## CUME_DIST Returns the cumulative fraction of rows whose `value` is at most `threshold` (0.0–1.0). This is an aggregate function, not a window function. ```sql CUME_DIST(value, threshold) ``` ```sql SELECT CUME_DIST(latency_ms, 100) FROM api_log; ``` --- title: "Window/Series Functions" url: https://docs.machbase.com/dbms/reference/sql/functions/series/ language: en kind: page --- # Window/Series Functions This page describes `ROWNUM()`, which numbers result rows, and `SERIESNUM()`, which identifies contiguous intervals. `SERIES BY` analyzes intervals in ordered data where a condition holds continuously. For functions such as `LAG()` and `LEAD()` that use `OVER`, see [Window Function Syntax](../../syntax/window-function-over-syntax/). ## Quick Reference | Function | Syntax | Description | |------|------|------| | ROWNUM | `ROWNUM()` | Number SELECT result rows | | SERIESNUM | `SERIESNUM()` | Number of the contiguous interval containing the row; rows in the same interval share a number | --- ## ROWNUM Assigns sequential numbers to `SELECT` result rows. It can be used in subqueries and inline views. Assign an alias in an inline view's select list so the outer query can reference it. ```sql ROWNUM() ``` ### Allowed Clauses | Allowed | Not Allowed | |-----------|----------| | SELECT Target List, GROUP BY, ORDER BY | WHERE, HAVING | To filter by row number in WHERE/HAVING, calculate `ROWNUM()` in an inline view and reference it from the outer query. ```sql -- Select only the first two rows Mach> SELECT INNER_RANK, c3 AS NAME FROM (SELECT ROWNUM() AS INNER_RANK, * FROM rownum_table) WHERE INNER_RANK < 3; INNER_RANK NAME -------------------------- 1 Fourth Row 2 Third Row ``` ### Using ORDER BY Place the query with `ORDER BY` in an inline view and call `ROWNUM()` in the outer SELECT to number rows in sorted order. ```sql Mach> SELECT ROWNUM(), c2 AS SORT, c3 AS NAME FROM (SELECT * FROM rownum_table ORDER BY c3); ROWNUM() SORT NAME -------------------------- 1 1 NULL 2 2 John 3 4.3 Micheal 4 3.3 Sarah ``` --- ## SERIESNUM Returns the series number for each record grouped by `SERIES BY`. Without `SERIES BY`, it always returns 1. The return type is `BIGINT`. ```sql SERIESNUM() ``` ```sql Mach> CREATE LOG TABLE T1 (C1 INTEGER, C2 INTEGER); Mach> INSERT INTO T1 VALUES (0, 1); Mach> INSERT INTO T1 VALUES (1, 2); Mach> INSERT INTO T1 VALUES (2, 3); Mach> INSERT INTO T1 VALUES (3, 2); Mach> INSERT INTO T1 VALUES (4, 1); Mach> INSERT INTO T1 VALUES (5, 2); Mach> INSERT INTO T1 VALUES (6, 3); Mach> INSERT INTO T1 VALUES (7, 1); -- Split contiguous intervals satisfying C2 > 1 into series Mach> SELECT SERIESNUM(), C1, C2 FROM T1 ORDER BY C1 SERIES BY C2 > 1; SERIESNUM() C1 C2 -------------------- 1 1 2 1 2 3 1 3 2 2 5 2 2 6 3 [5] row(s) selected. ``` - `C1=1,2,3` (contiguous interval satisfying C2>1) → Series 1 - `C1=4` (C2=1, condition false) → Series boundary - `C1=5,6` (contiguous interval satisfying C2>1) → Series 2 --- ## SERIES BY Overview `SERIES BY` works with `ORDER BY` to group consecutive rows satisfying a condition into a series. Use `SERIESNUM()` to identify each series and aggregate functions to calculate interval statistics. For interval statistics, generate series numbers in an inner query and aggregate in the outer query. Replace `threshold` in the example below with the threshold to compare. ```sql SELECT series_id, COUNT(*), AVG(value) FROM ( SELECT value, SERIESNUM() AS series_id FROM sensor_log ORDER BY ts SERIES BY value > threshold ) GROUP BY series_id ORDER BY series_id; ``` --- title: "Regular Expression Functions" url: https://docs.machbase.com/dbms/reference/sql/functions/regex/ language: en kind: page --- # Regular Expression Functions Machbase provides PCRE (Perl Compatible Regular Expressions) functions. All regular expression functions operate only on `VARCHAR` columns. ## Quick Reference | Function | Syntax | Description | |------|------|------| | REGEXP_LIKE | `REGEXP_LIKE(src, pat [, flag])` | Test for a pattern match | | REGEXP_INSTR | `REGEXP_INSTR(src, pat [, pos [, occ [, ret [, flag]]]])` | Return the match position | | REGEXP_SUBSTR | `REGEXP_SUBSTR(src, pat [, pos [, occ [, flag]]])` | Extract a matching substring | | REGEXP_REPLACE | `REGEXP_REPLACE(src, pat [, repl [, pos [, occ [, flag]]]])` | Replace matching text | ### match_param (Common Parameter) | Value | Description | |----|------| | `'c'` | Case-sensitive (default) | | `'i'` | Case-insensitive | --- ## REGEXP_LIKE Tests whether a string matches a regular expression. Commonly used in WHERE, it returns a Boolean (1/0). ```sql REGEXP_LIKE(source, pattern) REGEXP_LIKE(source, pattern, match_param) ``` - `source`: `VARCHAR` column or expression to test - `pattern`: Constant `VARCHAR` regular expression - `match_param`: `'c'` (case-sensitive, default) or `'i'` (case-insensitive) ```sql -- Query messages containing 'error' or 'warn', ignoring case SELECT * FROM sensor_text WHERE REGEXP_LIKE(message, 'error|warn', 'i'); -- Query codes starting with digits SELECT * FROM event_log WHERE REGEXP_LIKE(code, '^[0-9]+'); -- Validate email format SELECT name FROM users WHERE REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'); ``` --- ## REGEXP_INSTR Returns the position of a match, or `0` if none exists. Positions are 1-based. ```sql REGEXP_INSTR(source, pattern) REGEXP_INSTR(source, pattern, position) REGEXP_INSTR(source, pattern, position, occurrence) REGEXP_INSTR(source, pattern, position, occurrence, return_pos) REGEXP_INSTR(source, pattern, position, occurrence, return_pos, match_param) ``` | Parameter | Description | |---------|------| | `source` | `VARCHAR` to search | | `pattern` | Constant `VARCHAR` regular expression | | `position` | Starting position (at least 1; default: 1) | | `occurrence` | Match occurrence to find (at least 1; default: 1) | | `return_pos` | `0`: Start position; `1`: Position after the match | | `match_param` | `'c'` or `'i'` | ```sql -- Position after the first 'The' match, ignoring case SELECT REGEXP_INSTR('TechOnTheNet', 'The', 1, 1, 1, 'i'); -- Result: 10 (position after 'The') ``` --- ## REGEXP_SUBSTR Returns the substring matching the regular expression, or NULL if none exists. ```sql REGEXP_SUBSTR(source, pattern) REGEXP_SUBSTR(source, pattern, position) REGEXP_SUBSTR(source, pattern, position, occurrence) REGEXP_SUBSTR(source, pattern, position, occurrence, match_param) ``` | Parameter | Description | |---------|------| | `source` | `VARCHAR` to search | | `pattern` | Constant `VARCHAR` regular expression | | `position` | Starting position (at least 1; default: 1) | | `occurrence` | Match occurrence to find (at least 1; default: 1) | | `match_param` | `'c'` or `'i'` | ```sql -- Extract the second vowel, ignoring case SELECT REGEXP_SUBSTR('TechOnTheNet', 'a|e|i|o|u', 1, 2, 'i'); -- Result: 'O' -- Extract the first octet from an IP address SELECT REGEXP_SUBSTR(ip_str, '[0-9]+', 1, 1) FROM log_table; -- Extract an error code from a log SELECT REGEXP_SUBSTR(message, 'ERR-[0-9]+') FROM event_log; ``` --- ## REGEXP_REPLACE Replaces matching text with the specified string. ```sql REGEXP_REPLACE(source, pattern) REGEXP_REPLACE(source, pattern, replacement) REGEXP_REPLACE(source, pattern, replacement, position) REGEXP_REPLACE(source, pattern, replacement, position, occurrence) REGEXP_REPLACE(source, pattern, replacement, position, occurrence, match_param) ``` | Parameter | Description | |---------|------| | `source` | Target `VARCHAR` | | `pattern` | Constant `VARCHAR` regular expression | | `replacement` | Replacement string; omitted means remove the match | | `position` | Starting position (at least 1; default: 1) | | `occurrence` | `0`: Replace all; positive n: replace the nth match only (default: 0) | | `match_param` | `'c'` or `'i'` | ```sql -- Replace the second vowel with 'Z', ignoring case SELECT REGEXP_REPLACE('TechOnTheNet', 'a|e|i|o|u', 'Z', 1, 2, 'i'); -- Result: 'TechZnTheNet' -- Remove all digits SELECT REGEXP_REPLACE(code, '[0-9]', '') FROM log_table; -- Normalize consecutive whitespace to one space SELECT REGEXP_REPLACE(message, '\s+', ' ') FROM event_log; ``` --- ## PCRE Basics | Pattern | Description | Example | |------|------|------| | `.` | Any single character | `a.c` → abc, aXc | | `*` | Zero or more repetitions | `ab*c` → ac, abc, abbc | | `+` | One or more repetitions | `ab+c` → abc, abbc | | `?` | Zero or one occurrence | `colou?r` → color, colour | | `^` | Start of string | `^error` | | `$` | End of string | `\.log$` | | `[abc]` | Character class | `[aeiou]` | | `[^abc]` | Negated character class | `[^0-9]` | | `\d` | Digit (`[0-9]`) | `\d+` | | `\w` | Word character | `\w+` | | `\s` | Whitespace | `\s+` | | `a\|b` | a or b | `error\|warn` | | `(abc)` | Group | `(foo)+` | | `{n,m}` | n to m repetitions | `\d{3,5}` | --- ## Comparison with SEARCH / ESEARCH | Feature | REGEXP_LIKE | SEARCH / ESEARCH | |------|:-----------:|:----------------:| | Applicable Type | `VARCHAR` | `TEXT` (full-text index) | | Regex support | O (PCRE) | X (keyword search) | | Index use | X | O | | Large text volumes | Limited | Recommended | For keyword searches over large text volumes, `TEXT` and SEARCH provide better performance. Use VARCHAR and REGEXP_LIKE when regex pattern matching is required. --- title: "JSON Functions and Dot Notation" url: https://docs.machbase.com/dbms/reference/sql/functions/operators-json/ language: en kind: page --- # JSON Functions and Dot Notation Machbase provides functions and JSON dot notation for querying and modifying data in `JSON` columns. ## Quick Reference | Function/Notation | Syntax | Description | |-------------|------|------| | JSON dot notation | `col.key` | Extract an object key's value | | `JSON_EXTRACT` | `JSON_EXTRACT(doc, path)` | Extract a path value as a JSON string | | `JSON_EXTRACT_STRING` | `JSON_EXTRACT_STRING(doc, path)` | Extract a path value as a string | | `JSON_EXTRACT_INTEGER` | `JSON_EXTRACT_INTEGER(doc, path)` | Extract a path value as an integer | | `JSON_EXTRACT_DOUBLE` | `JSON_EXTRACT_DOUBLE(doc, path)` | Extract a path value as a floating-point number | | `JSON_TYPEOF` | `JSON_TYPEOF(doc, path)` | Check the type at a JSON path | | `JSON_IS_VALID` | `JSON_IS_VALID(json_text)` | Validate a JSON string | | `JSON_SET` | `JSON_SET(doc, path, scalar)` | Set a scalar value at a JSON path | | `JSON_SET_JSON` | `JSON_SET_JSON(doc, path, json_text)` | Set a JSON subtree at a path | | `JSON_REMOVE` | `JSON_REMOVE(doc, path)` | Remove a member at a JSON path | The `path` argument to `JSON_TYPEOF` is required. Use `JSON_TYPEOF(doc, '$')` to check the type of the entire document. --- ## JSON Dot Notation Append a dot (`.`) and key name to a JSON column to query that key's value. Use this to access JSON members without writing a JSONPath string. ```sql json_column.key ``` ```sql -- Extract a key from a JSON column SELECT data.temperature AS temp FROM sensor_log; -- Use in WHERE SELECT * FROM sensor_log WHERE data.status = 'active'; ``` To specify a JSONPath string explicitly, use the `->` operator, as in `data -> '$.temperature'`. Keep this distinct from dot notation above. --- ## JSON_SET Stores a SQL scalar as a JSON scalar at the specified document path. ```sql JSON_SET(json_doc, path, scalar) ``` - `path` must be a full JSONPath, such as `$.key.subkey`. - `JSON_SET(..., path, NULL)` stores JSON `null`. - If the JSON document argument is SQL `NULL`, the result is SQL `NULL`. - Array element updates such as `$.items[0]` are not supported. ```sql Mach> SELECT JSON_SET('{"ship":{"status":"READY"}}', '$.ship.status', 'DONE') FROM dual; {"ship":{"status":"DONE"}} Mach> SELECT JSON_SET('{"count":0}', '$.count', 42) FROM dual; {"count":42} ``` --- ## JSON_SET_JSON Parses the third argument as JSON text and stores an object or array subtree. ```sql JSON_SET_JSON(json_doc, path, json_text) ``` - If the third argument is SQL `NULL`, the result is SQL `NULL`. - Invalid JSON text causes an error. - Array element updates are not supported. ```sql Mach> SELECT JSON_SET_JSON('{"ship":{}}', '$.ship.owner', '{"name":"machbase"}') FROM dual; {"ship":{"owner":{"name":"machbase"}}} Mach> SELECT JSON_SET_JSON('{"tags":{}}', '$.tags.sensors', '[1,2,3]') FROM dual; {"tags":{"sensors":[1,2,3]}} ``` --- ## JSON_REMOVE Removes a member or subpath from a JSON document. ```sql JSON_REMOVE(json_doc, path) ``` - `path` must be a full JSONPath. - A missing path is a no-op. - `JSON_REMOVE(..., '$')` is not allowed. - If the JSON document argument is SQL `NULL`, the result is SQL `NULL`. ```sql Mach> SELECT JSON_REMOVE('{"owner":{"name":"machbase","team":"db"}}', '$.owner.team') FROM dual; {"owner":{"name":"machbase"}} Mach> SELECT JSON_REMOVE('{"a":1,"b":2}', '$.a') FROM dual; {"b":2} ``` --- ## JSON Insertion Example ```sql -- LOG table with a JSON column CREATE LOG TABLE device_log ( ts DATETIME, data JSON ); -- Insert JSON data INSERT INTO device_log VALUES (NOW, '{"temperature":23.5,"humidity":60,"status":"active"}'); -- Extract values with JSON dot notation SELECT ts, data.temperature AS temp FROM device_log WHERE data.status = 'active'; ``` --- ## JSON Support by Table Type | Table Type | JSON Columns | JSON Path Queries | Notes | |------------|:---------:|:---------------:|------| | TAG | O | O | JSON columns and functions supported; JSON PK not supported | | LOG | O | O | Fully supported | | LOOKUP | O | O | Ordinary columns supported; JSON path indexes not supported | | VOLATILE | X | X | Cannot create JSON columns | | TRANSACTION | O | O | Fully supported | For details, see [JSON Support by Table Type](/dbms/lookup-table-usage/json-column-query/). --- title: "Date/Time Functions" url: https://docs.machbase.com/dbms/reference/sql/functions/datetime/ language: en kind: page --- # Date/Time Functions Machbase DATETIME internally stores nanoseconds elapsed since 1970-01-01 00:00:00 UTC. Date/time functions convert these values to readable formats or perform arithmetic. ## Quick Reference | Function | Syntax | Description | |------|------|------| | SYSDATE / NOW | `SYSDATE`, `NOW` | Return current system time | | TO_DATE | `TO_DATE(str [, fmt])` | Convert a string to DATETIME | | TO_DATE_SAFE | `TO_DATE_SAFE(str [, fmt])` | Return NULL on conversion failure | | TO_CHAR | `TO_CHAR(col [, fmt])` | Convert DATETIME to a string | | ADD_TIME | `ADD_TIME(col, diff)` | Add/subtract date/time components | | DATE_TRUNC | `DATE_TRUNC(unit, col [, count])` | Truncate to the specified unit | | DATE_BIN | `DATE_BIN(unit, count, col [, origin])` | Bucket time relative to a specified origin | | DAYOFWEEK | `DAYOFWEEK(col)` | Return weekday number (0=Sunday) | | YEAR / MONTH / DAY | `YEAR(col)`, `MONTH(col)`, `DAY(col)` | Extract year, month, and day | | FROM_UNIXTIME | `FROM_UNIXTIME(unix_ts)` | Convert a 32-bit Unix timestamp to DATETIME | | UNIX_TIMESTAMP | `UNIX_TIMESTAMP(col)` | Convert DATETIME to a 32-bit Unix timestamp | | FROM_TIMESTAMP | `FROM_TIMESTAMP(ns)` | Convert nanosecond integer to DATETIME | | TO_TIMESTAMP | `TO_TIMESTAMP(col)` | Convert DATETIME to nanosecond integer | --- ## SYSDATE / NOW Pseudocolumns that return current system time. SYSDATE and NOW return the same value. ```sql SYSDATE NOW ``` ```sql Mach> SELECT SYSDATE, NOW FROM t1; SYSDATE NOW ------------------------------------------------------------------- 2017-01-16 14:14:53 310:973:000 2017-01-16 14:14:53 310:973:000 ``` --- ## TO_DATE Converts a string to DATETIME using the specified format. The default format is `YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn`. ```sql TO_DATE(date_string [, format_string]) ``` ```sql Mach> SELECT TO_DATE('2014-12-30 11:22:33 444:555:666'); 2014-12-30 11:22:33 444:555:666 Mach> SELECT TO_DATE('1999-12-31 13:12:32', 'YYYY-MM-DD HH24:MI:SS'); 1999-12-31 13:12:32 000:000:000 Mach> SELECT TO_DATE('1999', 'YYYY'); 1999-01-01 00:00:00 000:000:000 ``` `TO_DATE_SAFE()` returns NULL instead of an error when conversion fails. ```sql Mach> SELECT TO_DATE_SAFE('2016-12-32', 'YYYY-MM-DD'); NULL ``` --- ## TO_CHAR (DATETIME) Converts a DATETIME column value to a string. The default format is `YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn`. ```sql TO_CHAR(datetime_col [, format_string]) ``` ### Format Strings | Format | Description | |------------|------| | `YYYY` | Four-digit year | | `YY` | Two-digit year | | `MM` | Two-digit month (`01~12`) | | `MON` | Three-letter English month abbreviation (JAN, FEB, ...) | | `DD` | Two-digit day | | `DAY` | Three-letter English weekday abbreviation (SUN, MON, ...) | | `IW` | ISO 8601 week (`1~53`, Monday-based) | | `WW` | Week of year (`1~53`, independent of weekday) | | `W` | Week of month (`1~5`, independent of weekday) | | `HH` | Two-digit hour | | `HH12` | 12-hour clock (`1~12`) | | `HH24` | 24-hour clock (`0~23`) | | `HH2`, `HH3`, `HH6` | Truncate hours to the specified multiple | | `MI` | Two-digit minute | | `MI2`, `MI5`, `MI10`, `MI20`, `MI30` | Truncate minutes to the specified multiple | | `SS` | Two-digit second | | `SS2`, `SS5`, `SS10`, `SS20`, `SS30` | Truncate seconds to the specified multiple | | `AM` | AM/PM | | `mmm` | Three-digit milliseconds (`0~999`) | | `uuu` | Three-digit microseconds (`0~999`) | | `nnn` | Three-digit nanoseconds (`0~999`) | ```sql Mach> SELECT TO_CHAR(dt, 'YYYY-MM-DD HH24:MI:SS') FROM datetime_table; 2014-12-30 11:22:33 2013-11-11 01:02:03 Mach> SELECT TO_CHAR(dt, 'YYYY-MM-DD HH24:MI:SS mmm.uuu.nnn') FROM datetime_table; 2014-12-30 11:22:33 444.555.666 ``` --- ## ADD_TIME Adds or subtracts years, months, days, hours, minutes, and seconds from DATETIME. Milliseconds, microseconds, and nanoseconds are not supported. ```sql ADD_TIME(column, time_diff_format) ``` `time_diff_format`: `"Year/Month/Day Hour:Minute:Second"`; each component can be positive or negative. ```sql -- One year later Mach> SELECT ADD_TIME(dt, '1/0/0 0:0:0') FROM t; -- One hour, one minute, and one second later Mach> SELECT ADD_TIME(dt, '0/0/0 1:1:1') FROM t; -- One year, one month, and one day earlier Mach> SELECT ADD_TIME(dt, '-1/-1/-1 0:0:0') FROM t; ``` --- ## DATE_TRUNC Truncates a DATETIME value to the specified unit. With `count`, truncates to that multiple of the unit. ```sql DATE_TRUNC(field, date_val [, count]) ``` ### Supported Units and Maximum Ranges | Unit | Maximum Range | |-----------|----------| | `nanosecond` (`nsec`) | 1,000,000,000 (1 second) | | `microsecond` (`usec`) | 60,000,000 (60 seconds) | | `millisecond` (`msec`) | 60,000 (60 seconds) | | `second` (`sec`) | 86,400 (1 day) | | `minute` (`min`) | 1,440 (1 day) | | `hour` | 24 (1 day) | | `day` | 1 | | `week` | 1 (starts on Sunday) | | `month` | 1 | | `year` | 1 | ```sql -- Truncate to seconds Mach> SELECT COUNT(*), DATE_TRUNC('second', i2) tm FROM t GROUP BY tm ORDER BY 2; -- Truncate to 2-second intervals Mach> SELECT COUNT(*), DATE_TRUNC('second', i2, 2) tm FROM t GROUP BY tm ORDER BY 2; -- Truncate to 2-minute intervals (same as DATE_TRUNC('second', time, 120)) Mach> SELECT COUNT(*), DATE_TRUNC('minute', ts, 2) tm FROM t GROUP BY tm; ``` --- ## DATE_BIN Buckets DATETIME by the specified unit and count relative to `origin`. If omitted, origin is `1970-01-01 00:00:00` in the local timezone. ```sql DATE_BIN(field, count, source [, origin]) ``` ```sql -- 2-hour buckets with a specific origin SELECT DATE_BIN('hour', 2, time, TO_DATE('2020-01-01 00:00:00')) FROM log ORDER BY time; -- 3-hour buckets aligned to the local timezone SELECT DATE_BIN('hour', 3, ts) FROM t ORDER BY ts; ``` --- ## DAYOFWEEK Returns the weekday of a DATETIME value as an integer. ```sql DAYOFWEEK(date_val) ``` | Return Value | Weekday | |--------|------| | 0 | Sunday | | 1 | Monday | | 2 | Tuesday | | 3 | Wednesday | | 4 | Thursday | | 5 | Friday | | 6 | Saturday | ```sql SELECT DAYOFWEEK(dt) FROM log_table; ``` --- ## YEAR / MONTH / DAY Extracts year, month, and day from DATETIME as integers. ```sql YEAR(datetime_col) MONTH(datetime_col) DAY(datetime_col) ``` ```sql Mach> SELECT YEAR(c1), MONTH(c1), DAY(c1) FROM extract_table; year(c1) month(c1) day(c1) --------------------------------- 2001 1 1 ``` --- ## FROM_UNIXTIME / UNIX_TIMESTAMP FROM_UNIXTIME converts a 32-bit Unix timestamp integer to DATETIME. UNIX_TIMESTAMP converts DATETIME to a 32-bit Unix timestamp. ```sql FROM_UNIXTIME(unix_timestamp_value) UNIX_TIMESTAMP(datetime_value) ``` ```sql Mach> SELECT FROM_UNIXTIME(315540671); 1980-01-01 11:11:11 000:000:000 Mach> INSERT INTO unix_table VALUES (UNIX_TIMESTAMP('2001-01-01')); Mach> SELECT * FROM unix_table; C1 ----------- 978274800 ``` --- ## FROM_TIMESTAMP / TO_TIMESTAMP FROM_TIMESTAMP converts an integer count of nanoseconds since 1970-01-01 00:00:00 UTC to DATETIME. TO_TIMESTAMP converts DATETIME to nanoseconds elapsed since the same epoch. The epoch appears as 1970-01-01 09:00:00 in UTC+09:00. Dates and times in the examples below use UTC+09:00. ```sql FROM_TIMESTAMP(nanosecond_time_value) TO_TIMESTAMP(datetime_value) ``` ```sql Mach> SELECT FROM_TIMESTAMP(1562302560007248869); 2019-07-05 13:56:00 007:248:869 Mach> SELECT TO_TIMESTAMP(c1) FROM datetime_tbl; to_timestamp(c1) ----------------------- 1262308210000000000 ``` Nanosecond arithmetic example: ```sql -- 1ms (1,000,000 ns) before the current time SELECT FROM_TIMESTAMP(SYSDATE - 1000000) FROM t; ``` --- title: "NEXTVAL Function" url: https://docs.machbase.com/dbms/reference/sql/functions/nextval/ language: en kind: page --- # NEXTVAL Function `NEXTVAL` returns the next automatic value for a LOOKUP table SEQUENCE column as `INT64`. It can be used only in an `INSERT` value expression. ## Syntax ```sql NEXTVAL(sequence_column) ``` - `sequence_column` must be created with `PROPERTY(SEQUENCE=...)`. - It cannot be used outside `INSERT`, such as in SELECT or WHERE. - Exactly one argument is required: a SEQUENCE column in the same INSERT target table. --- ## Creating a Sequence Column SEQUENCE columns are supported on LOOKUP `LONG` or `INT64` columns. `PROPERTY(SEQUENCE=1)` sets the starting value to 1. ```sql CREATE LOOKUP TABLE seq_lookup ( id LONG PROPERTY(SEQUENCE=1) PRIMARY KEY, name VARCHAR(64) ); ``` --- ## Using NEXTVAL ```sql -- Insert automatic IDs with NEXTVAL INSERT INTO seq_lookup (id, name) VALUES (NEXTVAL(id), 'sensor-a'); INSERT INTO seq_lookup (id, name) VALUES (NEXTVAL(id), 'sensor-b'); INSERT INTO seq_lookup (id, name) VALUES (NEXTVAL(id), 'sensor-c'); -- Check results SELECT * FROM seq_lookup; id name ---------- 1 sensor-a 2 sensor-b 3 sensor-c DROP TABLE seq_lookup; ``` --- ## Notes - `NEXTVAL` can be used only in `INSERT`. - SEQUENCE columns are supported only in **LOOKUP tables**. They are unavailable in TAG, LOG, VOLATILE, and TRANSACTION tables. - Types other than `LONG`/`INT64`, ordinary columns, and SELECT/WHERE calls cause errors. - Sequence values may not be reused after transaction rollback or errors, so gaps may occur. - For DDL details, see [DDL - Sequence Column](../../syntax/). --- title: "Complete Function Reference" url: https://docs.machbase.com/dbms/reference/sql/functions/functions-full/ language: en kind: page --- # Complete Function Reference ## Error Handling | Error Type | Code | Condition | |---|---|---| | Argument type error | `ERR-02036`, `ERR-02037` | Nonnumeric input or arguments supplied to `PI` | | Execution error | `ERR-02317` | Negative input to `SQRT`, division by zero in `MOD`, invalid base/value in `LOG`, overflow in `EXP`/`POWER`, and similar errors | NULL input produces NULL output. ## ABS Returns the absolute value of a numeric column as a floating-point number. ```sql ABS(column_expr) ``` ```sql Mach> CREATE LOG TABLE abs_table (c1 INTEGER, c2 DOUBLE, c3 VARCHAR(10)); Created successfully. Mach> INSERT INTO abs_table VALUES(1, 1.0, ''); 1 row(s) inserted. Mach> INSERT INTO abs_table VALUES(2, 2.0, 'sqltest'); 1 row(s) inserted. Mach> INSERT INTO abs_table VALUES(3, 3.0, 'sqltest'); 1 row(s) inserted. Mach> SELECT ABS(c1), ABS(c2) FROM abs_table; SELECT ABS(c1), ABS(c2) from abs_table; ABS(c1) ABS(c2) ----------------------------------------------------------- 3 3 2 2 1 1 [3] row(s) selected. ``` ## ADD_TIME Adds or subtracts years, months, days, hours, minutes, and seconds from DATETIME. Milliseconds, microseconds, and nanoseconds are not supported. Diff format is `"Year/Month/Day Hour:Minute:Second"`; each component can be positive or negative. ```sql ADD_TIME(column,time_diff_format) ``` ```sql Mach> CREATE LOG TABLE add_time_table (id INTEGER, dt DATETIME); Created successfully. Mach> INSERT INTO add_time_table VALUES(1, TO_DATE('1999-11-11 1:2:3 4:5:6')); 1 row(s) inserted. Mach> INSERT INTO add_time_table VALUES(2, TO_DATE('2000-11-11 1:2:3 4:5:6')); 1 row(s) inserted. Mach> INSERT INTO add_time_table VALUES(3, TO_DATE('2012-11-11 1:2:3 4:5:6')); 1 row(s) inserted. Mach> INSERT INTO add_time_table VALUES(4, TO_DATE('2013-11-11 1:2:3 4:5:6')); 1 row(s) inserted. Mach> INSERT INTO add_time_table VALUES(5, TO_DATE('2014-12-30 11:22:33 444:555:666')); 1 row(s) inserted. Mach> INSERT INTO add_time_table VALUES(6, TO_DATE('2014-12-30 23:22:33 444:555:666')); 1 row(s) inserted. Mach> SELECT ADD_TIME(dt, '1/0/0 0:0:0') FROM add_time_table; ADD_TIME(dt, '1/0/0 0:0:0') ---------------------------------- 2015-12-30 23:22:33 444:555:666 2015-12-30 11:22:33 444:555:666 2014-11-11 01:02:03 004:005:006 2013-11-11 01:02:03 004:005:006 2001-11-11 01:02:03 004:005:006 2000-11-11 01:02:03 004:005:006 [6] row(s) selected. Mach> SELECT ADD_TIME(dt, '0/0/0 1:1:1') FROM add_time_table; ADD_TIME(dt, '0/0/0 1:1:1') ---------------------------------- 2014-12-31 00:23:34 444:555:666 2014-12-30 12:23:34 444:555:666 2013-11-11 02:03:04 004:005:006 2012-11-11 02:03:04 004:005:006 2000-11-11 02:03:04 004:005:006 1999-11-11 02:03:04 004:005:006 [6] row(s) selected. Mach> SELECT ADD_TIME(dt, '1/1/1 0:0:0') FROM add_time_table; ADD_TIME(dt, '1/1/1 0:0:0') ---------------------------------- 2016-01-31 23:22:33 444:555:666 2016-01-31 11:22:33 444:555:666 2014-12-12 01:02:03 004:005:006 2013-12-12 01:02:03 004:005:006 2001-12-12 01:02:03 004:005:006 2000-12-12 01:02:03 004:005:006 [6] row(s) selected. Mach> SELECT ADD_TIME(dt, '-1/0/0 0:0:0') FROM add_time_table; ADD_TIME(dt, '-1/0/0 0:0:0') ---------------------------------- 2013-12-30 23:22:33 444:555:666 2013-12-30 11:22:33 444:555:666 2012-11-11 01:02:03 004:005:006 2011-11-11 01:02:03 004:005:006 1999-11-11 01:02:03 004:005:006 1998-11-11 01:02:03 004:005:006 [6] row(s) selected. Mach> SELECT ADD_TIME(dt, '0/0/0 -1:-1:-1') FROM add_time_table; ADD_TIME(dt, '0/0/0 -1:-1:-1') ---------------------------------- 2014-12-30 22:21:32 444:555:666 2014-12-30 10:21:32 444:555:666 2013-11-11 00:01:02 004:005:006 2012-11-11 00:01:02 004:005:006 2000-11-11 00:01:02 004:005:006 1999-11-11 00:01:02 004:005:006 [6] row(s) selected. Mach> SELECT ADD_TIME(dt, '-1/-1/-1 0:0:0') FROM add_time_table; ADD_TIME(dt, '-1/-1/-1 0:0:0') ---------------------------------- 2013-11-29 23:22:33 444:555:666 2013-11-29 11:22:33 444:555:666 2012-10-10 01:02:03 004:005:006 2011-10-10 01:02:03 004:005:006 1999-10-10 01:02:03 004:005:006 1998-10-10 01:02:03 004:005:006 [6] row(s) selected. Mach> SELECT * FROM add_time_table WHERE dt > ADD_TIME(TO_DATE('2014-12-30 11:22:33 444:555:666'), '-1/-1/-1 0:0:0'); ID DT ----------------------------------------------- 6 2014-12-30 23:22:33 444:555:666 5 2014-12-30 11:22:33 444:555:666 [2] row(s) selected. Mach> SELECT * FROM add_time_table WHERE dt > ADD_TIME(TO_DATE('2014-12-30 11:22:33 444:555:666'), '-1/-2/-1 0:0:0'); ID DT ----------------------------------------------- 6 2014-12-30 23:22:33 444:555:666 5 2014-12-30 11:22:33 444:555:666 4 2013-11-11 01:02:03 004:005:006 [3] row(s) selected. Mach> SELECT ADD_TIME(TO_DATE('2000-12-01 00:00:00 000:000:001'), '-1/0/0 0:0:-1') FROM add_time_table; ADD_TIME(TO_DATE('2000-12-01 00:00:00 000:000:001'), '-1/0/0 0:0:-1') ------------------------------------------ 1999-11-30 23:59:59 000:000:001 1999-11-30 23:59:59 000:000:001 1999-11-30 23:59:59 000:000:001 1999-11-30 23:59:59 000:000:001 1999-11-30 23:59:59 000:000:001 1999-11-30 23:59:59 000:000:001 [6] row(s) selected. Mach> SELECT * FROM add_time_table WHERE dt > ADD_TIME(TO_DATE('2014-12-30 11:22:33 444:555:666'), '-1/-2/-1 0:0:0'); ID DT ----------------------------------------------- 6 2014-12-30 23:22:33 444:555:666 5 2014-12-30 11:22:33 444:555:666 4 2013-11-11 01:02:03 004:005:006 [3] row(s) selected. ``` ## APPROX_PERCENTILE {#approx_percentile-family} ``` APPROX_PERCENTILE APPROX_MEDIAN APPROX_P05 APPROX_P10 APPROX_P90 APPROX_P95 ``` These functions approximate percentiles using a bounded summary instead of sorting every raw value. They are useful for very large datasets when a small error is acceptable. ```sql APPROX_PERCENTILE(value, ratio) APPROX_MEDIAN(value) APPROX_P05(value) APPROX_P10(value) APPROX_P90(value) APPROX_P95(value) ``` - `value` must be numeric. - `ratio` must be a constant from `0.0` through `1.0`. - The return type is `DOUBLE`. - NULL values are ignored. `APPROX_MEDIAN(value)` is the approximate median. `APPROX_P05`, `APPROX_P10`, `APPROX_P90`, and `APPROX_P95` are shorthands for common percentiles. ```sql SELECT APPROX_PERCENTILE(latency_ms, 0.95) AS ap95, APPROX_MEDIAN(latency_ms) AS amedian, APPROX_P05(latency_ms) AS ap05 FROM api_log; ``` ## ARRAY_LENGTH `ARRAY_LENGTH(array_value)` returns the declared cardinality of a non-NULL ARRAY. ```sql SELECT ARRAY_LENGTH(ARRAY[10, NULL, 30]); -- 3 ``` It returns cardinality even if every element is NULL. A whole-array NULL returns NULL; `ARRAY_LENGTH(NULL)` without type information is an error. For ARRAY syntax and constraints, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/). ## ARRAY_SPARSE `ARRAY_SPARSE` specifies only populated positions in a fixed-length ARRAY. Positions start at 0; omitted positions are element NULLs. ```sql -- Infer type and cardinality from the target column. INSERT INTO sensor_array (id, channels) VALUES (1, ARRAY_SPARSE(0 => 10, 3 => 40)); -- Specify type and cardinality for an expression without a target. SELECT ARRAY_SPARSE(INT32[4], 0 => 10, 3 => 40); -- Bracket shorthand infers cardinality as the largest position + 1. SELECT [1 => 12, 33 => 23]; ``` With an ARRAY target, bracket shorthand uses the target's type and cardinality. A standalone expression uses the same common numeric type rules as a dense ARRAY, and sets cardinality to the largest position plus one. Targetless all-NULL sparse values, duplicate positions, and out-of-range positions are errors. For ingestion methods and SDK sparse objects, see [Sparse ARRAY and Selected-column Append APIs](/dbms/development-tools-integration/data-input-load-export/array-append/). ## AREA {#area} `AREA(y, x)` is an aggregate function that calculates the exact area under a curve of numeric `(x, y)` points. ```sql AREA(y, x) ``` - Both arguments must be numeric. - Rows with NULL in either argument are ignored. - Fewer than two valid points produce NULL. - The return type is `DOUBLE`. ```sql SELECT AREA(power_kw, sample_sec) FROM power_log; ``` ## AVG Aggregate function returning the average of a numeric column. ```sql AVG(column_name) ``` ```sql Mach> CREATE LOG TABLE avg_table (id1 INTEGER, id2 INTEGER); Created successfully. Mach> INSERT INTO avg_table VALUES(1, 1); 1 row(s) inserted. Mach> INSERT INTO avg_table VALUES(1, 2); 1 row(s) inserted. Mach> INSERT INTO avg_table VALUES(1, 3); 1 row(s) inserted. Mach> INSERT INTO avg_table VALUES(2, 1); 1 row(s) inserted. Mach> INSERT INTO avg_table VALUES(2, 2); 1 row(s) inserted. Mach> INSERT INTO avg_table VALUES(2, 3); 1 row(s) inserted. Mach> INSERT INTO avg_table VALUES(null, 4); 1 row(s) inserted. Mach> SELECT id1, AVG(id2) FROM avg_table GROUP BY id1; id1 AVG(id2) ------------------------------------------- 2 2 NULL 4 1 2 ``` ## BITAND / BITOR Converts two integers to signed 64-bit integers and returns their bitwise AND/OR. Inputs must be integers; the output is also a signed 64-bit integer. Negative integers can produce platform-dependent results. Using only uinteger and ushort types is recommended. ```sql BITAND (, ) BITOR (, ) ``` ```sql Mach> CREATE LOG TABLE bit_table (i1 INTEGER, i2 UINTEGER, i3 FLOAT, i4 DOUBLE, i5 SHORT, i6 VARCHAR(10)); Created successfully. Mach> INSERT INTO bit_table VALUES (-1, 1, 1, 1, 2, 'aaa'); 1 row(s) inserted. Mach> INSERT INTO bit_table VALUES (-2, 2, 2, 2, 3, 'bbb'); 1 row(s) inserted. Mach> SELECT BITAND(i1, i2) FROM bit_table; BITAND(i1, i2) ----------------------- 2 1 [2] row(s) selected. Mach> SELECT * FROM bit_table WHERE BITAND(i2, 1) = 1; I1 I2 I3 I4 I5 I6 --------------------------------------------------------------------------------------------------------------- -1 1 1 1 2 aaa [1] row(s) selected. Mach> SELECT BITOR(i5, 1) FROM bit_table WHERE BITOR(i5, 1) = 3; BITOR(i5, 1) ----------------------- 3 3 [2] row(s) selected. Mach> SELECT * FROM bit_table WHERE BITOR(i2, 1) = 1; I1 I2 I3 I4 I5 I6 --------------------------------------------------------------------------------------------------------------- -1 1 1 1 2 aaa [1] row(s) selected. Mach> SELECT * FROM bit_table WHERE BITAND(i3, 1) = 1; I1 I2 I3 I4 I5 I6 --------------------------------------------------------------------------------------------------------------- [ERR-02037 : Function [BITAND] argument data type is mismatched.] [0] row(s) selected. Mach> SELECT * FROM bit_table WHERE BITAND(i4, 1) = 1; I1 I2 I3 I4 I5 I6 --------------------------------------------------------------------------------------------------------------- [ERR-02037 : Function [BITAND] argument data type is mismatched.] [0] row(s) selected. Mach> SELECT BITAND(i5, 1) FROM bit_table WHERE BITAND(i5, 1) = 1; BITAND(i5, 1) ----------------------- 1 [1] row(s) selected. Mach> SELECT * FROM bit_table WHERE BITOR(i6, 1) = 1; I1 I2 I3 I4 I5 I6 --------------------------------------------------------------------------------------------------------------- [ERR-02037 : Function [BITOR] argument data type is mismatched.] [0] row(s) selected. Mach> SELECT BITOR(i1, i2) FROM bit_table; BITOR(i1, i2) ----------------------- -2 -1 [2] row(s) selected. Mach> SELECT BITAND(i1, i3) FROM bit_table; BITAND(i1, i3) ----------------------- [ERR-02037 : Function [BITAND] argument data type is mismatched.] [0] row(s) selected. Mach> SELECT BITOR(i1, i6) FROM bit_table; BITOR(i1, i6) ----------------------- [ERR-02037 : Function [BITOR] argument data type is mismatched.] [0] row(s) selected. ``` ## CAST Available since Machbase 8.7.0 `CAST` explicitly converts a value, column, or expression to the specified data type. It is available in SELECT, predicates, CASE, UNION ALL, VIEW definitions, and prepared statements. ### Syntax ```sql CAST(expression AS data_type) CAST(expression AS data_type(length)) CAST(expression AS DECIMAL(precision[, scale])) CAST(array_expression AS numeric_type[cardinality]) CAST(array_expression AS DECIMAL(precision[, scale])[cardinality]) ``` - `expression` is the value, column, or SQL expression to convert. - `array_expression` is a numeric ARRAY or SQL NULL. - `data_type` is a target type or alias listed below. - Type names are case-insensitive. - `length`, `precision`, and `scale` are allowed only for target types that support them. - Input and target ARRAY cardinalities must match exactly. ### Supported Types and Aliases | Category | Target Type | Accepted Names | |------|-----------|---------------------| | Signed integer | 16-bit | `INT16`, `SHORT` | | | 32-bit | `INT32`, `INT`, `INTEGER` | | | 64-bit | `INT64`, `LONG` | | Unsigned integer | 16-bit | `UINT16`, `USHORT` | | | 32-bit | `UINT32`, `UINTEGER` | | | 64-bit | `UINT64`, `ULONG` | | Floating-point | Single/double precision | `FLOAT`, `DOUBLE` | | Fixed-point | DECIMAL | `DECIMAL`, `NUMERIC`, `DEC`, `FIXED`, `NUMBER` | | Character | Fixed/variable length | `CHAR`, `VARCHAR` | | Character LOB | Text | `TEXT`, `CLOB` | | Date/time | Nanosecond precision | `DATETIME` | | Network address | IP address | `IPV4`, `IPV6` | | Binary | Binary/binary LOB | `BINARY`, `BLOB` | | Document | JSON | `JSON` | Names in the same row represent the same type. For example, INTEGER, INT, and INT32 all represent signed 32-bit integers. Result column metadata may display the canonical type name. ### Length and Precision #### CHAR, VARCHAR, BINARY | Type | Default Length | Allowed Length | Overflow Handling | |------|-------------------:|-----------|----------------| | `CHAR(n)` | 1 byte | 1–32,767 bytes | Retain the first n bytes | | `VARCHAR(n)` | 32,767 bytes | 1–32,767 bytes | Retain the first n bytes | | `BINARY(n)` | 1 byte | 1–67,108,864 bytes | Retain the first n bytes | Length is measured in bytes, not characters. Specify enough space for UTF-8 strings because a multibyte character can be truncated in the middle. CHAR does not pad unused space with blanks. Result metadata for `CAST(... AS CHAR(n))` currently reports `VARCHAR(n)`. ```sql SELECT '[' || CAST('abc' AS CHAR) || ']' AS char_default; -- [a] SELECT '[' || CAST('abc' AS CHAR(5)) || ']' AS char_value; -- [abc] (no spaces added) SELECT CAST('abcdef' AS VARCHAR(3)) AS varchar_value; -- abc SELECT CAST('414243' AS BINARY(2)) AS binary_value; -- 4142 ``` TEXT, CLOB, BLOB, and JSON do not accept a length. CAST results of these types currently support up to 32,767 bytes. If exceeding the permitted limit would damage the result's meaning, conversion returns an error rather than truncating it automatically. #### DECIMAL | Syntax | Interpretation | |------|------| | `DECIMAL` | `DECIMAL(10,0)` | | `DECIMAL(p)` | `DECIMAL(p,0)` | | `DECIMAL(p,s)` | precision `p`, scale `s` | - Precision p ranges from 1 through 65. - Scale s ranges from 0 through 30 and cannot exceed precision. - Excess fractional digits are rounded half away from zero. - Precision and scale are allowed only for DECIMAL-family types. ```sql SELECT CAST('12.34' AS DECIMAL(5,2)); -- 12.34 SELECT CAST(123.456 AS NUMERIC(6,2)); -- 123.46 ``` ### NULL and Empty Strings - NULL input returns NULL of the target type. - Machbase treats the zero-length string literal `''` as SQL NULL. - `''''` is a string containing one single quote, not an empty string. ```sql SELECT CAST(NULL AS INTEGER) AS null_integer; SELECT CAST('' AS VARCHAR(10)) AS empty_value; SELECT CAST('''' AS VARCHAR(10)) AS quote_value; ``` ### Numeric Conversion Numeric types can be converted to one another, and numeric strings can be converted to numeric types. ```sql SELECT CAST('123' AS INTEGER); SELECT CAST('1.25' AS DOUBLE); SELECT CAST(12.9 AS SHORT); -- 12 SELECT CAST(-12.9 AS INTEGER); -- -12 SELECT CAST('9223372036854775806e0' AS LONG); ``` - Floating-point-to-integer conversion truncates toward zero without rounding. - Exponent notation in integer strings is parsed while preserving integer precision. - Values outside the target type's range cause errors. - Negative results are not allowed for unsigned integers. A value whose fractional truncation produces zero can be converted to zero. - NaN and positive/negative infinity cannot be converted to integers. CAST produces the integer ranges below. Values reserved for NULL in each type are excluded from valid result ranges. | Target Type | CAST Result Range | |-----------|----------------| | `INT16`, `SHORT` | -32,767~32,767 | | `UINT16`, `USHORT` | 0~65,534 | | `INT32`, `INT`, `INTEGER` | -2,147,483,647~2,147,483,647 | | `UINT32`, `UINTEGER` | 0~4,294,967,294 | | `INT64`, `LONG` | -9,223,372,036,854,775,807~9,223,372,036,854,775,807 | | `UINT64`, `ULONG` | 0~18,446,744,073,709,551,614 | ### Converting an Entire Numeric ARRAY Numeric ARRAYs with the same cardinality support conversion of all elements. Target types include `INT16`, `UINT16`, `INT32`, `UINT32`, `INT64`, `UINT64`, `FLOAT`, `DOUBLE`, and `DECIMAL`, plus the numeric aliases in the supported type table. ```sql SELECT CAST([1.9, NULL, -3.9] AS INT32[3]); SELECT CAST([1.235, NULL, -2.345] AS DECIMAL(6,2)[3]); ``` - A whole-array NULL remains a whole-array NULL after conversion. - Each element NULL remains NULL at the same position. - Each non-NULL element follows the corresponding scalar numeric CAST rules for truncation, rounding, and range checking. - If any element cannot be converted, the CAST and its containing statement fail. No partially converted elements or rows remain as results. - `DECIMAL[N]` means `DECIMAL(10,0)[N]`; `DECIMAL(p)[N]` means `DECIMAL(p,0)[N]`. In a prepared statement, the CAST target also determines the parameter's element type, cardinality, and DECIMAL precision/scale. The same statement can be rebound with dense ARRAYs, sparse ARRAYs, and whole-array NULLs. ```sql SELECT CAST(? AS INT32[3]); SELECT CAST(? AS DECIMAL(12,4)[3]); ``` A scalar cannot be expanded to an ARRAY, and an ARRAY cannot be reduced to a scalar. Different cardinalities are not padded or truncated. String, date, IP, BINARY, and JSON ARRAYs are not supported as targets. ### String and LOB Conversion Numbers, date/time values, IP addresses, binary values, and JSON can be converted to character types. - Integers and DECIMAL return their decimal representation. - FLOAT uses up to 9 significant digits; DOUBLE uses up to 17. - DATETIME is formatted using the session date format and timezone. - IPV4 and IPV6 use normalized address strings. - BINARY and BLOB use uppercase hexadecimal without a prefix. - JSON preserves its original JSON representation. ```sql SELECT CAST(123456 AS VARCHAR(8)); -- 123456 SELECT CAST(CAST('2001:db8::1' AS IPV6) AS VARCHAR(64)); SELECT CAST(CAST('0x00ff10' AS BLOB) AS VARCHAR(8)); -- 00FF10 ``` To convert a string to BINARY or BLOB, use an even-length hexadecimal string with no prefix, or with a `0x`/`0X` prefix. ```sql SELECT CAST('414243' AS BINARY(3)); SELECT CAST('0x00ff10' AS BLOB); SELECT CAST(X'414243' AS VARCHAR(6)); ``` BINARY(n) retains only the first n bytes. Nonhexadecimal characters and odd-length hexadecimal strings cause errors. ### DATETIME Conversion Strings and numbers can be converted to DATETIME. - Strings are parsed using the session's default date format and timezone. - Numbers are interpreted as nanoseconds since the Unix epoch. - Numeric -1 is reserved for DATETIME NULL and cannot be converted. - Converting DATETIME to a number returns nanoseconds since the Unix epoch. ```sql SELECT CAST('2026-08-15 12:34:56' AS DATETIME); SELECT CAST(1000000000 AS DATETIME); SELECT CAST(CAST(1000000000 AS DATETIME) AS VARCHAR(40)); ``` The same epoch value can display as different dates and times when session timezones differ. ### IPV4 and IPV6 Conversion Strings can be converted to IPV4 or IPV6. The entire address must be valid. ```sql SELECT CAST('127.0.0.1' AS IPV4); SELECT CAST('2001:db8::1' AS IPV6); ``` Invalid addresses and address formats incompatible with the target type cause errors. ### JSON Conversion When converting a string to JSON, the entire input must be valid JSON. JSON strings, numbers, true, false, and null are accepted, as well as objects and arrays. ```sql SELECT CAST('{"ok":true}' AS JSON); SELECT CAST('[1,2,3]' AS JSON); SELECT CAST('"abc"' AS JSON); SELECT CAST(CAST('"abc"' AS JSON) AS VARCHAR(16)); -- "abc" ``` Partially valid JSON or trailing non-JSON characters prevent conversion. ### Expressions and Result Metadata CAST is an ordinary SQL expression and can be used in WHERE predicates, CASE, UNION ALL, and VIEW definitions. ```sql SELECT CASE WHEN reading >= 0 THEN CAST(reading AS VARCHAR(32)) ELSE 'invalid' END AS reading_text FROM sensor_log; CREATE VIEW sensor_cast_view AS SELECT CAST(sensor_id AS VARCHAR(100)) AS sensor_id_text, CAST(value AS DECIMAL(12,3)) AS value_decimal FROM sensor_log; ``` CAST syntax is the same in prepared statements. Supply values through `?` or SDK named markers; declare the target type and precision/scale in SQL. ```sql SELECT CAST(? AS DECIMAL(12,2)) AS amount; ``` CAST result type, byte length, and DECIMAL precision/scale are reflected in result metadata and VIEW column information. Result nullability follows input expression nullability. To combine ARRAY results in CASE or UNION ALL, element type, cardinality, and DECIMAL precision/scale must all match. If they differ, explicitly CAST each result to the same ARRAY type before combining. Each SDK exposes CAST results through existing result metadata APIs. No CAST-specific SDK API is provided. | SDK | CAST Result Metadata API | |-----|------------------------| | Machbase SQLCLI | `SQLDescribeCol()`, `SQLColAttribute()` | | ODBC | `SQLDescribeCol()`, `SQLColAttribute()` | | JDBC | `ResultSetMetaData` | | Python | `cursor.description` | | Node.js | `ColumnMeta` | | .NET | `GetSchemaTable()` | | Go (native) | native column metadata | | Go (`database/sql`) | `ColumnTypeNullable()` and `ColumnType` APIs | ### Error Conditions | Cause | Example | |------|-----| | Unsupported target type | `CAST('1' AS UNKNOWN_TYPE)` | | Invalid length or precision/scale | `CAST('1' AS INTEGER(2))`, `CAST('1' AS DECIMAL(2,3))` | | Numeric overflow or NULL reserved value | `CAST('65535' AS USHORT)` | | Negative value converted to unsigned integer | `CAST('-1' AS UINTEGER)` | | Nonnumeric string | `CAST('12x' AS INTEGER)` | | Conversion between scalar and ARRAY | `CAST(1 AS INT32[1])`, `CAST([1] AS INT32)` | | ARRAY cardinality mismatch | `CAST([1, 2] AS INT32[3])` | | Unsupported ARRAY target type | `CAST([1] AS VARCHAR[1])` | | Invalid IP address | `CAST('999.1.1.1' AS IPV4)` | | Odd-length or nonhexadecimal binary string | `CAST('123' AS BINARY(4))`, `CAST('GG' AS BLOB)` | | Invalid JSON | `CAST('{bad}' AS JSON)` | | LOB or JSON result exceeding the allowed size | TEXT, CLOB, BLOB, or JSON results exceeding 32,767 bytes | ### Compatibility CAST and whole numeric ARRAY CAST are supported in Machbase 8.7.0 in Standard and Cluster Editions. In Cluster Edition, all cluster nodes must use the same version with CAST support. Mixed execution with older nodes that do not support CAST is not supported. ### Related Documentation - [SQL Syntax Dictionary](../../syntax/) - [Data Type Dictionary](../../types/) - [Numeric ARRAY Types](../../types/array/) - [DECIMAL and NUMERIC Fixed-point Types](../../types/decimal-numeric-fixed-point/) ## COUNT Aggregate function that counts records in a column. ```sql COUNT(column_name) ``` ```sql Mach> CREATE LOG TABLE count_table (id1 INTEGER, id2 INTEGER); Created successfully. Mach> INSERT INTO count_table VALUES(1, 1); 1 row(s) inserted. Mach> INSERT INTO count_table VALUES(1, 2); 1 row(s) inserted. Mach> INSERT INTO count_table VALUES(1, 3); 1 row(s) inserted. Mach> INSERT INTO count_table VALUES(2, 1); 1 row(s) inserted. Mach> INSERT INTO count_table VALUES(2, 2); 1 row(s) inserted. Mach> INSERT INTO count_table VALUES(2, 3); 1 row(s) inserted. Mach> INSERT INTO count_table VALUES(null, 4); 1 row(s) inserted. Mach> SELECT COUNT(*) FROM count_table; COUNT(*) ----------------------- 7 [1] row(s) selected. Mach> SELECT COUNT(id1) FROM count_table; COUNT(id1) ----------------------- 6 [1] row(s) selected. ``` ## CUME_DIST {#cume_dist} `CUME_DIST(value, threshold)` returns the cumulative fraction of rows whose value is at most threshold. ```sql CUME_DIST(value, threshold) ``` - This is an aggregate function, not a window function. - Both arguments must be numeric. - threshold must be constant. - The result is DOUBLE from 0.0 through 1.0. ```sql SELECT CUME_DIST(latency_ms, 100) FROM api_log; ``` ## CURRENT_USER / SESSION_USER / CURRENT_USER_ID / SESSION_USER_ID Available since Machbase 8.7.0 Returns the effective user for current SQL execution and the authenticated session user, by name or internal ID. Supported in both Standard and Cluster Editions. | Function | Return Type | Description | |---|---|---| | `CURRENT_USER()` | `VARCHAR` | Effective username for current SQL execution | | `SESSION_USER()` | `VARCHAR` | Authenticated username of the current session | | `CURRENT_USER_ID()` | `INTEGER` | Effective user's internal ID | | `SESSION_USER_ID()` | `INTEGER` | Authenticated session user's internal ID | All four functions take no arguments and require parentheses. The parenthesis-free CURRENT_USER keyword and USER, SYSTEM_USER, and CURRENT_SCHEMA aliases are not supported. ```sql SELECT CURRENT_USER() AS current_name, SESSION_USER() AS session_name, CURRENT_USER_ID() AS current_id, SESSION_USER_ID() AS session_id; ``` In ordinary SQL, current user and session user are the same. ```text CURRENT_NAME SESSION_NAME CURRENT_ID SESSION_ID SYS SYS 1 1 ``` ### User Context in Views When querying another user's definer VIEW, SQL inside the VIEW runs with the owner's privileges. - CURRENT_USER() and CURRENT_USER_ID() return the VIEW owner. - SESSION_USER() and SESSION_USER_ID() return the calling session user. For a reproducible owner/caller example, see [VIEW Syntax](../../syntax/view-syntax/#view-user-context). ### Active Sessions After User Deletion If another administrator session drops a connected user, existing connections do not terminate immediately. The four functions continue to return the username and ID saved at login. The deleted user cannot reconnect and no longer appears in M$SYS_USERS. User IDs are internal Machbase metadata identifiers. Use them only to compare or join current metadata, not as long-term business user keys. ```sql SELECT COUNT(*) FROM M$SYS_USERS WHERE NAME = SESSION_USER() AND USER_ID = SESSION_USER_ID(); ``` ### Errors Passing arguments returns ERR-02036. The other three functions follow the same rule. ```sql SELECT CURRENT_USER(1); -- ERR-02036: Function [CURRENT_USER] has an invalid argument. ``` For account lifecycle details, see [Account Management](../../../../security-access-control/account/). ## DATE_TRUNC Truncates a DATETIME value to the specified time unit. ```sql DATE_TRUNC (field, date_val [, count]) ``` ```sql Mach> CREATE LOG TABLE trunc_table (i1 INTEGER, i2 DATETIME); Created successfully. Mach> INSERT INTO trunc_table VALUES (1, TO_DATE('1999-11-11 1:2:0 4:5:1')); 1 row(s) inserted. Mach> INSERT INTO trunc_table VALUES (2, TO_DATE('1999-11-11 1:2:0 5:5:2')); 1 row(s) inserted. Mach> INSERT INTO trunc_table VALUES (3, TO_DATE('1999-11-11 1:2:1 6:5:3')); 1 row(s) inserted. Mach> INSERT INTO trunc_table VALUES (4, TO_DATE('1999-11-11 1:2:1 7:5:4')); 1 row(s) inserted. Mach> INSERT INTO trunc_table VALUES (5, TO_DATE('1999-11-11 1:2:2 8:5:5')); 1 row(s) inserted. Mach> INSERT INTO trunc_table VALUES (6, TO_DATE('1999-11-11 1:2:2 9:5:6')); 1 row(s) inserted. Mach> INSERT INTO trunc_table VALUES (7, TO_DATE('1999-11-11 1:2:3 10:5:7')); 1 row(s) inserted. Mach> INSERT INTO trunc_table VALUES (8, TO_DATE('1999-11-11 1:2:3 11:5:8')); 1 row(s) inserted. Mach> SELECT COUNT(*), DATE_TRUNC('second', i2) tm FROM trunc_table group by tm ORDER BY 2; COUNT(*) tm -------------------------------------------------------- 2 1999-11-11 01:02:00 000:000:000 2 1999-11-11 01:02:01 000:000:000 2 1999-11-11 01:02:02 000:000:000 2 1999-11-11 01:02:03 000:000:000 [4] row(s) selected. Mach> SELECT COUNT(*), DATE_TRUNC('second', i2, 2) tm FROM trunc_table group by tm ORDER BY 2; COUNT(*) tm -------------------------------------------------------- 4 1999-11-11 01:02:00 000:000:000 4 1999-11-11 01:02:02 000:000:000 [2] row(s) selected. Mach> SELECT COUNT(*), DATE_TRUNC('nanosecond', i2, 2) tm FROM trunc_table group by tm ORDER BY 2; COUNT(*) tm -------------------------------------------------------- 1 1999-11-11 01:02:00 004:005:000 1 1999-11-11 01:02:00 005:005:002 1 1999-11-11 01:02:01 006:005:002 1 1999-11-11 01:02:01 007:005:004 1 1999-11-11 01:02:02 008:005:004 1 1999-11-11 01:02:02 009:005:006 1 1999-11-11 01:02:03 010:005:006 1 1999-11-11 01:02:03 011:005:008 [8] row(s) selected. Mach> SELECT COUNT(*), DATE_TRUNC('nsec', i2, 1000000000) tm FROM trunc_table group by tm ORDER BY 2; //Same as DATE_TRUNC('sec', i2, 1) COUNT(*) tm -------------------------------------------------------- 2 1999-11-11 01:02:00 000:000:000 2 1999-11-11 01:02:01 000:000:000 2 1999-11-11 01:02:02 000:000:000 2 1999-11-11 01:02:03 000:000:000 [4] row(s) selected. ``` Allowed ranges by time unit are as follows. * Nanosecond, microsecond, and millisecond units and abbreviations are available from 5.5.6. * Weeks start on Sunday. | Time Unit | Range | |--|--| |nanosecond (nsec)|1000000000 (1 second)| |microsecond (usec)|60000000 (60 seconds)| |millisecond (msec)|60000 (60 seconds)| |second (sec)|86400 (1 day)| |minute (min)|1440 (1 day)| |hour|24 (1 day)| |day|1| |week|1| |month|1| |year|1| For example, DATE_TRUNC('second', time, 120) returns values at **2-minute** intervals, equivalent to DATE_TRUNC('minute', time, 2). ## DATE_BIN Bins DATETIME values by time unit and range relative to the specified origin. ```sql DATE_BIN(field, count, source [, origin]) ``` - With origin specified, buckets are calculated relative to that timestamp. - Without origin, buckets are relative to 1970-01-01 00:00:00 in the server's local timezone. - count must be an integer of at least 1. To align buckets to local timezone boundaries like DATE_TRUNC() or ROLLUP(), use the three-argument form without origin. To keep boundaries identical regardless of server timezone, use the four-argument form with an explicit origin. For example, with a UTC+09:00 server timezone, aligning to local boundaries previously required a timezone-adjusted origin instead of DATE_BIN(..., 0). `DATE_BIN(field, count, source)` now provides the same effect. ```sql Mach> CREATE LOG TABLE log (time DATETIME); Created successfully. Mach> INSERT INTO log VALUES (TO_DATE('2000-01-01 00:00:00')); 1 row(s) inserted. Mach> INSERT INTO log VALUES (TO_DATE('2000-01-01 01:00:00')); 1 row(s) inserted. Mach> INSERT INTO log VALUES (TO_DATE('2000-01-01 02:00:00')); 1 row(s) inserted. Mach> INSERT INTO log VALUES (TO_DATE('2000-01-01 03:00:00')); 1 row(s) inserted. Mach> INSERT INTO log VALUES (TO_DATE('2000-01-01 04:00:00')); 1 row(s) inserted. Mach> SELECT TIME, DATE_BIN('hour', 2, time, TO_DATE('2020-01-01 00:00:00')) FROM log ORDER BY time; TIME DATE_BIN('hour', 2, time, TO_DATE('2020-01-01 00:00:00')) --------------------------------------------------------------------------------------------- 2000-01-01 00:00:00 000:000:000 2000-01-01 00:00:00 000:000:000 2000-01-01 01:00:00 000:000:000 2000-01-01 00:00:00 000:000:000 2000-01-01 02:00:00 000:000:000 2000-01-01 02:00:00 000:000:000 2000-01-01 03:00:00 000:000:000 2000-01-01 02:00:00 000:000:000 2000-01-01 04:00:00 000:000:000 2000-01-01 04:00:00 000:000:000 [5] row(s) selected. ``` Example of buckets aligned to local timezone boundaries: ```sql Mach> CREATE LOG TABLE t3521 (ts DATETIME); Created successfully. Mach> INSERT INTO t3521 VALUES (TO_DATE('2000-01-01 00:30:00')); 1 row(s) inserted. Mach> INSERT INTO t3521 VALUES (TO_DATE('2000-01-01 02:59:59')); 1 row(s) inserted. Mach> INSERT INTO t3521 VALUES (TO_DATE('2000-01-01 03:00:00')); 1 row(s) inserted. Mach> INSERT INTO t3521 VALUES (TO_DATE('2000-01-01 08:00:00')); 1 row(s) inserted. Mach> SELECT ts, DATE_BIN('hour', 3, ts) AS date_bin_3arg, DATE_TRUNC('hour', ts, 3) AS date_trunc_3arg FROM t3521 ORDER BY ts; ts date_bin_3arg date_trunc_3arg ---------------------------------------------------------------------------------------------------- 2000-01-01 00:30:00 000:000:000 2000-01-01 00:00:00 000:000:000 2000-01-01 00:00:00 000:000:000 2000-01-01 02:59:59 000:000:000 2000-01-01 00:00:00 000:000:000 2000-01-01 00:00:00 000:000:000 2000-01-01 03:00:00 000:000:000 2000-01-01 03:00:00 000:000:000 2000-01-01 03:00:00 000:000:000 2000-01-01 08:00:00 000:000:000 2000-01-01 06:00:00 000:000:000 2000-01-01 06:00:00 000:000:000 [4] row(s) selected. ``` Allowed ranges by time unit are listed below. * Nanosecond, microsecond, and millisecond units and abbreviations are available from 5.5.6. * A week equals 7 days. | Time Unit | |----:| |nanosecond (nsec)| |microsecond (usec)| |millisecond (msec)| |second (sec)| |minute (min)| |hour| |day| |week| |month| |year| ## DAYOFWEEK Returns the weekday of a DATETIME value as an integer. Semantically equivalent to [TO_CHAR(time, 'DAY')](#to_char), but returns an integer. ```sql DAYOFWEEK(date_val) ``` Return values represent weekdays as follows. | Return Value | Weekday | |--|--| | 0 | Sunday | | 1 | Monday | | 2 | Tuesday | | 3 | Wednesday | | 4 | Thursday | | 5 | Friday | | 6 | Saturday | ## DECODE Compares a column value with search values and returns the corresponding return value for a match. If none matches, returns default, or NULL if default is omitted. ```sql DECODE(column, [search, return],.. default) ``` ```sql Mach> CREATE LOG TABLE decode_table (id1 VARCHAR(11)); Created successfully. Mach> INSERT INTO decode_table VALUES('decodetest1'); 1 row(s) inserted. Mach> INSERT INTO decode_table VALUES('decodetest2'); 1 row(s) inserted. Mach> SELECT id1, DECODE(id1, 'decodetest1', 'result1', 'decodetest2', 'result2', 'DEFAULT') FROM decode_table; id1 DECODE(id1, 'decodetest1', 'result1', 'decodetest2', 'result2', 'DEFAULT') --------------------------------------------------------- decodetest2 result2 decodetest1 result1 [2] row(s) selected. Mach> SELECT id1, DECODE(id1, 'codetest', 2, 99) FROM decode_table; id1 DECODE(id1, 'codetest', 2, 99) ----------------------------------------------- decodetest2 99 decodetest1 99 [2] row(s) selected. Mach> SELECT DECODE(id1, 'decodetest1', 2) FROM decode_table; DECODE(id1, 'decodetest1', 2) -------------------------------- NULL 2 [2] row(s) selected. Mach> SELECT DECODE(id1, 'codetest', 2) FROM decode_table; DECODE(id1, 'codetest', 2) ----------------------------- NULL NULL [2] row(s) selected. ``` ## EXTRACT_* Functions for extracting bits from binary frames. EXTRACT_* uses big-endian order; EXTRACT_LE_* uses little-endian order. All functions accept BINARY/VARBINARY and return NULL for a NULL frame. **Endianness** - EXTRACT_*: MSB first (bit 0 is the MSB of byte[0]) - EXTRACT_LE_*: LSB first (bit 0 is the LSB of byte[0]) - Bit indexes are 0-based across the entire frame. **Common Rules** - Single bit: `0 <= bit_pos < frame_bits` - Range extraction: `start_bit >= 0`, `1 <= bit_count <= 64`, `start_bit + bit_count <= frame_bits` - EXTRACT_FLOAT* reads 32 bits; EXTRACT_DOUBLE* reads 64 bits. - Signed extraction interprets two's complement and sign-extends to 64 bits. - Range error: ERR_QP_INVALID_ARG_VALUE (ERR-02229 family) - Argument type error: ERR_QP_FUNCTION_ARG_TYPE ### EXTRACT_BIT ``` EXTRACT_BIT(frame, bit_pos) / EXTRACT_LE_BIT(frame, bit_pos) → TINYINT ``` Returns one bit as 0 or 1. ```sql -- frame = 0x80 (1000 0000) SELECT EXTRACT_BIT(frame, 0) AS be_bit0, EXTRACT_LE_BIT(frame, 0) AS le_bit0 FROM t; ``` ### EXTRACT_LONG, EXTRACT_ULONG ``` EXTRACT_ULONG(frame, start_bit, bit_count) → BIGINT UNSIGNED EXTRACT_LE_ULONG(frame, start_bit, bit_count) → BIGINT UNSIGNED EXTRACT_LONG(frame, start_bit, bit_count) → BIGINT EXTRACT_LE_LONG(frame, start_bit, bit_count) → BIGINT ``` Reads 1–64 bits as an unsigned or two's-complement integer. ```sql -- frame = 0x12 34 SELECT EXTRACT_ULONG(frame, 0, 16) AS be_u16, -- 0x1234 EXTRACT_LE_ULONG(frame, 0, 16) AS le_u16 -- 0x3412 FROM t; ``` ### EXTRACT_FLOAT,EXTRACT_DOUBLE ``` EXTRACT_FLOAT(frame, start_bit) → FLOAT EXTRACT_LE_FLOAT(frame, start_bit) → FLOAT EXTRACT_DOUBLE(frame, start_bit) → DOUBLE EXTRACT_LE_DOUBLE(frame, start_bit) → DOUBLE ``` Reinterprets 32/64 bits as IEEE 754 float/double. The specified bit range must fit within the frame. ```sql SELECT EXTRACT_FLOAT(frame, 0) AS be_f32, EXTRACT_LE_FLOAT(frame, 0) AS le_f32, EXTRACT_DOUBLE(frame, 64) AS be_f64, EXTRACT_LE_DOUBLE(frame, 64) AS le_f64 FROM sensor_bin; ``` ### EXTRACT_SCALED_DOUBLE ``` EXTRACT_SCALED_DOUBLE(frame, start_bit, bit_count, signed, scale, offset) → DOUBLE EXTRACT_LE_SCALED_DOUBLE(frame, start_bit, bit_count, signed, scale, offset) → DOUBLE ``` Reads 1–64 bits as unsigned when signed=0 or two's-complement signed when signed=1, then returns `raw * scale + offset`. ```sql -- 20-bit sensor value, scale 0.01, offset -40.0 SELECT EXTRACT_SCALED_DOUBLE(frame, 0, 20, 0, 0.01, -40.0) AS be_value, EXTRACT_LE_SCALED_DOUBLE(frame, 0, 20, 0, 0.01, -40.0) AS le_value FROM t_bin; ``` ## FIRST / LAST Aggregate functions returning a specified value from the first or last record in each group ordered by a reference value. * FIRST: Returns the value from the first record in sort order. * LAST: Returns the value from the last record in sort order. ```sql FIRST(sort_expr, return_expr) LAST(sort_expr, return_expr) ``` ```sql Mach> create table firstlast_table (id integer, name varchar(20), group_no integer); Created successfully. Mach> insert into firstlast_table values (1, 'John', 0); 1 row(s) inserted. Mach> insert into firstlast_table values (2, 'Grey', 1); 1 row(s) inserted. Mach> insert into firstlast_table values (5, 'Ryan', 0); 1 row(s) inserted. Mach> insert into firstlast_table values (4, 'Andrew', 0); 1 row(s) inserted. Mach> insert into firstlast_table values (7, 'Kyle', 1); 1 row(s) inserted. Mach> insert into firstlast_table values (6, 'Ross', 1); 1 row(s) inserted. Mach> select group_no, first(id, name) from firstlast_table group by group_no; group_no first(id, name) ------------------------------------- 1 Grey 0 John [2] row(s) selected. Mach> select group_no, last(id, name) from firstlast_table group by group_no; group_no last(id, name) ------------------------------------- 1 Kyle 0 Ryan ``` ## FROM_TIMESTAMP Converts nanoseconds elapsed since 1970-01-01 00:00:00 UTC to datetime. (TO_TIMESTAMP() converts datetime to nanoseconds elapsed since the same epoch.) The epoch appears as 1970-01-01 09:00:00 in UTC+09:00. Dates and times below use UTC+09:00. ```sql FROM_TIMESTAMP(nanosecond_time_value) ``` ```sql Mach> SELECT FROM_TIMESTAMP(1562302560007248869); FROM_TIMESTAMP(1562302560007248869) -------------------------------------- 2019-07-05 13:56:00 007:248:869 ``` SYSDATE and NOW are DATETIME values representing the current time. The example below converts the current time directly and after subtracting 1 millisecond (1,000,000 nanoseconds). ```sql Mach> select sysdate, from_timestamp(sysdate) from test_tbl; sysdate from_timestamp(sysdate) ------------------------------------------------------------------- 2019-07-05 14:00:59 722:822:443 2019-07-05 14:00:59 722:822:443 [1] row(s) selected. Mach> select sysdate, from_timestamp(sysdate-1000000) from test_tbl; sysdate from_timestamp(sysdate-1000000) ------------------------------------------------------------------- 2019-07-05 14:01:05 130:939:525 2019-07-05 14:01:05 129:939:525 -- Difference: 1 ms (1,000,000 ns) [1] row(s) selected. ``` ## FROM_UNIXTIME Converts a 32-bit UNIXTIME integer to datetime. (UNIX_TIMESTAMP converts datetime to a 32-bit UNIXTIME integer.) Dates and times below use UTC+09:00. ```sql FROM_UNIXTIME(unix_timestamp_value) ``` ```sql Mach> SELECT FROM_UNIXTIME(315540671) FROM TEST; FROM_UNIXTIME(315540671) ---------------------------------- 1980-01-01 11:11:11 000:000:000 Mach> SELECT FROM_UNIXTIME(UNIX_TIMESTAMP('2001-01-01')) FROM unix_table; FROM_UNIXTIME(UNIX_TIMESTAMP('2001-01-01')) ------------------------------------------ 2001-01-01 00:00:00 000:000:000 ``` ## GROUP_CONCAT Aggregate function that concatenates column values within a group into a string. {{< callout type="warning" >}} Unavailable in Cluster Edition. {{< /callout >}} ```sql GROUP_CONCAT( [DISTINCT] column [ORDER BY { unsigned_integer | column } [ASC | DESC] [, column ...]] [SEPARATOR str_val] ) ``` * DISTINCT: Concatenate each distinct value once. * ORDER BY: Order concatenated values by the specified columns. * SEPARATOR: Delimiter between column values. Default: comma (,). Syntax notes: * Only one column can be specified. To combine columns, use TO_CHAR() and concatenation (||) to form one expression. * ORDER BY can reference columns other than the concatenated column and can contain multiple columns. * SEPARATOR must be a string constant, not a string column. ```sql Mach> CREATE LOG TABLE concat_table(id1 INTEGER, id2 DOUBLE, name VARCHAR(10)); Created successfully. Mach> INSERT INTO concat_table VALUES (1, 2, 'John'); 1 row(s) inserted. Mach> INSERT INTO concat_table VALUES (2, 1, 'Ram'); 1 row(s) inserted. Mach> INSERT INTO concat_table VALUES (3, 2, 'Zara'); 1 row(s) inserted. Mach> INSERT INTO concat_table VALUES (4, 2, 'Jill'); 1 row(s) inserted. Mach> INSERT INTO concat_table VALUES (5, 1, 'Jack'); 1 row(s) inserted. Mach> INSERT INTO concat_table VALUES (6, 1, 'Jack'); 1 row(s) inserted. Mach> SELECT GROUP_CONCAT(name) AS G_NAMES FROM concat_table GROUP BY id2; G_NAMES ------------------------------------------------------------------------------------ Jack,Jack,Ram Jill,Zara,John [2] row(s) selected. Mach> SELECT GROUP_CONCAT(DISTINCT name) AS G_NAMES FROM concat_table GROUP BY Id2; G_NAMES ------------------------------------------------------------------------------------ Jack,Ram Jill,Zara,John [2] row(s) selected. Mach> SELECT GROUP_CONCAT(name SEPARATOR '.') G_NAMES FROM concat_table GROUP BY Id2; G_NAMES ------------------------------------------------------------------------------------ Jack.Jack.Ram Jill.Zara.John [2] row(s) selected. Mach> SELECT GROUP_CONCAT(name ORDER BY id1) G_NAMES, GROUP_CONCAT(id1 ORDER BY id1) G_SORTID FROM concat_table GROUP BY id2; G_NAMES ------------------------------------------------------------------------------------ G_SORTID ------------------------------------------------------------------------------------ Ram,Jack,Jack 2,5,6 John,Zara,Jill 1,3,4 [2] row(s) selected. ``` ## INSTR Returns the 1-based starting position of a pattern string in the target string. * Returns 0 if the pattern is absent. * Returns NULL if the pattern has zero length or is NULL. ```sql INSTR(target_string, pattern_string) ``` ```sql Mach> CREATE LOG TABLE string_table(c1 VARCHAR(20)); Created successfully. Mach> INSERT INTO string_table VALUES ('abstract'); 1 row(s) inserted. Mach> INSERT INTO string_table VALUES ('override'); 1 row(s) inserted. Mach> SELECT c1, INSTR(c1, 'act') FROM string_table; c1 INSTR(c1, 'act') ------------------------------------------ override 0 abstract 6 [2] row(s) selected. ``` ## LEAST / GREATEST Given multiple columns or values, LEAST returns the minimum and GREATEST the maximum. Zero or one input causes an error. A NULL input returns NULL; when inputs are columns, transform NULLs with a function first. Noncomparable columns such as BLOB or TEXT, or values that cannot be converted for comparison, cause errors. ```sql LEAST(value_list, value_list,...) GREATEST(value_list, value_list,...) ``` ```sql Mach> CREATE LOG TABLE lgtest_table(c1 INTEGER, c2 LONG, c3 VARCHAR(10), c4 VARCHAR(5)); Created successfully. Mach> INSERT INTO lgtest_table VALUES (1, 2, 'abstract', 'ace'); 1 row(s) inserted. Mach> INSERT INTO lgtest_table VALUES (null, 100, null, 'bag'); 1 row(s) inserted. Mach> SELECT LEAST (c1, c2) FROM lgtest_table; LEAST (c1, c2) ----------------------- NULL 1 [2] row(s) selected. Mach> SELECT LEAST (c1, c2, -1) FROM lgtest_table; LEAST (c1, c2, -1) ----------------------- NULL -1 [2] row(s) selected. Mach> SELECT GREATEST(c3, c4) FROM lgtest_table; GREATEST(c3, c4) -------------------- NULL ace [2] row(s) selected. Mach> SELECT LEAST(c3, c4) FROM lgtest_table; LEAST(c3, c4) ----------------- NULL abstract [2] row(s) selected. Mach> SELECT LEAST(NVL(c3, 'aa'), c4) FROM lgtest_table; LEAST(NVL(c3, 'aa'), c4) ---------------------------- aa abstract [2] row(s) selected. ``` ## LENGTH Returns the length of a string column in bytes, based on English (ASCII) characters. ```sql LENGTH(column_name) ``` ```sql Mach> CREATE LOG TABLE length_table (id1 INTEGER, id2 DOUBLE, name VARCHAR(15)); Created successfully. Mach> INSERT INTO length_table VALUES(1, 10, 'Around the Horn'); 1 row(s) inserted. Mach> INSERT INTO length_table VALUES(NULL, 20, 'Alfreds Futterkiste'); 1 row(s) inserted. Mach> INSERT INTO length_table VALUES(3, NULL, 'Antonio Moreno'); 1 row(s) inserted. Mach> INSERT INTO length_table VALUES(4, 40, NULL); 1 row(s) inserted. Mach> select * FROM length_table; ID1 ID2 NAME ------------------------------------------------------------- 4 40 NULL 3 NULL Antonio Moreno NULL 20 Alfreds Futterk 1 10 Around the Horn [4] row(s) selected. Mach> select id1 * 10 FROM length_table; id1 * 10 ----------------------- 40 30 NULL 10 [4] row(s) selected. Mach> select * FROM length_table Where id1 > 1 and id2 < 50; ID1 ID2 NAME ------------------------------------------------------------- 4 40 NULL [1] row(s) selected. Mach> select name || ' with null concat' FROM length_table; name || ' with null concat' ------------------------------------ NULL Antonio Moreno with null concat Alfreds Futterk with null concat Around the Horn with null concat [4] row(s) selected. Mach> select LENGTH(name) FROM length_table; LENGTH(name) --------------- NULL 14 15 15 [4] row(s) selected. ``` ## LOWER Converts English letters to lowercase. ```sql LOWER(column_name) ``` ```sql Mach> CREATE LOG TABLE lower_table (name VARCHAR(20)); Created successfully. Mach> INSERT INTO lower_table VALUES(''); 1 row(s) inserted. Mach> INSERT INTO lower_table VALUES('James Backley'); 1 row(s) inserted. Mach> INSERT INTO lower_table VALUES('Alfreds Futterkiste'); 1 row(s) inserted. Mach> INSERT INTO lower_table VALUES('Antonio MORENO'); 1 row(s) inserted. Mach> INSERT INTO lower_table VALUES (NULL); 1 row(s) inserted. Mach> SELECT LOWER(name) FROM lower_table; LOWER(name) ------------------------ NULL antonio moreno alfreds futterkiste james backley NULL [5] row(s) selected. ``` ## LPAD / RPAD Pads the left (LPAD) or right (RPAD) of an input string to the specified length. The final char parameter is optional; the default padding character is a space (' '). If the input is longer than the specified length, returns only that many characters from the beginning without padding. ```sql LPAD(str, len, padstr) RPAD(str, len, padstr) ``` ```sql Mach> CREATE LOG TABLE pad_table (c1 integer, c2 varchar(15)); Created successfully. Mach> INSERT INTO pad_table VALUES (1, 'Antonio'); 1 row(s) inserted. Mach> INSERT INTO pad_table VALUES (25, 'Johnathan'); 1 row(s) inserted. Mach> INSERT INTO pad_table VALUES (30, 'M'); 1 row(s) inserted. Mach> SELECT LPAD(to_char(c1), 5, '0') FROM pad_table; LPAD(to_char(c1), 5, '0') ----------------------------- 00030 00025 00001 [3] row(s) selected. Mach> SELECT RPAD(to_char(c1), 5, '0') FROM pad_table; RPAD(to_char(c1), 5, '0') ----------------------------- 30000 25000 10000 [3] row(s) selected. Mach> SELECT LPAD(c2, 5) FROM pad_table; LPAD(c2, 5) --------------- M Johna Anton [3] row(s) selected. Mach> SELECT RPAD(c2, 5) FROM pad_table; RPAD(c2, 5) --------------- M Johna Anton [3] row(s) selected. Mach> SELECT RPAD(c2, 10, '***') FROM pad_table; RPAD(c2, 10, '***') ----------------------- M********* Johnathan* Antonio*** [3] row(s) selected. ``` ## LTRIM / RTRIM Removes characters present in the pattern string from the first argument. LTRIM scans from the left and RTRIM from the right, stopping at the first character absent from the pattern. Returns NULL if every character is removed. If pattern is omitted, trims spaces (' '). ```sql LTRIM(column_name, pattern) RTRIM(column_name, pattern) ``` ```sql Mach> CREATE LOG TABLE trim_table1(name VARCHAR(10)); Created successfully. Mach> INSERT INTO trim_table1 VALUES (' smith '); 1 row(s) inserted. Mach> SELECT ltrim(name) FROM trim_table1; ltrim(name) --------------- smith [1] row(s) selected. Mach> SELECT rtrim(name) FROM trim_table1; rtrim(name) --------------- smith [1] row(s) selected. Mach> SELECT ltrim(name, ' s') FROM trim_table1; ltrim(name, ' s') --------------------- mith [1] row(s) selected. Mach> SELECT rtrim(name, 'h ') FROM trim_table1; rtrim(name, 'h ') --------------------- smit [1] row(s) selected. Mach> CREATE LOG TABLE trim_table2 (name VARCHAR(10)); Created successfully. Mach> INSERT INTO trim_table2 VALUES ('ddckaaadkk'); 1 row(s) inserted. Mach> SELECT ltrim(name, 'dc') FROM trim_table2; ltrim(name, 'dc') --------------------- kaaadkk [1] row(s) selected. Mach> SELECT rtrim(name, 'dk') FROM trim_table2; rtrim(name, 'dk') --------------------- ddckaaa [1] row(s) selected. Mach> SELECT ltrim(name, 'dckak') FROM trim_table2; ltrim(name, 'dckak') ------------------------ NULL [1] row(s) selected. Mach> SELECT rtrim(name, 'dckak') FROM trim_table2; rtrim(name, 'dckak') ------------------------ NULL [1] row(s) selected. ``` ## MAX Aggregate function returning the maximum of the specified numeric column. ```sql MAX(column_name) ``` ```sql Mach> CREATE LOG TABLE max_table (c INTEGER); Created successfully. Mach> INSERT INTO max_table VALUES(10); 1 row(s) inserted. Mach> INSERT INTO max_table VALUES(20); 1 row(s) inserted. Mach> INSERT INTO max_table VALUES(30); 1 row(s) inserted. Mach> SELECT MAX(c) FROM max_table; MAX(c) -------------- 30 [1] row(s) selected. ``` ## MEDIAN {#median} MEDIAN(value) returns the exact median of a numeric expression, using the same behavior as PERCENTILE_CONT(value, 0.5). ```sql MEDIAN(value) ``` - value must be numeric. - NULL values are ignored. - The return type is DOUBLE. ```sql SELECT MEDIAN(temp_c) FROM sensor_log; ``` ## MIN Aggregate function returning the minimum of the specified numeric column. ```sql MIN(column_name) ``` ```sql Mach> CREATE LOG TABLE min_table(c1 INTEGER); Created successfully. Mach> INSERT INTO min_table VALUES(1); 1 row(s) inserted. Mach> INSERT INTO min_table VALUES(22); 1 row(s) inserted. Mach> INSERT INTO min_table VALUES(33); 1 row(s) inserted. Mach> SELECT MIN(c1) FROM min_table; MIN(c1) -------------- 1 [1] row(s) selected. ``` ## NVL Replaces a NULL column value with the specified value; otherwise returns the original value. ```sql NVL(string1, replace_with) ``` ```sql Mach> CREATE LOG TABLE nvl_table (c1 varchar(10)); Created successfully. Mach> INSERT INTO nvl_table VALUES ('Johnathan'); 1 row(s) inserted. Mach> INSERT INTO nvl_table VALUES (NULL); 1 row(s) inserted. Mach> SELECT NVL(c1, 'Thomas') FROM nvl_table; NVL(c1, 'Thomas') --------------------- Thomas Johnathan ``` ## NEXTVAL NEXTVAL(sequence_column) returns the next value of a Lookup table sequence column. ```sql NEXTVAL(sequence_column) ``` - NEXTVAL is available only in INSERT. - The argument must be a column configured with PROPERTY(SEQUENCE=...). - For sequence column creation and examples, see [Sequence Column](/dbms/lookup-table-usage/sequence-column/). ```sql INSERT INTO seq_lookup (id, name) VALUES (NEXTVAL(id), 'sensor-a'); ``` ## ROUND Returns the input rounded at the specified decimal position (using the next digit). If omitted, rounds to zero decimal places. A negative position rounds within the integer part. ```sql ROUND(column_name, [decimals]) ``` ```sql Mach> CREATE LOG TABLE round_table (c1 DOUBLE); Created successfully. Mach> INSERT INTO round_table VALUES (1.994); 1 row(s) inserted. Mach> INSERT INTO round_table VALUES (1.995); 1 row(s) inserted. Mach> SELECT c1, ROUND(c1, 2) FROM round_table; c1 ROUND(c1, 2) ----------------------------------------------------------- 1.995 2 1.994 1.99 ``` ## ROWNUM Numbers SELECT result rows. Can be used inside SELECT subqueries and inline views. Assign an alias to ROWNUM() in an inline view's select list to reference it externally. ```sql ROWNUM() ``` **Allowed Clauses** Allowed in SELECT lists, GROUP BY, and ORDER BY; not allowed in WHERE or HAVING. To filter by row number, calculate ROWNUM() in an inline view and reference it in the outer query. | Allowed Clauses | Disallowed Clauses | |--|--| |Target List / GROUP BY / ORDER BY|WHERE / HAVING| ```sql Mach> CREATE LOG TABLE rownum_table(c1 INTEGER, c2 DOUBLE, c3 VARCHAR(10)); Created successfully. Mach> INSERT INTO rownum_table VALUES(1, 1.0, ''); 1 row(s) inserted. Mach> INSERT INTO rownum_table VALUES(2, 2.0, 'Second Row'); 1 row(s) inserted. Mach> INSERT INTO rownum_table VALUES(3, 3.3, 'Third Row'); 1 row(s) inserted. Mach> INSERT INTO rownum_table VALUES(4, 4.3, 'Fourth Row'); 1 row(s) inserted. Mach> SELECT INNER_RANK, c3 AS NAME 2 FROM (SELECT ROWNUM() AS INNER_RANK, * FROM rownum_table) 3 WHERE INNER_RANK < 3; INNER_RANK NAME ------------------------------------ 1 Fourth Row 2 Third Row [2] row(s) selected. ``` **Effect of Sorting on Row Numbers** With ORDER BY, ROWNUM() values in the select list may appear out of sequence because ROWNUM() is evaluated before sorting. For sequential numbering, place the ordered query in an inline view and call ROWNUM() in the outer SELECT. ```sql Mach> CREATE LOG TABLE rownum_table(c1 INTEGER, c2 DOUBLE, c3 VARCHAR(10)); Created successfully. Mach> INSERT INTO rownum_table VALUES(1, 1.0, ''); 1 row(s) inserted. Mach> INSERT INTO rownum_table VALUES(2, 2.0, 'John'); 1 row(s) inserted. Mach> INSERT INTO rownum_table VALUES(3, 3.3, 'Sarah'); 1 row(s) inserted. Mach> INSERT INTO rownum_table VALUES(4, 4.3, 'Micheal'); 1 row(s) inserted. Mach> SELECT ROWNUM(), c2 AS SORT, c3 AS NAME 2 FROM ( SELECT * FROM rownum_table ORDER BY c3 ); ROWNUM() SORT NAME ----------------------------------------------------------------- 1 1 NULL 2 2 John 3 4.3 Micheal 4 3.3 Sarah [4] row(s) selected. ``` ## SERIESNUM Returns the number of the contiguous SERIES BY interval containing each row. Rows in the same interval share a number; this is not the row's position within the interval. Return type: BIGINT. Without SERIES BY, always returns 1. ```sql SERIESNUM() ``` ```sql Mach> CREATE LOG TABLE T1 (C1 INTEGER, C2 INTEGER); Created successfully. Mach> INSERT INTO T1 VALUES (0, 1); 1 row(s) inserted. Mach> INSERT INTO T1 VALUES (1, 2); 1 row(s) inserted. Mach> INSERT INTO T1 VALUES (2, 3); 1 row(s) inserted. Mach> INSERT INTO T1 VALUES (3, 2); 1 row(s) inserted. Mach> INSERT INTO T1 VALUES (4, 1); 1 row(s) inserted. Mach> INSERT INTO T1 VALUES (5, 2); 1 row(s) inserted. Mach> INSERT INTO T1 VALUES (6, 3); 1 row(s) inserted. Mach> INSERT INTO T1 VALUES (7, 1); 1 row(s) inserted. Mach> SELECT SERIESNUM(), C1, C2 FROM T1 ORDER BY C1 SERIES BY C2 > 1; SERIESNUM() C1 C2 ------------------------------------------------- 1 1 2 1 2 3 1 3 2 2 5 2 2 6 3 [5] row(s) selected. ``` ## STDDEV / STDDEV_POP Aggregate functions returning sample standard deviation (STDDEV) and population standard deviation (STDDEV_POP), respectively the square roots of VARIANCE and VAR_POP. ```sql STDDEV(column) STDDEV_POP(column) ``` ```sql Mach> CREATE LOG TABLE stddev_table(c1 INTEGER, C2 DOUBLE); Mach> INSERT INTO stddev_table VALUES (1, 1); 1 row(s) inserted. Mach> INSERT INTO stddev_table VALUES (2, 1); 1 row(s) inserted. Mach> INSERT INTO stddev_table VALUES (3, 2); 1 row(s) inserted. Mach> INSERT INTO stddev_table VALUES (4, 2); 1 row(s) inserted. Mach> SELECT c2, STDDEV(c1) FROM stddev_table GROUP BY c2; c2 STDDEV(c1) ----------------------------------------------------------- 1 0.707107 2 0.707107 [2] row(s) selected. Mach> SELECT c2, STDDEV_POP(c1) FROM stddev_table GROUP BY c2; c2 STDDEV_POP(c1) ----------------------------------------------------------- 1 0.5 2 0.5 [2] row(s) selected. ``` ## SUBSTR Returns SIZE characters from a string column starting at START. * START is 1-based; 0 returns NULL. * If SIZE exceeds the remaining length, returns from START to the end of the string. SIZE is optional and defaults to the string length. ```sql SUBSTRING(column_name, start, [length]) ``` ```sql Mach> CREATE LOG TABLE substr_table (c1 VARCHAR(10)); Created successfully. Mach> INSERT INTO substr_table values('ABCDEFG'); 1 row(s) inserted. Mach> INSERT INTO substr_table values('abstract'); 1 row(s) inserted. Mach> SELECT SUBSTR(c1, 1, 1) FROM substr_table; SUBSTR(c1, 1, 1) -------------------- a A [2] row(s) selected. Mach> SELECT SUBSTR(c1, 3, 3) FROM substr_table; SUBSTR(c1, 3, 3) -------------------- str CDE [2] row(s) selected. Mach> SELECT SUBSTR(c1, 2) FROM substr_table; SUBSTR(c1, 2) ----------------- bstract BCDEFG [2] row(s) selected. Mach> drop table substr_table; Dropped successfully. Mach> CREATE LOG TABLE substr_table (c1 VARCHAR(10)); Created successfully. Mach> INSERT INTO substr_table values('ABCDEFG'); 1 row(s) inserted. Mach> SELECT SUBSTR(c1, 1, 1) FROM substr_table; SUBSTR(c1, 1, 1) -------------------- A [1] row(s) selected. Mach> SELECT SUBSTR(c1, 3, 3) FROM substr_table; SUBSTR(c1, 3, 3) -------------------- CDE [1] row(s) selected. Mach> SELECT SUBSTR(c1, 2) FROM substr_table; SUBSTR(c1, 2) ----------------- BCDEFG [1] row(s) selected. ``` ## SUBSTRING_INDEX Returns the substring before count occurrences of delim. For negative count, searches from the end and returns the substring from the delimiter position to the end. count=0 returns NULL. If count is nonzero and the delimiter is absent, returns the entire input string. ```sql SUBSTRING_INDEX(expression, delim, count) ``` ```sql Mach> CREATE LOG TABLE substring_table (url VARCHAR(30)); Created successfully. Mach> INSERT INTO substring_table VALUES('www.machbase.com'); 1 row(s) inserted. Mach> SELECT SUBSTRING_INDEX(url, '.', 1) FROM substring_table; SUBSTRING_INDEX(url, '.', 1) ---------------------------------- www [1] row(s) selected. Mach> SELECT SUBSTRING_INDEX(url, '.', 2) FROM substring_table; SUBSTRING_INDEX(url, '.', 2) ---------------------------------- www.machbase [1] row(s) selected. Mach> SELECT SUBSTRING_INDEX(url, '.', -1) FROM substring_table; SUBSTRING_INDEX(url, '.', -1) ---------------------------------- com [1] row(s) selected. Mach> SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(url, '.', 2), '.', -1) FROM substring_table; SUBSTRING_INDEX(SUBSTRING_INDEX(url, '.', 2), '.', -1) ------------------------------------------- machbase [1] row(s) selected. Mach> SELECT SUBSTRING_INDEX(url, '.', 0) FROM substring_table; SUBSTRING_INDEX(url, '.', 0) ---------------------------------- NULL [1] row(s) selected. ``` ## SUM Aggregate function returning the sum of a numeric column. ```sql SUM(column_name) ``` ```sql Mach> CREATE LOG TABLE sum_table (c1 INTEGER, c2 INTEGER); Created successfully. Mach> INSERT INTO sum_table VALUES(1, 1); 1 row(s) inserted. Mach> INSERT INTO sum_table VALUES(1, 2); 1 row(s) inserted. Mach> INSERT INTO sum_table VALUES(1, 3); 1 row(s) inserted. Mach> INSERT INTO sum_table VALUES(2, 1); 1 row(s) inserted. Mach> INSERT INTO sum_table VALUES(2, 2); 1 row(s) inserted. Mach> INSERT INTO sum_table VALUES(2, 3); 1 row(s) inserted. Mach> INSERT INTO sum_table VALUES(3, 4); 1 row(s) inserted. Mach> SELECT c1, SUM(c1) from sum_table group by c1; c1 SUM(c1) ------------------------------------ 2 6 3 3 1 3 [3] row(s) selected. Mach> SELECT c1, SUM(c2) from sum_table group by c1; c1 SUM(c2) ------------------------------------ 2 6 3 4 1 6 [3] row(s) selected. ``` ## SUMSQ SUMSQ returns the sum of squared numeric values. ```sql SUMSQ(value) ``` ```sql Mach> CREATE LOG TABLE sumsq_table (c1 INTEGER, c2 INTEGER); Created successfully. Mach> INSERT INTO sumsq_table VALUES (1, 1); 1 row(s) inserted. Mach> INSERT INTO sumsq_table VALUES (1, 2); 1 row(s) inserted. Mach> INSERT INTO sumsq_table VALUES (1, 3); 1 row(s) inserted. Mach> INSERT INTO sumsq_table VALUES (2, 4); 1 row(s) inserted. Mach> INSERT INTO sumsq_table VALUES (2, 5); 1 row(s) inserted. Mach> SELECT c1, SUMSQ(c2) FROM sumsq_table GROUP BY c1; c1 SUMSQ(c2) ------------------------------------ 2 41 1 14 [2] row(s) selected. ``` ## SYSDATE / NOW SYSDATE is a pseudocolumn, not a function, and returns current system time. NOW provides the same behavior as SYSDATE for convenience. ```sql SYSDATE NOW ``` ```sql Mach> SELECT SYSDATE, NOW FROM t1; SYSDATE NOW ------------------------------------------------------------------- 2017-01-16 14:14:53 310:973:000 2017-01-16 14:14:53 310:973:000 ``` ## TO_CHAR Converts the input data type to a string. format_string is available depending on type, but cannot be used for binary types. ```sql TO_CHAR(column) ``` **TO_CHAR: Basic Data Types** Basic data types convert to strings as shown below. ```sql Mach> CREATE LOG TABLE fixed_table (id1 SHORT, id2 INTEGER, id3 LONG, id4 FLOAT, id5 DOUBLE, id6 IPV4, id7 IPV6, id8 VARCHAR (128)); Created successfully. Mach> INSERT INTO fixed_table values(200, 19234, 1234123412, 3.14, 7.8338, '192.168.0.1', '::127.0.0.1', 'log varchar'); 1 row(s) inserted. Mach> SELECT '[ ' || TO_CHAR(id1) || ' ]' FROM fixed_table; '[ ' || TO_CHAR(id1) || ' ]' ------------------------------------------------------------------------------------ [ 200 ] [1] row(s) selected. Mach> SELECT '[ ' || TO_CHAR(id2) || ' ]' FROM fixed_table; '[ ' || TO_CHAR(id2) || ' ]' ------------------------------------------------------------------------------------ [ 19234 ] [1] row(s) selected. Mach> SELECT '[ ' || TO_CHAR(id3) || ' ]' FROM fixed_table; '[ ' || TO_CHAR(id3) || ' ]' ------------------------------------------------------------------------------------ [ 1234123412 ] [1] row(s) selected. Mach> SELECT '[ ' || TO_CHAR(id4) || ' ]' FROM fixed_table; '[ ' || TO_CHAR(id4) || ' ]' ------------------------------------------------------------------------------------ [ 3.140000 ] [1] row(s) selected. Mach> SELECT '[ ' || TO_CHAR(id5) || ' ]' FROM fixed_table; '[ ' || TO_CHAR(id5) || ' ]' ------------------------------------------------------------------------------------ [ 7.833800 ] [1] row(s) selected. Mach> SELECT '[ ' || TO_CHAR(id6) || ' ]' FROM fixed_table; '[ ' || TO_CHAR(id6) || ' ]' ------------------------------------------------------------------------------------ [ 192.168.0.1 ] [1] row(s) selected. Mach> SELECT '[ ' || TO_CHAR(id7) || ' ]' FROM fixed_table; '[ ' || TO_CHAR(id7) || ' ]' ------------------------------------------------------------------------------------ [ 0000:0000:0000:0000:0000:0000:7F00:0001 ] [1] row(s) selected. Mach> SELECT '[ ' || TO_CHAR(id8) || ' ]' FROM fixed_table; '[ ' || TO_CHAR(id8) || ' ]' ------------------------------------------------------------------------------------ [ log varchar ] [1] row(s) selected. ``` **TO_CHAR: Floating-point Numbers** * Supported from 5.5.6 Converts float and double values to strings. The format expression cannot be repeated and must have the form '[letter][number]'. | Format | Description | |--|--| | F / f | Decimal places. Maximum: 30. | | N / n | Decimal places with a comma every three integer digits. Maximum: 30. | ```sql Mach> create table float_table (i1 float, i2 double); Created successfully. Mach> insert into float_table values (1.23456789, 1234.5678901234567890); 1 row(s) inserted. Mach> select TO_CHAR(i1, 'f8'), TO_CHAR(i2, 'N9') from float_table; TO_CHAR(i1, 'f8') TO_CHAR(i2, 'N9') -------------------------------------------------------------- 1.23456788 1,234.567890123 [1] row(s) selected. ``` **TO_CHAR: DATETIME** Converts datetime column values to formatted strings that can be generated and combined as needed. If format_string is omitted, the default is "YYYY-MM-DD HH24: MI: SS mmm: uuu: nnn". | Format | Description | |--|--| | YYYY | Four-digit year | | YY | Two-digit year | | MM | Two-digit month | | MON | Three-letter English month abbreviation, such as JAN, FEB, MAY | | DD | Two-digit day | | DAY | Three-letter English weekday abbreviation, such as SUN, MON | | IW | ISO 8601 week of year, 1–53, accounting for weekdays.
Weeks start on Monday.
The first week may belong to the previous year; the last week may belong to the next year.
See ISO 8601 for details. | | WW | Week of year, 1–53, independent of weekday.
For example, January 1–7 returns 1. | | W | Week of month, 1–5, independent of weekday.
For example, March 1–7 returns 1. | | HH | Two-digit hour | | HH12 | Two-digit hour in the range 1–12 | | HH24 | Two-digit hour in the range 00–23 | | HH2, HH3, HH6 | Truncate hours to the multiple after HH.
For HH6, hours 0–5 return 0 and 6–11 return 6.
Useful for time-series statistics.
Values use the 24-hour clock. | | MI | Two-digit minute | | MI2, MI5, MI10, MI20, MI30 | Truncate minutes to the multiple after MI.
For MI30, minutes 0–29 return 0 and 30–59 return 30.
Useful for time-series statistics. | | SS | Two-digit second | | SS2, SS5, SS10, SS20, SS30 | Truncate seconds to the multiple after SS.
For SS30, seconds 0–29 return 0 and 30–59 return 30.
Useful for time-series statistics. | | AM | Display AM/PM | | mmm | Three-digit milliseconds, 0–999 | | uuu | Three-digit microseconds, 0–999 | | nnn | Three-digit nanoseconds, 0–999 | ```sql Mach> CREATE LOG TABLE datetime_table (id integer, dt datetime); Created successfully. Mach> INSERT INTO datetime_table values(1, TO_DATE('1999-11-11 1:2:3 4:5:6')); 1 row(s) inserted. Mach> INSERT INTO datetime_table values(2, TO_DATE('2012-11-11 1:2:3 4:5:6')); 1 row(s) inserted. Mach> INSERT INTO datetime_table values(3, TO_DATE('2013-11-11 1:2:3 4:5:6')); 1 row(s) inserted. Mach> INSERT INTO datetime_table values(4, TO_DATE('2014-12-30 11:22:33 444:555:666')); 1 row(s) inserted. Mach> SELECT id, dt FROM datetime_table WHERE dt > TO_DATE('2000-11-11 1:2:3 4:5:0'); id dt ----------------------------------------------- 4 2014-12-30 11:22:33 444:555:666 3 2013-11-11 01:02:03 004:005:006 2 2012-11-11 01:02:03 004:005:006 [3] row(s) selected. Mach> SELECT id, dt FROM datetime_table WHERE dt > TO_DATE('2013-11-11 1:2:3') and dt < TO_DATE('2014-11-11 1:2:3'); id dt ----------------------------------------------- 3 2013-11-11 01:02:03 004:005:006 [1] row(s) selected. Mach> SELECT id, TO_CHAR(dt) FROM datetime_table; id TO_CHAR(dt) ------------------------------------------------------------------------------------------------- 4 2014-12-30 11:22:33 444:555:666 3 2013-11-11 01:02:03 004:005:006 2 2012-11-11 01:02:03 004:005:006 1 1999-11-11 01:02:03 004:005:006 [4] row(s) selected. Mach> SELECT id, TO_CHAR(dt, 'YYYY') FROM datetime_table; id TO_CHAR(dt, 'YYYY') ------------------------------------------------------------------------------------------------- 4 2014 3 2013 2 2012 1 1999 [4] row(s) selected. Mach> SELECT id, TO_CHAR(dt, 'YYYY-MM') FROM datetime_table; id TO_CHAR(dt, 'YYYY-MM') ------------------------------------------------------------------------------------------------- 4 2014-12 3 2013-11 2 2012-11 1 1999-11 [4] row(s) selected. Mach> SELECT id, TO_CHAR(dt, 'YYYY-MM-DD') FROM datetime_table; id TO_CHAR(dt, 'YYYY-MM-DD') ------------------------------------------------------------------------------------------------- 4 2014-12-30 3 2013-11-11 2 2012-11-11 1 1999-11-11 [4] row(s) selected. Mach> SELECT id, TO_CHAR(dt, 'YYYY-MM-DD TO_CHAR') FROM datetime_table; id TO_CHAR(dt, 'YYYY-MM-DD TO_CHAR') ------------------------------------------------------------------------------------------------- 4 2014-12-30 TO_CHAR 3 2013-11-11 TO_CHAR 2 2012-11-11 TO_CHAR 1 1999-11-11 TO_CHAR [4] row(s) selected. Mach> SELECT id, TO_CHAR(dt, 'YYYY-MM-DD HH24:MI:SS') FROM datetime_table; id TO_CHAR(dt, 'YYYY-MM-DD HH24:MI:SS') ------------------------------------------------------------------------------------------------- 4 2014-12-30 11:22:33 3 2013-11-11 01:02:03 2 2012-11-11 01:02:03 1 1999-11-11 01:02:03 [4] row(s) selected. Mach> SELECT id, TO_CHAR(dt, 'YYYY-MM-DD HH24:MI:SS mmm.uuu.nnn') FROM datetime_table; id TO_CHAR(dt, 'YYYY-MM-DD HH24:MI:SS mmm. ------------------------------------------------------------------------------------------------- 4 2014-12-30 11:22:33 444.555.666 3 2013-11-11 01:02:03 004.005.006 2 2012-11-11 01:02:03 004.005.006 1 1999-11-11 01:02:03 004.005.006 [4] row(s) selected. ``` **TO_CHAR: Unsupported Types** TO_CHAR currently does not support binary types. They cannot be converted to ordinary strings. Use TO_HEX() to inspect hexadecimal output. ## TO_DATE Converts a string to datetime using the specified format. If format_string is omitted, the default is "YYYY-MM-DD HH24: MI: SS mmm: uuu: nnn". ```sql -- default format is "YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn" if no format exists. TO_DATE(date_string [, format_string]) ``` ```sql Mach> CREATE LOG TABLE to_date_table (id INTEGER, dt datetime); Created successfully. Mach> INSERT INTO to_date_table VALUES(1, TO_DATE('1999-11-11 1:2:3 4:5:6')); 1 row(s) inserted. Mach> INSERT INTO to_date_table VALUES(2, TO_DATE('2012-11-11 1:2:3 4:5:6')); 1 row(s) inserted. Mach> INSERT INTO to_date_table VALUES(3, TO_DATE('2014-12-30 11:22:33 444:555:666')); 1 row(s) inserted. Mach> INSERT INTO to_date_table VALUES(4, TO_DATE('2014-12-30 23:22:34 777:888:999', 'YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn')); 1 row(s) inserted. Mach> SELECT id, dt FROM to_date_table WHERE dt > TO_DATE('1999-11-11 1:2:3 4:5:0'); id dt ----------------------------------------------- 4 2014-12-30 23:22:34 777:888:999 3 2014-12-30 11:22:33 444:555:666 2 2012-11-11 01:02:03 004:005:006 1 1999-11-11 01:02:03 004:005:006 [4] row(s) selected. Mach> SELECT id, dt FROM to_date_table WHERE dt > TO_DATE('2000-11-11 1:2:3 4:5:0'); id dt ----------------------------------------------- 4 2014-12-30 23:22:34 777:888:999 3 2014-12-30 11:22:33 444:555:666 2 2012-11-11 01:02:03 004:005:006 [3] row(s) selected. Mach> SELECT id, dt FROM to_date_table WHERE dt > TO_DATE('2012-11-11 1:2:3','YYYY-MM-DD HH24:MI:SS') and dt < TO_DATE('2014-11-11 1:2:3','YYYY-MM-DD HH24:MI:SS'); id dt ----------------------------------------------- 2 2012-11-11 01:02:03 004:005:006 [1] row(s) selected. Mach> SELECT id, TO_DATE('1999', 'YYYY') FROM to_date_table LIMIT 1; id TO_DATE('1999', 'YYYY') ----------------------------------------------- 4 1999-01-01 00:00:00 000:000:000 [1] row(s) selected. Mach> SELECT id, TO_DATE('1999-12', 'YYYY-MM') FROM to_date_table LIMIT 1; id TO_DATE('1999-12', 'YYYY-MM') ----------------------------------------------- 4 1999.12.01 00:00:00 000:000:000 [1] row(s) selected. Mach> SELECT id, TO_DATE('1999', 'YYYY') FROM to_date_table LIMIT 1; id TO_DATE('1999', 'YYYY') ----------------------------------------------- 4 1999-01-01 00:00:00 000:000:000 [1] row(s) selected. Mach> SELECT id, TO_DATE('1999-12', 'YYYY-MM') FROM to_date_table LIMIT 1; id TO_DATE('1999-12', 'YYYY-MM') ----------------------------------------------- 4 1999-12-01 00:00:00 000:000:000 [1] row(s) selected. Mach> SELECT id, TO_DATE('1999-12-31 13:12', 'YYYY-MM-DD HH24:MI') FROM to_date_table LIMIT 1; id TO_DATE('1999-12-31 13:12', 'YYYY-MM-DD HH24:MI') ------------------------------------------------------- 4 1999-12-31 13:12:00 000:000:000 [1] row(s) selected. Mach> SELECT id, TO_DATE('1999-12-31 13:12:32', 'YYYY-MM-DD HH24:MI:SS') FROM to_date_table LIMIT 1; id TO_DATE('1999-12-31 13:12:32', 'YYYY-MM-DD HH24:MI:SS') ------------------------------------------------------- 4 1999-12-31 13:12:32 000:000:000 [1] row(s) selected. Mach> SELECT id, TO_DATE('1999-12-31 13:12:32 123', 'YYYY-MM-DD HH24:MI:SS mmm') FROM to_date_table LIMIT 1; id TO_DATE('1999-12-31 13:12:32 123', 'YYYY-MM-DD HH24:MI:SS mmm') ------------------------------------------------------- 4 1999-12-31 13:12:32 123:000:000 [1] row(s) selected. Mach> SELECT id, TO_DATE('1999-12-31 13:12:32 123:456', 'YYYY-MM-DD HH24:MI:SS mmm:uuu') FROM to_date_table LIMIT 1; id TO_DATE('1999-12-31 13:12:32 123:456', 'YYYY-MM-DD HH24:MI:SS mmm:uuu') ------------------------------------------------------- 4 1999-12-31 13:12:32 123:456:000 [1] row(s) selected. Mach> SELECT id, TO_DATE('1999-12-31 13:12:32 123:456:789', 'YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn') FROM to_date_table LIMIT 1; id TO_DATE('1999-12-31 13:12:32 123:456:789', 'YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn') ------------------------------------------------------- 4 1999-12-31 13:12:32 123:456:789 [1] row(s) selected. ``` ## TO_DATE_SAFE Similar to TO_DATE(), but returns NULL without an error when conversion fails. ```sql TO_DATE_SAFE(date_string [, format_string]) ``` ```sql Mach> CREATE LOG TABLE date_table (ts DATETIME); Created successfully. Mach> INSERT INTO date_table VALUES (TO_DATE_SAFE('2016-01-01', 'YYYY-MM-DD')); 1 row(s) inserted. Mach> INSERT INTO date_table VALUES (TO_DATE_SAFE('2016-01-02', 'YYYY')); 1 row(s) inserted. Mach> INSERT INTO date_table VALUES (TO_DATE_SAFE('2016-12-32', 'YYYY-MM-DD')); 1 row(s) inserted. Mach> SELECT ts FROM date_table; ts ---------------------------------- NULL NULL 2016-01-01 00:00:00 000:000:000 [3] row(s) selected. ``` ## TO_HEX Returns NULL for NULL input; otherwise returns a hexadecimal string. short, int, and long are converted to big-endian order for consistent output. ```sql TO_HEX(column) ``` ```sql Mach> CREATE LOG TABLE hex_table (id1 SHORT, id2 INTEGER, id3 VARCHAR(10), id4 FLOAT, id5 DOUBLE, id6 LONG, id7 IPV4, id8 IPV6, id9 TEXT, id10 BINARY, id11 DATETIME); Created successfully. Mach> INSERT INTO hex_table VALUES(256, 65535, '0123456789', 3.141592, 1024 * 1024 * 1024 * 3.14, 13513135446, '192.168.0.1', '::192.168.0.1', 'textext', 'binary', TO_DATE('1999', 'YYYY')); 1 row(s) inserted. Mach> SELECT TO_HEX(id1), TO_HEX(id2), TO_HEX(id3), TO_HEX(id4), TO_HEX(id5), TO_HEX(id6), TO_HEX(id7), TO_HEX(id8), TO_HEX(id9), TO_HEX(id10), TO_HEX(id11) FROM hex_table; TO_HEX(id1) TO_HEX(id2) TO_HEX(id3) TO_HEX(id4) TO_HEX(id5) TO_HEX(id6) TO_HEX(id7) ------------------------------------------------------------------------------------------------------------------------- TO_HEX(id8) TO_HEX(id9) -------------------------------------------------------------------------------------------------------------------------- TO_HEX(id10) TO_HEX(id11) -------------------------------------------------------------------------------------------------------- 0100 0000FFFF 30313233343536373839 D80F4940 1F85EB51B81EE941 0000000325721556 04C0A80001 06000000000000000000000000C0A80001 74657874657874 62696E617279 0CB325846E226000 [1] row(s) selected. ``` ## TO_INET_STR TO_INET_STR(ipv4_value) converts IPV4 to a dotted-decimal string. ```sql TO_INET_STR(ipv4_value) ``` ```sql SELECT TO_INET_STR(TO_IPV4('192.168.0.1')); ``` ## TO_IPV4 / TO_IPV4_SAFE Converts a string to IPv4. If the string cannot be converted to a numeric address, TO_IPV4() returns an error and stops the operation. TO_IPV4_SAFE() instead returns NULL on error, allowing the operation to continue. ```sql TO_IPV4(string_value) TO_IPV4_SAFE(string_value) ``` ```sql Mach> CREATE LOG TABLE ipv4_table (c1 varchar(100)); Created successfully. Mach> INSERT INTO ipv4_table VALUES('192.168.0.1'); 1 row(s) inserted. Mach> INSERT INTO ipv4_table VALUES(' 192.168.0.2 '); 1 row(s) inserted. Mach> INSERT INTO ipv4_table VALUES(NULL); 1 row(s) inserted. Mach> SELECT c1 FROM ipv4_table; c1 ------------------------------------------------------------------------------------ NULL 192.168.0.2 192.168.0.1 [3] row(s) selected. Mach> SELECT TO_IPV4(c1) FROM ipv4_table; TO_IPV4(c1) ------------------ NULL 192.168.0.2 192.168.0.1 [3] row(s) selected. Mach> INSERT INTO ipv4_table VALUES('192.168.0.1.1'); 1 row(s) inserted. Mach> SELECT TO_IPV4(c1) FROM ipv4_table limit 1; TO_IPV4(c1) ------------------ [ERR-02068 : Invalid IPv4 address format (192.168.0.1.1).] [0] row(s) selected. Mach> SELECT TO_IPV4_SAFE(c1) FROM ipv4_table; TO_IPV4_SAFE(c1) ------------------- NULL NULL 192.168.0.2 192.168.0.1 [4] row(s) selected. ``` ## TO_IPV6 / TO_IPV6_SAFE Converts a string to IPv6. If conversion fails, TO_IPV6() returns an error and stops the operation. TO_IPV6_SAFE() instead returns NULL on error, allowing the operation to continue. ```sql TO_IPV6(string_value) TO_IPV6_SAFE(string_value) ``` ```sql Mach> CREATE LOG TABLE ipv6_table (id varchar(100)); Created successfully. Mach> INSERT INTO ipv6_table VALUES('::0.0.0.0'); 1 row(s) inserted. Mach> INSERT INTO ipv6_table VALUES('::127.0.0.1'); 1 row(s) inserted. Mach> INSERT INTO ipv6_table VALUES('::127.0' || '.0.2'); 1 row(s) inserted. Mach> INSERT INTO ipv6_table VALUES(' ::127.0.0.3'); 1 row(s) inserted. Mach> INSERT INTO ipv6_table VALUES('::127.0.0.4 '); 1 row(s) inserted. Mach> INSERT INTO ipv6_table VALUES(' ::FFFF:255.255.255.255 '); 1 row(s) inserted. Mach> INSERT INTO ipv6_table VALUES('21DA:D3:0:2F3B:2AA:FF:FE28:9C5A'); 1 row(s) inserted. Mach> SELECT TO_IPV6(id) FROM ipv6_table; TO_IPV6(id) --------------------------------------------------------------- 21da:d3::2f3b:2aa:ff:fe28:9c5a ::ffff:255.255.255.255 ::127.0.0.4 ::127.0.0.3 ::127.0.0.2 ::127.0.0.1 :: [7] row(s) selected. Mach> INSERT INTO ipv6_table VALUES('127.0.0.10.10'); 1 row(s) inserted. Mach> SELECT TO_IPV6(id) FROM ipv6_table limit 1; TO_IPV6(id) --------------------------------------------------------------- [ERR-02148 : Invalid IPv6 address format.(127.0.0.10.10)] [0] row(s) selected. Mach> SELECT TO_IPV6_SAFE(id) FROM ipv6_table; TO_IPV6_SAFE(id) --------------------------------------------------------------- NULL 21da:d3::2f3b:2aa:ff:fe28:9c5a ::ffff:255.255.255.255 ::127.0.0.4 ::127.0.0.3 ::127.0.0.2 ::127.0.0.1 :: [8] row(s) selected. ``` ## TO_NUMBER / TO_NUMBER_SAFE Converts a string to a number (double). If conversion fails, TO_NUMBER() returns an error and stops the operation. TO_NUMBER_SAFE() instead returns NULL on error, allowing the operation to continue. ```sql TO_NUMBER(string_value) TO_NUMBER_SAFE(string_value) ``` ```sql Mach> CREATE LOG TABLE number_table (id varchar(100)); Created successfully. Mach> INSERT INTO number_table VALUES('10'); 1 row(s) inserted. Mach> INSERT INTO number_table VALUES('20'); 1 row(s) inserted. Mach> INSERT INTO number_table VALUES('30'); 1 row(s) inserted. Mach> SELECT TO_NUMBER(id) from number_table; TO_NUMBER(id) ------------------------------ 30 20 10 [3] row(s) selected. Mach> CREATE LOG TABLE safe_table (id varchar(100)); Created successfully. Mach> INSERT INTO safe_table VALUES('invalidnumber'); 1 row(s) inserted. Mach> SELECT TO_NUMBER(id) from safe_table; TO_NUMBER(id) ------------------------------ [ERR-02145 : The string cannot be converted to number value.(invalidnumber)] [0] row(s) selected. Mach> SELECT TO_NUMBER_SAFE(id) from safe_table; TO_NUMBER_SAFE(id) ------------------------------ NULL [1] row(s) selected. ``` ## TOP_K {#top_k} TOP_K(value, k) returns the k most frequent numeric values as a value:count string. ```sql TOP_K(value, k) ``` - value must be numeric. - k must be a positive integer constant. - NULL values are ignored. - The return type is VARCHAR. - Results are ordered by descending frequency, then ascending value for ties. ```sql SELECT TOP_K(alarm_code, 3) FROM event_log; ``` Example result: ```text 101:532,205:317,301:90 ``` ## TO_TIMESTAMP Converts datetime to nanoseconds elapsed since 1970-01-01 00:00:00 UTC. Dates and times below use UTC+09:00. ```sql TO_TIMESTAMP(datetime_value) ``` ```sql Mach> create table datetime_tbl (c1 datetime); Created successfully. Mach> insert into datetime_tbl values ('2010-01-01 10:10:10'); 1 row(s) inserted. Mach> select to_timestamp(c1) from datetime_tbl; to_timestamp(c1) ----------------------- 1262308210000000000 [1] row(s) selected. ``` ## TRUNC TRUNC truncates a value to n decimal places. If n is omitted, it defaults to 0 and removes all decimal places. Negative n truncates at the corresponding position before the decimal point. ```sql TRUNC(number [, n]) ``` ```sql Mach> CREATE LOG TABLE trunc_table (i1 DOUBLE); Created successfully. Mach> INSERT INTO trunc_table VALUES (158.799); 1 row(s) inserted. Mach> SELECT TRUNC(i1, 1), TRUNC(i1, -1) FROM trunc_table; TRUNC(i1, 1) TRUNC(i1, -1) ----------------------------------------------------------- 158.7 150 [1] row(s) selected. Mach> SELECT TRUNC(i1, 2), TRUNC(i1, -2) FROM trunc_table; TRUNC(i1, 2) TRUNC(i1, -2) ----------------------------------------------------------- 158.79 100 [1] row(s) selected. ``` ## TS_CHANGE_COUNT Aggregate function counting changes in a column's value. Cannot be used with JOIN or an inline view because chronological input order cannot be guaranteed. VARCHAR is not supported. * **Unavailable in Cluster Edition.** ```sql TS_CHANGE_COUNT(column) ``` ```sql Mach> CREATE LOG TABLE ipcount_table (id INTEGER, ip IPV4); Created successfully. Mach> INSERT INTO ipcount_table VALUES (1, '192.168.0.1'); 1 row(s) inserted. Mach> INSERT INTO ipcount_table VALUES (1, '192.168.0.2'); 1 row(s) inserted. Mach> INSERT INTO ipcount_table VALUES (1, '192.168.0.1'); 1 row(s) inserted. Mach> INSERT INTO ipcount_table VALUES (1, '192.168.0.2'); 1 row(s) inserted. Mach> INSERT INTO ipcount_table VALUES (2, '192.168.0.3'); 1 row(s) inserted. Mach> INSERT INTO ipcount_table VALUES (2, '192.168.0.3'); 1 row(s) inserted. Mach> INSERT INTO ipcount_table VALUES (2, '192.168.0.4'); 1 row(s) inserted. Mach> INSERT INTO ipcount_table VALUES (2, '192.168.0.4'); 1 row(s) inserted. Mach> SELECT id, TS_CHANGE_COUNT(ip) from ipcount_table GROUP BY id; id TS_CHANGE_COUNT(ip) ------------------------------------ 2 2 1 4 [2] row(s) selected. ``` ## UNIX_TIMESTAMP UNIX_TIMESTAMP converts a date value to a 32-bit integer based on Unix time(). FROM_UNIXTIME performs the reverse conversion. ```sql UNIX_TIMESTAMP(datetime_value) ``` ```sql Mach> CREATE table unix_table (c1 int); Created successfully. Mach> INSERT INTO unix_table VALUES (UNIX_TIMESTAMP('2001-01-01')); 1 row(s) inserted. Mach> SELECT * FROM unix_table; C1 -------------- 978274800 [1] row(s) selected. ``` ## UPPER Converts English letters to uppercase. ```sql UPPER(string_value) ``` ```sql Mach> CREATE LOG TABLE upper_table(id INTEGER,name VARCHAR(10)); Created successfully. Mach> INSERT INTO upper_table VALUES(1, ''); 1 row(s) inserted. Mach> INSERT INTO upper_table VALUES(2, 'James'); 1 row(s) inserted. Mach> INSERT INTO upper_table VALUES(3, 'sarah'); 1 row(s) inserted. Mach> INSERT INTO upper_table VALUES(4, 'THOMAS'); 1 row(s) inserted. Mach> SELECT id, UPPER(name) FROM upper_table; id UPPER(name) ---------------------------- 4 THOMAS 3 SARAH 2 JAMES 1 NULL [4] row(s) selected. ``` ## VARIANCE / VAR_POP Aggregate functions returning variance of a numeric column. VARIANCE returns sample variance; VAR_POP returns population variance. ```sql VARIANCE(column_name) VAR_POP(column_name) ``` ```sql Mach> CREATE LOG TABLE var_table(c1 INTEGER, c2 DOUBLE); Created successfully. Mach> INSERT INTO var_table VALUES (1, 1); 1 row(s) inserted. Mach> INSERT INTO var_table VALUES (2, 1); 1 row(s) inserted. Mach> INSERT INTO var_table VALUES (1, 2); 1 row(s) inserted. Mach> INSERT INTO var_table VALUES (2, 2); 1 row(s) inserted. Mach> SELECT VARIANCE(c1) FROM var_table; VARIANCE(c1) ------------------------------ 0.333333 [1] row(s) selected. Mach> SELECT VAR_POP(c1) FROM var_table; VAR_POP(c1) ------------------------------ 0.25 [1] row(s) selected. ``` ## YEAR / MONTH / DAY Extracts year, month, and day from a datetime column as integers. ```sql YEAR(datetime_col) MONTH(datetime_col) DAY(datetime_col) ``` ```sql Mach> CREATE LOG TABLE extract_table(c1 DATETIME, c2 INTEGER); Created successfully. Mach> INSERT INTO extract_table VALUES (to_date('2001-01-01 12:30:00 000:000:000'), 1); 1 row(s) inserted. Mach> SELECT YEAR(c1), MONTH(c1), DAY(c1) FROM extract_table; year(c1) month(c1) day(c1) ---------------------------------------- 2001 1 1 ``` ## ISNAN / ISINF Tests whether a numeric argument is NaN or Inf, returning 1 if so and 0 otherwise. ```sql ISNAN(number) ISINF(number) ``` The example assumes the table already contains NaN and Inf values. SQL INSERT cannot use nan or inf tokens directly as values. ```sql Mach> SELECT * FROM test; I1 I2 I3 ------------------------------------------------------------------------ 1 1 1 nan inf 0 NULL NULL NULL [3] row(s) selected. Mach> SELECT ISNAN(i1), ISNAN(i2), ISNAN(i3), i3 FROM test ; ISNAN(i1) ISNAN(i2) ISNAN(i3) i3 ----------------------------------------------------- 0 0 0 1 1 0 0 0 NULL NULL NULL NULL [3] row(s) selected. Mach> SELECT * FROM test WHERE ISNAN(i1) = 1; I1 I2 I3 ------------------------------------------------------------------------ nan inf 0 [1] row(s) selected. ``` ## JSON_SET Stores a SQL scalar as a JSON scalar at the specified document path. ```sql JSON_SET(json_doc, path, scalar) ``` ```sql Mach> SELECT JSON_SET('{"ship":{"status":"READY"}}', '$.ship.status', 'DONE') FROM dual; JSON_SET('{"ship":{"status":"READY"}}', '$.ship.status', 'DONE') -------------------------------------------------------------------------------- {"ship":{"status":"DONE"}} [1] row(s) selected. ``` Notes: - path must be a full JSONPath. - JSON_SET(..., path, NULL) stores JSON null. - A NULL document argument produces SQL NULL. - A NULL or empty path causes an error. - Support focuses on object paths. - Array element updates such as $.items[0] are not supported. ## JSON_SET_JSON Parses the third argument as JSON text and stores an object or array subtree. ```sql JSON_SET_JSON(json_doc, path, json_text) ``` ```sql Mach> SELECT JSON_SET_JSON('{"ship":{}}', '$.ship.owner', '{"name":"machbase"}') FROM dual; JSON_SET_JSON('{"ship":{}}', '$.ship.owner', '{"name":"machbase"}') ---------------------------------------------------------------------------- {"ship":{"owner":{"name":"machbase"}}} [1] row(s) selected. ``` Notes: - path must be a full JSONPath. - If the third argument is SQL NULL, the result is SQL NULL. - Invalid JSON text causes an error. - Support focuses on object paths. - Array element updates are not supported. ## JSON_REMOVE Removes a member or subpath from a JSON document. ```sql JSON_REMOVE(json_doc, path) ``` ```sql Mach> SELECT JSON_REMOVE('{"owner":{"name":"machbase","team":"db"}}', '$.owner.team') FROM dual; JSON_REMOVE('{"owner":{"name":"machbase","team":"db"}}', '$.owner.team') -------------------------------------------------------------------------- {"owner":{"name":"machbase"}} [1] row(s) selected. ``` Notes: - path must be a full JSONPath. - A missing path is a no-op. - JSON_REMOVE(..., '$') is not allowed. - A NULL document argument produces SQL NULL. ## PI() {#pi} Returns π as DOUBLE. ```sql SELECT PI(); ``` ```sql Mach> SELECT PI(); PI() ------------------------------ 3.141592653589793 [1] row(s) selected. ``` ## SQRT() {#sqrt} Returns the square root. ```sql SELECT SQRT(9), SQRT(2.25), SQRT(16.0); ``` ```sql Mach> SELECT SQRT(9), SQRT(2.25), SQRT(16.0); SQRT(9) SQRT(2.25) SQRT(16.0) ----------------------------------------------- 3 1.5000000000000000 4 [1] row(s) selected. ``` ## POWER() {#power} Returns base raised to exponent. ```sql SELECT POWER(2, 3), POWER(9, 0.5), POWER(4, -1); ``` ```sql Mach> SELECT POWER(2, 3), POWER(9, 0.5), POWER(4, -1); POWER(2, 3) POWER(9, 0.5) POWER(4, -1) ------------------------------------------------ 8 3.0000000000000000 0.2500000000000000 [1] row(s) selected. ``` ## POW() {#pow} Alias for POWER(). ```sql SELECT POW(2, 3), POW(2, -1), POW(10, 0); ``` ```sql Mach> SELECT POW(2, 3), POW(2, -1), POW(10, 0); POW(2, 3) POW(2, -1) POW(10, 0) ----------------------------------------- 8 0.5 1 [1] row(s) selected. ``` ## LOG() {#log} LOG(n) calculates the natural logarithm; LOG(base, n) calculates the logarithm to the specified base. ```sql SELECT LOG(2, 8), LOG(100), LOG(10, 1000); ``` ```sql Mach> SELECT LOG(2, 8), LOG(100), LOG(10, 1000); LOG(2, 8) LOG(100) LOG(10, 1000) ------------------------------------------------ 3 4.605170185988092 3 [1] row(s) selected. ``` ## LN() {#ln} Returns the natural logarithm ln(n). ```sql SELECT LN(1), LN(10), LN(1000); ``` ```sql Mach> SELECT LN(1), LN(10), LN(1000); LN(1) LN(10) LN(1000) ----------------------------------- 0 2.302585092994046 6.907755278982137 [1] row(s) selected. ``` ## EXP() {#exp} Returns e^n. ```sql SELECT EXP(0), EXP(1), EXP(-1); ``` ```sql Mach> SELECT EXP(0), EXP(1), EXP(-1); EXP(0) EXP(1) EXP(-1) ----------------------------------- 1 2.718281828459045 0.36787944117144233 [1] row(s) selected. ``` ## FLOOR() {#floor} Rounds down toward negative infinity. ```sql SELECT FLOOR(-1.2), FLOOR(3.9), FLOOR(-3.0); ``` ```sql Mach> SELECT FLOOR(-1.2), FLOOR(3.9), FLOOR(-3.0); FLOOR(-1.2) FLOOR(3.9) FLOOR(-3.0) ----------------------------------------- -2 3 -3 [1] row(s) selected. ``` ## CEIL() {#ceil} Rounds up toward positive infinity. ```sql SELECT CEIL(-1.2), CEIL(3.2), CEIL(-3.0); ``` ```sql Mach> SELECT CEIL(-1.2), CEIL(3.2), CEIL(-3.0); CEIL(-1.2) CEIL(3.2) CEIL(-3.0) ------------------------------------- -1 4 -3 [1] row(s) selected. ``` ## SIN() {#sin} Returns sine for an input in radians. ```sql SELECT SIN(0), SIN(PI()/2), SIN(PI()); ``` ```sql Mach> SELECT SIN(0), SIN(PI()/2), SIN(PI()); SIN(0) SIN(PI()/2) SIN(PI()) ------------------------------------ 0 1 0 [1] row(s) selected. ``` ## SLOPE {#slope} SLOPE(y, x) calculates the linear regression slope for numeric (x, y) points. ```sql SLOPE(y, x) ``` - Both arguments must be numeric. - NULL values are ignored. - Insufficient valid data or zero x variance produces NULL. - The return type is DOUBLE. ```sql SELECT SLOPE(temp_c, sample_sec) FROM sensor_log; ``` ## COS() {#cos} Returns cosine for an input in radians. ```sql SELECT COS(0), COS(PI()), COS(PI()/2); ``` ```sql Mach> SELECT COS(0), COS(PI()), COS(PI()/2); COS(0) COS(PI()) COS(PI()/2) ------------------------------------- 1 -1 0 [1] row(s) selected. ``` ## TAN() {#tan} Returns tangent for an input in radians. ```sql SELECT TAN(0), TAN(PI()/4), TAN(PI()); ``` ```sql Mach> SELECT TAN(0), TAN(PI()/4), TAN(PI()); TAN(0) TAN(PI()/4) TAN(PI()) ----------------------------------- 0 1 0 [1] row(s) selected. ``` ## MOD() {#mod} Calculates the remainder with the quotient truncated toward zero. ```sql SELECT MOD(10, 3), MOD(11, 4), MOD(-10, 3), MOD(3.5, 0.5); ``` ```sql Mach> SELECT MOD(10, 3), MOD(11, 4), MOD(-10, 3), MOD(3.5, 0.5); MOD(10, 3) MOD(11, 4) MOD(-10, 3) MOD(3.5, 0.5) ------------------------------------------------------- 1 3 -1 0 [1] row(s) selected. ``` ## MODE {#mode} MODE(value) returns the most frequent numeric value in the input set. ```sql MODE(value) ``` - value must be numeric. - NULL values are ignored. - Ties return the smaller value. - The return type is DOUBLE. ```sql SELECT MODE(alarm_code) FROM event_log; ``` ## P05 / P10 / P90 / P95 {#p05-p10-p90-p95} Exact percentile shorthand functions for frequently used percentiles. ```sql P05(value) P10(value) P90(value) P95(value) ``` - value must be numeric. - NULL values are ignored. - The return type is DOUBLE. P05, P10, P90, and P95 correspond to PERCENTILE_CONT(value, 0.05), 0.10, 0.90, and 0.95 respectively. ```sql SELECT P05(response_ms), P10(response_ms), P90(response_ms), P95(response_ms) FROM web_log; ``` ## PERCENTILE_CONT / PERCENTILE_DISC {#percentile_cont-percentile_disc} Aggregate functions calculating exact percentiles for numeric input. ```sql PERCENTILE_CONT(value, ratio) PERCENTILE_DISC(value, ratio) ``` - value must be numeric. - ratio must be a constant from 0.0 through 1.0. - PERCENTILE_CONT interpolates between adjacent sorted values when needed. - PERCENTILE_DISC selects an observed value at the target rank. - Both return DOUBLE. ```sql SELECT PERCENTILE_CONT(latency_ms, 0.95) AS pcont95, PERCENTILE_DISC(latency_ms, 0.95) AS pdisc95 FROM api_log; ``` ## QUANTILE {#quantile} QUANTILE(value, ratio) calculates an exact continuous percentile for numeric input. ```sql QUANTILE(value, ratio) ``` - value must be numeric. - ratio must be a constant from 0.0 through 1.0. - The return type is DOUBLE. - Uses the same continuous-percentile semantics as PERCENTILE_CONT. ```sql SELECT QUANTILE(cpu_usage, 0.75) FROM host_metric; ``` ## RAND() {#rand} Generates a random value. ```sql SELECT RAND(5) = RAND(5) AS same_seed, RAND(7) = RAND(8) AS diff_seed, RAND() = RAND() AS diff_default; ``` ```sql Mach> SELECT RAND(5) = RAND(5) AS same_seed, RAND(7) = RAND(8) AS diff_seed, RAND() = RAND() AS diff_default FROM m$sys_users WHERE name = 'SYS'; same_seed diff_seed diff_default ------------------------------------ 1 0 0 [1] row(s) selected. ``` RAND(seed) returns the same value for the same seed. RAND() generates a value in [0,1) from internal session state. ## REGEXP_LIKE REGEXP_LIKE tests whether a string matches a regular expression and returns a Boolean. It is commonly used in WHERE. ```sql REGEXP_LIKE(source, pattern) REGEXP_LIKE(source, pattern, match_param) ``` - source must be VARCHAR. - pattern must be a constant VARCHAR regular expression. - Optional match_param must be a constant VARCHAR. c enables case-sensitive matching; i enables case-insensitive matching. Default: c. ```sql SELECT * FROM sensor_text WHERE REGEXP_LIKE(message, 'error|warn', 'i'); ``` ## REGEXP_INSTR REGEXP_INSTR returns the 1-based position of a regular expression match, or 0 if none exists. ```sql REGEXP_INSTR(source, pattern[, position[, occurrence[, return_pos[, match_param]]]]) ``` - source must be VARCHAR. - pattern must be a constant VARCHAR regular expression. - position and occurrence must be constant integers of at least 1. - return_pos must be a constant integer: 0 returns the start position; 1 returns the position after the match. - match_param accepts c or i; default: c. ```sql SELECT REGEXP_INSTR('TechOnTheNet', 'The', 1, 1, 1, 'i'); ``` ## REGEXP_SUBSTR REGEXP_SUBSTR returns the substring matching a regular expression. ```sql REGEXP_SUBSTR(source, pattern[, position[, occurrence[, match_param]]]) ``` - source must be VARCHAR. - pattern must be a constant VARCHAR regular expression. - position and occurrence must be constant integers of at least 1. - match_param accepts c or i; default: c. ```sql SELECT REGEXP_SUBSTR('TechOnTheNet', 'a|e|i|o|u', 1, 2, 'i'); ``` ## REGEXP_REPLACE REGEXP_REPLACE replaces text matching a regular expression. ```sql REGEXP_REPLACE(source, pattern[, replacement[, position[, occurrence[, match_param]]]]) ``` - source must be VARCHAR. - pattern and replacement must be constant VARCHAR values. - Omitting replacement removes matching text. - position must be a constant integer of at least 1. - occurrence must be a constant integer: 0 replaces every match; a positive value replaces only that occurrence. - match_param accepts c or i; default: c. ```sql SELECT REGEXP_REPLACE('TechOnTheNet', 'a|e|i|o|u', 'Z', 1, 2, 'i'); ``` ## Supported Types for Built-in Functions | |Short|Integer|Long|Float|Double|Varchar|Text|Ipv4|Ipv6|Datetime|Binary| |--|--|--|--|--|--|--|--|--|--|--|--| |ABS|o|o|o|o|o|x|x|x|x|x|x| |ADD_TIME|x|x|x|x|x|x|x|x|x|o|x| |APPROX_PERCENTILE / APPROX_MEDIAN / APPROX_P05 / APPROX_P10 / APPROX_P90 / APPROX_P95|o|o|o|o|o|x|x|x|x|x|x| |AREA|o|o|o|o|o|x|x|x|x|x|x| |AVG|o|o|o|o|o|x|x|x|x|x|x| |BITAND / BITOR|o|o|o|x|x|x|x|x|x|x|x| |COUNT|o|o|o|o|o|o|x|o|o|o|x| |CUME_DIST|o|o|o|o|o|x|x|x|x|x|x| |DATE_TRUNC|x|x|x|x|x|x|x|x|x|o|x| |DECODE|o|o|o|o|o|o|x|o|x|o|x| |FIRST / LAST|o|o|o|o|o|o|x|o|o|o|x| |FROM_TIMESTAMP|o|o|o|o|o|x|x|x|x|x|x| |FROM_UNIXTIME|o|o|o|o|o|x|x|x|x|x|x| |GROUP_CONCAT|o|o|o|o|o|o|x|o|o|o|x| |INSTR|x|x|x|x|x|o|o|x|x|x|x| |LEAST / GREATEST|o|o|o|o|o|o|x|x|x|x|x| |LENGTH|x|x|x|x|x|o|o|x|x|x|o| |LOWER|x|x|x|x|x|o|x|x|x|x|x| |LPAD / RPAD|x|x|x|x|x|o|x|x|x|x|x| |LTRIM / RTRIM|x|x|x|x|x|o|x|x|x|x|x| |MAX|o|o|o|o|o|o|x|o|o|o|x| |MEDIAN|o|o|o|o|o|x|x|x|x|x|x| |MIN|o|o|o|o|o|o|x|o|o|o|x| |MODE|o|o|o|o|o|x|x|x|x|x|x| |NVL|x|x|x|x|x|o|x|o|x|x|x| |P05 / P10 / P90 / P95|o|o|o|o|o|x|x|x|x|x|x| |PERCENTILE_CONT / PERCENTILE_DISC|o|o|o|o|o|x|x|x|x|x|x| |QUANTILE|o|o|o|o|o|x|x|x|x|x|x| |REGEXP_LIKE|x|x|x|x|x|o|x|x|x|x|x| |REGEXP_INSTR|x|x|x|x|x|o|x|x|x|x|x| |REGEXP_SUBSTR|x|x|x|x|x|o|x|x|x|x|x| |REGEXP_REPLACE|x|x|x|x|x|o|x|x|x|x|x| |SLOPE|o|o|o|o|o|x|x|x|x|x|x| |TOP_K|o|o|o|o|o|x|x|x|x|x|x| |ROUND|o|o|o|o|o|x|x|x|x|x|x| |ROWNUM|o|o|o|o|o|o|o|o|o|o|o| |SERIESNUM|o|o|o|o|o|o|o|o|o|o|o| |STDDEV / STDDEV_POP|o|o|o|o|o|x|x|x|x|x|x| |SUBSTR|x|x|x|x|x|o|x|x|x|x|x| |SUBSTRING_INDEX|x|x|x|x|x|o|o|x|x|x|x| |SUM|o|o|o|o|o|x|x|x|x|x|x| |SYSDATE / NOW|x|x|x|x|x|x|x|x|x|x|x| |TO_CHAR|o|o|o|o|o|o|x|o|o|o|x| |TO_DATE / TO_DATE_SAFE|x|x|x|x|x|o|x|x|x|x|x| |TO_HEX|o|o|o|o|o|o|o|o|o|o|o| |TO_INET_STR|x|x|x|x|x|x|x|o|x|x|x| |TO_IPV4 / TO_IPV4_SAFE|x|x|x|x|x|o|x|x|x|x|x| |TO_IPV6 / TO_IPV6_SAFE|x|x|x|x|x|o|x|x|x|x|x| |TO_NUMBER / TO_NUMBER_SAFE|x|x|x|x|x|o|x|x|x|x|x| |TO_TIMESTAMP|x|x|x|x|x|x|x|x|x|o|x| |TRUNC|o|o|o|o|o|x|x|x|x|x|x| |TS_CHANGE_COUNT|o|o|o|o|o|x|x|o|o|o|x| |UNIX_TIMESTAMP|x|x|x|x|x|x|x|x|x|o|x| |UPPER|x|x|x|x|x|o|x|x|x|x|x| |VARIANCE / VAR_POP|o|o|o|o|o|x|x|x|x|x|x| |YEAR / MONTH / DAY|x|x|x|x|x|x|x|x|x|o|x| |ISNAN / ISINF|o|o|o|o|o|x|x|x|x|x|x| ## JSON Functions These functions take JSON data as arguments. | Function | Description | Notes | |--|--|--| | JSON_EXTRACT(JSON column name, 'json path') | Returns a string.
Returns ERROR if the value is missing. | JSON object/array: serialize to a string.
String: return unchanged.
Numeric: convert to a string.
Boolean: return "True" or "False". | | JSON_EXTRACT_DOUBLE(JSON column name, 'json path') | Returns a 64-bit double.
Returns NULL if the value is missing. | JSON object/array: NULL.
String: convert if possible; otherwise NULL.
Numeric: 64-bit floating-point value.
Boolean: "True" becomes 1.0; "False" becomes 0.0. | | JSON_EXTRACT_INTEGER(JSON column name, 'json path') | Returns a 64-bit integer.
Returns NULL if the value is missing. | JSON object/array: NULL.
String: convert if possible; otherwise NULL.
Numeric: 64-bit integer.
Boolean: "True" becomes 1; "False" becomes 0. | | JSON_EXTRACT_STRING(JSON column name, 'json path') | Returns a string.
Returns NULL if the value is missing.
Same result as the arrow (→) operator. | JSON object/array: serialize to a string.
String: return unchanged.
Numeric: convert to a string.
Boolean: return "True" or "False". | | JSON_SET(json_doc, path, scalar) | Returns a new JSON document with a SQL scalar stored as a JSON scalar at the path. | Full JSONPath required.
NULL values become JSON null.
Only object paths supported. | | JSON_SET_JSON(json_doc, path, json_text) | Returns a new JSON document with JSON text stored as an object or array subtree at the path. | Full JSONPath required.
SQL NULL third argument produces SQL NULL.
Invalid JSON text causes an error. | | JSON_REMOVE(json_doc, path) | Returns a new JSON document with the member or subtree at the path removed. | Full JSONPath required.
Missing path is a no-op.
JSON_REMOVE(..., '$') is not allowed. | | JSON_IS_VALID('json string') | Checks whether JSON text is valid. | 0: False
1: True | | JSON_TYPEOF(JSON column name, 'json path') | Returns the value type. | None: key absent
Object: object
Integer: integer
Real: floating-point
String: string
True/False: Boolean
Array: array
Null: NULL | ```sql Mach> CREATE LOG TABLE jsontbl (name VARCHAR(20), jval JSON); Created successfully. Mach> INSERT INTO jsontbl VALUES("name1", '{"name":"test1"}'); 1 row(s) inserted. Mach> INSERT INTO jsontbl VALUES("name2", '{"name":"test2", "value":123}'); 1 row(s) inserted. Mach> INSERT INTO jsontbl VALUES("name3", '{"name":{"class1": "test3"}}'); 1 row(s) inserted. Mach> INSERT INTO jsontbl VALUES("name4", '{"myarray": [1, 2, 3, 4]}'); 1 row(s) inserted. Mach> INSERT INTO jsontbl VALUES("name5", '{"name":"error"'); [ERR-02233: Error occurred at column (2): (Error in json load.)] Mach> SELECT name, JSON_EXTRACT_STRING(jval, '$.name') FROM jsontbl; name JSON_EXTRACT_STRING(jval, '$.name') ----------------------------------------------------------------------------------------------------------- name4 NULL name3 {"class1": "test3"} name2 test2 name1 test1 [4] row(s) selected. Mach> SELECT name, JSON_EXTRACT_INTEGER(jval, '$.myarray[1]') FROM jsontbl; name JSON_EXTRACT_INTEGER(jval, '$.myarray[1]') -------------------------------------------------------------------- name4 2 name3 NULL name2 NULL name1 NULL [4] row(s) selected. Mach> SELECT name, JSON_TYPEOF(jval, '$.name') FROM jsontbl; name JSON_TYPEOF(jval, '$.name') ----------------------------------------------------------------------------------------------------------- name4 None name3 Object name2 String name1 String [4] row(s) selected. ``` ## JSON Operators The -> operator accesses objects in JSON data. Returns the same result as JSON_EXTRACT_STRING. ```sql json_col -> 'json path' ``` Access JSON column members with the JSONPath -> operator or dot shorthand. ```sql -- JSONPath arrow syntax jval->'$.sensor.temperature' -- JSON dot shorthand jval.sensor.temperature ``` Both expressions retrieve the same JSON value. The existing -> operator remains available; dot notation is additional syntax for a shorter expression. ```sql Mach> SELECT name, jval->'$.name' FROM jsontbl; name JSON_EXTRACT_STRING(jval, '$.name') ----------------------------------------------------------------------------------------------------------- name4 NULL name3 {"class1": "test3"} name2 test2 name1 test1 [4] row(s) selected. Mach> SELECT name, jval->'$.myarray[1]' FROM jsontbl; name JSON_EXTRACT_INTEGER(jval, '$.myarray[1]') -------------------------------------------------------------------- name4 2 name3 NULL name2 NULL name1 NULL [4] row(s) selected. Mach> SELECT name, jval->'$.name.class1' FROM jsontbl; name jval->'$.name.class1' ----------------------------------------------------------------------------------------------------------- name4 NULL name3 test3 name2 NULL name1 NULL [4] row(s) selected ``` ### JSONPath Arrow Syntax Arrow syntax uses a JSONPath string. ```sql jval->'$.name' jval->'$.sensor.temperature' jval->'$.items[0].name' ``` Brackets can also specify JSON keys directly. Use brackets when a key contains a dot (.). ```sql -- Key named a.b jval->'$["a.b"]' jval->'$[a.b]' -- Multiple key levels with brackets jval->'$[Plant1][Line1][Temperature]' -- One key name containing dots jval->'$[Plant1.Line1.Temperature]' ``` `$[Plant1.Line1.Temperature]` looks up one key named Plant1.Line1.Temperature. To traverse Plant1, Line1, and Temperature separately, use `$[Plant1][Line1][Temperature]` or `$.Plant1.Line1.Temperature`. For keys containing special characters or dots, quoted bracket syntax is recommended: ```sql jval->'$["a.b"]["c.d"]["e.f"]' ``` The following syntax is not supported. ```sql jval->'$."a.b"' ``` ### JSON Dot Shorthand Append member names to a JSON column to query JSON values. ```sql -- Single member jval.name -- Nested member jval.sensor.temperature -- Array index jval.items[0].name -- Key containing special characters jval.items[0]."product-id" ``` Double-quoted keys in dot syntax preserve case and special characters. ```sql SELECT name, jval."Camel-Key", jval.items[0]."product-id" FROM jsontbl ORDER BY name; ``` ### Type Comparison in WHERE JSON member access results display as strings. When compared with SQL numeric values in WHERE, however, JSON values are parsed as numbers and compared numerically. ```sql SELECT name FROM jsontbl WHERE jval->'$.value' > 100 ORDER BY name; SELECT name FROM jsontbl WHERE jval.value BETWEEN 10 AND 30 ORDER BY name; SELECT name FROM jsontbl WHERE jval.value IN (10, 20, 30) ORDER BY name; ``` Supported comparisons: - JSON integer with SQL integer - JSON real/double with SQL numeric - JSON numeric string with SQL numeric - JSON Boolean with strings 'true' and 'false' - `=`, `<>`, `<`, `<=`, `>`, `>=`, `BETWEEN`, literal `IN (...)` When compared with SQL integers, JSON integers use integer comparison. Values beyond double precision, such as 9007199254740992 and 9007199254740993, remain distinguishable. Comparisons with character values continue to use string comparison. ```sql SELECT name FROM jsontbl WHERE jval->'$.name' = 'test1' ORDER BY name; ``` In numeric comparisons, JSON values that cannot be parsed as numbers do not match; they do not cause errors. Ordinary VARCHAR-versus-number comparison rules are unchanged. Automatic numeric comparison applies only to JSON member access expressions. ### Name Resolution Ordinary SQL column name resolution takes precedence over JSON dot resolution. ```sql SELECT t.jval.name FROM jsontbl t; ``` The expression above is first resolved as an ordinary column name. If that fails and jval is a JSON column, jval.name is treated as JSON member access. JSON dot access must be rooted in a JSON column. ```sql -- Not supported (jval->'$.sensor').temperature name.member ``` ### Constraints The following syntax is not supported. - wildcard: `jval.items[*].name` - recursive descent: `jval..name` - filter expression: `jval.items[?(@.price > 10)]` - negative array index: `jval.items[-1]` - single quoted key: `jval.'product-id'` - Mixing dot and arrow syntax: `jval.items->'$.name'` - Dot access on a non-JSON column: `name.member` - Dot access after an arbitrary expression: `(jval->'$.sensor').temperature` - quoted member arrow path: `jval->'$."a.b"'` Automatic numeric comparison of JSON members is not supported in subquery IN, `IN (SELECT ...)`. Use literal IN (...). ## Window Functions Window functions compare and calculate across rows and are also called analytic or ranking functions. Available only in SELECT. ### Window Function Syntax Window functions must include OVER. ``` WINDOW_FUNCTION (ARGUMENTS) OVER ([PARTITION BY column_name] [ORDER BY column_name]) ``` * WINDOW_FUNCTION: Function name * ARGUMENTS: Zero or more arguments, depending on the function * PARTITION BY clause: Divide the full set into smaller groups (optional) * ORDER BY clause: Specify sort order (optional) ### Window Function List #### LAG Returns the value from N rows before the current row within each partition's window. Returns NULL if no such row exists. ``` LAG(column_name, N) OVER ([PARTITION BY column_name] [ORDER BY column_name]) ``` ``` Mach> CREATE LOG TABLE lag_table (name varchar(10), dt datetime, value INTEGER); Created successfully. Mach> INSERT INTO lag_table VALUES('name1', TO_DATE('2024-01-01'), 1); 1 row(s) inserted. Mach> INSERT INTO lag_table VALUES('name1', TO_DATE('2024-01-02'), 2); 1 row(s) inserted. Mach> INSERT INTO lag_table VALUES('name1', TO_DATE('2024-01-03'), 3); 1 row(s) inserted. -- Divide the set by name, sort by dt, and retrieve the first previous value. Mach> SELECT name, dt, value, LAG(value, 1) OVER(PARTITION BY name ORDER BY dt) FROM lag_table; name dt value LAG(value, 1) --------------------------------------------------------------------------- name1 2024-01-01 00:00:00 000:000:000 1 NULL name1 2024-01-02 00:00:00 000:000:000 2 1 name1 2024-01-03 00:00:00 000:000:000 3 2 [3] row(s) selected. ``` #### LEAD Returns the value from N rows after the current row within each partition's window. Returns NULL if no such row exists. ``` LEAD(column_name, N) OVER ([PARTITION BY column_name] [ORDER BY column_name]) ``` ``` Mach> CREATE LOG TABLE lead_table (name varchar(10), dt datetime, value INTEGER); Created successfully. Mach> INSERT INTO lead_table VALUES('name1', TO_DATE('2024-01-01'), 1); 1 row(s) inserted. Mach> INSERT INTO lead_table VALUES('name1', TO_DATE('2024-01-02'), 2); 1 row(s) inserted. Mach> INSERT INTO lead_table VALUES('name1', TO_DATE('2024-01-03'), 3); 1 row(s) inserted. -- Divide the set by name, sort by dt, and retrieve the first and subsequent values. Mach> SELECT name, dt, value, LEAD(value, 1) OVER(PARTITION BY name ORDER BY dt) FROM lead_table; name dt value LEAD(value, 1) ---------------------------------------------------------------------------- name1 2024-01-01 00:00:00 000:000:000 1 2 name1 2024-01-02 00:00:00 000:000:000 2 3 name1 2024-01-03 00:00:00 000:000:000 3 NULL [3] row(s) selected. ``` #### NTILE NTILE(n) divides ordered rows into n buckets as evenly as possible and returns each row's bucket number. ``` NTILE(n) OVER ([PARTITION BY column_name] ORDER BY column_name) ``` - n must be a positive constant. - ORDER BY inside OVER (...) is required. - When rows do not divide evenly, earlier buckets each receive one extra row. ``` Mach> SELECT user_id, score, NTILE(4) OVER (ORDER BY score) AS score_band FROM exam_result; ``` --- title: "16.1.4 Relative Time Expressions" url: https://docs.machbase.com/dbms/reference/sql/relative-time/ language: en kind: page --- # 16.1.4 Relative Time Expressions Relative time expressions specify offsets from a reference such as `NOW` or `SYSDATE` directly in SQL. They provide concise time-series windows without separate function calls. > Relative time literals such as `now - 1h` are supported from Machbase 8.0.50. Use `ADD_TIME` for month/year adjustments and `TO_DATE` for string conversion. ## Quick Reference | Expression | Example | Description | |------|------|------| | `NOW` / `now` | `now` | Current time with nanosecond precision | | `SYSDATE` / `sysdate` | `sysdate` | Current time (same as `NOW`) | | `now - offset` | `now - 1h` | Subtract an offset from the current time | | `now + offset` | `now + 30m` | Add an offset to the current time | | Direct nanosecond integer | `value + 1000000000` | Add an integer number of nanoseconds to DATETIME | ## Relative Time Units (Literal Suffixes) | Suffix | Meaning | Example | |--------|------|------| | `ns` | Nanoseconds | `500ns` | | `us` | Microseconds | `20us` | | `ms` | Milliseconds | `15ms` | | `s` | Seconds | `45s` | | `m` | Minutes | `30m` | | `h` | Hours | `12h` | | `d` | Days | `7d` | | `w` | Weeks | `2w` (= 14 days) | > Month (`month`, `mo`) and year (`year`, `y`) suffixes are not supported. Use `ADD_TIME()` > to move by calendar months or years. `30d` and `365d` are fixed day counts and do not > always equal a calendar month or year. ## ADD_TIME Function Use `ADD_TIME()` for calendar adjustments such as months and years that relative time literals cannot express. For arguments, format, and errors, see the [SQL Function Dictionary](../functions/functions-full/#add_time). ## TO_DATE Function Use `TO_DATE()` to create DATETIME values when specifying query boundaries as date strings. For formats and conversion errors, see the [SQL Function Dictionary](../functions/functions-full/#to_date). ## Usage Patterns ### Filtering Time Windows ```sql -- Last hour with a relative time literal SELECT * FROM sensor_tag WHERE time > now - 1h; -- Last hour with ADD_TIME SELECT * FROM sensor_tag WHERE time > ADD_TIME(now, '0/0/0 -1:0:0'); -- Records from the last 24 hours SELECT * FROM app_log WHERE _arrival_time BETWEEN now - 1d AND now; -- Alarms from the last 10 minutes SELECT alert_id, level, occurred_at FROM alert_log WHERE occurred_at >= sysdate - 10m; ``` ### Compound Time Expressions ```sql -- 2 days, 6 hours, and 15 minutes from now SELECT * FROM maintenance_plan WHERE planned_at < now + 2d6h15m; -- Combined subsecond units SELECT TO_CHAR(now + 3s125ms10us4ns, 'YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn'); ``` ### Applying Offsets to TO_DATE Results ```sql -- Add 3 days to a date string SELECT TO_CHAR(TO_DATE('2024-05-01', 'YYYY-MM-DD') + 3d, 'YYYY-MM-DD'); -- Result: 2024-05-04 -- Subtract 4 hours and 15 minutes from a date string SELECT TO_CHAR( TO_DATE('2024-05-01 08:00:00', 'YYYY-MM-DD HH24:MI:SS') - 4h15m, 'YYYY-MM-DD HH24:MI:SS' ); -- Result: 2024-05-01 03:45:00 ``` ### Using Nanosecond Integers Directly Numeric literals are interpreted as nanoseconds. ```sql -- 1 second = 1,000,000,000 nanoseconds SELECT event_time + 1000000000 AS event_time_plus_1s FROM events; -- Subtract 250 nanoseconds SELECT event_time - 250 AS event_time_minus_250ns FROM events; ``` ## Constraints - Relative time literals such as `1h` and `30m` require Machbase 8.0.50 or later. - Month (`mo`) and year (`y`) literals are not supported. Use the year/month positions in `ADD_TIME()`. - String literals are not implicitly converted to DATETIME in interval arithmetic. Convert them with `TO_DATE()` first. - An interval itself cannot be used in `ORDER BY`. ## Error Handling | Situation | Error | Resolution | |------|------|-----------| | Unsupported suffix (`1y`, `5mo`) | `ERR-02034` invalid time expression | Use `ADD_TIME()` for calendar units or supported suffixes such as `d` for fixed durations | | Missing unit (`now + 10`) | Interpreted as nanoseconds | Specify the intended unit suffix | | Excessive value (`1000000d`) | `ERR_OVERFLOW_INTERVAL` | Reduce the value | ## DURATION for LOG Tables Relative time literals and DURATION serve different purposes. `event_time >= now - 1h` is a WHERE predicate on the selected column; DURATION specifies the LOG `_arrival_time` range. Use WHERE for TAG time columns and user-defined DATETIME columns. ```text SELECT ... FROM log_table [WHERE ...] DURATION n unit [BEFORE base_time | AFTER base_time] [GROUP BY ...] [HAVING ...] [ORDER BY ...] [LIMIT ...] SELECT ... FROM log_table [WHERE ...] DURATION FROM from_time TO to_time [GROUP BY ...] [HAVING ...] [ORDER BY ...] [LIMIT ...] ``` These are the basic forms. Durations use units such as `HOUR`, `MINUTE`, and `DAY`. `ALL` can also specify the entire range. Place DURATION after WHERE and before GROUP BY/ORDER BY. | Form | Range | Specified Scan Direction | |---|---|---| | DURATION 1 HOUR | Last hour relative to the current time | Newest first | | DURATION 1 HOUR BEFORE t | From t−1 hour to t | Newest first | | DURATION 1 HOUR AFTER t | From t to t+1 hour | Oldest first | | DURATION FROM a TO b, a < b | From a to b | Oldest first | | DURATION FROM a TO b, a > b | From b to a | Newest first | Both endpoints are inclusive. If FROM and TO are equal, rows at that timestamp are selected. Distinguish scan direction from final output order after joins or aggregation. Specify ORDER BY when order matters, with additional sort keys for rows sharing a timestamp. The following example also selects row 2 at the end timestamp. ```sql CREATE LOG TABLE ch7_ref_duration (event_id INTEGER); INSERT INTO ch7_ref_duration(_arrival_time, event_id) VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1); INSERT INTO ch7_ref_duration(_arrival_time, event_id) VALUES (TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS'), 2); SELECT event_id FROM ch7_ref_duration DURATION 1 HOUR BEFORE TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS') ORDER BY event_id; DROP TABLE ch7_ref_duration; ``` The result contains rows 1 and 2. When dividing data into consecutive daily ranges, use half-open predicates such as `WHERE _arrival_time >= start_time AND _arrival_time < end_time` to avoid counting boundary rows twice. For queries combining LOG and LOOKUP, use a WHERE range on the LOG column instead of DURATION. ## Related Documentation - [LOG Time-range Exercise](/dbms/log-table-usage/query-analysis/) — Compare boundaries, ordering, and joins - [Relative Time Expressions](/dbms-8.5/sql-reference/time-expressions/) — Detailed 8.5 reference --- title: "16.1.6 ROWID" url: https://docs.machbase.com/dbms/reference/sql/rowid/ language: en kind: page --- # 16.1.6 ROWID Available since Machbase 8.7.0 `ROWID` is a 64-bit identifier used to locate a row within a table. This page defines its SQL meaning, per-table predicates, INSERT results, and lifetime. For SDK access APIs and code, see [SDK Feature Support](/dbms/development-tools-integration/sdk-support-scope/) and the relevant language page. This feature is supported in Standard Edition. Update both the server and SDK to versions supporting ROWID. It is unavailable in Cluster Edition. ## ROWID and Business Keys ROWID identifies a stored row's location in the current table. It is not a permanent business key such as an order number or device ID. - It is not an ordinary column and is excluded from `SELECT *`. Select it explicitly when needed. - Do not compare ROWIDs across tables or use one table's ROWID to query another table. - Do not decompose ROWID values or use them in arithmetic. - Numeric order does not indicate ingestion order across the entire table. - New tables cannot define a real column named `ROWID`. - For legacy tables with a real `ROWID` column, that column takes precedence. Rename the existing column to use the ROWID pseudocolumn. ```sql SELECT ROWID, name, time, value FROM sensor_tag WHERE name = 'TAG-01'; ``` ## Support by Table Type | Table | ROWID Meaning | Predicates | Single-row INSERT Result | |--------|--------------|-----------|------------------| | LOG | Identifier of a stored log row | `=`, `<`, `<=`, `>`, `>=`, `BETWEEN`, `ORDER BY` | Returns generated ROWID | | TAG | Identifier of a stored original TAG row | One `ROWID = value` within a top-level `AND` | Returns generated ROWID | | TRANSACTION | Single `LONG`/`INT64` PRIMARY KEY value | Predicates supported by the existing PK | Returns PK as ROWID | | LOOKUP | Single `LONG`/`INT64` PRIMARY KEY value | Predicates supported by the existing PK | Returns PK as ROWID | | VOLATILE | Single `LONG`/`INT64` PRIMARY KEY value | Predicates supported by the existing PK | Returns PK as ROWID | TRANSACTION, LOOKUP, and VOLATILE use a single `LONG`/`INT64` PRIMARY KEY with a value of `0` or greater as ROWID, regardless of `AUTO_INCREMENT`. If the application supplies the PK, that value is returned. If an `AUTO_INCREMENT` PK is omitted or NULL, the server-generated value is returned. Negative PK values cannot be used as ROWIDs. LOG and TAG ROWIDs range from `0..UINT64_MAX-1`; the three PRIMARY KEY-based table types use `0..INT64_MAX`. `0` is valid. `UINT64_MAX` cannot be used as ROWID. ### LOG Queries LOG ROWIDs support range queries and ordering. Because `_ARRIVAL_TIME` can be equal in multiple rows, use ROWID to locate a specific row again. ```sql SELECT ROWID, message FROM app_log WHERE ROWID >= ? AND ROWID < ? ORDER BY ROWID; ``` `ROWID IN (...)` is not supported. ### TAG Queries TAG supports only single-ROWID equality lookup. You can combine tag name, time, and value predicates with `AND`; a row is returned only when every condition matches. ```sql SELECT ROWID, name, time, value FROM sensor_tag WHERE ROWID = ? AND name = 'TAG-01' AND time >= TO_DATE('2026-08-10 00:00:00', 'YYYY-MM-DD HH24:MI:SS'); ``` The following conditions cannot be used with TAG ROWID. | Usage | Support | |--------|:---------:| | `ROWID = ?` | O | | `ROWID > ?`, `BETWEEN`, and other ranges | X | | `ROWID IN (...)` | X | | `ROWID = ? OR ...` | X | | `ORDER BY ROWID` | X | | `DELETE ... WHERE ROWID = ?` | X | | Combined with rollup, custom rollup, or stat results | X | ### Comparing TRANSACTION, LOOKUP, and VOLATILE The following three tables support the same `AUTO_INCREMENT` declaration, but differ in restart behavior and ingestion features. ```sql CREATE TRANSACTION TABLE orders ( id LONG PRIMARY KEY AUTO_INCREMENT, item VARCHAR(100) ); CREATE LOOKUP TABLE lookup_orders ( id LONG PRIMARY KEY AUTO_INCREMENT, item VARCHAR(100) ); CREATE VOLATILE TABLE volatile_orders ( id LONG PRIMARY KEY AUTO_INCREMENT, item VARCHAR(100) ); ``` | Feature | TRANSACTION | LOOKUP | VOLATILE | |------|-------------|--------|----------| | Rows and next automatic value survive restart | O | O | X | | Explicit transactions | O | X | X | | Generate automatic values with `INSERT ... SELECT` | O | X | X | | UPSERT on AUTO_INCREMENT tables | O (no ROWID return) | X | X | | ROWID result from single `INSERT ... VALUES` | O | O | O | LOOKUP `PROPERTY(SEQUENCE)` and `NEXTVAL()` are separate from `AUTO_INCREMENT`. Do not configure both mechanisms on the same column. TRANSACTION table DDL cannot run during an explicit transaction. If `CREATE TRANSACTION TABLE` fails with `ERR-02362`, run `COMMIT` or `ROLLBACK` first, then retry. ### JOIN, Aggregation, and Views JOIN results have no ROWID representing the entire result. Select the ROWID of each required source table alias separately. ```sql SELECT a.ROWID AS order_rowid, b.ROWID AS item_rowid, a.customer, b.item FROM orders a JOIN order_items b ON a.id = b.order_id; ``` | Query Form | ROWID Handling | |-----------|------------| | JOIN | Specify `alias.ROWID` for each required source table | | Aggregation, `GROUP BY`, `DISTINCT`, set operations | No new ROWID is generated for result rows | | View, CTE, inline view | Passed through only when explicitly selected in the inner SELECT | ## Conditions for Receiving ROWID from INSERT Do not use `INSERT ... RETURNING ROWID`. Supported SDKs return ROWID with the execution result of a successful single-row `INSERT ... VALUES`. | Ingestion Method | Generated ROWID | Description | |-----------|:---------------:|------| | Single direct `INSERT ... VALUES` | O | One row successfully created | | Single prepared INSERT | O | Returns the current result on each execution | | `INSERT ... SELECT` | X | May create multiple rows; returns no single value | | execute-array, batch, `executemany()` | X | Does not expose the last internal row as a representative value | | Append API, append batch | X | Not returned on the high-speed ingestion path | | loader | X | Not returned on the file ingestion path | | UPSERT | X | A single ROWID does not represent both INSERT and UPDATE outcomes | | Failed INSERT | X | Also clears ROWID from the previous execution | Generated ROWID is a per-statement result. There is no SQL function that retrieves the latest value for the entire connection. ## Empty Results and Errors A valid ROWID absent from the current table returns zero rows, not an error. This includes deleted rows and rows failing additional predicates. In contrast, NULL, negative PKs, `UINT64_MAX`, values that cannot convert to numbers, and unsupported TAG ranges/IN/OR/ordering are errors. ## Lifetime and Retries Do not use ROWID as a long-term business key. | Situation | Existing ROWID | |------|------------| | Normal restart | Retained for preserved rows | | Product backup/restore supporting ROWID preservation | Retained for preserved rows | | Row DELETE | Invalid | | Transaction ROLLBACK | ROWID of that INSERT becomes invalid | | Row discarded by snapshot recovery | Invalid | | LOG TRUNCATE | Old values may be reused | | Table DROP and recreation | Old values may identify different rows | | Export/import or row reinsertion | Not preserved | An INSERT may succeed without the application receiving its ROWID if the network response is lost. Automatically repeating the INSERT can create duplicate rows. First verify whether it was applied using a business key or a separate idempotency policy. ## Related Documentation - [SDK Feature Support](/dbms/development-tools-integration/sdk-support-scope/) - [AUTO_INCREMENT](/dbms/reference/sql/syntax/auto-increment-syntax/) - [LOG Data Ingestion](/dbms/log-table-usage/data-input-mutation/) - [TAG Data Ingestion](/dbms/tag-table-usage/data-input-mutation/) --- title: "16.2 Configuration Reference" url: https://docs.machbase.com/dbms/reference/configuration/ language: en kind: section --- # 16.2 Configuration Reference Machbase server behavior is controlled by properties in `$MACHBASE_HOME/conf/machbase.conf`. This section provides a quick reference to each property's allowed range and default value. ## Subsections | Section | Description | |------|------| | [Configuration Property Dictionary](./configuration/) | Standard Edition properties for server operation, performance, security, and logging | | [Cluster Configuration Property Dictionary](./configuration-2/) | Cluster Edition properties for Coordinator, Broker, and Warehouse nodes | | [PVO Cache Property Dictionary](./pvo-cache/) | SQL execution plan cache (PVO Statement Cache) properties | | [Timezone Configuration Dictionary](./configuration-timezone/) | Timezone properties and client timezone settings | ## Checking Property Values Query the `v$property` system view to check current property values while the server is running. ```sql -- Query all properties SELECT name, value, type FROM v$property ORDER BY name; -- Query a specific property SELECT name, value, min, max FROM v$property WHERE name = 'PORT_NO'; ``` ## Dynamically Configurable Properties Some properties can be changed with `ALTER SYSTEM SET` without restarting the server. ```sql ALTER SYSTEM SET TRACE_LOG_LEVEL = 3; ALTER SYSTEM SET PVO_CACHE_MAX_MEMORY_SIZE = 536870912; ``` Query `v$property` after a change to verify that it took effect. Attempting to change a property that requires a restart returns an error. --- title: "16.2.1 Configuration Property Dictionary" url: https://docs.machbase.com/dbms/reference/configuration/configuration/ language: en kind: page --- # 16.2.1 Configuration Property Dictionary This dictionary lists the main Standard Edition properties configured in `$MACHBASE_HOME/conf/machbase.conf`. A server restart is required unless otherwise stated. ## Basic Server Settings | Property | Default | Range | Description | |----------|--------|------|------| | `PORT_NO` | 5656 | 1024~65535 | Client TCP/IP connection port | | `BIND_IP_ADDRESS` | 0.0.0.0 | - | Client listener bind IP. `0.0.0.0` means all interfaces | | `GRANT_REMOTE_ACCESS` | 1 | 0~1 | Allows remote access. 0 allows local access only | | `MAX_SESSION_COUNT` | 4096 | 64~2^64-1 | Maximum concurrent sessions | | `MAX_STMT_COUNT_PER_SESSION` | 1024 | 512~2^32-1 | Maximum statements per session | | `SESSION_IDLE_TIMEOUT_SEC` | 0 | 0~2^64-1 | Session idle timeout in seconds. 0 disables it | | `SESSION_QUERY_TIMEOUT_SEC` | 0 | 0~2^64-1 | Query execution timeout in seconds. 0 disables it | | `UNIX_PATH` | machbase-unix | - | Unix domain socket filename | | `DBS_PATH` | ?/dbs | - | Database file directory (`?` means `$MACHBASE_HOME`) | | `PID_PATH` | ?/conf | - | PID file directory | ## CPU and Thread Settings | Property | Default | Range | Description | |----------|--------|------|------| | `CPU_COUNT` | 1 | 0~2^32-1 | CPUs to use. 0 uses all CPUs | | `CPU_PARALLEL` | 1 | 1~2^32-1 | Parallel threads per CPU | | `CPU_AFFINITY_BEGIN_ID` | 0 | 0~2^32-1 | Starting CPU affinity ID | | `CPU_AFFINITY_COUNT` | 0 | 0~2^32-1 | CPUs used for affinity. 0 means all | | `DISK_IO_THREAD_COUNT` | 3 | 1~2^32-1 | Disk I/O threads | | `INDEX_BUILD_THREAD_COUNT` | 3 | 0~2^32-1 | Index build threads. 0 disables index creation | | `INDEX_LEVEL_PARTITION_BUILD_THREAD_COUNT` | 3 | 1~1024 | LSM index merge threads | | `INDEX_LEVEL_PARTITION_AGER_THREAD_COUNT` | 1 | 1~1024 | Threads that delete obsolete LSM index files | | `QUERY_PARALLEL_FACTOR` | 0 | 0~100 | Parallel query execution threads. Default: 0 for Standard, 4 for Cluster | ## Memory Settings | Property | Default | Range | Description | |----------|--------|------|------| | `PROCESS_MAX_SIZE` | 8GB | 1GB~2^64-1 | Maximum server process memory in bytes. Distribution samples may specify `16GB` | | `DISK_COLUMNAR_TABLESPACE_MEMORY_MAX_SIZE` | 8GB | 256MB~2^64-1 | Log table ingestion buffer limit. Adjust within the total memory budget | | `DISK_COLUMNAR_TABLESPACE_MEMORY_MIN_SIZE` | 100MB | 1MB~2^64-1 | Memory preallocated at server startup | | `DISK_COLUMNAR_TABLESPACE_MEMORY_EXT_SIZE` | 2MB | 1MB~2^64-1 | Column partition memory block size | | `DISK_COLUMNAR_TABLESPACE_DWFILE_INT_SIZE` | 2MB | 1MB~2^32-1 | Initial doublewrite file size for data consistency and recovery | | `DISK_COLUMNAR_TABLESPACE_DWFILE_EXT_SIZE` | 1MB | 1MB~2^32-1 | Doublewrite file growth increment | | `DISK_COLUMNAR_PAGE_CACHE_MAX_SIZE` | 2GB | 0~2^64-1 | Maximum page cache size in bytes | | `VOLATILE_TABLESPACE_MEMORY_MAX_SIZE` | 2GB | 0~2^64-1 | Total memory limit for Volatile/Lookup tables | | `MAX_QPX_MEM` | 1GB | 1MB~2^64-1 | Maximum query processor memory for GROUP BY, ORDER BY, and similar operations | | `MEMORY_ROW_TEMP_TABLE_PAGESIZE` | 32768 | 8KB~2^32-1 | Volatile/Lookup temporary table page size in bytes | ## Disk I/O Settings | Property | Default | Range | Description | |----------|--------|------|------| | `DISK_BUFFER_COUNT` | 16 | 1~2^32-1 | Disk I/O buffers | | `DISK_TABLESPACE_DIRECT_IO_WRITE` | 1 | 0~1 | Enables direct I/O for writes. Set to 0 for unsupported filesystems such as ZFS | | `DISK_TABLESPACE_DIRECT_IO_READ` | 0 | 0~1 | Enables direct I/O for reads | | `DISK_TABLESPACE_DIRECT_IO_FSYNC` | 0 | 0~1 | Enables fsync with direct I/O | | `DISK_TABLESPACE_SYNCHRONOUS` | 1 | 0~3 | Synchronization policy. 0=OFF, 1=NORMAL, 2=FULL, 3=EXTRA | | `DISK_COLUMNAR_TABLE_COLUMN_PART_IO_INTERVAL_MIN_SEC` | 3 | 0~2^32-1 | Partition file disk write interval in seconds | | `DISK_COLUMNAR_TABLE_COLUMN_PART_FLUSH_MODE` | 0 | 0~1 | Whether to flush column partitions only when full | | `DISK_COLUMNAR_TABLE_CHECKPOINT_INTERVAL_SEC` | 120 | 1~2^32-1 | Table checkpoint interval in seconds | | `DISK_COLUMNAR_INDEX_CHECKPOINT_INTERVAL_SEC` | 120 | 1~2^32-1 | Index checkpoint interval in seconds | | `DISK_COLUMNAR_TABLE_TIME_INVERSION_MODE` | 1 | 0~1 | For reversed LOG timestamps: 1=adjust to previous timestamp+1ns, 0=reject ingestion | | `DISK_COLUMNAR_TABLESPACE_MEMORY_SLOWDOWN_HIGH_LIMIT_PCT` | 80 | 0~100 | Memory usage threshold (%). Ingestion slows above this threshold | | `DISK_COLUMNAR_TABLESPACE_MEMORY_SLOWDOWN_MSEC` | 1 | 0~2^32-1 | Wait per record in ms above the threshold | For LOG tables, `DISK_COLUMNAR_TABLE_TIME_INVERSION_MODE=1` does not mean an explicitly supplied past timestamp is stored unchanged. Values earlier than the preceding `_ARRIVAL_TIME` are adjusted. Equal timestamps do not satisfy this reversal condition, so this setting does not make every row's timestamp unique. During migration, also check ordering and target state in the [time model](/dbms/log-table-usage/arrival-time-model/). ## Index Settings | Property | Default | Range | Description | |----------|--------|------|------| | `DEFAULT_LSM_MAX_LEVEL` | 2 | 0~3 | Default maximum LSM index level | | `INDEX_BUILD_MAX_ROW_COUNT_PER_THREAD` | 100000 | 1~2^32-1 | Unindexed record count that triggers an index build | | `INDEX_FLUSH_MAX_REQUEST_COUNT_PER_INDEX` | 3 | 1~2^32-1 | Maximum flush requests per index | | `INDEX_LEVEL_PARTITION_BUILD_MEMORY_HIGH_LIMIT_PCT` | 70 | 0~100 | Maximum memory usage percentage for LSM index builds | | `DISK_COLUMNAR_INDEX_SHUTDOWN_BUILD_FINISH` | 0 | 0~1 | Whether to flush all indexes to disk at shutdown | | `DISK_COLUMNAR_INDEX_FDCACHE_COUNT` | 0 | 0~2^32-1 | Open index partition file descriptors | | `DISK_COLUMNAR_TABLE_COLUMN_FDCACHE_COUNT` | 0 | 0~2^32-1 | Open column file descriptors | | `DISK_COLUMNAR_TABLE_COLUMN_MINMAX_CACHE_SIZE` | 100MB | 0~2^64-1 | `_ARRIVAL_TIME` column MINMAX cache size in bytes | ## TAG Table Settings | Property | Default | Range | Description | |----------|--------|------|------| | `TAG_CACHE_ENABLE` | 31 | 0~31 | TAG cache scope (bitwise OR). 0=disabled, 1=map, 2=row, 4=data file, 8=varchar file, 16=delete vector | | `TAG_CACHE_MAX_MEMORY_SIZE` | 512MB | 32KB~2^64-1 | Maximum memory per TAG cache pool in bytes | | `TAG_CACHE_POOL_COUNT` | 1 | 1~128 | TAG cache pools. Total limit = `TAG_CACHE_MAX_MEMORY_SIZE × TAG_CACHE_POOL_COUNT` | | `TAG_MEMORY_INDEX_TYPE` | 1 | 0~1 | Memory index type. 0=RBTree, 1=BTree | | `TAG_MEMORY_INDEX_PANOUT` | 255 | 127~65536 | B-tree index fanout. Applies when `TAG_MEMORY_INDEX_TYPE=1` | | `TAGDATA_AUTO_META_INSERT` | 2 | 0~2 | Action when TAG_NAME is missing. 0=fail, 1=insert name only, 2=insert with metadata | | `TAG_TABLE_META_MAX_SIZE` | 524288000 | 1MB~2^32-1 | Maximum TAGDATA table metadata memory in bytes | | `TAG_PARTITION_COUNT` | 4 | 1~1024 | Tag table key-value partitions | | `TAG_DATA_PART_SIZE` | 16MB | 1MB~1GB | Tag data partition size in bytes | | `ROLLUP_FETCH_COUNT_LIMIT` | 3000000 | 0~2^32-1 | Rows fetched per rollup thread iteration. 0=unlimited | ## Security Settings | Property | Default | Range | Description | |----------|--------|------|------| | `ENABLE_CASE_SENSITIVE_PASSWORD` | 0 | 0~1 | Case-sensitive passwords. 0 converts passwords to uppercase | ## Session and Query Settings `TABLE_SCAN_DIRECTION` is not exclusive to TAG tables. It can also affect queries that use scan direction on LOG and other tables, and does not guarantee final result ordering. Use ORDER BY to specify output order and EXPLAIN to check the actual access path. | Property | Default | Range | Description | |----------|--------|------|------| | `TABLE_SCAN_DIRECTION` | 0 | -1~1 | -1=reverse, 0=table type default, 1=forward | | `DDL_LOCK_TIMEOUT` | 0 | 0~1000000 | Standard Edition DDL lock wait in seconds. 0 returns an error immediately | | `SHOW_HIDDEN_COLS` | 0 | 0~1 | Whether `SELECT *` includes `_ARRIVAL_TIME` | | `DURATION_BEGIN` | 0 | 0~2^32-1 | Default start offset in seconds for SELECT without `DURATION` | | `DURATION_GAP` | 0 | 0~2^31-1 | Default duration in seconds for SELECT without `DURATION` | | `LOOKUP_APPEND_UPDATE_ON_DUPKEY` | 0 | 0~1 | Duplicate key handling for Lookup table Append. 0=fail, 1=UPDATE | | `LIN_HASH_BIT_SIZE` | 7 | 1~31 | Initial bucket bits for internal linear hashing | After a server restart, `DDL_LOCK_TIMEOUT` in `machbase.conf` is copied to new sessions. Change the current session value with `ALTER SESSION SET DDL_LOCK_TIMEOUT = seconds` and check it in `V$SESSION`. Cluster Edition does not provide this property. ## TRANSACTION Settings | Property | Default | Range | Description | |----------|--------|------|------| | `TRANSACTION_BUSY_TIMEOUT_MS` | 30000 | -1~2147483647 | Wait in ms for retryable TRANSACTION lock conflicts. -1 waits until cancellation or release; 0 returns immediately | | `TRANSACTION_SYNCHRONOUS` | 2 | 1~2 | TRANSACTION table transaction durability. 1=NORMAL, 2=FULL | | `TRANSACTION_JOURNAL_MODE` | 4 | 0~4 | TRANSACTION journal mode. 0=DELETE, 4=WAL | New sessions copy the server's TRANSACTION_BUSY_TIMEOUT_MS. Use ALTER SESSION to change it for the current connection. This value does not guarantee a minimum wait for every busy error. In WAL mode, upgrading an obsolete read snapshot to a write can fail immediately even with -1. In that case, do not repeat the same statement: ROLLBACK and repeat the reads and decisions in a new transaction. The [two-connection exercise](/dbms/rdb-table-usage/locking-conflict-timeout/) compares temporary write locks with snapshot conflicts. ## Logging and Diagnostics | Property | Default | Range | Description | |----------|--------|------|------| | `TRACE_LOG_LEVEL` | 277 | 0~2^32-1 | Trace log verbosity. Higher values provide more detail | | `TRACE_LOGFILE_PATH` | ?/trc | - | Trace log directory | | `TRACE_LOGFILE_SIZE` | 10MB | 1MB~2^32-1 | Maximum trace log file size in bytes | | `TRACE_LOGFILE_COUNT` | 1000 | 1~2^32-1 | Maximum trace log files | | `DUMP_TRACE_INFO` | 300 | 0~2^32-1 | Interval in seconds for writing DBMS status to trc. 0 disables it | | `DUMP_APPEND_ERROR` | 0 | 0~1 | Logs Append API errors to trc. Recommended for testing only | | `FEEDBACK_APPEND_ERROR` | 1 | 0~1 | Sends Append error data to the client | | `GEN_CORE_FILE` | 1 | 0~1 | Generates a core file on abnormal termination | | `GEN_CALLSTACK_FOR_ABORT_ERROR` | 0 | 0~1 | Records a call stack on abnormal termination | ## Property Query Examples ```sql -- Query all current property values SELECT name, value, type FROM v$property ORDER BY name; -- Query details for a specific property SELECT name, value, min, max FROM v$property WHERE name = 'MAX_SESSION_COUNT'; ``` Dynamically configurable properties can be changed with `ALTER SYSTEM SET` without a server restart. ```sql ALTER SYSTEM SET TRACE_LOG_LEVEL = 3; ALTER SYSTEM SET SESSION_QUERY_TIMEOUT_SEC = 30; ``` --- title: "16.2.2 Cluster Configuration Property Dictionary" url: https://docs.machbase.com/dbms/reference/configuration/configuration-2/ language: en kind: page --- # 16.2.2 Cluster Configuration Property Dictionary Cluster Edition is configured through each node's configuration files in `$MACHBASE_COORDINATOR_HOME/conf/`, `$MACHBASE_BROKER_HOME/conf/`, and `$MACHBASE_WAREHOUSE_HOME/conf/`. This page lists the main cluster properties used during operation. ## Coordinator Settings The Coordinator manages cluster-wide metadata and node status. | Property | Default | Description | |----------|--------|------| | `CLUSTER_LINK_HOST` | - | IP address to which the Coordinator binds | | `CLUSTER_LINK_PORT_NO` | 3868 | Internal cluster communication port | | `CLUSTER_LINK_THREAD_COUNT` | 16 | Number of cluster link processing threads | | `CLUSTER_LINK_MAX_LISTEN` | 512 | Maximum cluster link listen connections | | `CLUSTER_LINK_MAX_POLL` | 4096 | Maximum cluster link poll events | | `CLUSTER_LINK_BUFFER_SIZE` | 33554432 | Cluster link buffer size in bytes. Default: 32MB | | `HTTP_ADMIN_PORT` | 5779 | Coordinator/Deployer administration REST port | | `HTTP_THREAD_COUNT` | 2 | Number of administration REST request threads | `HTTP_ADMIN_PORT` can also be set with the `MACHBASE_HTTP_ADMIN_PORT` environment variable. This port is used exclusively for cluster administration requests, rather than SQL queries or data ingestion. ## Cluster Link Timeouts All values are in microseconds (μs). | Property | Default (μs) | Description | |----------|-----------|------| | `CLUSTER_LINK_ACCEPT_TIMEOUT` | 5000000 | Accept timeout (5 seconds) | | `CLUSTER_LINK_CHECK_INTERVAL` | 1000000 | Connection status check interval (1 second) | | `CLUSTER_LINK_CONNECT_RETRY_TIMEOUT` | 60000000 | Maximum connection retry duration (60 seconds) | | `CLUSTER_LINK_CONNECT_TIMEOUT` | 5000000 | Connection timeout (5 seconds) | | `CLUSTER_LINK_HANDSHAKE_TIMEOUT` | 5000000 | Handshake timeout (5 seconds) | | `CLUSTER_LINK_RECEIVE_TIMEOUT` | 30000000 | Receive timeout (30 seconds) | | `CLUSTER_LINK_SEND_TIMEOUT` | 30000000 | Send timeout (30 seconds) | | `CLUSTER_LINK_REQUEST_TIMEOUT` | 60000000 | Request timeout (60 seconds) | | `CLUSTER_LINK_SESSION_TIMEOUT` | 3600000000 | Session timeout (1 hour) | | `CLUSTER_LINK_LONG_WAIT_INTERVAL` | 1000000 | Long wait interval (1 second) | | `CLUSTER_LINK_LONG_TERM_CALLBACK_INTERVAL` | 1000000 | Long-term callback interval (1 second) | ## Broker Settings A Broker accepts client queries and distributes processing across Warehouses. Its `machbase.conf` contains common server and cluster settings. Supported properties and defaults vary by edition and node role; do not apply a Standard Edition configuration file unchanged. | Property | Default | Description | |----------|--------|------| | `PORT_NO` | 5656 | Client connection port | | `QUERY_PARALLEL_FACTOR` | 4 | Number of parallel query processing threads (Cluster default) | | `CLUSTER_LINK_HOST` | - | IP address to which the Broker binds for cluster communication | | `CLUSTER_LINK_PORT_NO` | - | Broker cluster communication port | ## Warehouse Settings A Warehouse stores and processes the actual data. It uses the following cluster settings in addition to storage settings. Properties exclusive to Standard Edition, such as `DDL_LOCK_TIMEOUT`, are not supported in Cluster Edition. | Property | Default | Description | |----------|--------|------| | `PORT_NO` | 5656 | Warehouse service port | | `CLUSTER_LINK_HOST` | - | IP address to which the Warehouse binds for cluster communication | | `CLUSTER_LINK_PORT_NO` | - | Warehouse cluster communication port | | `DBS_PATH` | ?/dbs | Warehouse data file directory | ## Checking Cluster Configuration Use `machcoordinatoradmin --configure` to display cluster settings. ```bash machcoordinatoradmin --configure ``` To check an individual setting, use `--configuration=name`. ```bash machcoordinatoradmin --configuration=decision ``` ## Example Cluster Port Allocation The following example assigns ports for a cluster on a single host. | Node | Service Port | HTTP Port | Cluster Link Port | |------|------------|-----------|------------------| | Coordinator | - | 5102 | 5101 | | Deployer | - | - | 5201 | | Broker | 5757 | 5302 | 5301 | | Warehouse-A1 | 5400 | 5402 | 5401 | | Warehouse-A2 | 5500 | 5502 | 5501 | --- title: "16.2.3 PVO Cache Property Dictionary" url: https://docs.machbase.com/dbms/reference/configuration/pvo-cache/ language: en kind: page --- # 16.2.3 PVO Cache Property Dictionary PVO Statement Cache reduces repeated SQL processing costs by reusing parsing, validation, optimization results, and execution plans. This manual does not expand the acronym without a public source. It is available only in Standard Edition. ## Properties | Property | Default | Range | Dynamic | Description | |----------|--------|------|----------|------| | `PVO_CACHE_ENABLE` | 1 | 0~1 | Yes | Enables PVO Cache. 0=disabled, 1=enabled | | `PVO_CACHE_MAX_MEMORY_SIZE` | 268435456 | 32768~2^64-1 | Yes | Maximum total PVO Cache memory in bytes. Default: 256MB | | `PVO_CACHE_SHARD_COUNT` | 16 | 1~256 | No | Number of cache shards. Requires a server restart | | `PVO_CACHE_MAX_SQL_ENTRIES` | 0 | 0~2^64-1 | Yes | Maximum cached SQL entries. 0=unlimited | | `PVO_CACHE_MAX_PLANS_PER_SQL` | 512 | 1~512 | Yes | Maximum plans (handles) per SQL statement | ## Property Details ### PVO_CACHE_ENABLE Controls whether PVO Statement Cache is enabled. ``` PVO_CACHE_ENABLE = 1 ``` ### PVO_CACHE_MAX_MEMORY_SIZE Maximum total memory, in bytes, available to PVO Cache. The value is distributed evenly across `PVO_CACHE_SHARD_COUNT` shards. ``` PVO_CACHE_MAX_MEMORY_SIZE = 536870912 # 512MB ``` ### PVO_CACHE_SHARD_COUNT Number of internal cache shards. This setting applies at initialization and requires a server restart. Increasing the shard count can reduce lock contention with many concurrent connections. ``` PVO_CACHE_SHARD_COUNT = 32 ``` ### PVO_CACHE_MAX_SQL_ENTRIES Maximum number of SQL entries retained in PVO Cache. 0 means unlimited. A configured limit is distributed across the shards. ``` PVO_CACHE_MAX_SQL_ENTRIES = 10000 ``` ### PVO_CACHE_MAX_PLANS_PER_SQL Maximum number of plans retained for one SQL statement. Different bind parameter types can generate different plans for the same SQL text. ``` PVO_CACHE_MAX_PLANS_PER_SQL = 256 ``` ## Dynamic Changes Use `ALTER SYSTEM SET` to apply properties that can be changed without a server restart. ```sql -- Enable PVO Cache ALTER SYSTEM SET PVO_CACHE_ENABLE = 1; -- Set maximum memory to 512MB ALTER SYSTEM SET PVO_CACHE_MAX_MEMORY_SIZE = 536870912; -- Limit the number of SQL entries ALTER SYSTEM SET PVO_CACHE_MAX_SQL_ENTRIES = 5000; ``` ## Clearing the Cache Use the following command to force a PVO Cache reset. ```sql ALTER SYSTEM FLUSH PVO_CACHE; ``` ## Checking Cache Settings ```sql SELECT name, value FROM v$property WHERE name LIKE 'PVO_CACHE%' ORDER BY name; ``` --- title: "16.2.4 Timezone Configuration Dictionary" url: https://docs.machbase.com/dbms/reference/configuration/configuration-timezone/ language: en kind: page --- # 16.2.4 Timezone Configuration Dictionary Machbase supports a timezone option for client connections. Internally, datetime values are processed as nanosecond values; the timezone option affects conversion to and from strings. ## Supported Timezone Format | Format | Example | Description | |------|------|------| | UTC offset | `+0900`, `-0530` | Hour and minute offset from UTC | The format documented in the original 8.5 manual and current `machsql` and `machloader` help is an offset in `+-HHMM` format. IANA region names such as `Asia/Seoul` and the `DEFAULT_TIMEZONE` server property have not been verified in the current distribution samples, so this chapter does not list them as supported formats. ## Client Timezone Settings ### machsql Use `-z` to set the session timezone. ```bash machsql -s 127.0.0.1 -u SYS -p MANAGER -z +0900 ``` ### machloader Use `-z` to set the timezone for datetime conversion during import and export. ```bash machloader -i -d data.csv -t table_name -z +0900 machloader -o -d data.csv -t table_name -z +0900 ``` ### JDBC For JDBC timezone settings, check the connection options in the driver documentation. This page describes the `+-HHMM` offset format used by `machsql` and `machloader`. ## Timezone Precedence An explicit client timezone, such as `-z +0900`, applies to input and output conversion in that session. ## Timezone Conversion Example Connect as follows to use the `+0900` timezone. ```bash machsql -s 127.0.0.1 -u SYS -p MANAGER -z +0900 ``` --- title: "16.3 System Catalog Reference" url: https://docs.machbase.com/dbms/reference/system-catalog/ language: en kind: section --- # 16.3 System Catalog Reference The system catalog is a set of read-only tables for querying Machbase server metadata and current operational status with SQL. It contains two types of tables. | Type | Prefix | Description | |------|--------|------| | Metadata tables | `M$` | Schema information, including table definitions, columns, indexes, and users | | Virtual tables (dynamic views) | `V$` | Current operational status, including sessions, running queries, memory, and storage | ## General Rules - All system catalog tables are **read-only**. `INSERT`, `UPDATE`, and `DELETE` return errors. - `M$` tables automatically reflect DDL operations (`CREATE`, `ALTER`, and `DROP`). - `V$` tables reflect live server status and return current values on each query. - Use the following queries to list all tables. ```sql -- List all metadata tables SELECT name FROM m$tables ORDER BY name; -- List all virtual tables SELECT name FROM v$tables WHERE name LIKE 'V$%' ORDER BY name; ``` ## Subsections | Section | Description | |------|------| | [Metadata Table Dictionary](./meta/) | Schema metadata tables such as M$SYS_TABLES and M$SYS_COLUMNS | | [Virtual Table Dictionary](./virtual/) | Dynamic views such as V$SESSION, V$STMT, and V$PROPERTY | | [Per-tag Statistics Views](/dbms/tag-table-usage/query-analysis/#tag-stat-axis-schema) | Time- and distance-axis schemas and queries for `V$
_STAT` | | [V$ROLLUP Dictionary](./vrollup/) | Rollup job status view columns | | [V$STORAGE_MOUNT_* Dictionary](./vstorage-mount/) | Mounted backup database view columns | | [Complete Virtual Table Reference](./virtual-table-full/) | All entries from the original 8.5 virtual table reference | --- title: "16.3.1 Metadata Table Dictionary" url: https://docs.machbase.com/dbms/reference/system-catalog/meta/ language: en kind: page --- # 16.3.1 Metadata Table Dictionary Metadata tables use the `M$` prefix and expose Machbase schema information, including table definitions, columns, indexes, and users. They are read-only and automatically reflect DDL operations. In 8.7.0 Standard Edition with multiple databases, joins between catalog-local metadata must use `DATABASE_ID`, `TABLESPACE_ID`, and the parent object ID together. Logical `DATABASE_ID` and physical `TABLESPACE_ID` are not interchangeable. For database operation boundaries, see the [Multiple Database Operations Guide](/dbms/operations-configuration-recovery/multi-database/). ## Metadata Tables | Table | Description | |------------|------| | `M$SYS_TABLES` | User-created tables and their types | | `M$SYS_TABLE_PROPERTY` | Properties applied to tables | | `M$SYS_COLUMNS` | Table column definitions (type, length, and other attributes) | | `M$SYS_INDEXES` | Index definitions | | `M$SYS_INDEX_COLUMNS` | Columns that make up each index | | `M$SYS_TABLESPACES` | Tablespaces | | `M$SYS_TABLESPACE_DISKS` | Disk paths used by tablespaces | | `M$SYS_USERS` | Registered users | | `M$SYS_VIEWS` | SQL text defining views | | `M$SYS_USER_ACCESS` | User privileges per table | | `M$RETENTION` | Retention policy information | | `M$TABLES` | The M$ metadata tables themselves | | `M$COLUMNS` | Columns of M$ metadata tables | ## M$SYS_TABLES Lists user-created tables and their types. | Column | Type | Description | |--------|------|------| | `NAME` | VARCHAR | Table name | | `TYPE` | INTEGER | Table type | | `ID` | LONG | Table identifier | | `DATABASE_ID` | LONG | Logical database identifier | | `TABLESPACE_ID` | LONG | Physical tablespace identifier | | `USER_ID` | INTEGER | Identifier of the user who created the table | | `COLCOUNT` | INTEGER | Number of columns | | `FLAG` | INTEGER | Subtype (1: Tag Data, 2: Rollup, 4: Tag Meta, 8: Tag Stat) | **TYPE values:** | Value | Table Type | |----|------------| | `0` | Log table | | `1` | Fixed table | | `3` | Volatile table | | `4` | Lookup table | | `5` | Key Value table | | `6` | Tag table | | `7` | View | | `8` | TRANSACTION table | ## M$SYS_COLUMNS Lists table column definitions. | Column | Type | Description | |--------|------|------| | `NAME` | VARCHAR | Column name | | `TYPE` | INTEGER | Column data type | | `TABLE_ID` | LONG | Parent table identifier | | `DATABASE_ID` | LONG | Logical database identifier | | `TABLESPACE_ID` | LONG | Physical tablespace identifier | | `LENGTH` | INTEGER | Maximum column length | | `PART_PAGE_COUNT` | INTEGER | Pages per partition | | `MINMAX_CACHE_SIZE` | LONG | MIN-MAX cache size | ## M$SYS_INDEXES Lists index definitions. | Column | Type | Description | |--------|------|------| | `NAME` | VARCHAR | Index name | | `TYPE` | INTEGER | Index type | | `TABLE_ID` | LONG | Parent table identifier | | `DATABASE_ID` | LONG | Logical database identifier | | `TABLESPACE_ID` | LONG | Physical tablespace identifier | | `COLCOUNT` | INTEGER | Number of index columns | | `MAX_LEVEL` | INTEGER | Maximum LSM level | ## M$SYS_USERS Lists registered users. | Column | Type | Description | |--------|------|------| | `USER_ID` | INTEGER | User identifier | | `NAME` | VARCHAR | Username | | `PWD_POLICY_LEVEL` | INTEGER | Password policy level | | `VALID_BEFORE` | VARCHAR | Account validity period | ## M$RETENTION Lists retention policy information. | Column | Type | Description | |--------|------|------| | `POLICY_NAME` | VARCHAR | Policy name | | `DURATION` | LONG | Retention period in seconds | | `INTERVAL` | LONG | Deletion interval in seconds | ## SQL Examples ```sql -- List all tables, including their types SELECT name, type, colcount FROM m$sys_tables ORDER BY name; -- List Tag tables only (type = 6) SELECT name FROM m$sys_tables WHERE type = 6; -- List columns of a specific table SELECT c.name AS col_name, c.type AS col_type, c.length FROM m$sys_columns c JOIN m$sys_tables t ON c.database_id = t.database_id AND c.tablespace_id = t.tablespace_id AND c.table_id = t.id WHERE t.name = 'SENSOR_TAG' ORDER BY c.id; -- List indexes of a specific table SELECT i.name AS idx_name, i.type AS idx_type, i.colcount FROM m$sys_indexes i JOIN m$sys_tables t ON i.database_id = t.database_id AND i.tablespace_id = t.tablespace_id AND i.table_id = t.id WHERE t.name = 'SENSOR_TAG'; -- Check the columns that make up an index SELECT ic.name AS col_name, ic.index_type FROM m$sys_index_columns ic JOIN m$sys_indexes i ON ic.index_id = i.id JOIN m$sys_tables t ON i.table_id = t.id WHERE t.name = 'SENSOR_TAG'; -- Check tablespace disk paths SELECT ts.name AS tbs_name, d.path, d.io_thread_count FROM m$sys_tablespace_disks d JOIN m$sys_tablespaces ts ON d.tablespace_id = ts.id; -- List users SELECT user_id, name, pwd_policy_level, valid_before FROM m$sys_users; -- List retention policies SELECT * FROM m$retention; ``` > Metadata tables are read-only. `INSERT`, `UPDATE`, and `DELETE` return errors. Use DDL such as `CREATE TABLE`, `ALTER TABLE`, and `DROP TABLE` to change schemas. --- title: "16.3.2 Virtual Table Dictionary" url: https://docs.machbase.com/dbms/reference/system-catalog/virtual/ language: en kind: page --- # 16.3.2 Virtual Table Dictionary Virtual tables (dynamic views) use the `V$` prefix and expose current Machbase server status as tables. They are read-only and return the latest state on each query. ## Virtual Tables | Category | Table | Description | |---------|------------|------| | Session/System | `V$VERSION` | Server version information | | Session/System | `V$SESSION` | Connected sessions | | Database | `V$DATABASES` | Active/mounted database status | | Database | `V$DATABASE_OPERATIONS` | Database lifecycle operation history | | Session/System | `V$STMT` | Running SQL statements | | Session/System | `V$PROPERTY` | Current server settings | | Session/System | `V$SYSMEM` | System memory usage | | Session/System | `V$SYSSTAT` | System statistics | | Session/System | `V$SYSTIME` | System time statistics | | Storage | `V$STORAGE` | Storage file size summary | | Storage | `V$STORAGE_USAGE` | Disk usage and usage limit ratio | | Storage | `V$STORAGE_TABLES` | Storage usage per table | | Storage | `V$STORAGE_MOUNT_DATABASES` | Mounted backup databases | | Tag Rollup | `V$ROLLUP` | Rollup job status | | TAG Table | `V$
_STAT` | Per-table tag and axis statistics. The actual name is generated from the TAG table name | | License | `V$LICENSE_INFO` | License information | | Locking | `V$MUTEX` | Lock status | `V$
_STAT` is generated dynamically for each TAG table and is separate from the fixed list of global virtual tables. For column names and types by time and distance axis, see [Per-tag Statistics Views](/dbms/tag-table-usage/query-analysis/#tag-stat-axis-schema). ## V$VERSION Returns server version information. | Column | Description | |----------|------| | `BINARY_SIGNATURE` | Server version string | ```sql SELECT binary_signature FROM v$version; ``` ## V$DATABASES Returns the status of logical and mounted databases. `DATABASE_ID` identifies a logical catalog and differs from `TABLESPACE_ID`. | Column | Description | |------|------| | `DATABASE_ID` | Logical database identifier | | `SOURCE_DATABASE_ID` | Source database identifier of a mounted backup | | `NAME` | Database name or mount alias | | `KIND` | `ACTIVE` or `MOUNTED` | | `ACCESS_MODE` | `READ_WRITE` or `READ_ONLY` | | `CAN_USE` | Whether the database can be selected with `USE` | | `STATE` | Lifecycle state | | `IS_DEFAULT` | Whether this is the default `MACHBASEDB` | ```sql SELECT database_id, name, kind, access_mode, can_use, state, is_default FROM v$databases ORDER BY database_id; ``` ## V$DATABASE_OPERATIONS Returns status and errors for `CREATE`, `ALTER`, `DROP`, `BACKUP`, `RESTORE`, `MOUNT`, and `UMOUNT` operations. For `FAILED_NEEDS_ACTION`, also inspect the actual `V$DATABASES` state and server log. | Column | Description | |------|------| | `OPERATION_ID` | Operation identifier | | `DATABASE_ID` | Target logical database identifier | | `DATABASE_NAME` | Target database name | | `STATE` | Operation state | | `LAST_ERROR` | Failure cause | | `CREATED_AT` | Creation timestamp | | `UPDATED_AT` | Last update timestamp | ```sql SELECT operation_id, database_name, state, last_error FROM v$database_operations ORDER BY operation_id DESC; ``` ## V$SESSION Lists connected sessions and their status. | Column | Description | |----------|------| | `ID` | Session identifier | | `CLOSED` | Whether the connection is closed (0: active) | | `USER_ID` | User identifier | | `LOGIN_TIME` | Connection timestamp | | `CLIENT_TYPE` | Connected client type | | `USER_NAME` | Username | | `USER_IP` | User IP address | | `SQL_LOGGING` | Whether trace logging is enabled for the session | | `IDLE_TIMEOUT` | Idle session termination timeout in seconds | | `QUERY_TIMEOUT` | Query response timeout | ```sql -- List currently active sessions SELECT id, user_name, user_ip, client_type, login_time FROM v$session WHERE closed = 0 ORDER BY login_time; ``` ## V$STMT Displays information about SQL statements that are running or waiting. | Column | Description | |----------|------| | `ID` | Query identifier | | `SESS_ID` | Identifier of the session executing the query | | `STATE` | Query state | | `RECORD_SIZE` | SELECT result record size | | `QUERY` | Query text | ```sql -- Check running queries SELECT id, sess_id, state, query FROM v$stmt WHERE state LIKE 'Execute in progress%' OR state LIKE 'Fetch in progress%' OR state LIKE 'Append in progress%'; ``` ## V$PROPERTY Returns all server property values. | Column | Description | |----------|------| | `NAME` | Property name | | `VALUE` | Current value | | `TYPE` | Data type | | `DEFLT` | Default value | | `MIN` | Minimum value | | `MAX` | Maximum value | ```sql -- Check specific settings SELECT name, value, deflt FROM v$property WHERE name IN ('PORT_NO', 'TRACE_LOG_LEVEL', 'MAX_SESSION_COUNT'); -- Query settings that differ from defaults SELECT name, value, deflt FROM v$property WHERE value != deflt ORDER BY name; ``` ## V$STORAGE_USAGE Displays storage system disk usage. | Column | Description | |----------|------| | `TOTAL_SPACE` | Total capacity of the storage containing the data directory | | `USED_SPACE` | Used capacity | | `USED_RATIO` | Usage ratio (%) | | `RATIO_CAP` | Usage limit (ingestion stops when exceeded) | ```sql SELECT total_space, used_space, used_ratio, ratio_cap FROM v$storage_usage; ``` ## V$SYSMEM Returns system memory usage. | Column | Description | |----------|------| | `ID` | Memory manager identifier | | `NAME` | Memory manager name | | `USAGE` | Current usage | | `MAX_USAGE` | Recorded peak usage | ```sql SELECT name, usage, max_usage FROM v$sysmem ORDER BY usage DESC; ``` ## V$LICENSE_INFO Returns server license information. | Column | Description | |----------|------| | `ID` | License ID | | `ISSUE_DATE` | Issue date | | `TYPE` | License type | | `CUSTOMER` | Customer name | | `PROJECT` | Project name | | `INSTALL_DATE` | Installation date | | `VIOLATE_STATUS` | License violation status | | `VIOLATE_MSG` | License violation message | ```sql SELECT id, type, customer, issue_date, install_date, violate_status, violate_msg FROM v$license_info; ``` ## Listing All Virtual Tables ```sql -- List all V$ virtual tables available on the current server SELECT name FROM v$tables WHERE name LIKE 'V$%' ORDER BY name; ``` > Virtual tables are read-only. Tables available only in Cluster Edition, such as V$NODE_STATUS and V$REPLICATION, cannot be queried in Standard Edition. --- title: "16.3.3 V$ROLLUP Dictionary" url: https://docs.machbase.com/dbms/reference/system-catalog/vrollup/ language: en kind: page --- # 16.3.3 V$ROLLUP Dictionary `V$ROLLUP` is a virtual table that shows the current status of Tag data rollup jobs. Use it to check rollup operation and monitor execution intervals and elapsed time. ## Column Details | Column | Type | Description | |----------|------|------| | `ID` | INTEGER | Rollup job ID | | `ROLLUP_NAME` | VARCHAR | Rollup job name | | `ROLLUP_TABLE` | VARCHAR | Table that stores rollup results | | `SOURCE_TABLE` | VARCHAR | Source TAG table to aggregate | | `COLUMN_NAME` | VARCHAR | Column to aggregate | | `INTERVAL_TIME` | ULONG | Data aggregation interval in milliseconds | | `WAKEUP_INTERVAL` | ULONG | Rollup job execution interval in milliseconds | | `LAST_WAKEUP_TIME` | DATETIME | Most recent execution timestamp | | `ENABLED` | INTEGER | Whether enabled (1: enabled, 0: disabled) | | `LAST_ELAPSED_MSEC` | DOUBLE | Duration of the previous execution in milliseconds | | `RUN_STATE` | VARCHAR | Thread state (I: initializing, S: sleeping, R: running) | ## RUN_STATE Values | Value | Description | |----|------| | `I` | Initializing | | `S` | Sleeping until the next execution | | `R` | Currently running | ## SQL Examples ```sql -- Check all rollup job statuses SELECT rollup_name, rollup_table, source_table, column_name, interval_time, wakeup_interval, enabled, last_elapsed_msec, run_state FROM v$rollup ORDER BY rollup_table; -- Check the most recent execution timestamp SELECT rollup_name, rollup_table, last_wakeup_time, last_elapsed_msec, run_state FROM v$rollup; -- Check disabled rollups SELECT rollup_name, rollup_table, source_table, enabled FROM v$rollup WHERE enabled = 0; -- Check long-running rollups SELECT rollup_name, rollup_table, wakeup_interval, last_elapsed_msec, last_elapsed_msec * 100.0 / wakeup_interval AS usage_ratio FROM v$rollup WHERE last_elapsed_msec > 0 AND wakeup_interval > 0 ORDER BY last_elapsed_msec DESC; ``` ## Notes - `INTERVAL_TIME` is the data aggregation interval; `WAKEUP_INTERVAL` is the rollup job execution interval. - If `LAST_ELAPSED_MSEC` exceeds `WAKEUP_INTERVAL`, the previous execution took longer than the configured interval. Check the amount of source data and the execution interval. The example's `usage_ratio` is the previous execution duration as a percentage of the interval. - `ENABLED = 0` means the rollup is disabled. Re-enable it with `ALTER ROLLUP rollup_name START`. Set `rollup_name` to the queried `ROLLUP_NAME` value. - For rollup creation and management, see [TAG Tables and Rollup](/dbms/tag-rollup-usage/overview-use-criteria/#rollup). --- title: "16.3.4 V$STORAGE_MOUNT_DATABASES Dictionary" url: https://docs.machbase.com/dbms/reference/system-catalog/vstorage-mount/ language: en kind: page --- # 16.3.4 V$STORAGE_MOUNT_DATABASES Dictionary `V$STORAGE_MOUNT_DATABASES` lists backup databases mounted read-only on the current instance. ## Columns | Column | Type | Description | |---|---|---| | `NAME` | VARCHAR | Backup database name | | `PATH` | VARCHAR | Original backup image path | | `BACKUP_TBSID` | LONG | Backup tablespace identifier | | `BACKUP_SCN` | LONG | backup SCN | | `BACKUP_SCN` | LONG | Backup SCN | | `MOUNTDB` | VARCHAR | Database alias specified for MOUNT | | `DB_BEGIN_TIME` | VARCHAR | Start timestamp of backup data | | `DB_END_TIME` | VARCHAR | End timestamp of backup data | | `BACKUP_BEGIN_TIME` | VARCHAR | Backup operation start timestamp | | `BACKUP_END_TIME` | VARCHAR | Backup operation end timestamp | | `FLAG` | INTEGER | Internal status flags. Do not infer their meaning | ```sql SELECT NAME, PATH, MOUNTDB, DB_BEGIN_TIME, DB_END_TIME, BACKUP_BEGIN_TIME, BACKUP_END_TIME FROM V$STORAGE_MOUNT_DATABASES ORDER BY MOUNTDB; ``` ## Query ```sql MOUNT DATABASE '/data/backup/sc15_snapshot' TO backup_check; SELECT * FROM backup_check.sys.target_table LIMIT 10; UMOUNT DATABASE backup_check; ``` ## MOUNT and Query Example Operands appear in this order: backup path, `TO`, and alias. Query mounted database objects with the three-part name `mount_alias.owner.table`. For complete privileges and safety restrictions, see [BACKUP/RESTORE/MOUNT Syntax](/dbms/reference/sql/syntax/backup-restore-mount-syntax/). --- title: "16.3.5 Complete Virtual Table Reference" url: https://docs.machbase.com/dbms/reference/system-catalog/virtual-table-full/ language: en kind: page --- # 16.3.5 Complete Virtual Table Reference Virtual tables are read-only tables that expose Machbase server operational information. Their names start with `V$`. Use them to inspect server status or JOIN them with other tables to analyze operational data. INSERT, UPDATE, and DELETE are not supported. ## Contents * [Session/System](#sessionsystem) * [V$PROPERTY](#vproperty) * [V$SESSION](#vsession) * [V$SESMEM](#vsesmem) * [V$SESSTAT](#vsesstat) * [V$SESTIME](#vsestime) * [V$SYSMEM](#vsysmem) * [V$SYSSTAT](#vsysstat) * [V$SYSTIME](#vsystime) * [V$STMT](#vstmt) * [V$VERSION](#vversion) * [V$DATABASES](#vdatabases) * [V$DATABASE_OPERATIONS](#vdatabase_operations) * [V$NEO\_SESSION](#vneo_session) * [V$NEO\_STMT](#vneo_stmt) * [PVO Statement Cache](#pvo-statement-cache) * [V$PVO\_CACHE\_STAT](#vpvo_cache_stat) * [V$PVO\_CACHE\_LIST](#vpvo_cache_list) * [Storage](#storage) * [V$STORAGE](#vstorage) * [V$STORAGE\_MOUNT\_DATABASES](#vstorage_mount_databases) * [V$CACHE](#vcache) * [V$CACHE\_OBJECTS](#vcache_objects) * [V$STORAGE\_DC\_TABLESPACES](#vstorage_dc_tablespaces) * [V$STORAGE\_DC\_TABLESPACE\_DISKS](#vstorage_dc_tablespace_disks) * [V$STORAGE\_DC\_DWFILES](#vstorage_dc_dwfiles) * [V$STORAGE\_DC\_PAGECACHE](#vstorage_dc_pagecache) * [V$STORAGE\_DC\_PAGECACHE\_LRU\_LST](#vstorage_dc_pagecache_lru_lst) * [V$STORAGE\_USAGE](#vstorage_usage) * [V$STORAGE\_TABLES](#vstorage_tables) * [Log Table](#log-table) * [V$STORAGE\_DC\_TABLES](#vstorage_dc_tables) * [V$STORAGE\_DC\_TABLES\_STAT](#vstorage_dc_tables_stat) * [V$STORAGE\_DC\_TABLE\_COLUMNS](#vstorage_dc_table_columns) * [V$STORAGE\_DC\_TABLE\_COLUMN\_PARTS](#vstorage_dc_table_column_parts) * [V$STORAGE\_DC\_TABLE\_INDEXES](#vstorage_dc_table_indexes) * [LSM(Log Structured Merge) Index](#lsmlog-structured-merge-index) * [V$STORAGE\_DC\_LSMINDEX\_LEVEL\_PARTS](#vstorage_dc_lsmindex_level_parts) * [V$STORAGE\_DC\_LSMINDEX\_LEVEL\_PARTS\_CACHE](#vstorage_dc_lsmindex_level_parts_cache) * [V$STORAGE\_DC\_LSMINDEX\_LEVELS](#vstorage_dc_lsmindex_levels) * [V$STORAGE\_DC\_LSMINDEX\_FILES](#vstorage_dc_lsmindex_files) * [V$STORAGE\_DC\_LSMINDEX\_AGER\_JOBS](#vstorage_dc_lsmindex_ager_jobs) * [Volatile Table](#volatile-table) * [V$STORAGE\_DC\_VOLATILE\_TABLE](#vstorage_dc_volatile_table) * [Tag Table](#tag-table) * [V$STORAGE\_TAG\_TABLES](#vstorage_tag_tables) * [V$STORAGE\_TAG\_CACHE](#vstorage_tag_cache) * [V$STORAGE\_TAG\_CACHE\_BASE](#vstorage_tag_cache_base) * [V$STORAGE\_TAG\_CACHE\_OBJECTS](#vstorage_tag_cache_objects) * [V$STORAGE\_TAG\_TABLE\_FILES](#vstorage_tag_table_files) * [V$STORAGE\_TAG\_INDEX](#vstorage_tag_index) * [Tag Rollup](#tag-rollup) * [V$ROLLUP](#vrollup) * [License](#license) * [V$LICENSE\_INFO](#vlicense_info) * [Mutex](#mutex) * [V$MUTEX](#vmutex) * [V$MUTEX\_WAIT\_STAT](#vmutex_wait_stat) * [Cluster](#cluster) * [V$NODE\_STATUS](#vnode_status) * [V$DDL\_INFO](#vddl_info) * [V$REPLICATION](#vreplication) * [V$REPL\_SENDER](#vrepl_sender) * [V$REPL\_SENDER\_META](#vrepl_sender_meta) * [V$REPL\_RECEIVER](#vrepl_receiver) * [V$REPL\_RECEIVER\_META](#vrepl_receiver_meta) * [V$REPL\_READER](#vrepl_reader) * [V$REPL\_READER\_META](#vrepl_reader_meta) * [V$REPL\_WRITER](#vrepl_writer) * [V$REPL\_WRITER\_META](#vrepl_writer_meta) * [Others](#others) * [V$TABLES](#vtables) * [V$COLUMNS](#vcolumns) * [V$RETENTION\_JOB](#vretention_job) * [V$USER\_AUTH\_KEYS](#vuser_auth_keys) ## Session/System ### V$PROPERTY --- Displays server property settings. | Column | Description | | ----- | ------------ | |NAME|Property name| |VALUE|Property value| |TYPE|Data type| |DEFLT|Default value| |MIN|Minimum set value| |MAX|Maximum set value| ### V$SESSION --- Displays sessions connected to the Machbase server. | Column | Description | | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | |HOSTNAME (Cluster Only)|Name of the HOST which the session is connected.| |ID|Session identifier| |CLOSED|Whether connection is closed| |USER_ID|User identifier| |LOGIN_TIME|Connection time| |CLIENT_TYPE|Connected client type| |USER_NAME|User name| | CURRENT_DB_ID | Current logical database identifier for the session | | CURRENT_DB_NAME | Current database name for the session | |USER_IP|User IP address| | SQL_LOGGING | Whether to write messages to the session trace log.
Logs errors during parsing, validation, and optimization.
Logs DDL execution results.
(Includes both cases above) | |SHOW_HIDDEN_COLS|Whether hidden columns are shown upon SELECT| | FEEDBACK_APPEND_ERROR | Whether to fail immediately when an APPEND error is detected | |DEFAULT_DATE_FORMAT|Default input format upon Datetime input | |MAX_QPX_MEM|Maximum memory size available when performing query| |IDLE_TIMEOUT|Terminate the session if the client does nothing for that time after the session connected.| |QUERY_TIMEOUT|Response waiting time for query execution| | DDL_LOCK_TIMEOUT (Standard Only) | Wait for a conflicting DDL lock, in seconds. `0` returns an error immediately. | | TRANSACTION_BUSY_TIMEOUT_MS | Wait for a TRANSACTION write conflict, in milliseconds. `-1` waits indefinitely; `0` returns an error immediately. | ### V$SESMEM --- Displays session memory information. | Column | Description | | ----- | ----------- | |SID|Session identifier| |ID|Memory manager identifier| |USAGE|Usage size| ### V$SESSTAT --- Displays session statistics. | Column | Description | | ----- | --------- | |SID|Session identifier| |ID|Statistical information identifier| |VALUE|Statistical information value| ### V$SESTIME --- Displays session timing information. `ACCUM_MSEC` and `MAX_MSEC` are `DOUBLE` values in milliseconds. | Column | Description | | ---------- | -------------- | |SID|Session identifier| |ID|Performance unit identifier| | ACCUM_MSEC | Accumulated time | | MAX_MSEC | Maximum time per operation | ### V$SYSMEM --- Displays system memory information. | Column | Description | | --------- | ------------ | |ID|Memory manager identifier| |NAME|Memory manager name| |USAGE|Current usage| |MAX_USAGE|(Recorded) Maximum usage| ### V$SYSSTAT --- Displays system statistics. | Column | Description | | ----- | --------- | |ID|Statistical information identifier| |NAME|Statistical information name| |VALUE|Statistical information value| ### V$SYSTIME --- Displays system timing information. `ACCUM_MSEC`, `AVG_MSEC`, `MIN_MSEC`, and `MAX_MSEC` are `DOUBLE` values in milliseconds. | Column | Description | | ---------- | -------------- | |ID|Performance unit identifier| |NAME|Performance unit name| | ACCUM_MSEC | Accumulated time | | AVG_MSEC | Average time per operation | | MIN_MSEC | Minimum time per operation | | MAX_MSEC | Maximum time per operation | |COUNT|Performance frequency| ### V$STMT --- Displays information about queries currently running for users. | Column | Description | | ----------- | ----------------------------- | |ID|Query identifier| |SESS_ID|Performed query session identifier| |STATE|Query status| |RECORD_SIZE|Resulting record size of select statements| |QUERY|Query statement| ### V$VERSION --- Displays Machbase version information. | Column | Description | | ------------------------- | ---------------------------------------- | |BINARY_DB_MAJOR_VERSION|Database major version| |BINARY_DB_MINOR_VERSION|Database minor version| |BINARY_META_MAJOR_VERSION|META major version| |BINARY_META_MINOR_VERSION|META minor version| |BINARY_CM_MAJOR_VERSION|Client (Communication Level) major version| |BINARY_CM_MINOR_VERSION|Client (Communication Level) minor version| | BINARY_SIGNATURE | Version name of the database server binary | |FILE_DB_MAJOR_VERSION|File DB major version| |FILE_DB_MINOR_VERSION|File DB minor version| |FILE_META_MAJOR_VERSION|File META major version| |FILE_META_MINOR_VERSION|File META minor version| |FILE_CM_MAJOR_VERSION|File Client (Communication Level) major version| |FILE_CM_MINOR_VERSION|File Client (Communication Level) minor version| |FILE_CREATE_TIME|File creation time| |EDITION|Machbase type| ### V$DATABASES --- Displays the status of logical active databases and mounted databases. `DATABASE_ID` is a logical catalog identifier and differs from the physical `TABLESPACE_ID`. | Column | Description | |-----------|------| | DATABASE_ID | Logical database identifier | | SOURCE_DATABASE_ID | Source database identifier of a mounted backup | | NAME | Database name or mount alias | | KIND | `ACTIVE` or `MOUNTED` | | ACCESS_MODE | `READ_WRITE` or `READ_ONLY` | | CAN_USE | Whether the database can be selected with `USE` | | STATE | Lifecycle state | | IS_DEFAULT | Whether this is the default `MACHBASEDB` | ```sql SELECT database_id, name, kind, access_mode, can_use, state, is_default FROM v$databases ORDER BY database_id; ``` ### V$DATABASE_OPERATIONS --- Displays database lifecycle operation status and errors. | Column | Description | |-----------|------| | OPERATION_ID | Operation identifier | | DATABASE_ID | Target logical database identifier | | DATABASE_NAME | Target database name | | STATE | Operation state | | LAST_ERROR | Failure cause | | CREATED_AT | Creation timestamp | | UPDATED_AT | Last update timestamp | ```sql SELECT operation_id, database_name, state, last_error FROM v$database_operations ORDER BY operation_id DESC; ``` ### V$NEO_SESSION --- Displays session status for Neo protocol clients. | Column | Description | | -- | -- | |ID|Session identifier| |USER_ID|User identifier| |USER_NAME|User name| |STMT_COUNT|Statement count in the session| |DISCONN_FLAG|Disconnect flag| ### V$NEO_STMT --- Displays statement status for Neo protocol clients. | Column | Description | | -- | -- | |ID|Statement identifier| |SESS_ID|Session identifier| |STATE|Statement state| |QUERY|Statement text| |APPEND_SUCCESS_CNT|Append success count| |APPEND_FAILURE_CNT|Append failure count| ## PVO Statement Cache Displays global PVO Statement Cache status, available only in Standard Edition. ### V$PVO_CACHE_STAT --- Displays overall PVO Statement Cache statistics. | Column | Description | | -- | -- | |CACHE_ENTRY_COUNT|Number of SQL entries stored in cache| |CACHE_HANDLE_COUNT|Total cached plans (handles) across SQLs| |CACHE_MEMORY_USAGE|Current cache memory usage| |CACHE_MAX_MEMORY_SIZE|Configured cache memory limit| |CACHE_MAX_PLANS_PER_SQL|Maximum plans allowed per SQL| |CACHE_MAX_SQL_ENTRIES|Maximum SQL entries allowed (0 = unlimited)| |CACHE_SHARD_COUNT|Number of cache shards| |CACHE_HIT|Cache hit count| |CACHE_MISS|Cache miss count| |SINGLEFLIGHT_WAIT|Wait count for concurrent same-SQL build| |BUILD_COUNT|Plan build attempts| |BUILD_FAIL|Plan build failures| |INVALIDATE_COUNT|Invalidated plans| |EVICT_COUNT|Evictions due to limits| |FLUSH_COUNT|Explicit or internal flush count| ### V$PVO_CACHE_LIST --- Displays details for each SQL statement stored in PVO Statement Cache. | Column | Description | | -- | -- | |TOUCH_TIME|Last touch time| |USER_ID|Owner user identifier| |QUERY|Original SQL text| | DEFAULT_DATE_FORMAT | Date format at execution time | | TIMEZONE_OFFSET | Timezone offset at execution time | |SHOW_HIDDEN_COLS|Whether hidden columns are shown| |QUERY_PARALLEL_FACTOR|Parallel execution factor| |HANDLE_COUNT|Number of cached plans| |BUSY_COUNT|Number of handles currently in use| |HIT_COUNT|Cache hit count| |BUILD_IN_PROGRESS|Whether a build is in progress| ## Storage ### V$STORAGE --- Displays storage system internals. | Column | Description | | ------------------------- | ------------------------------------ | |DC_TABLE_FILE_SIZE|Total capacity of disk column data| |DC_INDEX_FILE_SIZE|Total capacity of index file data| |DC_TABLESPACE_DWFILE_SIZE|Total capacity of DWFILE for all column data| | DC_KV_TABLE_FILE_SIZE | Total data file size of TAGDATA partition tables | ### V$STORAGE_MOUNT_DATABASES --- Displays backup databases mounted with the mount feature. | Column | Description | | ----------------- | ---------------------- | |NAME|Mounted database name| |PATH|Backup file location| |BACKUP_TBSID|Backup database tablespace identifier| |BACKUP_SCN|Backup database identifier| | MOUNTDB | Database alias specified when mounting | |DB_BEGIN_TIME|Backup database first entry time| |DB_END_TIME|Backup database last entry time| |BACKUP_BEGIN_TIME|Backup begin time| |BACKUP_END_TIME|Backup end time| |FLAG|Property flag| ### V$CACHE --- Displays aggregate information about objects that cache results read by the Storage Manager. | Column | Description | | --------- | ---------------- | |OBJ_COUNT|Current number of result set cache objects| ### V$CACHE_OBJECTS --- Displays each object that caches results read from the storage system. | Column | Description | | --------- | -------------- | |OID|Object identifier| |REF_COUNT|Reference count| |FLAG|(Internal server use flag)| ### V$STORAGE_DC_TABLESPACES --- Displays storage system tablespace information. | Column | Description | | ---------- | ---------------------------- | |NAME|Tablespace name| |ID|Tablespace identifier| |FLAG|Flag indicating tablespace property| |REF_COUNT|Tablespace reference count| |DISK_COUNT|Tablespace disk count| ### V$STORAGE_DC_TABLESPACE_DISKS --- Displays storage system tablespace information. | Column | Description | | ------------------ | ------------------- | |NAME|Disk name| |ID|Disk identifier| |TABLESPACE_ID|Disk tablespace identifier| |PATH|Disk path| |IO_THREAD_COUNT|I/O Thread count| |IO_JOB_COUNT|I/O Job count| |VIRTUAL_DISK_COUNT|Virtual disk count| ### V$STORAGE_DC_DWFILES --- Displays doublewrite (DW) files managed by the storage system. | Column | Description | | -------------------- | ----------------------- | |TBS_ID|Tablespace identifier| |DISK_ID|Disk identifier| |FILE|File path| |TABLE_ID|Table identifier| |COLUMN_ID|Column identifier| |PARTITION_ID|Partition identifier| |PAGE_ID|Page identifier| |DISK_OFFSET|Disk offset| |DISK_IMAGE_SIZE|Disk image size| |HEAD_CRC32CODE_IMAGE|Head CRC32 Code Image| |TAIL_CRC32CODE_IMAGE|Tail CRC32 Code Image| |CRC32CODE_PAGE|CRC32 Code Page| |HEAD_TIMESTAMP_PAGE|Head Timestamp Page| |TAIL_TIMESTAMP_PAGE|Tail Timestamp Page| ### V$STORAGE_DC_PAGECACHE --- Displays the page cache managed by the storage system. | Column | Description | | ------------ | ---------------------- | |MAX_MEM_SIZE|Maximum memory size of Page Cache| |CUR_MEM_SIZE|Current memory size of Page Cache| |PAGE_CNT|Number of cached pages| |CHECK_TIME|Check time| ### V$STORAGE_DC_PAGECACHE_LRU_LST --- Displays the LRU list of the page cache managed by the storage system. | Column | Description | | ------------ | ------------------- | |SIZE|Page size| |REF_CNT|Reference count| |PARTITION_ID|Partition identifier| |OFFSET|Page Cache Offset| |OBJECT_ID|Object identifier| |LEVEL|Partition level| ### V$STORAGE_USAGE --- Displays storage usage. | Column | Description | | ----------- | ------------------------------------------------------ | |TOTAL_SPACE|Total storage capacity where the $MACHBASE_HOME/dbs directory is located| |USED_SPACE|Total storage usage where the $MACHBASE_HOME/dbs directory is located| |USED_RATIO|Percentage of usage(%)| |RATIO_CAP|Storage usage limit. Data input/index construction stops when USED_RATIO reaches this limit.| ### V$STORAGE_TABLES --- Displays table details. | Column | Description | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |ID|Table ID| | TYPE | Table type
Persistent: LOG and TAG tables
Volatile: Volatile tables
Key-Value: Auxiliary tables of TAG tables | |STATUS|Current Status
- Creating...: Creating table by CREATE TABLE query
- Normal: normal
- Predrop: DROP TABLE query accepted
- Dropping...: DROP TABLE query processing
- Dropped: DROP TABLE query completed
- Mounted: The backed up database loaded with the MOUNT query| |STORAGE_USAGE|Capacity occupied by the table in storage| ## Log Table ### V$STORAGE_DC_TABLES --- Displays Log table internals. | Column | Description | | -------------------- | ------------------------------------------ | |ID|Table identifier| | TABLESPACE_ID | Tablespace identifier | |CREATE_SCN|System Change Number at time of creation| |UPDATE_SCN|System Change Number at time of most recent update| |DDL_REF_COUNT|Number of sessions referencing table in DDL syntax execution| |BEGIN_RID|Minimum table RID| |END_RID|Last row ID of table + 1| |BEGIN_META_RID|ID at start of recording meta information| |END_META_RID|ID at end of recording meta information| |END_SYNC_RID|Last row ID recorded on disk + 1| |FLAG|Flag indicating table property| |COLUMN_COUNT|Table column count| |INDEX_COUNT|Table index count| |INDEX_MIN_END_RID|Last RID recorded in index + 1| |LAST_ARRIVAL_TIME|Last recorded _arrival_time value| |LAST_CHECKPOINT_TIME|Last checkpoint time| |TYPE|Table type| ### V$STORAGE_DC_TABLES_STAT --- Displays Log table internals. | Column | Description | | ------------- | ----------- | |TABLESPACE_ID|Tablespace identifier| |TABLE_ID|Table identifier| |COUNT|Record count| |COLUMN_ID|Column identifier| ### V$STORAGE_DC_TABLE_COLUMNS --- Displays Log table column information. | Column | Description | | ------------------------- | ------------------------------- | |TABLE_ID|Table identifier| | TABLESPACE_ID | Tablespace identifier | |ID|Column identifier| |FLAG|Property flag| |SIZE|Column data size| |PARTITION_VALUE_COUNT|Maximum number of data stored in partition| |PAGE_VALUE_COUNT|Maximum number of data stored in page| |CACHE_VALUE_COUNT|Maximum number of cache values| |MINMAX_CACHE_SIZE|Maximum size of MIN / MAX cache for column partitions| |CUR_APPEND_PARTITION_ID|Current partition in progress of input identifier| |CUR_CACHE_PARTITION_COUNT|Number of partitions that have read data in current cache| |CUR_MINMAX_CACHE_SIZE|Current Min / MAX cache size| | END_RID_FOR_DEFAULT_VALUE | Column values with RIDs below this value use the default value | |DISK_FILE_SIZE|Total size of column partition data file for that column| |MEMORY_TOTAL_SIZE|Memory size used by table| |MEMORY_ALLOC_SIZE|Memory size allocated by table| ### V$STORAGE_DC_TABLE_COLUMN_PARTS --- Displays Log table column partition information. | Column | Description | | ----------------------------- | ---------------------------------------------------------------------------------- | |TABLE_ID|Table identifier| | TABLESPACE_ID | Tablespace identifier | |COLUMN_ID|Column identifier| |ID|Partition identifier| |FLAG|Flag indicating column property| |BEGIN_RID|First RID stored in partition| |END_RID|Last RID stored in partition| |END_SYNC_RID|Last RID SYNC ended.

Data with a RID greater than the starting RID and less than the last SYNC RID is recorded in the partition file.| |MIN_TIME|First time data was entered into column partition| |MAX_TIME|Last time data was entered into column partition| |MAX_VALUE_COUNT_PER_PARTITION|Maximum partition data count| |MAX_VALUE_COUNT_PER_PAGE|Maximum page data count| |MAX_PAGE_COUNT|Maximum partition page count| |PAGE_SIZE|Page size stored in column partition| |PAGE_COUNT|Page count created in current column partition| |COMPRESS_RATIO|Column partition compression ratio. If it is 0, data compression has not been performed yet.| |DISK_FILENAME|Partition file name| |EXTERNAL_PART_SIZE|A large amount of data is written to the external partition file, indicating the size of the file| |MIN_VALUE|Minimum column partition value| |MAX_VALUE|Maximum column partition value| ### V$STORAGE_DC_TABLE_INDEXES --- Displays indexes created on Log tables. | Column | Description | | -------------------- | ---------------------------- | |TABLE_ID|Table identifier| | TABLESPACE_ID | Tablespace identifier | |ID|Index identifier| |FLAG|Flag indicating index property| |TABLE_BEGIN_RID|First RID entered into table| |TABLE_END_RID|Last table RID| |BEGIN_RID|First index RID| |END_RID|Last index RID| |END_SYNC_RID|Last recorded RID in file + 1| |COLUMN_COUNT|Index column count| |BEGIN_PART_ID|Index first partition identifier| |END_PART_ID|Index last partition identifier| |FLUSH_REQUEST_COUNT|Number of index partitions requested to reflect on disk| |MAX_KEY_SIZE|Maximum key size| |INDEX_TYPE|Index type| |DISK_FILE_SIZE|Total size of index partition file for that index| |LAST_CHECKPOINT_TIME|Last checkpoint time| ## LSM(Log Structured Merge) Index ### V$STORAGE_DC_LSMINDEX_LEVEL_PARTS --- Displays LSM index partition information. | Column | Description | | -------------------------- | --------------------------------------- | |TABLE ID|Index table identifier| |TABLESPACE_ID|Tablespace identifier| |INDEX_ID|Index identifier| |LEVEL|Index partition LSM level| |PARTITION_ID|Partition identifier| |BEGIN_RID|First RID entered into partition| |END_RID|Last RID entered into partition + 1| |KEY_VALUE_COUNT|Key value count entered into partition| |KEY_VALUE_TABLE_SIZE|Size of page storing key value| |KEY_VALUE_TABLE_PAGE_COUNT|Number of pages storing key value| |MIN_KEY_VALUE|Minimum key value| |MAX_KEY_VALUE|Maximum key value| |BITMAP_TABLE_SIZE|Total size of page storing bitmap value| |BITMAP_TABLE_PAGE_COUNT|Number of pages storing bitmap value| |META_SIZE|Total size of page storing meta information| |META_PAGE_COUNT|Number of pages storing meta information| |TOTAL_BUILD_MSEC|Total time to complete partition| |KEYVAL_BUILD_MSEC|Total time to complete partition for KeyValue Mode| |BITMAP_BUILD_MSEC|Total time to complete partition for Bitmap Mode| ### V$STORAGE_DC_LSMINDEX_LEVEL_PARTS_CACHE --- Displays LSM index partition cache information. | Column | Description | | -------------------------- | --------------------------- | |BEGIN_RID|First RID entered into partition| |BITMAP_TABLE_PAGE_COUNT|Number of pages storing bitmap value| |BITMAP_TABLE_SIZE|Total size of page storing bitmap value| |END_RID|Last RID entered into partition + 1| |INDEX_ID|Index identifier| |KEY_VALUE_COUNT|Number of key values entered into partition| |KEY_VALUE_TABLE_PAGE_COUNT|Number of pages storing key value| |KEY_VALUE_TABLE_SIZE|Size of page storing key value| |LEVEL|Index partition LSM level| |MEMORY_SIZE|Memory usage| |MEMORY_SIZE_RBTREE|Redblack Tree memory usage| |META_PAGE_COUNT|Number of pages storing meta information| |META_SIZE|Total size of page storing meta information| |PARTITION_ID|Partition identifier| |TABLE_ID|Index Table identifier| |TABLESPACE_ID|Tablespace identifier| ### V$STORAGE_DC_LSMINDEX_LEVELS --- Displays LSM index level information. | Column | Description | | -------------- | ---------------------- | | TABLE_ID | Table identifier | | TABLESPACE_ID | Tablespace identifier | |INDEX_ID|Index identifier| |LEVEL|Level| |BEGIN_RID|First partition RID| |END_RID|Last partition RID + 1| |META_BEGIN_RID|RID at start time of recording meta information| |META_END_RID|RID at end time of recording meta information| |DELETE_END_RID|Maximum deleted RID + 1| ### V$STORAGE_DC_LSMINDEX_FILES --- Displays files that make up LSM indexes. | Column | Description | | ------------ | --------------- | |TABLE_ID|Table identifier| | TABLESPACE_ID | Tablespace identifier | |INDEX_ID|Index identifier| |LEVEL|Index partition LSM level| |PARTITION_ID|Partition identifier| |BEGIN_RID|Partition first RID| |END_RID|Partition last RID + 1| |PATH|Index file location| ### V$STORAGE_DC_LSMINDEX_AGER_JOBS --- Displays job status for the ager responsible for LSM index deletion. | Column | Description | | --------- | ------------------ | |TABLE_ID|Table identifier| |INDEX_ID|Index identifier| |LEVEL|Index partition LSM level| |BEGIN_RID|First partition RID| |END_RID|Last partition RID + 1| |STATE|Index Ager working status| ## Volatile Table ### V$STORAGE_DC_VOLATILE_TABLE --- Displays Volatile table information. | Column | Description | | ------------ | --------------------------- | |MAX_MEM_SIZE|Maximum Volatile Tablespace size| |CUR_MEM_SIZE|Current Volatile Tablespace size| ## Tag Table ### V$STORAGE_TAG_TABLES --- Displays partition tables of Tagdata tables. | Column | Description | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |ID|Table identifier| |TABLE_BEGIN_RID|Table start RID| |TABLE_END_RID|Table end RID| |WRITE_END_RID|Last RID which is written to data file.| |EXT_ROW_COUNT|Number of entries to external partitions in VARCHAR records| |EXT_WRITE_COUNT|Number of entries to data files in VARCHAR records| |DISK_INDEX_END_RID|Index end RID stored in storage| |MEMORY_INDEX_END_RID|Table end RID in memory index| |DELETE_MIN_DATE|Minimum time of deleted data by execute DELETE BETWEEN query| |DELETE_MAX_DATE|Maximum time of deleted data by execute DELETE BETWEEN/BEFORE query| |INDEX_STATE|Current Index Build State
- IDLE: Build Complete, waiting
- PROGRESS: Build in progress
- IOWAIT: Waiting for I/O operation in storage
- PENDING: Waiting for table read lock
- SHUTDOWN: Stopped. DELETE operation or DROP operation in progress.
- ABNORMAL: Abnormal end| | DELETE_STATE | Current DELETE operation state. There is no IDLE state because this runs only when a DELETE command is received.
PROGRESS: Deletion in progress
IOWAIT: Waiting for storage I/O
PENDING: Waiting for a table read/write lock
SHUTDOWN: Stopped; no DELETE operation is running
ABNORMAL: Abnormal termination | |SAVE_STATE|Current Table Save operation state.
- IDLE: Save Complete, waiting
- PROGRESS: Save in progress
- IOWAIT: Waiting for I/O operation in storage
- PENDING: Waiting for table read lock
- SHUTDOWN: Stopped. DELETE operation or DROP operation in progress.
- ABNORMAL: Abnormal end| |VINDEX_STATE|Current VARCHAR Index Build State
- IDLE: Build Complete, waiting
- PROGRESS: Build in progress
- IOWAIT: Waiting for I/O operation in storage
- PENDING: Waiting for table read lock
- SHUTDOWN: Stopped. DELETE operation or DROP operation in progress.
- ABNORMAL: Abnormal end| ### V$STORAGE_TAG_CACHE --- Displays the cache used by Tagdata partition tables. | Column | Description | | ----------- | ------------------------ | | POOL_ID | Cache pool identifier | |CATEGORY|Type of object in cache| |USED_MEMORY|Size of memory in use| |BLOCK_COUNT|Data cache count| |CACHE_HIT|Data cache hit count| |CACHE_MISS|Data cache miss count| | FLUSHOUT | Pages flushed out because of data cache conflicts | | COLD_READ | Data pages read directly from storage | | MEMORY_WAIT | Times data memory waited because of cache conflicts | |IO_WAIT|Data read operation wait count| ### V$STORAGE_TAG_CACHE_BASE --- Displays aggregate tag cache pool information. | Column | Description | | -- | -- | |POOL_ID|Cache pool identifier| |TOTAL_CACHE_MEMORY|Total cache memory| |TOTAL_OBJECT_COUNT|Total cached object count| |TOTAL_LRU_LOOP_COUNT|Total LRU loop count| ### V$STORAGE_TAG_CACHE_OBJECTS --- Displays details for each cache block used by Tagdata partition tables. | Column | Description | | ---------- | -------------------------------------------------------------------------------------------------------------------- | |CATEGORY|Object classification being cached| | LATEST_HIT | Last access timestamp | |STATUS|Cache status
- None: Memory allocation done
- Resides: Already stored in cache
- Loading: Loading table data from storage
- ERROR!: Error appears while loading data| |WAIT_COUNT|The number of waiting times because the cache could not be read in the Loading state| |REF_COUNT|Number of sessions currently referencing the cache block| |HIT_COUNT|Number of times a cache block was referenced| |TABLE_ID|Table Identifier| |FILE_ID|File Identifier| |PART_ID|Partition identifier inside the datafile| |SAVE_SCN|SCN of table save| |VSAVE_SCN|SCN of table save| |DELETE_SCN|SCN of delete operation| |OFFSET|Datafile offset| |DATA_SIZE|Data size before compression, or 0| ### V$STORAGE_TAG_TABLE_FILES --- Displays files of Tagdata partition tables. | Column | Description | | --------- | ---------------------------------------------------------------------------------------------------------------------------------- | |TABLE_ID|Table identifier| |FILE_ID|File identifier| |STATE|Index status
- COMPLETE: Data stored, index build complete
- INDEXING: Index build in progress
- FILLED: Data is full, waiting for Index build
- PARTIAL: Data not yet full, waiting for Index build| |REF_COUNT|Number of sessions currently referencing the file| |ROW_COUNT|Number of records stored in the file, including those that were deleted| |DEL_COUNT|Number of records deleted from the file| |MIN_DATE|Minimum datetime value of this data file.| |MAX_DATE|Maximum datetime value of this data file.| ### V$STORAGE_TAG_INDEX --- Displays indexes created on Tagdata tables. | Column | Description | | -------------------- | ----------------------------------------------------------------------------------------------------- | |TABLE_ID|Table identifier| |INDEX_ID|Index identifier (if INDEX_ID is 4294967295 it is a default index that is created automatically when the tag table is created.)| |INDEX_STATE|Current index build state
- IDLE: Build Complete, waiting
- INDEXING: Build in progress
- STORAGE FULL: Stopped because of disk full| |DISK_INDEX_END_RID|Index end RID stored in storage| | MEMORY_INDEX_END_RID | End RID of the index most recently applied to memory | |TABLE_END_RID|Table end RID| ## Tag Rollup ### V$ROLLUP --- Displays rollup information for Tagdata tables. | Column | Description | | -------------- | ------------------------------------------------------- | | DATABASE_ID | Logical database identifier | |ID|Rollup job ID| |ROLLUP_TABLE|Name of the rollup table| |SOURCE_TABLE|Source table name (TAG/ROLLUP)| |COLUMN_NAME|Target value column aggregated by this rollup| |ROOT_TABLE|Root source tag table name| |USER_ID|Owner user ID| | INTERVAL_TIME | Data aggregation interval in milliseconds | | WAKEUP_INTERVAL | Rollup job execution interval in milliseconds | |LAST_WAKEUP_TIME|Last time the rollup thread woke up| |NEXT_WAKEUP_TIME|Next scheduled wakeup time| |ENABLED|Whether the rollup is enabled (1/0)| |END_RID|Source table end RID processed by this rollup| |LAST_ELAPSED_MSEC|Elapsed time of the last rollup run (msec)| | EXT_TYPE | EXTENSION flag | |PREDICATE|Filter predicate for conditional rollups (NULL if none)| |RUN_STATE|Current worker state: I=INIT, S=SLEEPING, R=RUNNING| ## License ### V$LICENSE_INFO --- Displays license information. | Column | Description | | ---------------- | ---------------------- | |ID|License ID| |ISSUE_DATE|Issue date| |TYPE|License type| |CUSTOMER|Customer name| |PROJECT|Project name| |COUNTRY_CODE|Country code| |INSTALL_DATE|Installation date| |VIOLATE_STATUS|License violation status| |VIOLATE_MSG|License violation message| `V$LICENSE_STATUS` is not exposed by Standard 8.5.4 servers. Use `V$LICENSE_INFO` for license fields available in Standard Edition. ## Mutex ### V$MUTEX --- Displays current mutex status. `WAIT_MSEC`, `WAIT_AVG_MSEC`, `HELD_MSEC`, and `HELD_AVG_MSEC` are `DOUBLE` values in milliseconds. | Column | Description | Notes | | -------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------- | |OBJECT|Address of the mutex object| | |NAME|The name given when creating the mutex| | |TYPE|Mutex type| - Mutex: pmuMutex
- RW Mutex: pmuRWMutex| |OWNER|ID of the thread that acquired the mutex| - Mutex: 0 if no thread acquired the mutex.
- RW Mutex w/ Read-Lock: 0
- RW Mutex w/ Write-Lock: ID of the thread that acquired the write lock.| |LOCK_COUNT|Number of threads that acquired the mutex| - RW Mutex can be 2 or more.| |PEND_COUNT|Number of threads waiting to acquire a mutex| - Collect only when TRACE_MUTEX_WAIT_STATUS=1| |TRY_COUNT|Number of attempts to acquire the mutex| - Collect only when TRACE_MUTEX_WAIT_STATUS=1| |CONFLICT_COUNT|Number of failed to acquire mutex| - Collect only when TRACE_MUTEX_WAIT_STATUS=1| | WAIT_MSEC | Total time waiting to acquire the mutex | Collected only when TRACE_MUTEX_WAIT_STATUS=1
Not recorded for RW mutexes | | WAIT_AVG_MSEC | Average time from an acquisition attempt to success | Collected only when TRACE_MUTEX_WAIT_STATUS=1
Not recorded for RW mutexes | | HELD_MSEC | Total time from acquisition to release | Collected only when TRACE_MUTEX_WAIT_STATUS=1
Not recorded for RW mutexes | | HELD_AVG_MSEC | Average time from acquisition to release | Collected only when TRACE_MUTEX_WAIT_STATUS=1
Not recorded for RW mutexes | ### V$MUTEX_WAIT_STAT --- Displays call stacks currently waiting for mutexes. | Column | Description | Notes | | --------- | ------------------- | -------------------------------- | |THREAD_ID|ID of the thread waiting to acquire the mutex| | |OBJECT|Address of the mutex being acquired| - Same as OBJECT in V$MUTEX| | DEPTH | Call stack depth | Collected only when TRACE_MUTEX_WAIT_STACK=1 | | SYMBOL | Symbol of the function that requested mutex acquisition | Collected only when TRACE_MUTEX_WAIT_STACK=1 | ## Cluster The following virtual tables are exclusive to Cluster Edition and are not exposed on Standard servers. Before using them, check `V$TABLES` to confirm availability in the running edition. ### V$NODE_STATUS --- Displays the status of a cluster node. Returns one row. | Column | Description | | -------- | ------------------------------------------------------------- | |NODETYPE|Node type. There are two types that can be viewed by queries.
- Broker
- Warehouse| |STATE|Node status| ### V$DDL_INFO --- Displays DDL operations executed in the cluster. | Column | Description | | -------------- | ----------------------- | |SEQUENCENUMBER|DDL sequence number| |TIME|DDL execution time| |VALUE|DDL query result value (Internal server use)| |CLIENT|Client name| |BROKER|Lead Broker Node name| |USER|User name| |SQL|DDL query value| ### V$REPLICATION --- Displays replication operation information. | Column | Description | | ---------------- | ---------------------------------- | |HOSTNAME|Replication Node Hostname| |MODE|(Internal server use)| |STATE|Node status| |ADDR|Replication Manager address| |PORT_NO|Replication Manager port number| |MAX_SENDER_COUNT|Maximum number of Senders that can be created| |RUN_SENDER_COUNT|Maximum number of active Senders| ### V$REPL_SENDER --- Displays sender information during replication. | Column | Description | | ------------------ | ---------------------------------- | |HOSTNAME|Replication Node Hostname| |ID|Sender identifier| |STATUS|Sender operational status| |PAYLOAD_RECV_COUNT|Number of payloads received from sender| |PAYLOAD_RECV_BYTES|Total payload size received from Sender| |QUEUE_REMAIN_COUNT|Number of buffers remaining in the Receive Queue| |NET_SEND_COUNT|Net send count| |NET_SEND_SIZE|Net send size| |NET_RECV_COUNT|Net receive count| |NET_RECV_SIZE|Net receive size| ### V$REPL_SENDER_META --- Displays sender metadata during replication. | Column | Description | | ---------- | ---------------------------------- | |HOSTNAME|Replication Node Hostname| |SENDER_ID|Sender identifier| |TABLE_ID|Target table identifier| |TABLE_TYPE|Target table type| |BEGIN_RID|Target record start RID| |END_RID|Target record end RID| ### V$REPL_RECEIVER --- Displays receiver information during replication. | Column | Description | | ------------------ | ---------------------------------- | |HOSTNAME|Replication Node Hostname| |STATUS|Receiver operational status| |PAYLOAD_RECV_COUNT|Number of payloads received from sender| |PAYLOAD_RECV_BYTES|Total payload size received from Sender| |QUEUE_REMAIN_COUNT|Number of buffers remaining in the Receive Queue| |NET_SEND_COUNT|Net send count| |NET_SEND_SIZE|Net send size| |NET_RECV_COUNT|Net receive count| |NET_RECV_SIZE|Net receive size| ### V$REPL_RECEIVER_META --- Displays receiver metadata during replication. | Column | Description | | ---------- | ---------------------------------- | |HOSTNAME|Replication Node Hostname| |TABLE_ID|Target table identifier| |TABLE_TYPE|Target table type| |BEGIN_RID|Target record start RID| |END_RID|Target record end RID| ### V$REPL_READER --- Displays reader information during replication. | Column | Description | | ----------- | ---------------------------------- | |HOSTNAME|Replication Node Hostname| |SENDER_ID|Sender identifier| |ID|Reader identifier| |STATUS|Reader operation status| |FETCH_COUNT|FETCH count| ### V$REPL_READER_META --- Displays reader metadata during replication. | Column | Description | | ---------- | ---------------------------------- | |HOSTNAME|Replication Node Hostname| |SENDER_ID|Sender identifier| |ID|Reader identifier| |TABLE_ID|Target table identifier| |TABLE_TYPE|Target table type| |BEGIN_RID|Target record start RID| |END_RID|Target record end RID| ### V$REPL_WRITER --- Displays writer information during replication. | Column | Description | | ------------ | ---------------------------------- | |HOSTNAME|Replication Node Hostname| |ID|Writer identifier| |STATUS|Writer operational status| |APPEND_COUNT|APPEND count| ### V$REPL_WRITER_META --- Displays writer metadata during replication. | Column | Description | | ---------- | ---------------------------------- | |HOSTNAME|Replication Node Hostname| |ID|Writer identifier| |TABLE_ID|Target table identifier| |TABLE_TYPE|Target table type| |BEGIN_RID|Target record start RID| |END_RID|Target record end RID| ## Others ### V$TABLES --- Lists all virtual tables with names starting with V$. | Column | Description | | ----------- | ------------ | |NAME|Table name| |TYPE|Table type| |DATABASE_ID|Database identifier| |ID|Table identifier| |USER_ID|User who created table| |COLCOUNT|Column count| ### V$COLUMNS --- Displays virtual table column information. | Column | Description | | -------------------- | ---------- | |NAME|Column name| |TYPE|Column data type| |DATABASE_ID|Database identifier| |ID|Column identifier| |LENGTH|Column size| |TABLE_ID|Table identifier| |FLAG|Private data| |PART_PAGE_COUNT|Unused| |PAGE_VALUE_COUNT|Unused| |MINMAX_CACHE_SIZE|Unused| |MAX_CACHE_PART_COUNT|Unused| ### V$RETENTION_JOB --- Displays tables with a RETENTION POLICY applied. | Column | Description | |-------------------|------------------------------------------| | USER_NAME | User name | | TABLE_NAME | applied table name | | POLICY_NAME | applied policy name | | STATE | RETENTION state (RUNNING/WAITING/STOPPED) | | LAST_DELETED_TIME | most recently deleted time | ### V$USER_AUTH_KEYS --- Displays public keys registered for challenge authentication. | Column | Description | | -- | -- | |KEY_ID|Key identifier| |USER_ID|User identifier| |USER_NAME|User name| |KEY_ALGO|Key algorithm| |KEY_PARAM|Key parameter| |PUBKEY|Public key text| |ACTIVATED|Whether the key is active| |VALID_AFTER|Start date of key validity| |VALID_BEFORE|End date of key validity| |COMMENT|Key comment| --- title: "16.4 Command-Line Tool Reference" url: https://docs.machbase.com/dbms/reference/command-line-tools/ language: en kind: section --- # 16.4 Command-Line Tool Reference Machbase provides command-line tools for server administration, data import/export, and query execution. This section is a quick reference to their options and usage. ## Tools | Tool | Edition | Description | |------|--------|------| | [machadmin](./machadmin/) | Standard / Cluster | Server startup/shutdown, database creation/deletion, and license management | | [machsql](./machsql/) | Standard / Cluster | Interactive SQL terminal | | [machloader](./machloader/) | Standard / Cluster | Import/export of CSV and other text files | | [csvimport / csvexport](./csvimport-csvexport/) | Standard / Cluster | Simple CSV import/export wrappers | | [tagmetaimport](./tagmetaimport/) | Standard / Cluster | Bulk TAG table metadata import | | [machclusterctl](./machclusterctl/) | Cluster | Cluster-wide startup, shutdown, and management | | [machcoordinatoradmin](./machcoordinatoradmin/) | Cluster | Coordinator node management and cluster configuration | | [machdeployeradmin](./machdeployeradmin/) | Cluster | Deployer node management | ## Common Connection Options The following connection options apply to `machsql`. Option names and defaults vary by tool; check the tool's option dictionary or `--help` output before using another tool. In particular, distinguish `machadmin` server administration options from SQL client connection options. | Option | Default | Description | |------|--------|------| | `-s`, `--server` | 127.0.0.1 | Server IP address | | `-P`, `--port` | 5656 | Server port | | `-u`, `--user` | SYS | Username | | `-p`, `--password` | MANAGER | User password | ## Tool Location Tools included in the installation package are in `$MACHBASE_HOME/bin/`. Availability depends on the installed edition and package. ```bash ls $MACHBASE_HOME/bin/ # machadmin machsql machloader csvimport csvexport tagmetaimport ... ``` If `$MACHBASE_HOME/bin` is in PATH, run each tool by name. ```bash export PATH=$MACHBASE_HOME/bin:$PATH machadmin -e ``` --- title: "16.4.1 machadmin" url: https://docs.machbase.com/dbms/reference/command-line-tools/machadmin/ language: en kind: page --- # 16.4.1 machadmin `machadmin` starts and stops the Machbase server, creates and deletes databases, and checks server status. ## Options ```bash machadmin -h ``` | Option | Description | |------|------| | `-u`, `--startup` | Start the Machbase server | | `--recovery[=simple,complex,reset]` | Set the startup recovery mode (default: simple) | | `-s`, `--shutdown` | Shut down the Machbase server gracefully | | `-k`, `--kill` | Force the Machbase server to stop | | `-c`, `--createdb` | Create the Machbase database | | `-d`, `--destroydb` | Delete the Machbase database | | `-e`, `--check` | Check whether the server is running | | `-i`, `--silent` | Run without a banner | | `-r`, `--restore` | Restore the database from a backup | | `-x`, `--extract` | Convert a backup file to a backup directory | | `-w`, `--viewimage` | Display backup image file information | | `-t`, `--licinstall` | Install a license file | | `-f`, `--licinfo` | Display installed license information | | `--home-path=path` | Set the Machbase home path | ## Starting the Server ```bash machadmin -u ``` ### Specifying a Recovery Mode ```bash machadmin -u --recovery=simple # Default recovery after a clean shutdown machadmin -u --recovery=complex # Applied automatically after power loss machadmin -u --recovery=reset # Full scan if simple/complex recovery fails ``` | Recovery Mode | Description | |----------|------| | `simple` | Default recovery after a clean shutdown. Takes less time | | `complex` | Applied automatically after an abnormal shutdown such as power loss. Takes longer than `simple` | | `reset` | Scans all table data for recovery. Some data may be lost | ## Stopping the Server Graceful shutdown (waits for in-progress work to complete): ```bash machadmin -s ``` Forced shutdown (terminates the process immediately): ```bash machadmin -k ``` ## Creating and Deleting the Database ```bash # Create the database machadmin -c # Delete the database (displays a confirmation prompt) machadmin -d ``` ## Checking Server Status ```bash machadmin -e ``` Displays the PID if the server is running. ``` Machbase server is already running with PID (14098). ``` Displays an error if the server is not running. ``` [ERR] Server is not running. ``` ## Restoring the Database Restore the database from a backup directory. ```bash machadmin -r /path/to/backup ``` Example: ```bash machadmin -r /home/mach/backup/machbase_backup_20240101 ``` ## License Management Install a license file: ```bash machadmin -t /path/to/license.dat ``` Check the installed license: ```bash machadmin -f ``` ## Silent Mode Runs without a banner or status messages. Useful in scripts. ```bash machadmin -i -u # Start the server without a banner machadmin -i -s # Stop the server without a banner machadmin -i -e # Check status without a banner ``` ## Examples ```bash # Initialize the database and start the server machadmin -c machadmin -u # Check server status, then stop it machadmin -e machadmin -s # Renew the license machadmin -s machadmin -t new_license.dat machadmin -u ``` --- title: "16.4.2 machsql" url: https://docs.machbase.com/dbms/reference/command-line-tools/machsql/ language: en kind: page --- # 16.4.2 machsql `machsql` is an interactive terminal client for SQL queries. It also supports SQL script execution, saving results to files, and public key authentication. ## Options ```bash machsql -h ``` | Short Option | Long Option | Default | Description | |----------|---------|--------|------| | `-s` | `--server` | 127.0.0.1 | Server IP address | | `-P` | `--port` | 5656 | Server port | | `-u` | `--user` | SYS | Username | | `-p` | `--password` | MANAGER | User password | | `-K` | `--auth-key-file` | - | Private key file for public key authentication (8.5+) | | | `--auth-sig-scheme` | - | Authentication signature scheme: `ECDSA`, `RSA_PKCS1_V15`, or `RSA_PSS` (8.5+) | | `-f` | `--script` | - | SQL script file to execute | | `-o` | `--output` | - | Query result output file | | `-r` | `--format` | csv | Output format, such as `csv` or `json` | | `-z` | `--timezone` | - | Timezone, such as `+0900` or `-1230` | | `-n` | `--nls` | - | NLS settings | | `-c` | `--connstr` | - | Additional connection parameter string (6.1+) | | `-D` | `--database` | `MACHBASEDB` | Logical database to use immediately after connection (8.7.0 Standard) | | `-i` | `--silent` | - | Run without the copyright banner | | `-v` | `--verbose` | - | Verbose output | | `-x` | `--testing` | - | Run in test mode | | `-h` | `--help` | - | Display options | ## Connection Examples Basic connection: ```bash machsql -s 127.0.0.1 -u SYS -p MANAGER machsql --server=localhost --user=SYS --password=MANAGER ``` Specify a port: ```bash machsql -s 192.168.1.10 -P 5656 -u SYS -p MANAGER ``` Run a SQL script: ```bash machsql -s 127.0.0.1 -u SYS -p MANAGER -f create_tables.sql ``` Specify a timezone: ```bash machsql -s 127.0.0.1 -u SYS -p MANAGER -z +0900 machsql -s 127.0.0.1 -u SYS -p MANAGER -z -1230 ``` Save results to a file: ```bash machsql -s 127.0.0.1 -u SYS -p MANAGER -o result.csv -f query.sql ``` ## Public Key Authentication (Machbase 8.5+) You can use public key challenge authentication instead of a password. Connect with an ECDSA key: ```bash machsql -s 127.0.0.1 -u app_user \ -K /opt/machbase/keys/app_user_ecdsa.pem \ --auth-sig-scheme=ECDSA ``` Connect with an RSA-PSS key: ```bash machsql -s 127.0.0.1 -u app_user \ -K /opt/machbase/keys/app_user_rsa.pem \ --auth-sig-scheme=RSA_PSS ``` Supported key algorithms: | Algorithm | Key Parameters | Default Signature Scheme | |---------|-----------|--------------| | ECDSA | P-256, P-384, P-521 | `ECDSA` | | RSA | 2048, 3072, 4096 bits | `RSA_PKCS1_V15` | ## Additional Connection Parameters (6.1+) Use `-c` to supply additional connection parameters. ```bash machsql -s 127.0.0.1 -u SYS -p MANAGER -P 5656 \ -c 'ALTERNATIVE_SERVERS=192.168.0.147:9209;CONNECTION_TIMEOUT=10' ``` You can also use an environment variable. ```bash export MACHBASE_CONNECTION_STRING="ALTERNATIVE_SERVERS=192.168.0.148:8888;CONNECTION_TIMEOUT=3" machsql -s 127.0.0.1 -u SYS -p MANAGER ``` The `-c` option takes precedence over the environment variable. ## Selecting a Logical Database In Machbase 8.7.0 Standard Edition, use `-D` or `--database` to select the logical database immediately after connection. ```bash machsql -s 127.0.0.1 -u app_a -p 'AppA#1234' -D factory_a machsql -s 127.0.0.1 -u app_a -p 'AppA#1234' --database=factory_a ``` In a `-c` connection string, specify `DATABASE=factory_a` or its compatibility alias, `DBNAME=factory_a`. If `-D` and the connection string specify different databases, the connection is rejected. Specify the database once or use the same value. After connecting, verify the actual server catalog with the following SQL. ```sql SELECT CURRENT_DATABASE(); SHOW CURRENT DATABASE; ``` ## machsql Built-in Commands These commands are available at the machsql prompt (`Mach>`). | Command | Description | |------|------| | `SHOW TABLES` | List all tables | | `SHOW TABLE table_name` | Display column and index information for a table | | `SHOW INDEXES` | List all indexes | | `SHOW INDEX index_name` | Display a specific index | | `SHOW INDEXGAP` | Display index build gap information | | `SHOW LSM` | Display LSM index build information | | `SHOW TABLESPACES` | List all tablespaces | | `SHOW TABLESPACE name` | Display a specific tablespace | | `SHOW STORAGE` | Display disk usage per table | | `SHOW STATEMENTS` | List queries registered on the server | | `SHOW USERS` | List users | | `SHOW LICENSE` | Display license information | | `SHOW DATABASES` | List active/mounted databases | | `SHOW CURRENT DATABASE` | Display the current session database | | `SHOW LAST ROWID` | Display the ROWID of the most recent successful single-row INSERT | | `SHOW LASTID` | Same as `SHOW LAST ROWID` | ### Checking the Last INSERT's ROWID In Machbase 8.7.0 Standard Edition, you can check the inserted row's ROWID immediately after a single-row `INSERT ... VALUES`. ```sql INSERT INTO orders(item) VALUES('pump'); SHOW LAST ROWID; ``` ```text Last ROWID : 2048 ``` `SHOW LASTID` returns the same value. When no ROWID is available, the output is `NULL`, not `0`. Do not reuse the previous value after a failed INSERT, batch/Append/loader operation, `INSERT ... SELECT`, UPSERT, or reconnection. Non-INSERT statements such as SELECT and COMMIT preserve the last value. For per-table ROWID rules and SDK access, see [ROWID and INSERT Result IDs](/dbms/reference/sql/rowid/). ## DESC and PRIMARY KEY Metadata `DESC table_name` displays a `[ PRIMARY KEY ]` section after column and index information. It shows the PRIMARY KEY name, column names, and key sequence. It covers declared primary keys in TRANSACTION, LOOKUP, and VOLATILE tables, and `NAME` in TAG tables. Ordinary LOG tables display no primary key rows. ```sql DESC ACCOUNT; ``` This output is separate from SELECT result column metadata. To check whether a SELECT result column is part of a primary key through an SDK, see [PRIMARY KEY Metadata Support](/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-primary-key-metadata). ## ARRAY Display and DESC In Machbase DBMS 8.7.0, `DESC` displays ARRAY columns using canonical declarations such as `INT32[3]` and `DECIMAL(12,4)[2]`. Query results use `[value,null,value]`, where lowercase `null` represents an element NULL. If the entire column value is NULL, it appears as ordinary SQL `NULL`. ```sql SELECT ID, CHANNELS, ARRAY_LENGTH(CHANNELS), CHANNELS[1] FROM SENSOR_ARRAY ORDER BY ID; ``` For ARRAY declarations, NULL distinctions, and expressions, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/). ## Named Bind Parameter You can use `:name` markers in `machsql` `PREPARE` SQL. Assign values to `$1`, `$2`, ... variables in SQL occurrence order, rather than by name. ```sql PREPARE INSERT INTO SENSOR_DATA (ID, NAME, VALUE) VALUES (:id, :name, :value); $1 := 900; $2 := 'machsql-client'; $3 := 72.125000; EXECUTE; PREPARE CLEAN; ``` Assign a value to each occurrence even when a name is repeated. ```sql PREPARE SELECT ID, NAME FROM SENSOR_DATA WHERE ID = :id OR PARENT_ID = :id; $1 := 900; $2 := 900; EXECUTE; PREPARE CLEAN; ``` For marker naming syntax and occurrence ordering, see [Named Bind Parameter Syntax](../../sql/syntax/named-bind-parameter-syntax/). ## Examples ```bash # Connect interactively machsql -s 127.0.0.1 -u SYS -p MANAGER # Check tables after connecting Mach> SHOW TABLES; # Check table structure Mach> SHOW TABLE sensor_data; # Execute a SQL script and save results as CSV machsql -s 127.0.0.1 -u SYS -p MANAGER \ -f report.sql -o report_output.csv -i ``` --- title: "16.4.3 machloader" url: https://docs.machbase.com/dbms/reference/command-line-tools/machloader/ language: en kind: page --- # 16.4.3 machloader `machloader` imports and exports data between text files, such as CSV, and a Machbase server. It uses APPEND mode by default and supports more complex conversions through schema files. ## Options ```bash machloader -h ``` | Option | Description | |------|------| | `-s`, `--server=SERVER` | Server IP address (default: 127.0.0.1) | | `-P`, `--port=PORT` | Server port (default: 5656) | | `-u`, `--user=USER` | Username (default: SYS) | | `-p`, `--password=PASSWORD` | User password (default: MANAGER) | | `-i`, `--import` | Import mode | | `-o`, `--export` | Export mode | | `-c`, `--schema` | Schema file generation mode | | `-t`, `--table=TABLE_NAME` | Target table name | | `-f`, `--form=SCHEMA_FILE` | Schema filename | | `-d`, `--data=DATA_FILE` | Data filename | | `-m`, `--mode=MODE` | Import mode: `append` (default) or `replace` | | `-H`, `--header` | Treat the first import row as a header; write column names as a header on export | | `-D`, `--delimiter=DELIMITER` | Field delimiter (default: `,`) | | `-n`, `--newline=NEWLINE` | Record delimiter (default: `\n`) | | `-e`, `--enclosure=ENCLOSURE` | Field enclosure character | | `-r`, `--format=FORMAT` | File format (default: csv) | | `-E`, `--encoding=CHARSET` | File encoding: UTF8 (default), ASCII, MS949, KSC5601, EUCJP, SHIFTJIS, BIG5, GB231280, UTF16 | | `-F`, `--dateformat=DATEFORMAT` | Date format for datetime columns. Supports `unixtimestamp` and `nanotimestamp` | | `-z`, `--timezone` | Timezone, such as `+0900` or `-1230` | | `-a`, `--atime` | Include `_ARRIVAL_TIME` (excluded by default) | | `-C`, `--create` | Create the table on import if missing | | `-l`, `--log=LOG_FILE` | Execution log file | | `-b`, `--bad=BAD_FILE` | Bad file for failed import rows | | `--first=FIRST_ROW` | First row number to process | | `-I`, `--silent` | Run without banner or progress output | | `-S`, `--slash` | Set the backslash delimiter | | `--summary` | Display selected options and exit without processing | | `-h`, `--help` | Display options | ## Importing CSV Files Basic import: ```bash machloader -i -d data.csv -t sensor_data ``` Specify a server connection: ```bash machloader -i -s 192.168.0.10 -P 5656 -u SYS -p MANAGER \ -d data.csv -t sensor_data ``` Import CSV with a header: ```bash machloader -i -d data.csv -t sensor_data -H ``` Delete existing data before import (replace mode): ```bash machloader -i -d data.csv -t sensor_data -m replace ``` Start at a specific row: ```bash machloader -i -d data.csv -t sensor_data --first=10 ``` ## Exporting CSV Files ```bash machloader -o -d output.csv -t sensor_data machloader -o -d output.csv -t sensor_data -H ``` Export including `_ARRIVAL_TIME`: ```bash machloader -o -d output.csv -t sensor_data -a ``` ### ARRAY Columns Machbase DBMS 8.7.0 imports and exports ARRAY columns as `[value,null,value]`. Enclose the CSV field because the ARRAY contains commas. ```csv 1,"[1.5,null,3.5,4.5]" ``` A NULL field represents a whole-array NULL; `"[null,null]"` represents a non-NULL ARRAY whose elements are all NULL. Automatic table creation with `-C` does not infer ARRAY types. Explicitly create tables that require ARRAY columns before importing. For type and NULL rules, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/). ## Encoding and Delimiters EUC-KR encoding with a tab delimiter: ```bash machloader -i -d data.txt -t table_name -E MS949 -D '\t' ``` Pipe (`|`) delimiter: ```bash machloader -i -d data.txt -t table_name -D '|' machloader -o -d data.txt -t table_name -D '|' ``` ## Specifying a Timezone ```bash machloader -i -d data.csv -t sensor_data -z +0900 machloader -i -d data.csv -t sensor_data -z -1230 ``` ## Specifying datetime Formats Set the format directly on the command line: ```bash machloader -i -d data.csv -t sensor_data \ -F "_arrival_time YYYY-MM-DD HH24:MI:SS" ``` Import Unix timestamps: ```bash machloader -i -d data.csv -t sensor_data \ -F "time_column unixtimestamp" ``` Import nanosecond timestamps: ```bash machloader -i -d data.csv -t sensor_data \ -F "time_column nanotimestamp" ``` ## Using Schema Files Generate a schema file: ```bash machloader -c -t sensor_data -f sensor_data.fmt ``` Import/export with a schema file: ```bash machloader -i -f sensor_data.fmt -d data.csv machloader -o -f sensor_data.fmt -d output.csv ``` Example schema file (`sensor_data.fmt`): ``` table sensor_data { name varchar(64); time datetime; value double; } DATEFORMAT time "YYYY-MM-DD HH24:MI:SS" ``` Ignore a specific column: ``` table sensor_data { id integer; name varchar(64); extra varchar(32) IGNORE; } ``` ## Log and Bad Files ```bash machloader -i -d data.csv -t sensor_data \ -l import.log -b import.bad ``` - `-l`: Import execution log with success/failure statistics - `-b`: Failed row data in its original format ## Automatic Table Creation Create the table if missing. Columns are named `c0`, `c1`, ... and have type `varchar(32767)`. ```bash machloader -i -d data.csv -t new_table -C machloader -i -d data.csv -t new_table -C -H # Use header values as column names ``` ## Examples ```bash # Check settings before import (--summary) machloader -i -d data.csv -t sensor_data --summary # Import a large file with log and bad files machloader -i -d bigdata.csv -t sensor_data \ -H -z +0900 \ -l import_20240101.log -b import_20240101.bad # Export the entire table machloader -o -d export_20240101.csv -t sensor_data -H -a ``` --- title: "16.4.4 csvimport / csvexport" url: https://docs.machbase.com/dbms/reference/command-line-tools/csvimport-csvexport/ language: en kind: page --- # 16.4.4 csvimport / csvexport `csvimport` and `csvexport` are simple CSV import/export wrappers. They simplify the CSV options of `machloader`; options not listed below can be used as with `machloader`. ## csvimport Import a CSV file into a Machbase table. ### Options | Option | Description | |------|------| | `-t`, `--table=TABLE_NAME` | Target table name | | `-d`, `--data=DATA_FILE` | CSV file to import | | `-s`, `--server=SERVER` | Server IP address (default: 127.0.0.1) | | `-P`, `--port=PORT` | Server port (default: 5656) | | `-u`, `--user=USER` | Username (default: SYS) | | `-p`, `--password=PASSWORD` | User password (default: MANAGER) | | `-H` | Treat the first CSV row as a header and exclude it from ingestion | | `-C` | Create the table if missing (with `-H`, use header values as column names) | | `-m`, `--mode=MODE` | Import mode: `append` (default) or `replace` | | `-a`, `--atime` | Include `_ARRIVAL_TIME` | | `-F`, `--dateformat=DATEFORMAT` | Date format for datetime columns | | `-l`, `--log=LOG_FILE` | Execution log file | | `-b`, `--bad=BAD_FILE` | Bad file for failed import rows | | `-I`, `--silent` | Run without banner or status output | ### Basic Usage Specify the table and filename. ```bash csvimport -t table_name -d data.csv ``` You can also use positional arguments without options, in either order. ```bash csvimport table_name data.csv csvimport data.csv table_name ``` ### Header Handling Treat the first CSV row as a header and exclude it from the data. ```bash csvimport -t table_name -d data.csv -H ``` ### Automatic Table Creation Create the table automatically if it does not exist. ```bash # Generate column names c0, c1, ... csvimport -t table_name -d data.csv -C # Use CSV header values as column names csvimport -t table_name -d data.csv -C -H ``` All automatically created columns have type `varchar(32767)`. ### Replace Mode Delete existing data and refill the table from the CSV file. ```bash csvimport -t table_name -d data.csv -m replace ``` ### Specifying a Server Connection ```bash csvimport -s 192.168.0.10 -P 5656 -u SYS -p MANAGER \ -t sensor_data -d data.csv ``` ## csvexport Export Machbase table data to a CSV file. ### Options | Option | Description | |------|------| | `-t`, `--table=TABLE_NAME` | Table to export | | `-d`, `--data=DATA_FILE` | Output CSV filename | | `-s`, `--server=SERVER` | Server IP address (default: 127.0.0.1) | | `-P`, `--port=PORT` | Server port (default: 5656) | | `-u`, `--user=USER` | Username (default: SYS) | | `-p`, `--password=PASSWORD` | User password (default: MANAGER) | | `-H` | Write column names as the CSV header | | `-a`, `--atime` | Include `_ARRIVAL_TIME` | | `-F`, `--dateformat=DATEFORMAT` | Date format for datetime columns | | `-l`, `--log=LOG_FILE` | Execution log file | | `-I`, `--silent` | Run without banner or status output | ### Basic Usage ```bash csvexport -t table_name -d output.csv ``` You can also use positional arguments without options. ```bash csvexport table_name output.csv csvexport output.csv table_name ``` ### Exporting with a Header Write column names as the first row (header) of the CSV file. ```bash csvexport -t table_name -d output.csv -H ``` ### Exporting `_ARRIVAL_TIME` ```bash csvexport -t table_name -d output.csv -a ``` ## Examples ```bash # Basic import csvimport -t sensor_data -d sensor_20240101.csv # Import CSV with a header csvimport -t sensor_data -d sensor_20240101.csv -H # Export all data, including a header csvexport -t sensor_data -d export_20240101.csv -H # Import with log files csvimport -t sensor_data -d data.csv -H \ -l import.log -b import.bad # Export from a remote server csvexport -s 192.168.0.10 -P 5656 -u SYS -p MANAGER \ -t sensor_data -d remote_export.csv -H -a ``` --- title: "16.4.5 tagmetaimport" url: https://docs.machbase.com/dbms/reference/command-line-tools/tagmetaimport/ language: en kind: page --- # 16.4.5 tagmetaimport `tagmetaimport` imports TAG table metadata in bulk from CSV. Use it to register large numbers of tag names and metadata values. It does not automatically update existing tags or apply the entire file as one transaction. ## Options ```bash tagmetaimport -h ``` | Option | Description | |------|------| | `-s`, `--server=SERVER` | Server IP address (default: 127.0.0.1) | | `-P`, `--port=PORT` | Server port (default: 5656) | | `-u`, `--user=USER` | Username (default: SYS) | | `-p`, `--password=PASSWORD` | User password (default: MANAGER) | | `-t`, `--table=TABLE_NAME` | Target metadata storage table. For logical table sensor_tag, specify _SENSOR_TAG_META | | `-d`, `--data=DATA_FILE` | Metadata CSV path | | `-l`, `--log=LOG_FILE` | Log file path | | `-b`, `--bad=BAD_FILE` | File for failed input records | | `-H`, `--header` | Treat the first CSV row as a header | | `-D`, `--delimiter=DELIMITER` | Field delimiter (default: `,`) | | `-E`, `--encoding=CHARSET` | File encoding (default: UTF8) | | `-I`, `--silent` | Reduce progress output. Check success/failure counts in the completion summary | | `-h`, `--help` | Display options | ## Input File Format Arrange CSV columns in the same order as the TAG table's metadata columns. Example TAG table definition: ```sql CREATE TAG TABLE sensor_tag ( name VARCHAR(64) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED ) METADATA ( unit VARCHAR(32), location VARCHAR(128) ); ``` Metadata CSV for this table (`tag_meta.csv`): ``` name,unit,location sensor_001,celsius,Building-A Floor-1 sensor_002,celsius,Building-A Floor-2 sensor_003,bar,Boiler-Room sensor_004,rpm,Motor-Section ``` Data without a header: ``` sensor_001,celsius,Building-A Floor-1 sensor_002,celsius,Building-A Floor-2 ``` ## Examples ### Basic Import ```bash tagmetaimport -s 127.0.0.1 -P 5656 -u SYS -p MANAGER \ -t _SENSOR_TAG_META -d tag_meta.csv -H ``` ### Importing CSV with a Header ```bash tagmetaimport -s 127.0.0.1 -P 5656 -u SYS -p MANAGER \ -t _SENSOR_TAG_META -d tag_meta.csv -H ``` ### Importing to a Remote Server ```bash tagmetaimport -s 192.168.0.10 -P 5656 -u SYS -p MANAGER \ -t _SENSOR_TAG_META -d tag_meta.csv -H ``` ### Tab-delimited Files ```bash tagmetaimport -s 127.0.0.1 -P 5656 -u SYS -p MANAGER \ -t _SENSOR_TAG_META -d tag_meta.tsv -D '\t' -H ``` ### EUC-KR Files ```bash tagmetaimport -s 127.0.0.1 -P 5656 -u SYS -p MANAGER \ -t _SENSOR_TAG_META -d tag_meta_kr.csv -E MS949 -H ``` ## Behavior - `-t` does not automatically convert a logical TAG table to its METADATA target. For logical table sensor_tag, specify `_SENSOR_TAG_META`. Use this name only to select the tool's ingestion target. - Existing tag names cause ordinary METADATA INSERT errors. Check failure counts and the bad/log files. - This tool is efficient for adding metadata after data has already been ingested. - For small amounts of metadata, use SQL INSERT or enter statements directly in `machsql`. ```sql -- Insert metadata directly in machsql INSERT INTO sensor_tag METADATA (name, unit, location) VALUES ('sensor_005', 'volt', 'Panel-Room'); ``` ## Notes - Create the TAG table before importing. - CSV column order must match the TAG table's metadata column order. - Exclude the `BASETIME` column (`time`) and `SUMMARIZED` column (`value`) from the metadata file. Change existing values with `UPDATE sensor_tag METADATA ...` or an explicit SQL UPSERT. For reproducible examples of new ingestion and duplicate ingestion failures, see [Bulk Metadata Registration](../../../tag-table-usage/tagmetaimport/). The server maintains `_LAST_UPDATE_TIME` when new metadata is inserted or values actually change. --- title: "16.4.7 machclusterctl" url: https://docs.machbase.com/dbms/reference/command-line-tools/machclusterctl/ language: en kind: page --- # 16.4.7 machclusterctl `machclusterctl` manages an entire Machbase Cluster Edition cluster with a single command. It validates YAML configuration and handles installation, configuration changes on a running cluster, upgrades, startup/shutdown, and status checks. ## Main Commands | Command | Description | |------|------| | `validate` | Validate `cluster.yaml` | | `install` | Install a new cluster from `cluster.yaml` | | `apply` | Apply configuration changes to a running cluster | | `upgrade` | Upgrade packages (`--online`, `--full-stop`) | | `export` | Export the running cluster configuration as flat YAML | | `status` | Check all cluster node statuses | | `connect` | Connect to a Broker/Warehouse alias with `machsql` | | `start` | Start all cluster nodes | | `stop` | Shut down all cluster nodes gracefully | | `destroy` | Remove the cluster, including its data | ## Usage ```bash machclusterctl [options] ``` ## Command Details ### validate Validate the YAML configuration file. ```bash machclusterctl validate -f cluster.yaml ``` ### install Read the YAML configuration file and install a new cluster. ```bash machclusterctl install -f cluster.yaml ``` ### apply Apply configuration changes to a running cluster. ```bash machclusterctl apply -f cluster.yaml ``` ### upgrade Upgrade packages. ```bash machclusterctl upgrade --online broker machclusterctl upgrade --full-stop ``` ### start Start the entire cluster in this order: Coordinator → Deployer → Broker → Warehouse. ```bash machclusterctl start machclusterctl start -f cluster.yaml ``` ### stop Shut down the entire cluster gracefully. ```bash machclusterctl stop ``` ### destroy Remove the cluster completely. This also deletes database files; use with care. ```bash machclusterctl destroy ``` ### status Display the current status of each cluster node. ```bash machclusterctl status ``` ### connect Connect to a Broker node with `machsql`. ```bash machclusterctl connect ``` ### export Export the current cluster configuration to a YAML file. ```bash machclusterctl export -o cluster_backup.yaml ``` ## YAML Configuration Structure Basic YAML structure used by `machclusterctl validate`, `install`, and `apply`: ```yaml cluster: coordinator: host: 192.168.0.32 port: 5101 http_port: 5102 home: /home/machbase/coordinator1 deployer: - host: 192.168.0.32 port: 5201 home: /home/machbase/deployer1 broker: - host: 192.168.0.32 port: 5301 http_port: 5302 home: /home/machbase/broker1 service_port: 5757 warehouse: - group: Group1 host: 192.168.0.32 port: 5401 http_port: 5402 home: /home/machbase/warehouse_a1 service_port: 5400 ``` ## Options | Option | Description | |------|------| | `-f`, `--file` | Cluster configuration YAML path | | `-s`, `--silent` | Reduce progress log output | | `-v`, `--verbose` | Display detailed progress logs | | `--node` | Target node alias for `start`/`stop` | | `--type` | Target node type for `start`/`stop` | | `-o`, `--output` | Output path for `export` | | `-h`, `--help` | Display help | ## Examples ```bash # Validate YAML machclusterctl validate -f my_cluster.yaml # Install a new cluster machclusterctl install -f my_cluster.yaml # Apply changes to a running cluster machclusterctl apply -f my_cluster.yaml # Start the cluster machclusterctl start # Stop/start a specific node or node type machclusterctl stop --node broker-1 machclusterctl start --type warehouse # Check status machclusterctl status # Connect to a Broker and run SQL machclusterctl connect # Stop the cluster machclusterctl stop # Export the configuration machclusterctl export -o cluster_config_backup.yaml ``` --- title: "16.4.8 machcoordinatoradmin" url: https://docs.machbase.com/dbms/reference/command-line-tools/machcoordinatoradmin/ language: en kind: page --- # 16.4.8 machcoordinatoradmin `machcoordinatoradmin` manages Coordinator nodes and controls cluster configuration in Machbase Cluster Edition. It is included only in the Cluster Edition package. ## Options ```bash machcoordinatoradmin -h ``` ### Basic Administration | Option | Description | |------|------| | `-u`, `--startup` | Start the Coordinator process | | `-s`, `--shutdown` | Shut down the Coordinator process gracefully | | `-k`, `--kill` | Force the Coordinator process to stop | | `-c`, `--createdb` | Create Coordinator metadata | | `-d`, `--destroydb` | Delete Coordinator metadata and package files | | `-e`, `--check` | Check whether the Coordinator process is running | | `-i`, `--silent` | Run without a banner | | `--home-path=path` | Set the Machbase home path | ### Configuration Queries | Option | Description | |------|------| | `--configuration[=name]` | Display configuration keys and values, optionally for one key | | `--configure` | Display all system properties | ### Cluster State Control | Option | Description | |------|------| | `--activate` | Change cluster state to Service | | `--deactivate` | Change cluster state to Deactivate | | `--cluster-status` | Display a summary of each cluster node's status | | `--cluster-status-full` | Display detailed status for each cluster node | | `--cluster-node` | Display cluster information | | `--verbose` | Include Deployer status in status output | ### Package Management | Option | Description | |------|------| | `--list-package[=package]` | List registered packages, optionally for one package | | `--add-package=package` | Add a package | | `--remove-package=package` | Remove a package | ### Node Management | Option | Description | |------|------| | `--list-node[=node]` | List node information | | `--add-node=node` | Add a node | | `--remove-node=node` | Remove a node | | `--attach-node=node` | Attach an existing node to cluster metadata | | `--detach-node=node` | Detach a node from cluster metadata | | `--upgrade-node=node` | Upgrade a node | | `--startup-node=node` | Start a specific node | | `--shutdown-node=node` | Shut down a specific node gracefully | | `--kill-node=node` | Force a specific node to stop | ### Lookup Node Management | Option | Description | |------|------| | `--startup-lookup` | Start Lookup nodes | | `--shutdown-lookup` | Stop Lookup nodes | | `--set-lookup-master=node` | Set the Lookup master node | ### Warehouse Group and State Management | Option | Description | |------|------| | `--set-group-state=[normal\|readonly]` | Change a Warehouse group's state | | `--set-warehouse-state=[normal\|scrapped]` | Change the state of the Warehouse specified by `--node` | | `--force-restore-warehouse=node` | Force recovery of a scrapped Warehouse | ### Broker Management | Option | Description | |------|------| | `--deactivate-broker=node` | Set the specified node to inactive | | `--activate-broker=node` | Set the specified node to normal | ### Snapshot Management | Option | Description | |------|------| | `--snapshot-interval=sec` | Set the snapshot interval in seconds | | `--exec-snapshot` | Run a snapshot immediately (requires `--group`) | | `--snapshot-recover=node` | Recover the specified node from a snapshot | | `--exec-sync=node` | Synchronize the specified node | | `--snapshot-clean` | Clean up snapshots | ### Host Resource Monitoring | Option | Description | |------|------| | `--get-host-resource` | Display host resource information for each node | | `--host-resource-enable` | Start collecting host resource information | | `--host-resource-disable` | Stop collecting host resource information | ### Additional Options (Used with Other Options) | Additional Option | Required Option | Description | |----------|----------|------| | `--file-name=filename` | `--add-package` | Package filename | | `--port-no=portno` | `--add-node`, `--attach-node` | Service port | | `--http-admin-port=portno` | Coordinator/Deployer `--add-node`, `--attach-node` | Administration REST port | | `--deployer=node` | `--add-node` | Deployer node name | | `--package-name=name` | `--add-node`, `--upgrade-node` | Installation source package name | | `--home-path=path` | `--add-node`, `--attach-node` | Node installation path | | `--node-type=[broker\|warehouse\|lookup]` | `--add-node`, `--attach-node` | Node type | | `--lookup-type=[master\|slave\|monitor]` | `--add-node`, `--attach-node` | Lookup node type | | `--node=node` | `--set-warehouse-state` | Node whose state to change | | `--alias=alias` | `--add-node`, `--attach-node` | Node alias | | `--dbs-path=path` | `--add-node` (Broker/Warehouse) | Database file path | | `--group=groupname` | `--add-node`, `--attach-node`, `--set-group-state`, `--exec-snapshot` | Node group name | | `--replication=host:port` | `--add-node`, `--attach-node` | Replication target host:port | | `--no-replicate` | `--add-node`, `--attach-node` | Disable replication | | `--primary=host:port` | `-u`, `--startup` | Set the Primary for a Secondary Coordinator | | `--host=host` | `--get-host-resource` | Select a specific host | | `--metric=[cpu\|memory\|disk\|network]` | `--get-host-resource` | Metric to display | ## Examples ### Checking Process Status ```bash machcoordinatoradmin -e ``` ### Checking Cluster Status ```bash machcoordinatoradmin --cluster-status machcoordinatoradmin --cluster-status-full ``` ### Activating/Deactivating the Cluster ```bash machcoordinatoradmin --activate machcoordinatoradmin --deactivate ``` ### Adding a Warehouse Node ```bash machcoordinatoradmin \ --add-node=192.168.0.32:5401 \ --node-type=warehouse \ --deployer=192.168.0.32:5201 \ --package-name=machbase \ --home-path=/home/machbase/warehouse_a1 \ --port-no=5400 \ --group=Group1 \ --alias=warehouse-a1 \ --dbs-path=/data/machbase/warehouse_a1_dbs ``` ### Listing Nodes ```bash machcoordinatoradmin --list-node machcoordinatoradmin --list-node=192.168.0.32:5401 ``` ### Setting a Warehouse Group to Read-only ```bash machcoordinatoradmin --set-group-state=readonly --group=Group1 ``` ### Querying Configuration ```bash machcoordinatoradmin --configuration machcoordinatoradmin --configuration=decision ``` ### Monitoring Host Resources ```bash machcoordinatoradmin --host-resource-enable machcoordinatoradmin --get-host-resource machcoordinatoradmin --get-host-resource --metric=cpu machcoordinatoradmin --get-host-resource --host=192.168.0.33 machcoordinatoradmin --host-resource-disable ``` --- title: "16.4.9 machdeployeradmin" url: https://docs.machbase.com/dbms/reference/command-line-tools/machdeployeradmin/ language: en kind: page --- # 16.4.9 machdeployeradmin `machdeployeradmin` directly manages Deployer nodes in Machbase Cluster Edition. A Deployer distributes packages and performs installation on each node as instructed by the Coordinator. Use `machcoordinatoradmin` to control Deployers under normal conditions. Use `machdeployeradmin` directly when control through `machcoordinatoradmin` is unavailable. Included only in the Cluster Edition package. ## Options ```bash machdeployeradmin -h ``` | Option | Description | |------|------| | `-u`, `--startup` | Start the Deployer process | | `-s`, `--shutdown` | Shut down the Deployer process gracefully | | `-k`, `--kill` | Force the Deployer process to stop | | `-c`, `--createdb` | Create Deployer metadata | | `-d`, `--destroydb` | Delete Deployer metadata | | `-e`, `--check` | Check whether the Deployer process is running | | `-i`, `--silent` | Run without a banner | ## Process Management ### Start ```bash machdeployeradmin -u ``` ### Graceful Shutdown ```bash machdeployeradmin -s ``` ### Forced Stop ```bash machdeployeradmin -k ``` ### Check Status ```bash machdeployeradmin -e ``` Displays the PID if the process is running. ``` Machbase Deployer is running with pid(29373)! ``` ## Metadata Management Create new Deployer metadata. ```bash machdeployeradmin -c ``` Delete Deployer metadata. ```bash machdeployeradmin -d ``` ## Deployer Responsibilities The Deployer performs the following tasks under Coordinator instructions. - Distribute and install Machbase packages on Broker, Warehouse, and Lookup nodes - Create and manage node configuration files - Forward node startup/shutdown instructions - Support node upgrades ## Examples ```bash # Initialize the Deployer machdeployeradmin -c machdeployeradmin -u # Check status machdeployeradmin -e # Shut down gracefully machdeployeradmin -s # Force a stop if a problem occurs machdeployeradmin -k ``` ## Notes Use `machcoordinatoradmin` for most cluster configuration and node management tasks. Use `machdeployeradmin` for direct intervention when communication with the Coordinator is unavailable or the Deployer itself has a problem. For cluster management details, see [machcoordinatoradmin](../machcoordinatoradmin/). --- title: "16.6 Support Scope and Constraints" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/ language: en kind: section --- # 16.6 Support Scope and Constraints This section provides quick references to Machbase feature support by edition, table type, and SDK, along with known constraints. Use individual feature chapters for behavior and examples, and this section to check support in a specific environment. ## Pages | Page | Content | |--------|------| | [Feature Support by Edition](./edition/) | Standard Edition and Cluster Edition comparison | | [Feature Support by Table Type](./table-types-type/) | TAG / LOG / LOOKUP / VOLATILE / TRANSACTION support | | [Feature Support by SDK](/dbms/development-tools-integration/sdk-support-scope/) | JDBC, Python, Go, .NET, and Node.js support | | [ROLLUP Support](./rollup/) | ROLLUP support by edition and table type | | [Backup/Mount Support](./backup-mount/) | BACKUP / MOUNT support by edition | | [Feature Support by Privilege](./privileges/) | Database and table privileges | | [TRANSACTION Feature Support](./rdb/) | TRANSACTION table SQL support and constraints | | [Version and Compatibility](./compatibility-version/) | Upgrade considerations and supported operating systems/platforms | | [Server and SDK Compatibility](./compatibility-xma-protocol/) | Feature support by server/SDK version combination | | [LOOKUP SQL/JSON Support](./lookup-sql-json/) | LOOKUP table SQL/JSON support and constraints | | [TAG Data UPDATE Support](./tag-data-update/) | TAG UPDATE predicates and target columns | Do not depend on internal objects, flags, or protocol behavior absent from these tables. Check both server and client versions for SDK features. For feature-specific error diagnosis, see [Troubleshooting](/dbms/troubleshooting/). ## Notation Support tables in this section use the following symbols. | Symbol | Meaning | |:----:|------| | O | Fully supported | | X | Not supported | | △ | Partially supported or subject to constraints | --- title: "16.6.1 Feature Support by Edition" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/edition/ language: en kind: page --- # 16.6.1 Feature Support by Edition Machbase provides **Standard Edition** for a single server and **Cluster Edition** for horizontal scaling across nodes. They share core time-series features, but supported features differ according to scalability and high availability requirements. ## Feature Comparison | Feature | Standard | Cluster | Notes | |------|:--------:|:-------:|------| | **Table Types** | | | | | TAG tables | O | O | | | LOG tables | O | O | | | LOOKUP tables | O | O | | | TRANSACTION tables | O | X | Not supported in Cluster Edition | | VOLATILE tables | O | O | Check the node and restart lifecycle of in-memory data in your deployment | | **Data Management** | | | | | ROLLUP (basic) | O | O | | | Custom ROLLUP | O | X | Not supported in Cluster Edition | | ROLLUP_REBUILD | O | X | Not supported in Cluster Edition | | **Backup and Recovery** | | | | | Multiple logical databases | O | X | Standard Edition only. No physical CPU, memory, or disk quotas per database | | BACKUP DATABASE | O | O | | | BACKUP TABLE | O | O | | | MOUNT DATABASE | O | X | Not supported in Cluster Edition | | UMOUNT DATABASE | O | X | Not supported in Cluster Edition | | machadmin -r restore | O | X | Not supported in Cluster Edition | | **Scalability and HA** | | | | | Horizontal scaling | X | O | Scale by adding Warehouse nodes | | HA (high availability) | X | O | Broker/Warehouse redundancy | | AUTH KEY authentication | O | O | | ## Cluster Edition Constraints Cluster Edition has constraints on local file operations centered on a single node and on TRANSACTION features. - **TRANSACTION tables**: TRANSACTION tables providing ACID transactions are not supported in the distributed environment. Integrate with an external RDBMS for data requiring transactions. - **VOLATILE tables**: Creation and DML are supported, but in-memory data is local to each node and is not shared across nodes. Verify data visibility with the connected Broker, routing, and node restarts. - **MOUNT/UMOUNT**: Local filesystem backup mounts are not supported in the distributed environment. - **Custom ROLLUP / ROLLUP_REBUILD**: Custom rollup redefinition and rebuilding are not supported because the distributed aggregation architecture differs. ## Choosing an Edition | Requirement | Recommended Edition | |-----------|-------------| | Workload within one server's throughput and storage capacity | Standard Edition | | Workload requiring horizontal scaling beyond one server | Cluster Edition | | High availability with automatic failure recovery | Cluster Edition | | TRANSACTION tables or MOUNT | Standard Edition | | Real-time ingestion exceeds one server's capacity and requires more nodes | Cluster Edition | --- title: "16.6.2 Feature Support by Table Type" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/table-types-type/ language: en kind: page --- # 16.6.2 Feature Support by Table Type Machbase provides five table types for different uses. Each supports features according to its design goals. ## Table Type Overview | Table Type | Primary Use | |------------|----------| | **TAG** | High-speed time-series sensor ingestion and aggregation (ROLLUP) | | **LOG** | Sequential storage of logs/events in defined columns and text search | | **LOOKUP** | Metadata, code tables, and reference data (supports UPDATE/DELETE) | | **VOLATILE** | In-memory server state and caches; data is lost on restart | | **TRANSACTION** | General relational data requiring transactions | ## Feature Support Matrix | Feature | TAG | LOG | LOOKUP | VOLATILE | TRANSACTION | |------|:---:|:---:|:------:|:--------:|:---:| | **Writes** | | | | | | | INSERT (SQL) | O | O | O | O | O | | **Updates/Deletes** | | | | | | | UPDATE | △ | X | O | O | O | | DELETE | O | O | O | O | O | | **Transactions** | | | | | | | Transaction (COMMIT/ROLLBACK) | X | X | X | X | O | | **Aggregation and Search** | | | | | | | ROLLUP | O | X | X | X | X | | Text search (KEYWORD INDEX) | X | O | X | X | X | | **JSON** | | | | | | | JSON columns | O | O | O | X | O | | JSON path query | O | O | O | X | O | | **Fixed-point Numbers** | | | | | | | DECIMAL / NUMERIC columns | O | O | O | O | O | | **Fixed-length ARRAY** | | | | | | | ARRAY column creation | O | O | O | O | O | | ARRAY ADD/DROP COLUMN | △ | O | O | O | O | | **Indexes** | | | | | | | Default indexes | O | O | O | O | O | | LSM indexes | X | O | X | X | X | | **Queries** | | | | | | | SELECT | O | O | O | O | O | | Latest-value queries (`SCAN_BACKWARD`, TAG stat) | O | X | X | X | X | | JOIN (with other tables) | △ | △ | O | O | O | | Subquery | O | O | O | O | O | | VIEW | O | O | O | O | O | > Symbols: O = supported, X = not supported, △ = partially supported or constrained Append support by table type depends on the client API. For the language and API you use, check the [SDK Append Support Matrix](/dbms/development-tools-integration/sdk-support-scope/#append-table-type-matrix). DECIMAL is an exact fixed-point type available in all five table types. `NUMERIC`, `DEC`, `FIXED`, and `NUMBER` are aliases for DECIMAL. Maximum precision is 65 and maximum scale is 30. For details, see [DECIMAL and NUMERIC Fixed-point Types](../../sql/types/decimal-numeric-fixed-point/). ARRAY ADD/DROP is supported for LOG, VOLATILE, LOOKUP, TRANSACTION, and TAG METADATA in Standard Edition. The TAG column's `△` means that ALTER supports TAG METADATA only; ordinary TAG DATA columns cannot be added. Cluster Edition supports only the LOG path. For exact syntax and DEFAULT rules for existing rows, see [DDL Syntax](../../sql/syntax/ddl-syntax/#add-column) and [Numeric ARRAY Types](../../sql/types/array/). ## Main Constraints ### TAG Table UPDATE Constraints (△, Standard Edition) TAG table UPDATE must satisfy all of the following conditions. TAG data UPDATE is not available in Cluster Edition. - Include a tag selection predicate (`name =`, `name IN`, or `name LIKE`) in `WHERE` - Include a BASETIME column predicate in `WHERE` - SET targets must be actual data columns - Data UPDATE cannot modify `time` (BASETIME), `name`, or metadata columns - SET right-hand expressions cannot reference existing row columns; use constants, binds, or column-free expressions ```sql -- Allowed: update a data column using tag and time predicates UPDATE sensor_data SET value = 101 WHERE name = 'sensor01' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); -- Not allowed: update the BASETIME column UPDATE sensor_data SET time = SYSDATE WHERE name = 'sensor01' AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD'); ``` For details, see [TAG Data UPDATE Support](../tag-data-update/). ### Transaction Scope of LOOKUP and VOLATILE Each DML statement on LOOKUP and VOLATILE tables is applied independently. These tables do not participate in TRANSACTION table transactions grouping multiple statements with `BEGIN` and `COMMIT`/`ROLLBACK`. ### JSON Column Support JSON columns are supported in TAG, LOG, LOOKUP, and TRANSACTION tables. VOLATILE does not support JSON columns. LOOKUP JSON columns can be ordinary columns but cannot be primary keys. See [JSON Support by Table Type](../../sql/types/table-types-type-support-scope-json/). ## TAG Latest-value and Time-range Queries TAG tables use reverse scans and time predicates to query recent values and time ranges. ```sql -- Query the five latest values for a specific tag SELECT /*+ SCAN_BACKWARD(sensor_data) */ * FROM sensor_data WHERE name = 'sensor01' LIMIT 5; -- Query a time range SELECT * FROM sensor_data WHERE name = 'sensor01' AND time BETWEEN TO_DATE('2024-01-01') AND TO_DATE('2024-01-02'); ``` --- title: "16.6.3 TRANSACTION Feature Support" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/rdb/ language: en kind: page --- # 16.6.3 TRANSACTION Feature Support Machbase TRANSACTION tables store general relational data that requires transactions. Access them through Machbase SQL and supported drivers such as JDBC/ODBC. > **Note**: TRANSACTION tables are supported **only in Standard Edition**. They cannot be created or used in Cluster Edition. Unqualified `CREATE TABLE`, `CREATE TRANSACTION TABLE`, and `CREATE TXN TABLE` all create TRANSACTION tables. Cluster Edition therefore rejects all three forms. Use `CREATE LOG TABLE` to create LOG tables in Cluster Edition. ## SQL Feature Support | Feature | Support | Notes | |------|:---------:|------| | **Basic DML** | | | | SELECT | O | | | INSERT | O | | | UPDATE | O | | | DELETE | O | | | INSERT ... ON DUPLICATE KEY UPDATE | O | Update an existing row on a PRIMARY KEY or UNIQUE INDEX conflict | | **Transactions** | | | | Transaction (COMMIT/ROLLBACK) | O | plain `BEGIN`, `COMMIT`, `ROLLBACK` | | ROLLBACK of TRANSACTION TRUNCATE | O | Treated as deletion of all rows within an explicit transaction | | Savepoint | X | Not supported | | **Queries** | | | | Prepared Statement | O | | | Parameter binding | O | | | JOIN | O | Can join other table types | | Subquery | O | | | VIEW | O | | | **Objects** | | | | SEQUENCE | O | `CREATE SEQUENCE` | | PRIMARY KEY / UNIQUE INDEX | O | Single-column PRIMARY KEY and single-/multiple-column UNIQUE INDEX | | Secondary INDEX | O | Single-/multiple-column BTREE indexes | | JSON path INDEX | O | `json_column->'$.path'` | | AUTO_INCREMENT | O | Column-level PRIMARY KEY on a `LONG`/`INT64` column | | ALTER ADD/DROP COLUMN | O | Parentheses required around column definitions | | ALTER RENAME COLUMN / RENAME TO | O | Rename columns and tables | | ALTER MODIFY COLUMN | X | Not supported | | Trigger | X | Not supported | | Stored Procedure | X | Not supported | | Foreign Key | X | Not supported | For `AUTO_INCREMENT`, see [AUTO_INCREMENT](/dbms/reference/sql/syntax/auto-increment-syntax/); for upsert, see [INSERT ON DUPLICATE KEY UPDATE](/dbms/rdb-table-usage/insert-on-duplicate-key-update/). Append paths differ by client. Use the [SDK Append matrix](/dbms/development-tools-integration/sdk-support-scope/#append-table-type-matrix) as the canonical reference. ## Transaction and Concurrent Access Boundaries SELECT on other table types and mixed-type JOINs are allowed during an active transaction. However, LOG, TAG, LOOKUP, and VOLATILE writes cannot be included in the same TRANSACTION transaction. Allowed queries do not guarantee a shared snapshot across all table types. For ordinary constraint errors, distinguish a failed statement from the entire transaction. ROLLBACK is required to undo earlier successful changes. End a rollback-only transaction rather than continuing work. Open TRANSACTION cursors can block COMMIT and ROLLBACK. Currently, commits across TRANSACTION tables are applied sequentially to each table's storage handle. Support for normal multi-table COMMIT/ROLLBACK does not guarantee multi-table atomicity when a failure occurs during commit. After an error or a lost response, verify persisted state using a business key. A WAL conflict when upgrading an obsolete read snapshot to a write cannot be resolved by waiting, even with TRANSACTION_BUSY_TIMEOUT_MS=-1. See the [transaction exercise](../../../rdb-table-usage/transaction/) and [two-connection conflict exercise](../../../rdb-table-usage/locking-conflict-timeout/). ## Related Documentation - [Using TRANSACTION Tables](../../../rdb-table-usage/) - [TRANSACTION DDL and DML](../../sql/syntax/) - [SDK Feature Support](../../../development-tools-integration/sdk-support-scope/) --- title: "16.6.4 TAG Data UPDATE Support" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/tag-data-update/ language: en kind: page --- # 16.6.4 TAG Data UPDATE Support Modify the actual time-series data in TAG tables with `UPDATE table_name SET ... WHERE ...`. This page lists allowed WHERE predicates and SET targets for TAG data UPDATE. Use the separate `UPDATE ... METADATA` syntax to modify metadata. Available since Machbase 8.7.0 TAG data UPDATE is supported only on logical TAG tables in Standard Edition. Cluster Edition and direct UPDATE on internal raw component tables are not supported. ## WHERE Predicate Support TAG data UPDATE requires one tag selection predicate and one or more BASETIME axis predicates. | WHERE Predicate | Support | Notes | |-----------|:---:|------| | `name = 'tag-01'` | O | Select one tag | | `name = ?`, `name = :tag_name` | O | Select one tag with a positional/named bind | | `? = name`, `:tag_name = name` | O | Reversed equality is supported; column-on-left form is recommended | | `name IN ('tag-01', 'tag-02')` | O | Literal/bind lists supported; subquery `IN` is not supported | | `name LIKE 'tag-%'` | O | Expand to tags matching the pattern | | `time = t1` | O | BASETIME equality predicate | | `time = ?`, `time = :base_time` | O | Specify base time with a positional/named bind | | `? = time`, `:base_time = time` | O | Reversed equality supported | | `time BETWEEN t1 AND t2` | O | Both endpoints inclusive | | `time >= t1 AND time < t2` | O | Combinations of `>`, `>=`, `<`, and `<=` supported | | `time >= ? AND time < ?` | O | Bind markers supported for range bounds | | One-sided time predicate | O | For example, `time >= t1` | | Data column predicate | O | For example, `value > 100`, combined with tag/time predicates | | UPDATE without predicates | X | Updating all TAG data is not allowed | | Time predicate without tag selection | X | Target tags must be specified | | Tag predicate without a time predicate | X | A BASETIME range must be specified | | `OR` predicate | X | Not allowed in TAG data UPDATE predicates | | Subquery/aggregate expression | X | Cannot determine UPDATE targets | | Tag/axis columns wrapped in functions or expressions | X | Tag selectors and BASETIME predicates must reference columns directly | Bind parameters replace values only. They do not change the required tag and BASETIME predicates, allowed predicate structure, or SET targets. Reexecuting a prepared statement selects targets using the latest bind values. If no rows match, it succeeds with `0` affected rows. ## SET Target Support | SET Target | Support | Notes | |---------|:---:|------| | Data column | O | User data columns such as `value` and auxiliary columns | | `SUMMARIZED` data column | O | Updates original TAG data | | Multiple data columns | O | Can be specified in the same UPDATE | | `name` (PRIMARY KEY) | X | Tag names cannot be changed | | `time` (BASETIME) | X | The time axis column cannot be changed | | Metadata column | X | Use `UPDATE table_name METADATA SET ...` | | Hidden/system column | X | Internal columns cannot be UPDATE targets | SET expressions may use constants, bind variables, arithmetic, functions, `CASE`, and string concatenation without existing row column references, and NULL if column constraints allow it. SET right-hand expressions cannot reference existing row columns, subqueries, or aggregates. ## Canonical References For execution syntax and parameter metadata, see [TAG Data UPDATE](../../sql/syntax/dml-syntax/tag-data-update-syntax/#tag-data-update-predicate-bind). For marker APIs by SDK, see [Named Bind Parameters](../../sql/syntax/named-bind-parameter-syntax/). For diagnosis, see [TAG Constraints and Troubleshooting](../../../tag-table-usage/constraints-errors-troubleshooting/). --- title: "16.6.5 LOOKUP SQL/JSON Support" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/lookup-sql-json/ language: en kind: page --- # 16.6.5 LOOKUP SQL/JSON Support This page lists LOOKUP table SQL features and JSON constraints. ## Feature Support | Feature | Support | Notes | |------|:---:|------| | **Basic CRUD** | | | | INSERT | O | Ordinary INSERT | | SELECT | O | Primary key and general predicates are supported | | UPDATE (PK predicate) | O | Uses the primary key fast path | | DELETE (PK predicate) | O | Uses the primary key fast path | | UPDATE (general predicate) | O | Collects matching primary keys, then updates rows | | DELETE (general predicate) | O | Collects matching primary keys, then deletes rows | | **JSON Features** | | | | JSON columns | O | Create, store, query, and update ordinary columns | | JSON path query (`$.key`) | O | Supports `->`, `JSON_EXTRACT_*`, `JSON_TYPEOF`, and `JSON_IS_VALID` | | JSON PK | X | JSON columns cannot be primary keys | | JSON path index | X | Separate JSON path indexes are not supported | | **Other Features** | | | | Explicit transactions (`BEGIN`/`COMMIT`/`ROLLBACK`) | X | DML is applied per statement; multiple statements cannot be rolled back together | | Prepared Statement | O | Parameter binding for primary key and general predicates | | Append API | △ | Ordinary SQL INSERT is the default; Append follows a separate LOOKUP append policy | ## Canonical References For LOOKUP JSON schemas and examples, see [JSON Columns and Queries](../../../lookup-table-usage/json-column-query/). For UPDATE/DELETE syntax, see [DML Syntax](../../sql/syntax/dml-syntax/). --- title: "16.6.6 ROLLUP Support" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/rollup/ language: en kind: page --- # 16.6.6 ROLLUP Support ## Edition and Table Scope | Feature | Standard | Cluster | |---|:---:|:---:| | Create, query, and control ordinary, conditional, and extended ROLLUPs on time-axis TAG tables | O | O | | Automatic creation with WITH ROLLUP | O | O | | Supported JSON path and whole-document aggregation | O | O | | Custom INTO...AS | O | X | | ROLLUP_REBUILD | Supported for limited targets and arguments | X | Time-axis ROLLUP does not apply to distance-axis TAG, LOG, TRANSACTION, VOLATILE, or LOOKUP tables. In Cluster Edition, check status by relevant node and hierarchy level. ## Creation Types and Columns | Type | Requirements | |---|---| | Ordinary numeric | Supported numeric DATA column; SUMMARIZED is not required for explicit creation | | JSON path | JSON DATA column and a numeric path to aggregate | | Whole JSON document | JSON SUMMARIZED column | | WITH ROLLUP | Third SUMMARIZED column of a time-axis TAG table | | FROM hierarchy | A larger integer-multiple interval with matching extension and mode conditions | | Custom | One source time-axis TAG table and a precreated compatible target TAG table | ## Aggregation and Selection Ordinary numeric ROLLUP provides MIN/MAX/SUM/COUNT/AVG/SUMSQ; extended ROLLUP also provides FIRST/LAST. Users must reaggregate partial Custom results. Combine averages using sums and valid counts, and preserve corresponding timestamps when combining FIRST/LAST. Whole-document JSON COUNT is the stored aggregate count and need not equal the original COUNT(value). Candidate selection depends on predicates, columns, paths, mode, and interval. Do not infer priority from ordinary/extended status alone or assume a 24 HOUR ROLLUP automatically applies to daily buckets. Check the [query rules](../../../tag-rollup-usage/query-syntax-rollup/). ## REBUILD Scope Differs from Creation Scope REBUILD targets complete automatic SEC/MIN/HOUR hierarchies and supported Custom paths. It cannot rebuild every configuration that can be created, such as arbitrary manual names, partial automatic hierarchies, or 10 MIN Custom rollups. Custom time-boundary processing currently supports 1 SEC, 1 MIN, and 1 HOUR and must match SELECT buckets. For constant time arguments, expansion to whole buckets, state transitions, and checks after errors, follow the [REBUILD Reference](../../sql/syntax/rollup-rebuild-syntax/). ## Privileges Grant the operational account database access and required creation, deletion, and query privileges. The following example grants create/drop privileges to an existing account; it does not configure every required privilege in one script. ```sql GRANT CREATE, DROP ON DATABASE MACHBASEDB TO rollup_user; ``` Check ownership and operation scope in [Privilege Management](../../../security-access-control/privileges/). --- title: "16.6.7 Feature Support by Privilege" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/privileges/ language: en kind: page --- # 16.6.7 Feature Support by Privilege Machbase privileges are divided into **database privileges** and **table privileges** by scope. ## Database Privileges Database privileges apply to the specified active database. Grant `MOUNT` on `MACHBASEDB`. Grant `USAGE` and table `SELECT` separately for access to mounted databases. | Privilege | Allowed Operations | Granted by Default | |------|-------------|:--------:| | `CONNECT` | Connect to an active database, `USE`, and discover objects | O (MACHBASEDB compatibility) | | `CREATE` | Create tables, views, indexes, rollups, tablespaces, and retention policies | O | | `DROP` | Drop tables, views, indexes, rollups, tablespaces, and retention policies | O | | `ALTER` | Change table structure and execute `ALTER SYSTEM` | X | | `BACKUP` | Execute `BACKUP DATABASE` | X | | `MOUNT` | Execute `MOUNT DATABASE` / `UMOUNT DATABASE` | X | | `USAGE` | Discover objects in mounted databases | X | | `DDL` | CREATE + DROP (composite privilege) | — | | `ALL` | Grant CONNECT, CREATE, DROP, ALTER, and BACKUP together | — | > “Granted by default: O” means compatibility defaults on `MACHBASEDB` for users created with `CREATE USER`. > Grant privileges on other logical databases separately. ## Table Privileges Table privileges control DML on a specific table. | Privilege | Allowed Operations | |------|-------------| | `SELECT` | SELECT from the table | | `INSERT` | INSERT into the table | | `DELETE` | DELETE from the table | | `UPDATE` | UPDATE the table | ## GRANT / REVOKE Syntax ```sql -- Grant database privileges GRANT CONNECT ON DATABASE factory_a TO app_user; GRANT CREATE ON DATABASE factory_a TO app_user; GRANT BACKUP ON DATABASE factory_a TO backup_user; GRANT ALL ON DATABASE factory_a TO admin_user; -- Grant table privileges GRANT SELECT ON sys.sensor_data TO reader_user; GRANT INSERT ON sys.sensor_data TO writer_user; -- Revoke privileges REVOKE SELECT ON sys.sensor_data FROM reader_user; REVOKE BACKUP ON DATABASE factory_a FROM backup_user; ``` ## Privileges for Common Operations | Operation | Privilege Scope | Required Privilege | |------|-------------|---------| | `CREATE TABLE` | Database | CREATE | | `DROP TABLE` | Database | DROP | | `ALTER TABLE` | Database | ALTER | | `BACKUP DATABASE` | Database | BACKUP | | `MOUNT DATABASE` | Database | MOUNT | | Table SELECT | Table | SELECT | | Table INSERT | Table | INSERT | | Table UPDATE | Table | UPDATE | | Table DELETE | Table | DELETE | ## Checking Privileges ```sql -- List users SELECT user_name, user_id FROM m$sys_users; -- Query database privileges SELECT * FROM m$sys_grant_databases WHERE grantee = 'APP_USER'; -- Query table privileges SELECT * FROM m$sys_grant_tables WHERE grantee = 'APP_USER'; ``` ## Detailed Reference For the complete privilege model and examples, see [Privilege Management](/dbms/security-access-control/privileges/). --- title: "16.6.8 Backup/Mount Support" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/backup-mount/ language: en kind: page --- # 16.6.8 Backup/Mount Support Backup saves data to files. Mount connects saved backup files to the database for querying. ## Support by Edition | Feature | Standard | Cluster | Notes | |------|:--------:|:-------:|------| | Multiple logical databases | O | X | Standard Edition only | | BACKUP DATABASE | O | O | Back up an entire database | | BACKUP TABLE | O | O | Back up a specific table | | MOUNT DATABASE | O | X | Not supported in Cluster Edition | | UMOUNT DATABASE | O | X | Not supported in Cluster Edition | | machadmin -r restore | O | X | Not supported in Cluster Edition | `BACKUP DATABASE database_name INTO DISK` backs up one active logical database. A full-instance image containing multiple active databases cannot be used as input to logical `MOUNT` or `RESTORE DATABASE`. Querying a mounted database requires `USAGE` and table `SELECT`. `USE` and writes are not supported. ## Backup Support by Table Type | Table Type | BACKUP | Query After MOUNT | Notes | |------------|:-----------:|:------------:|------| | TAG tables | O | O | | | LOG tables | O | O | | | LOOKUP tables | O | O | | | TRANSACTION tables | O | O | | | VOLATILE tables | X | X | In-memory data cannot be backed up | ## Canonical References - Syntax: [BACKUP · RESTORE · MOUNT](../../sql/syntax/backup-restore-mount-syntax/) - Operations: [Backup, Restore, and Mount](../../../operations-configuration-recovery/backup-restore-mount/) --- title: "16.6.9 Server and SDK Compatibility" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/compatibility-xma-protocol/ language: en kind: page --- # 16.6.9 Server and SDK Compatibility When Machbase server and SDK versions differ, basic connections may work while newer authentication, metadata, and named bind parameter features remain limited. This section describes support by server/SDK version combination and upgrade order. ## Server and SDK Compatibility Matrix | Server Version | 8.5 Client Driver | 8.7.0 Client Driver | |-----------|:---------------------:|:---------------------:| | **8.7.0 server** | Limited compatibility | Full compatibility | | **8.5 server** | Full compatibility | Backward compatible; 8.7.0 named APIs unavailable | - **Full compatibility**: Matching versions. Actual feature availability depends on edition, table type, SDK support, and use of a build containing the feature. - **Limited compatibility**: Basic connections work, but new 8.7.0 features such as AUTH KEY extensions may be unavailable. - **Backward compatible**: Only features within the 8.5 server's scope are available. ## Main Changes in the Machbase 8.7.0 SDKs ### AUTH KEY Authentication Extensions 8.7.0 extends AUTH KEY challenge authentication. - Supported signature schemes: `ECDSA`, `RSA_PKCS1_V15`, `RSA_PSS` - Drivers at 8.5 or earlier may not support the new `RSA_PSS` signature scheme. - Update drivers to 8.7.0 when using AUTH KEY authentication. ```text -- Register an AUTH KEY on the server ALTER USER app_user ADD AUTH KEY ( KEY='-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n', VALID_BEFORE='2047-12-31' ); ``` ### Connection String Compatibility AUTH KEY parameters for Machbase SQLCLI and ODBC: ```ini AUTH_MODE=CHALLENGE; AUTH_KEY_FILE=./private_key.pem; AUTH_SIG_SCHEME=ECDSA; ``` 8.5 drivers may ignore `AUTH_SIG_SCHEME`. ### Nullable Metadata For APIs that report whether result columns allow NULL and constraints by server/SDK combination, see [Nullable Metadata Support](/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-nullable-metadata). Record both server and client versions when checking compatibility. ### Named Bind Parameter Whether named parameters are sent to a server-prepared statement, bound positionally, or converted into SQL text on the client depends on the SDK. Check the client's behavior in [SDK Feature Support](/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-transaction-prepare-bind). ### ARRAY and Selected-column Append Fixed-length numeric ARRAYs and selected-column Append are supported in Machbase DBMS 8.7.0. Use a DBMS 8.7.0 server with an SDK build containing ARRAY support. Older servers or SDKs without this feature do not substitute legacy scalar types for ARRAY metadata or values; they reject such requests with an error. SQL ARRAY element positions and Machbase-specific SDK positions are 0-based. Decrement positions in legacy 1-based SQL, sparse objects, and indexed Append targets by one. Stored data and dense ARRAY element order are unchanged. Positions defined as 1-based by standard APIs, such as JDBC parameter ordinals or `java.sql.Array` slices, are unaffected. In Cluster Edition, all Coordinators, Brokers, and Warehouses must use the same ARRAY-capable DBMS 8.7.0 build. Do not start ARRAY DDL or operations using ARRAY data while versions are mixed. For SQL and SDK requirements, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/) and [Sparse ARRAY and Selected-column Append APIs](/dbms/development-tools-integration/data-input-load-export/array-append/). ## Checking SDK Versions JDBC: ```java Connection conn = DriverManager.getConnection(url, props); DatabaseMetaData meta = conn.getMetaData(); System.out.println("Driver: " + meta.getDriverVersion()); ``` Machbase SQLCLI: ```c SQLGetInfo(conn, SQL_DRIVER_VER, buf, sizeof(buf), NULL); ``` ODBC: ```c SQLGetInfo(conn, SQL_DRIVER_VER, buf, sizeof(buf), NULL); ``` ## Upgrade Recommendations 1. Upgrade the server and SDKs together to the same version (8.7.0). 2. During a phased SDK upgrade, remember that 8.5 SDK connections to 8.7.0 servers have limited compatibility. 3. When using AUTH KEY authentication, upgrade SDKs first. 4. If application logic depends on nullable metadata, upgrade both the server and SDKs to 8.7.0. 5. If using SDK APIs that bind parameters by name, upgrade both the server and SDKs to 8.7.0. 6. If using ARRAY or selected-column Append, upgrade the server to Machbase DBMS 8.7.0 and clients to SDK builds containing those features. In Cluster Edition, align all nodes. --- title: "16.6.10 Version and Compatibility" url: https://docs.machbase.com/dbms/reference/support-scope-constraints/compatibility-version/ language: en kind: page --- # 16.6.10 Version and Compatibility This page covers Machbase 8.7.0 backward compatibility, upgrade considerations, and supported operating systems/platforms. ## 8.7.0 Backward Compatibility ### Client Driver Compatibility | Server Version | 8.5 Client Driver | 8.7.0 Client Driver | |-----------|:---------------------:|:---------------------:| | 8.7.0 server | Limited compatibility | Full compatibility | | 8.5 server | Full compatibility | Backward compatible | - With an 8.5 client driver, some new features of an 8.7.0 server may be unavailable. - Older server or driver combinations may return legacy or indeterminate nullable metadata. Applications that depend on this metadata must upgrade both the server and SDK to 8.7.0. - SQL using all CAST target types and length/precision options requires an 8.7.0 server. Conversion of an entire numeric ARRAY to another type with the same cardinality through `CAST(array_expression AS TYPE[N])` is also available from this version. In Cluster Edition, all nodes must run the same version with CAST and ARRAY support. For syntax and conversion rules, see the [CAST Function](/dbms/reference/sql/functions/functions-full/#cast). - 8.7.0 servers support `CREATE INDEX IF NOT EXISTS`. If the same index name already exists for the same database and owner, it succeeds while retaining the existing definition. Verify actual index mappings after repeated deployments. Older servers do not support this syntax. For details, see [INDEX Syntax](/dbms/reference/sql/syntax/index-syntax/#create-index-if-not-exists). - 8.7.0 Standard Edition servers support positional and named bind parameters for NAME and BASETIME predicate values in TAG data UPDATE. Older servers may reject the same prepared UPDATE with `ERR-02190`. For predicate forms and SDK APIs, see [TAG Data UPDATE Bind Parameters](/dbms/reference/sql/syntax/dml-syntax/tag-data-update-syntax/#tag-data-update-predicate-bind). - BASE DISTANCE TAG statistics views on 8.7.0 servers expose axis columns with `*_DISTANCE` names and their original `DOUBLE`, `LONG`, or `ULONG` types. Legacy `*_TIME` names are not provided as aliases. Existing tables also use the new schema after a server restart. The BASE TIME TAG `*_TIME DATETIME` schema is unchanged. Update application SQL and result mappings using the conversion table in [Per-tag Statistics Views](/dbms/tag-table-usage/query-analysis/#tag-stat-axis-schema). - In 8.7.0 Standard Edition, SELECT/JOIN plan improvements may change table scan order and unordered result order compared with older versions. Use `ORDER BY` when order matters. After upgrading, verify both results and execution plans using the procedure in [SELECT/JOIN Optimizer](/dbms/performance-tuning/performance-query-tuning/#select-join-optimizer). - With multi-host URLs, the 8.7.0 JDBC driver tries the next host after a connection-stage I/O error. If an older driver terminates on certain socket errors at the first host, replace it with the 8.7.0 JDBC driver and check the URL and timeout settings in [Multi-host Connections](/dbms/development-tools-integration/jdbc/#jdbc-multi-host). - Machbase DBMS 8.7.0 supports fixed-length numeric ARRAYs and selected-column Append. Applications using ARRAYs must pair a DBMS 8.7.0 server with an SDK build containing the feature. Upgrade all Cluster Edition nodes together. For SQL and API details, see [Numeric ARRAY Types](/dbms/reference/sql/types/array/) and [Sparse ARRAY and Selected-column Append APIs](/dbms/development-tools-integration/data-input-load-export/array-append/). - ARRAY columns support `ADD COLUMN` and `DROP COLUMN` in Standard Edition LOG, VOLATILE, LOOKUP, TRANSACTION, and TAG METADATA, and in Cluster Edition LOG tables. For differences in DEFAULT application to existing rows by table type, see [DDL Syntax](/dbms/reference/sql/syntax/ddl-syntax/#add-column). - Public ARRAY positions are 0-based. Code using the initial 1-based ARRAY SQL, sparse objects, or indexed Append targets must decrement each position by one. Stored ARRAY data and dense element order are unchanged, so data migration is unnecessary. - For feature differences by server/SDK combination, see [Server and SDK Compatibility](../compatibility-xma-protocol/). ### Features Removed in 8.7.0 Machbase 8.7.0 does not provide the following features or interfaces. There is no compatibility layer for removed settings, SQL, or C APIs. Update configuration files, operational SQL, and applications before upgrading. | 8.5 Feature or Interface | 8.7.0 Status | User Impact | Migration | |--------------------------|------------|-------------|-----------| | DB HTTP/REST (`/machbase`, `/machiot`, port 5657) | Removed | Existing HTTP query and Append requests are unavailable | Use SQLCLI, ODBC, JDBC, Python, Go, Node.js, or .NET SDKs | | WebAdmin/MWA, static ClusterAdmin UI | Removed | Web UIs and associated startup scripts are unavailable | Use server and cluster command-line tools | | STREAM SQL and catalogs | Removed | Registered STREAMs cannot run or expose status | Use Fluentd or application jobs | | Result Cache | Removed | Result cache settings, status queries, and flush commands are unavailable | Use indexes, ROLLUP, query optimization, or application caches | | `machcli.h` and `MachCLI*()` | Removed | Existing C/C++ source and binaries cannot be used unchanged | Migrate to Machbase SQLCLI or ODBC | The following similarly named features remain supported. | Retained Feature | Description | |-----------|------| | Machbase SQLCLI | `SQL*` APIs in ``. This API set is separate from ODBC. | | ODBC, JDBC, and language SDKs | Supported drivers, including Python, Go, Node.js, and .NET, remain available. | | MachEngine API | Existing `Mach*` APIs remain available. | | PVO Cache | Reuses execution plan objects; it is distinct from the removed Result Cache. | | Coordinator administration REST | Administration API, separate from data SQL REST. The Coordinator `/admin/` path remains available. | #### Clean Up Configuration Before Upgrading If the following properties remain in the 8.7.0 `machbase.conf`, they are treated as unknown properties and prevent server startup. Remove them all before replacing the binaries. ```text HTTP_AUTH HTTP_ENABLE HTTP_MAX_MEM HTTP_PORT_NO RS_CACHE_APPROXIMATE_RESULT_ENABLE RS_CACHE_ENABLE RS_CACHE_MAX_MEMORY_PER_QUERY RS_CACHE_MAX_MEMORY_SIZE RS_CACHE_MAX_RECORD_PER_QUERY RS_CACHE_TIME_BOUND_MSEC STREAM_THREAD_COUNT STREAM_WAIT_MS ``` If existing STREAM definitions are needed, record `V$STREAMS` and the associated SQL before stopping the 8.5 server. In 8.7.0, `SYS_STREAM_STMTS`, `V$STREAMS`, `V$HTTP_STATUS`, `V$RS_CACHE_LIST`, and `V$RS_CACHE_STAT` are not registered. After upgrading, verify that each query below returns `0`. ```sql SELECT COUNT(*) AS removed_property_count FROM V$PROPERTY WHERE NAME IN ( 'HTTP_AUTH', 'HTTP_ENABLE', 'HTTP_MAX_MEM', 'HTTP_PORT_NO', 'RS_CACHE_APPROXIMATE_RESULT_ENABLE', 'RS_CACHE_ENABLE', 'RS_CACHE_MAX_MEMORY_PER_QUERY', 'RS_CACHE_MAX_MEMORY_SIZE', 'RS_CACHE_MAX_RECORD_PER_QUERY', 'RS_CACHE_TIME_BOUND_MSEC', 'STREAM_THREAD_COUNT', 'STREAM_WAIT_MS' ); SELECT COUNT(*) AS removed_table_count FROM V$TABLES WHERE NAME IN ( 'SYS_STREAM_STMTS', 'V$HTTP_STATUS', 'V$RS_CACHE_LIST', 'V$RS_CACHE_STAT', 'V$STREAMS' ); ``` ### DDL Concurrency Compatibility Machbase 8.7.0 uses different DDL concurrency policies by edition. | Edition | 8.7.0 Behavior | `DDL_LOCK_TIMEOUT` | |---------|------------|--------------------| | Standard | DDL on independent objects can run concurrently | Available. Default: `0` (NOWAIT) | | Cluster | Retains the existing catalog-wide DDL policy | Not available | In Standard Edition, conflicting DDL on the same or directly related objects returns `ERR-02031: Resource busy ()` immediately by default. Deployment scripts that assume older waiting behavior must explicitly adopt an appropriate approach after upgrading. - Set a bounded wait in the deployment session with `ALTER SESSION SET DDL_LOCK_TIMEOUT = seconds`. - Apply bounded retries and wait intervals only to `ERR-02031`. - Recheck object state before retrying. Do not retry `already exists`, privilege, or syntax errors. For conflict relationships and configuration, see [DDL Concurrency and Locks](/dbms/reference/sql/syntax/ddl-syntax/#ddl-concurrency). ### Backup File Compatibility | Backup Version | Restore in 8.7.0 | Notes | |--------------|:-----------:|------| | 8.5 backup | O | Use `MOUNT` or `machadmin -r` | | 8.7.0 backup | O | | | 8.4 or earlier backup | △ | Version-dependent; testing required | ## Canonical Upgrade Reference For execution order, supported platforms, and prechecks, see [Upgrade](../../../installation-deployment-upgrade/upgrade/). This page maintains SQL, server, and client compatibility facts only. --- title: "16.7 Error Code Dictionary" url: https://docs.machbase.com/dbms/reference/error-codes/ language: en kind: page --- # 16.7 Error Code Dictionary Machbase errors appear in machsql, driver exceptions, and server trace logs. This page provides common errors and the complete error message catalog for Machbase 8.7.0. Depending on the execution path, errors appear as strings such as `ERR-02010: ...` or as driver-specific exceptions. Message wording may change as the product evolves. Applications should handle errors by code rather than message text. ## SQL Parser and Function Errors | Code | Message | Common Cause | |------|--------|-----------| | `ERR-02009` | `Insufficient parser memory.` | Insufficient SQL parser memory | | `ERR-02010` | `Syntax error: near token (%s).` | SQL syntax error | | `ERR-02011` | `Unrecognized token (%s).` | Unrecognized token | | `ERR-02034` | `Invalid format of time expression.` | Invalid time expression format | | `ERR-02035` | `Function [%s] does not exist.` | Call to a nonexistent function | | `ERR-02036` | `Function [%s] has an invalid argument.` | Invalid function argument count or value | | `ERR-02037` | `Function [%s] argument data type does not match.` | Function argument type mismatch | | `ERR-02040` | `Invalid time range.` | Time range is not allowed | ## Table, Column, and Input Data Errors | Code | Message | Common Cause | |------|--------|-----------| | `ERR-02014` | `Column name is duplicated: (%s).` | Duplicate column name | | `ERR-02015` | `Invalid column type: (%s).` | Unsupported column type | | `ERR-02024` | `Table %s already exists.` | A table with the same name already exists | | `ERR-02025` | `Table %s does not exist.` | Target table does not exist | | `ERR-02026` | `The number of insert values and that of columns are mismatched.` | INSERT column and value counts differ | | `ERR-02030` | `Column name (%s) does not exist.` | Nonexistent column | ## System Resource Errors | Code | Message | Common Cause | |------|--------|-----------| | `ERR-01007` | `There is no available disk space for writing <%lld>bytes to the file<%s>, errno = %d.` | Insufficient disk space for data files | | `ERR-01346` | `Current Allocate Memory / PROCESS_MAX_SIZE (%llu/%llu), increase PROCESS_MAX_SIZE property and restart.` | `PROCESS_MAX_SIZE` limit exceeded | ## Using the Complete Catalog The catalog below lists the product's original English error messages. `KEY` identifies each error in the source code. Placeholders such as `%s`, `%d`, and `%llu` are replaced with actual object names or numeric values when an error occurs. Account for placeholder differences when comparing messages, and search by `ERR-xxxxx` code whenever possible. The catalog is divided into ranges of 1,000 on this page. Use browser search to find an error code, symbol, or part of a message. If the message does not establish the cause or whether retrying is appropriate, also check [Troubleshooting](/dbms/troubleshooting/) and the constraints documented for the feature. ## Complete Error Messages The following 1,062 entries are from the Machbase 8.7.0 NFX error catalog, excluding entries for removed features. ### `ERR-00000`–`ERR-00999` (157) | Code | Symbol | Original Message | |------|------|------| | ERR-00001 | ERR_FILE_CREATE | Failed to create file<%s>, errno = %d. | | ERR-00002 | ERR_FILE_TRUNCATE | Failed to truncate file<%s>, errno = %d. | | ERR-00003 | ERR_FILE_DUP | Failed to duplicate file<%s>, errno = %d. | | ERR-00004 | ERR_FILE_COPY | Failed to copy file<%s> to file<%s>, errno = %d. | | ERR-00005 | ERR_FILE_RENAME | Failed to rename file<%s> to file<%s>, errno = %d. | | ERR-00006 | ERR_FILE_REMOVE | Failed to remove file<%s>, errno = %d. | | ERR-00007 | ERR_FILE_GETKEY | Failed to get key file<%s>, errno = %d. | | ERR-00008 | ERR_FILE_PIPE | Failed to create pipe<%s>, errno = %d. | | ERR-00009 | ERR_FILE_STAT | Failed to stat file<%s>, errno = %d. | | ERR-00010 | ERR_FILE_OPEN | Failed to open file<%s>, errno = %d. | | ERR-00011 | ERR_FILE_CLOSE | Failed to close file<%s>, errno = %d. | | ERR-00012 | ERR_FILE_SEEK | Failed to seek file<%s>, offset:%lld, Whence:%d, errno = %d. | | ERR-00013 | ERR_FILE_READ | Failed to read file<%s>, size:%llu, errno = %d. | | ERR-00014 | ERR_FILE_WRITE | Failed to write file<%s>, size:%llu, errno = %d. | | ERR-00015 | ERR_FILE_READ_SIZE | Failed to read file<%s> (offset:%llu, req size:%llu, read size: %llu), errno = %d. | | ERR-00016 | ERR_FILE_WRITE_SIZE | Failed to write file<%s> (offset:%llu, req size:%llu, read size: %llu), errno = %d. | | ERR-00017 | ERR_FILE_SYNC | Failed to sync file<%s>, errno = %d. | | ERR-00018 | ERR_FILE_LOCK | Failed to lock file<%s>, errno = %d. | | ERR-00019 | ERR_FILE_TRYLOCK | Failed to trylock file<%s>, errno = %d. | | ERR-00020 | ERR_FILE_UNLOCK | Failed to unlock file<%s>, errno = %d. | | ERR-00021 | ERR_FILE_NO_EXTENSION | There is no file extension. | | ERR-00022 | ERR_FILE_RENAME_RETRY | Failed to rename file<%s> to file<%s>, retry count<%d>, msec<%d>, errno = %d. | | ERR-00031 | ERR_STRING_SNPRINTF | Error occurred during snprintf: buffer size<%d>, errno = %d. | | ERR-00061 | ERR_ENV_GET | Failed to getenv variable<%s>, errno = %d. | | ERR-00062 | ERR_ENV_SET | Failed to setenv variable<%s> to value<%s>, errno = %d. | | ERR-00067 | ERR_DIR_OPEN | Failed to opendir <%s>, errno = %d. | | ERR-00068 | ERR_DIR_CLOSE | Failed to closedir, errno = %d. | | ERR-00069 | ERR_DIR_READ | Failed to readdir, errno = %d. | | ERR-00070 | ERR_DIR_REWIND | Failed to rewinddir, errno = %d. | | ERR-00071 | ERR_DIR_MAKE | Failed to makedir <%s>, errno = %d. | | ERR-00072 | ERR_DIR_REMOVE | Failed to removedir, errno = %d. | | ERR-00073 | ERR_DIR_SETCWD | Failed to setcwd, errno = %d. | | ERR-00074 | ERR_DIR_GETCWD | Failed to getcwd, errno = %d. | | ERR-00075 | ERR_DIR_GETHOME | Failed to gethome, errno = %d. | | ERR-00076 | ERR_DIR_PATH_TOO_LONG1 | Path<%s> is too long, errno = %d. | | ERR-00077 | ERR_DIR_PATH_TOO_LONG2 | Path<%s/%s> is too long, errno = %d. | | ERR-00078 | ERR_DIR_PATH_TOO_LONG3 | Path<%s/%s/%s> is too long, errno = %d. | | ERR-00079 | ERR_DIR_NOT_EXIST | The directory does not exist in this path<%s>, errno = %d. | | ERR-00080 | ERR_DIR_REMOVE_WITH_INFO | Failed to call removedir (%s), errno = %d. | | ERR-00091 | ULL_ERR_PMD_SQLITE3_ERROR | %1$s failed: [%2$d: %3$s]. | | ERR-00092 | ULL_ERR_PMD_SQLITE3_DISK_FULL | %1$s failed because the metadata store is full: [%2$d: %3$s]. | | ERR-00121 | ERR_STACK_CREATE | Stack create failed, errno = %d. | | ERR-00122 | ERR_STACK_PUSH | Stack push failed, errno = %d. | | ERR-00123 | ERR_STACK_POP | Stack pop failed, errno = %d. | | ERR-00131 | ERR_MEMORY_ALLOC | Failed to allocate memory(%lu bytes), errno = %d. | | ERR-00132 | ERR_MEMORY_ALLOC_BOUND | Memory allocation error (alloc'd: %llu, max: %llu). | | ERR-00133 | ERR_PM_PROCESS_MEMORY_LIMIT | Failed to allocate memory (ID = %d) (Request Size = %llu) : (Current Allocated Size / PROCESS_MAX_SIZE (%llu/%llu)). | | ERR-00141 | ERR_MEMPOOL_CREATE | Failed to create memory pool, errno = %d. | | ERR-00142 | ERR_MEMPOOL_ALLOC | Failed to allocate memory from memory pool, errno = %d. | | ERR-00151 | ERR_MUTEX_CREATE | Failed to create mutex, errno = %d. | | ERR-00152 | ERR_MUTEX_DESTROY | Failed to destroy mutex, errno = %d. | | ERR-00153 | ERR_MUTEX_LOCK | Failed to lock mutex, errno = %d. | | ERR-00154 | ERR_MUTEX_TRYLOCK | Failed to trylock mutex, errno = %d. | | ERR-00155 | ERR_MUTEX_UNLOCK | Failed to unlock mutex, errno = %d. | | ERR-00161 | ERR_QUEUE_CREATE | Failed to create queue, errno = %d. | | ERR-00162 | ERR_QUEUE_DESTROY | Failed to destroy queue, errno = %d. | | ERR-00163 | ERR_QUEUE_ENQUEUE | Failed to enqueue queue, errno = %d. | | ERR-00164 | ERR_QUEUE_DEQUEUE | Failed to dequeue queue, errno = %d. | | ERR-00171 | ERR_THR_ATTR_CREATE | Failed to create thread_attr, errno = %d. | | ERR-00172 | ERR_THR_ATTR_DESTROY | Failed to destroy thread_attr, errno = %d. | | ERR-00173 | ERR_THR_ATTR_SET_BOUND | Failed to set thread_attr bound, errno = %d. | | ERR-00174 | ERR_THR_ATTR_SET_DETACH | Failed to set thread_attr detach, errno = %d. | | ERR-00175 | ERR_THR_ATTR_SET_STACK_SIZE | Failed to set thread_attr stack size, errno = %d. | | ERR-00176 | ERR_THR_CREATE | Failed to create thread, errno = %d. | | ERR-00177 | ERR_THR_DETACH | Failed to detach thread, errno = %d. | | ERR-00178 | ERR_THR_JOIN | Failed to join thread, errno = %d. | | ERR-00179 | ERR_THR_GETID | Failed to get id of thread, errno = %d. | | ERR-00191 | ERR_THR_CV_CREATE | Failed to create thread condition variable, errno = %d. | | ERR-00192 | ERR_THR_CV_DESTROY | Failed to destroy thread condition variable, errno = %d. | | ERR-00193 | ERR_THR_CV_TIMEDWAIT | Failed to call cond_timedwait, errno = %d. | | ERR-00194 | ERR_THR_CV_SIGNAL | Failed to call cond_signal, errno = %d. | | ERR-00195 | ERR_THR_CV_BROADCAST | Failed to call cond_broadcast, errno = %d. | | ERR-00196 | ERR_THR_CV_WAIT | Failed to call cond_wait, errno = %d. | | ERR-00201 | ERR_RWMUTEX_CREATE | Failed to create rwlock, errno = %d. | | ERR-00202 | ERR_RWMUTEX_DESTROY | Failed to destroy rwlock, errno = %d. | | ERR-00203 | ERR_RWMUTEX_LOCK_READ | Failed to call rwlock_lock_read, errno = %d. | | ERR-00204 | ERR_RWMUTEX_TRYLOCK_READ | Failed to call rwlock_trylock_read, errno = %d. | | ERR-00205 | ERR_RWMUTEX_LOCK_WRITE | Failed to call rwlock_lock_write, errno = %d. | | ERR-00206 | ERR_RWMUTEX_TRYLOCK_WRITE | Failed to call rwlock_trylock_write, errno = %d. | | ERR-00211 | ERR_RBTREE_TOO_SMALL_BUFFER | RBTREE buffer<%d> is too small for value<%d>, errno = %d. | | ERR-00212 | ERR_RBTREE_CURSOR_OP_NOT_APPLICABLE | RBTREE cursor op not applicable. errno = %d. | | ERR-00213 | ERR_RBTREE_ALREADY_FREE_NODE | RBTREE node is already freed, errno = %d. | | ERR-00216 | ERR_TREEMAP_KEY_EXISTS | Key already exists. | | ERR-00221 | ERR_LZO_COMPRESS | LZO compress failed, errno = %d. | | ERR-00222 | ERR_LZO_DECOMPRESS | LZO decompress failed, errno = %d. | | ERR-00231 | ERR_GET_CPU_COUNT | Failed to get CPU count, errno = %d. | | ERR-00232 | ERR_CONF_NO_FILE | Configuration file does not exist(%S). | | ERR-00251 | ERR_TLSF_MEL_INITIALIZE | Tlsf memory manager initialization failed, errno = %d. | | ERR-00252 | ERR_TLSF_MEL_FINALIZE | Tlsf memory manager finalization failed, errno = %d. | | ERR-00253 | ERR_TLSF_MEL_ALLOC | Tlsf memory manager allocation(%lld) failed, errno = %d. | | ERR-00254 | ERR_TLSF_MEL_FREE | Tlsf memory manager free failed, errno = %d. | | ERR-00255 | ERR_TLSF_MEL_CONTROL | Tlsf memory manager control failed, errno = %d. | | ERR-00256 | ERR_TLSF_MEL_SHRINK | Tlsf memory manager shrink failed, errno = %d. | | ERR-00257 | ERR_TLSF_MEL_GETSTATISTICS | Tlsf memory manager getstatistics failed, errno = %d. | | ERR-00271 | ERR_SESSION_CLOSED | The session is closed. | | ERR-00272 | ERR_SESSION_CANCELED | The session is canceled. | | ERR-00291 | ERR_LICENSE_INVALID | The license is invalid or expired. | | ERR-00292 | ERR_LICENSE_NOTEXIST_VALUE | The value<%s> does not exist in the license file. | | ERR-00293 | ERR_LICENSE_GET_HARDWARE_KEY | Failed to get hardware key, errno =%d | | ERR-00294 | ERR_LICENSE_VERIFY | Failed to verify the license, errno = %d | | ERR-00300 | ERR_INVALID_DATE_VALUE | Invalid date value.(%s) | | ERR-00301 | ERR_INVALID_NETWORK_TYPE | Invalid network string.(%s) | | ERR-00321 | ERR_SHA_SHA1_INIT_ERROR | Error in initializing sha1, errno = %d | | ERR-00322 | ERR_SHA_SHA1_UPDATE_ERROR | Error in updating sha1, errno = %d | | ERR-00323 | ERR_SHA_SHA1_FINAL_ERROR | Error in finalizing sha1, errno = %d | | ERR-00324 | ERR_SHA_INVALID_TYPE_ERROR | Invalid SHA type.(%d) | | ERR-00325 | ERR_SHA_INVALID_HEX_STRING | Invalid SHA hex string.(%s) | | ERR-00341 | ERR_PARALLEL_JOB_MANAGER_THREAD_ABNORMAL_SHUTDOWN | Parallel job thread abnormally terminated | | ERR-00342 | ERR_PARALLEL_JOB_MANAGER_INVALID_THREAD_COUNT | The thread count should be between %d and %d | | ERR-00361 | ERR_RESFILE_BUFFER_SET_LOG_ERROR | Error in setting a log to the buffer of the result file: %s, errno = %d | | ERR-00381 | ERR_PCRE_COMPILE_ERROR | Regular expression error: an error occurred at offset %d of (%s). | | ERR-00400 | ERR_VERSION_NO_META | This DB file is older than binary (no meta-version table). Check database image and binary. | | ERR-00401 | ERR_VERSION_MISMATCH | Version mismatched. In Executable DB(%d.%d) META(%d.%d) CM(%d.%d) But, In File DB(%d.%d) META(%d.%d) CM(%d.%d) | | ERR-00402 | ERR_META_VERSION_TOO_HIGH | Incompatible meta version. File Meta Version(%d.%d) is higher than Executable Version(%d.%d) | | ERR-00420 | ERR_GET_SYS_INFO | Error in getting system information by the sysinfo, errno = %d | | ERR-00421 | ERR_GET_STACK_SIZE | Error in getting stack information by the pmuSysSetStackSize, errno = %d | | ERR-00422 | ERR_SET_STACK_SIZE | Error in setting stack information by the pmuSysSetStackSize, errno = %d | | ERR-00431 | ERR_MEM_MMAP | mmap (size<%u>) error, errno = %d | | ERR-00432 | ERR_MEM_UNMMAP | unmap (address<%p>, size<%u>) error, errno = %d | | ERR-00451 | ERR_CPU_AFFINITY_SET | Failed to set the CPU affinity [%u, %u), errno = %d | | ERR-00452 | ERR_CPU_AFFINITY_INVALID_CPUID | The IDs of CPUs should be between [0, %u), but [%u, %u) given. | | ERR-00453 | ERR_CPU_AFFINITY_INVALID_CPURANGE | Maximum abs value of CPU_AFFINITY_COUNT(%d) should be less than CPU count(%u). | | ERR-00461 | ERR_SYSCONF_CPUCNT | Failed to get the number of CPUs in sysconf, errno = %d | | ERR-00471 | ERR_PM_HEAP_INIT | Failed to initialize a heap. | | ERR-00472 | ERR_PM_HEAP_PUSH | Heap push failed, errno = %d | | ERR-00481 | ERR_PM_AUTH_NONCE_GENERATE | Failed to generate auth nonce. | | ERR-00482 | ERR_PM_AUTH_SIGN | Failed to sign auth challenge. | | ERR-00483 | ERR_PM_AUTH_VERIFY | Failed to verify auth signature. | | ERR-00484 | ERR_PM_AUTH_INVALID_KEY | Invalid auth key. | | ERR-00485 | ERR_PM_AUTH_INVALID_SIG_SCHEME | Invalid auth signature scheme. | | ERR-00486 | ERR_PM_AUTH_INVALID_SIGNATURE | Invalid auth signature. | | ERR-00487 | ERR_PM_AUTH_INVALID_NONCE | Invalid auth nonce. | | ERR-00488 | ERR_PM_AUTH_KEY_FILE_TOO_LARGE | Auth key file is too large. path=[%s], size=[%llu], limit=[%llu] | | ERR-00491 | ERR_JSON_DUMP | Error in json dump. | | ERR-00492 | ERR_JSON_LOAD | Error in json load. | | ERR-00493 | ERR_JSON_OBJ | json object error: %s | | ERR-00494 | ERR_JSON_ARR | Error in json-array. | | ERR-00495 | ERR_JSON_STR | Error in json-string (%s). | | ERR-00496 | ERR_JSON_INT | Error in json-integer (%lld). | | ERR-00497 | ERR_JSON_REAL | Error in json-real (%lf). | | ERR-00498 | ERR_JSON_COPY | Error in json copy. | | ERR-00499 | ERR_JSON_PACK | Error in json pack. | | ERR-00500 | ERR_JSON_UPACK | Error in json unpack. | | ERR-00501 | ERR_JSON_EXTR_PATH | No data matches for the json path (%s) | | ERR-00502 | ERR_JSON_PATH_LEN | Json path is too long. | | ERR-00503 | ERR_JSON_OBJECT_VALUE_SET | Error json object set (%s). | | ERR-00504 | ERR_JSON_OBJECT_ARRAY_APPEND | Error json array append. | | ERR-00505 | ERR_JSON_ENCODE | Error encode base64. | | ERR-00506 | ERR_JSON_DECODE | Error decode base64. | | ERR-00507 | ERR_JSON_OBJECT_VALUE_DEL | Error json object del (%s). | | ERR-00600 | ERR_INVALID_PROPERTY_VALUE | Invalid property value: %s. | | ERR-00601 | ERR_PM_CONVERSION_UTF8 | Failed to convert %s to UTF8. (%s, errno=%d) | | ERR-00602 | ERR_PM_CONVERTSION_STRING_LENGTH | Buffer size is not enough for code conversion. (%d > %d) | | ERR-00611 | ERR_INVALID_PROPERTY_EXPRESSION | Invalid property expression for %s: %s. | | ERR-00701 | ERR_PM_GEOHASH_INVALID_PRECISION | Geohash invalid precision (%u) | | ERR-00702 | ERR_PM_GEOHASH_INVALID_LENGTH | Geohash invalid length | | ERR-00703 | ERR_PM_GEOHASH_INVALID_DIRECTION | Geohash invalid direction | ### `ERR-01000`–`ERR-01999` (191) | Code | Symbol | Original Message | |------|------|------| | ERR-01000 | ERR_SM_INVALID_DISK_FILE | File<%s> is invalid. | | ERR-01001 | ERR_SM_INVALID_OBJ_STORAGE_ID | Invalid object storage id, errno = %d. | | ERR-01002 | ERR_SM_INVALID_ALREADY_FREE_OBJECT_STORAGE | Object storage<%d> already freed, errno = %d. | | ERR-01003 | ERR_SM_DBS_DIR_ALREADY_EXIST | Group storage dir<%s> already exists, errno = %d. | | ERR-01004 | ERR_SM_DBS_INVALID_OBJECT_FILENAME | Object filename<%s> is invalid, errno = %d. | | ERR-01005 | ERR_SM_DISK_FILE_IN_USE | Disk file<%s> is in use, errno = %d. | | ERR-01006 | ERR_SM_NOT_SUPPORT_FUNCTION | Functionality is not supported yet. | | ERR-01007 | ERR_SM_FILE_NO_AVAILABLE_DISK_SPACE | There is no available disk space for writing <%lld>bytes to the file<%s>, errno = %d. | | ERR-01008 | ERR_SM_FILE_DUPLICATE | Error in the duplicating file<%s>, errno = %d. | | ERR-01009 | ERR_SM_WRONG_READ_SIZE | Error in the read file size.(<io: %u>, <disk: %u>) | | ERR-01010 | ERR_SM_SPACE_NOT_AVAILABLE_4_APPEND | Used media space is reached to threshold. (%4.1lf%% cap < %4.1lf%% used) | | ERR-01011 | ERR_SM_FILE_WRITE_SIZE_MISMATCH | Error in the write file size.(<write: %u>, <written: %u>) | | ERR-01031 | ERR_SM_DB_ALREADY_MOUNTED | The database in <%s> has already been mounted. | | ERR-01032 | ERR_SM_DB_NOT_MOUNTED | The database in <%s> is not mounted. | | ERR-01033 | ERR_SM_DB_MOUNTING | The mount operation of database in <%s> is not completed. | | ERR-01034 | ERR_SM_DB_MOUNT_BUSY | The mounted database<%s> is busy. | | ERR-01035 | ERR_SM_DB_ALREADY_EXIST | The database creation is not complete. Destroy it and create a new one. | | ERR-01036 | ERR_SM_DB_CREATE_NOT_COMPLETE | The database creation is not complete. Destroy it and create a new one. | | ERR-01037 | ERR_SM_DB_MOUNT_INVALIDE_BASEDB | The mount database<%s> is not backed up from the primary database | | ERR-01038 | ERR_SM_DB_COULD_NOT_FIND_MOUNTDB | Cannot find MountDB with <TBSID: %lld>. | | ERR-01039 | ERR_SM_DB_STATE_OF_MOUNTDB_IS_ABNORMAL | Mount DB<%s>'s state is invalid. | | ERR-01101 | ERR_SM_COLUMN_PARTITION_CACHE_READ_BLOCK | Error in reading column partition cache block. Reading block of RID<%lld> in the column partition<%lld> failed, errno = %d. | | ERR-01102 | ERR_SM_INVALID_CACHE_OBJECT | Invalid cache object. | | ERR-01103 | ERR_SM_CHECKPOINT_THREAD_ABNORMAL_SHUTDOWN | Error occurred in checkpoint thread. Processing abnormal shutdown. | | ERR-01104 | ERR_SM_CACHE_WAIT_READ_PAGE | Error in waiting to read a page. | | ERR-01105 | ERR_SM_CACHE_PAGE_CLEAR_THREAD_ABNORMAL_SHUTDOWN | Error in clear thread of the page cache. | | ERR-01106 | ERR_SM_CACHE_PAGE_MAX_SET_SMALLER_SIZE | It<%llu> is smaller than the max size value of the page cache currently set<%llu>. | | ERR-01107 | ERR_SM_CACHE_PAGE_MAX_SET_IMPOSSIBLE_SIZE | It<%llu> is impossible to set a value larger than the memory size set in the current process<%llu>. | | ERR-01108 | ERR_SM_CP_INVALID_PAGE_ID | Invalid page id in column partition. Page id<%d> is greater than the page max id<%d>. | | ERR-01201 | ERR_SM_ALREADY_EXIST_TABLE_ID_TABLES | Duplicated table id<%llu> in SYS_STORAGE_TABLES, errno = %d. | | ERR-01202 | ERR_SM_ALREADY_EXIST_TABLE_ID_COLUMNS | Duplicated table id<%llu>, column id<%u> in the SYS_STORAGE_COLUMNS, errno = %d. | | ERR-01203 | ERR_SM_NOT_EXIST_TABLE_ID_IN_TABLES | Table id<%lld> does not exist in SYS_STORAGE_TABLES, errno = %d. | | ERR-01204 | ERR_SM_ALREADY_EXIST_INDEX_ID_INDEXES | Duplicated (table id<%llu>, index id<%llu>) in SYS_STORAGE_INDEXES, errno = %d. | | ERR-01205 | ERR_SM_ALREADY_EXIST_INDEX_ID_COLUMNS | Duplicated (table id<%llu>, index id<%llu>, column id<%u>) in SYS_STORAGE_INDEXES_COLUMNS, errno = %d. | | ERR-01206 | ERR_SM_NOT_EXIST_INDEX_ID_IN_INDEXES | Index ID<%llu> of table ID<%llu> does not exist in SYS_STORAGE_INDEXES, errno = %d. | | ERR-01207 | ERR_SM_INVALID_RECOVERY_MODE_STRING | Available recovery modes: simple, complex, reset | | ERR-01301 | ERR_SM_NOT_EXIST_PARTION_RANGE | Partition range does not exist. Partition id is less than <%lld> in the table(id<%lld>) with partitions between <%lld> and <%lld>. | | ERR-01302 | ERR_SM_NOT_EXIST_RECORD_RANGE | Invalid record range. No such record whose id is less than <%llu> in the table(id<%llu>) with records between <%llu> and <%llu>. | | ERR-01303 | ERR_SM_TOO_MANY_COLUMNS_FOR_TABLE | Maximum number of columns in a table is %d. | | ERR-01304 | ERR_SM_INVALID_COLUMN_ID | Invalid column ID (<%d>). | | ERR-01305 | ERR_SM_TABLE_NOT_EXIST | Invalid table ID (<%llu>). | | ERR-01306 | ERR_SM_TABLE_ALREADY_DROPPED | Table has been dropped. | | ERR-01307 | ERR_SM_TABLE_STRUCTURE_MODIFIED | Table structure was modified. | | ERR-01308 | ERR_SM_TABLE_INVALID_FIXED_COLUMN_SIZE | Invalid fixed column size. Invalid value size(<%u>) for the fixed column. | | ERR-01309 | ERR_SM_TABLE_VAR_COLUMN_SIZE_TOO_BIG | Invalid varying column size. Value size(<%u>) for the variable column is greater than the max size (<%u>). | | ERR-01310 | ERR_SM_TABLE_FLUSH_THREAD_ABNORMAL_SHUTDOWN | Table flush thread terminated abnormally. | | ERR-01311 | ERR_SM_TABLE_COLUMN_PARTITION_PREPARE_THREAD_ABNORMAL_SHUTDOWN | Table column partition prepare thread terminated abnormally. | | ERR-01312 | ERR_SM_TABLE_COLUMN_PARTITION_FILE_READ_HEAD | Failed to read the head of the table column partition file (<%s>). | | ERR-01313 | ERR_SM_TABLE_COLUMN_PARTITION_FILE_READ | Failed to read the table column partition file (<%s>). | | ERR-01314 | ERR_SM_TABLE_INDEX_BUILD_THREAD_ABNORMAL_SHUTDOWN | Index build thread terminated abnormally. | | ERR-01315 | ERR_SM_TABLE_INVALID_TYPE | Invalid table type<%d>. | | ERR-01316 | ERR_SM_TABLE_COLUMN_SIZE_TOO_BIG | Column size<%u> is too big. | | ERR-01317 | ERR_SM_TABLE_COLUMN_INVALID_TIME_VALUE | Value of the time column(<%lld>) is less than the last time value(<%lld>). | | ERR-01318 | ERR_SM_TABLE_COLUMN_INVALID_VARCHAR_SIZE | The size of VARCHAR column must be less than (<%llu>). | | ERR-01319 | ERR_SM_TABLE_COLUMN_INVALID_VALUE_SIZE | The size of column value must be less than (<%u>). | | ERR-01320 | ERR_SM_TABLE_COLUMN_REFERENCED_BY_INDEX | There is an index on the column(<%u>) of the table(<%llu>) | | ERR-01321 | ERR_SM_TABLE_NOT_SUPPORT_FUNCTION | This feature is not supported on this table type. | | ERR-01322 | ERR_SM_TABLE_COLUMN_INVALID_NEWSIZE | The new column size(<%u>) should be greater than the old one(<%u>) | | ERR-01323 | ERR_SM_TABLE_COLUMN_MAX | The table(%llu) reached max column count limit (%u) already. | | ERR-01324 | ERR_SM_TABLE_COLUMN_PARTITION_FILE_ADJUST_END_RID | An error occurred adjusting end rid of the table<%llu> column partition(<%llu>), errno = %d. | | ERR-01325 | ERR_SM_TABLE_COLUMN_TOO_SMALL_END_RID | The end RID<%lld> of the column<%d> is less than the end RID<%llu> of the table<%llu> | | ERR-01330 | ERR_SM_TABLE_COLUMN_NOT_FOUND | The column with ID<%hu> does not exist in the table with ID<%llu> | | ERR-01331 | ERR_SM_TABLE_CHECKPOINT_THREAD_ABNORMAL_SHUTDOWN | Table checkpoint thread terminated abnormally. | | ERR-01332 | ERR_SM_TABLE_NOT_EXIST_PARTION | Partition ID <%llu> of the table(id<%llu>) does not exist between <%llu> and <%llu>. | | ERR-01333 | ERR_SM_TABLE_MOUNT_ALREADY | The table<%llu> in the backup database<%s> has been mounted already. | | ERR-01334 | ERR_SM_TABLE_MOUNT_BUSY_WITH_MOUNTING | The table is busy with mounting. | | ERR-01335 | ERR_SM_TABLE_MOUNT_BUSY_WITH_UNMOUNTING | The mounted table is busy with unmounting. | | ERR-01336 | ERR_SM_TABLE_MOUNT_INVALID_STATE | The mounted table is invalid. | | ERR-01337 | ERR_SM_TABLE_MOUNT_IS_BUSY | The mounted table is busy. | | ERR-01338 | ERR_SM_TABLE_MOUNT_NOT_EXIST | The table is not mounted. | | ERR-01339 | ERR_SM_TABLE_MOUNT_TABLE_NOT_SAME_WITH_TABLE | The table<%llu> of the backup tablespace<%s> is different from the table in main database. | | ERR-01340 | ERR_SM_TABLE_MOUNT_TABLE_DROPPED_IN_MAIN_DATABASE | The table<%llu> of the backup tablespace<%s> is dropped from the main database. | | ERR-01341 | ERR_SM_TABLE_HAS_MOUNTED_TABLE | There is a mounted table in the table<%llu>. | | ERR-01342 | ERR_SM_TABLE_MOUNT_HAS_FUTURE_DATA | The mount table<end_rid:%llu> has more furture data than the base table<end_rid:%llu. | | ERR-01343 | ERR_SM_TABLE_UPDATE_COLUMN_INDEX_CREATED | Cannot update columns with indexes in VOLATILE / LOOKUP table. | | ERR-01344 | ERR_SM_TABLE_VOLITILE_MEMORY_LIMIT | The memory size<%llu bytes> of VOLATILE / LOOKUP tables exceeds <%llu bytes>. | | ERR-01345 | ERR_SM_TABLE_COLUMN_VALUE_NOT_NULL | The value of the column<%u> must not be NULL | | ERR-01346 | ERR_SM_PROCESS_MEMORY_LIMIT | Current Allocate Memory / PROCESS_MAX_SIZE (%llu/%llu), increase PROCESS_MAX_SIZE property and restart. | | ERR-01401 | ERR_SM_INDEX_INVALID_TYPE | Invalid index type. Index type<%d> does not exist. | | ERR-01402 | ERR_SM_INDEX_NOT_EXIST_IN_TABLE | Index id(<%llu>) does not exist in table id <%llu>. | | ERR-01403 | ERR_SM_INDEX_INVALID_COLUMN_COUNT | Index has invalid column count(<%d>). | | ERR-01404 | ERR_SM_INDEX_INVALID_KEYVALUE_COUNT | Index has invalid key value count(<%d>). | | ERR-01405 | ERR_SM_INDEX_INVALID_KEYVALUE_SIZE | Index has invalid key value size(<%d>). | | ERR-01406 | ERR_SM_INDEX_INVALID_FILE | Index column file(<%s>) is invalid. | | ERR-01407 | ERR_SM_INDEX_COLUMN_PARTITION_FILE_READ_HEAD | Failed to read the head of the index column partition file(<%s>). | | ERR-01408 | ERR_SM_INDEX_COLUMN_PARTITION_FILE_READ | Failed to read the index column partition file(<%s>). | | ERR-01409 | ERR_SM_INDEX_COLUMN_INVALID_COLUMN_TYPE | Type of the column for the index is invalid. | | ERR-01410 | ERR_SM_INDEX_FLUSH_THREAD_ABNORMAL_SHUTDOWN | Index flush thread terminated abnormally. | | ERR-01411 | ERR_SM_INDEX_BUILD_THREAD_ABNORMAL_SHUTDOWN | Index build thread terminated abnormally. | | ERR-01412 | ERR_SM_KDW_INDEX_INVALID_KEY_SIZE | The keyword size<%d> should be less than the max size<%d>. | | ERR-01413 | ERR_SM_INDEX_INVALID_WORDBITCNT | The word bit count(%d) is over than %d in the partition<%lld> of the index <%lld> | | ERR-01414 | ERR_SM_INDEX_INVALID_KEYVALCNT | Invalid key count <%u> is not equal to the count <%u> in partition <%lld> of index <%lld>. | | ERR-01415 | ERR_SM_INDEX_INVALID_LEVEL | The level<%u> of the index is bigger than the max level<%u> | | ERR-01416 | ERR_SM_INDEX_INVALID_LEVEL_PART_SIZE | The partition size<%u> of level<%u> is bigger than the max level<%u> | | ERR-01417 | ERR_SM_INDEX_ALREADY_DROPPED | The index has been dropped. | | ERR-01418 | ERR_SM_INDEX_UNIQUE_VIOLATION | The key already exists in the unique index. | | ERR-01419 | ERR_SM_INDEX_PRIMARY_INDEX_ALREADY_CREATED | The primary index is already created on the table. | | ERR-01420 | ERR_SM_INDEX_INVALID_KEYVALUE_N_BITVECTOR_COUNT | The number<%llu> of key values is different from the number<%llu> of bitvectors. | | ERR-01421 | ERR_SM_INDEX_LSM_INVALID_PART_FILE | The partition file<%llu> on the level<%u> of the index<%llu> is invalid.(KPC:%u, BPC:%u) | | ERR-01422 | ERR_SM_INDEX_PRAIMARY_INDEX_NOT_NULL | NULL value is not allowed for the primary index column | | ERR-01423 | ERR_SM_KEYVALUE_CACHE_EXHAUSTED | TAG cache exhausted, increase TAG_CACHE_MAX_MEMORY_SIZE(%llu) | | ERR-01424 | ERR_SM_KEYVALUE_CACHE_TIMEOUT | Could not allocate TAG cache: (Table,part=%llu,%llu) offset/size=%llu/%llu | | ERR-01425 | ERR_SM_KEYVALUE_INDEX_MEMORY_LIMIT | Failed to allocate index memory (Current Allocated Size / Threshold size (%llu/%llu)). | | ERR-01426 | ERR_SM_KEYVALUE_NOT_READY_TO_BUILD_INDEX | Not ready to build keyvalue index (Current Count / Target Count (%llu/%llu) in File). | | ERR-01501 | ERR_SM_CPFILE_INVALID_PAGE_ID | Invalid page id in cpfile. Page id<%d> for the column partition file<%s> is greater than the page max id. | | ERR-01502 | ERR_SM_CPFILE_INVALID_PAGE_TIMESTAMP | Error in reading page<%d> in the column partition file<%s>. Page timestamps <head:%lld, tail:%lld> are invalid. | | ERR-01503 | ERR_SM_CPFILE_INVALID_PAGE_CHECKSUM | Error in reading page<%d> in the column partition file<%s>. Page checksum <write:%#X, read:%#X> are invalid | | ERR-01504 | ERR_SM_CPFILE_FILE_INVALID_SIZE | The size<%u> of the column partition file<%s> is too small. It is supposed to be greater than the size<%u> | | ERR-01505 | ERR_SM_CPFILE_FILE_INVALID_PAGE_UPDATE | The offset<%u> and size<%u> of the update value for the page<id:%u, offset:%u, size:%u> in the column partition file<%s> is invalid | | ERR-01506 | ERR_SM_CPFILE_INVALIDE_FILE_HEAD_CRC | The checksum<write:%#X, read:%#X> of the head of the column partition file<%s> is invalid. | | ERR-01551 | ERR_SM_FDCACHE_GET_FD_FOR_FILE | Error in getting the fd of the file<%s> from the fd cache. | | ERR-01601 | ERR_SM_AGER_THREAD_ABNORMAL_SHUTDOWN | Ager thread terminated abnormally. | | ERR-01631 | ERR_SM_BACKUP_NOT_EXIST_BACKUP_ROOT_DIR | There is no root dir<%s> for the database backup. | | ERR-01632 | ERR_SM_BACKUP_NOT_DATABASE_DESTROYED | The database is not destroyed. | | ERR-01633 | ERR_SM_BACKUP_STATFILE_WRITE | Failed to write data<%u> of the backup stat file<%s>. | | ERR-01634 | ERR_SM_BACKUP_STATFILE_READ | Failed to read data<%u> of the backup stat file<%s>. | | ERR-01635 | ERR_SM_BACKUP_STATFILE_INVALID | The backup statfile<%s> is invalid(CRC<H:%u, B:%u, T:%u). | | ERR-01636 | ERR_SM_BACKUP_NOT_COMPLETE | The backup <%s> is not completed. | | ERR-01637 | ERR_SM_BACKUP_DIR_ALREADY_EXIST | The backup <%s> has already exist. | | ERR-01638 | ERR_SM_BACKUP_INVALID_END_RID | The end rid<%llu> of the table<%llu> in the restored database is invalid. | | ERR-01639 | ERR_SM_BACKUP_NAME_TOO_LONG | The name<%s> of backup is too long, errno = %d. | | ERR-01640 | ERR_SM_BACKUP_FILE_ALREADY_EXIST | The backup file<%s> already exists. | | ERR-01641 | ERR_SM_BACKUP_FILE_INVALID_MAGIC_STRING | The backup file<%s> has the invalid magic string<%s>. | | ERR-01642 | ERR_SM_BACKUP_FILE_HEAD_INVALID_CRC32 | The header of backup file<%s> has the invalid crc32<%u>. | | ERR-01643 | ERR_SM_BACKUP_FILE_INVALID_FILENAME_LEN | Length<%u> of backup file<%s> is too long. | | ERR-01644 | ERR_SM_BACKUP_FILE_INVALID_PAGESIZE | The page size <%u> of backup file<%s> is invalid. | | ERR-01645 | ERR_SM_BACKUP_FILE_INVALID_SIZE | The file size <%llu> of the head is different from the size<%llu> on the disk. | | ERR-01646 | ERR_SM_BACKUP_FILE_INVALID_STATE | The backup file is invalid since the backup is not completed. | | ERR-01647 | ERR_SM_INC_BACKUP_NOT_LATEST | An incremental backup requires a previous backup. | | ERR-01648 | ERR_SM_INC_BACKUP_TARGET_NOT_SAME | Backup targets are different from that of previous target. | | ERR-01701 | ERR_SM_TBS_REFERENCED_BY_OBJECTS | The tablespace<%s> is still referenced by other objects such as tables and indexes. | | ERR-01702 | ERR_SM_TBS_NOT_EXIST | The tablespace<%s> does not exist in the database. | | ERR-01703 | ERR_SM_TBS_CANNOT_DROP_SYSTEM_TBS | The SYSTEM_TABLESPACE cannot be dropped. | | ERR-01704 | ERR_SM_TBS_ALEADY_EXIST | Tablespace already exists. <%s> | | ERR-01705 | ERR_SM_TBS_DISKDIR_ALEADY_EXIST | The dir<%s> for the tablespace<%s> of datadisk<%s> already exists. | | ERR-01706 | ERR_SM_TBS_PHYDISK_NOT_EXIST | Disk<%s> does not exist in the tablespace<%s>. | | ERR-01707 | ERR_SM_TBS_PHYDISK_INVALID_PARALLEL_IO | The parallel I/O of a disk should be between %d and %d. | | ERR-01708 | ERR_SM_TBS_FILE_READ | Failed to read <%ld> bytes from the file<%s>, errno = %d. | | ERR-01709 | ERR_SM_TBS_FILE_PAGE_INVALID_TIMESTAMP | The page<offset:%u, size:%u> of the file<%s> is invalid because it has the invalid timestamp<head:%lld, tail:%lld> | | ERR-01710 | ERR_SM_TBS_FILE_PAGE_INVALID_CRC32 | The page<offset:%u, size:%u> of the file<%s> is invalid because it has the invalid crc<memory:%u, disk:%u> | | ERR-01711 | ERR_SM_TBS_VIRDISK_DIR_CREATE | Failed to create directory<%s> for virtual disk. | | ERR-01712 | ERR_SM_TBS_MEMORY_DIR_SHORTAGE | Failed to allocate memory for directory to be removed. | | ERR-01801 | ERR_SM_EXTCP_WAIT_READ_VALUE | Error in waiting to read value: value offset<%lld>, value size<%u>, and file<%s> | | ERR-01821 | ERR_SM_DWFILE_INVALID_IMAGE | The image in the DWFile<%s> is invalid. | | ERR-01841 | ERR_SM_ART_ABORT | The operation is aborted by ART. | | ERR-01851 | ERR_SM_NO_VAR_IN_TAG | Variable length columns are not allowed in tag table. | | ERR-01852 | ERR_SM_DELETE_IN_PROGRESS | Another deletion is in progress for table <%llX>. | | ERR-01853 | ERR_SM_KEYVALUE_CREATE_APPENDFILE | Cannot create append file for Key-Value table <%llX>, errno = %d. | | ERR-01854 | ERR_SM_KEYVALUE_SYNC_APPENDFILE | Cannot sync append file for Key-Value table <%llX>, errno = %d. | | ERR-01855 | ERR_SM_KEYVALUE_CLOSE_APPENDFILE | Cannot close append file for Key-Value table <%llX>, errno = %d. | | ERR-01856 | ERR_SM_KEYVALUE_CREATE_DATAFILE | Cannot create data file <%llX> for Key-Value table <%llX>, errno = %d. | | ERR-01857 | ERR_SM_KEYVALUE_OPEN_DATAFILE | Cannot open data file <%llX> for Key-Value table <%llX>, errno = %d. | | ERR-01858 | ERR_SM_KEYVALUE_READ_DATAFILE | Cannot read data file <%llX> for Key-Value table <%llX>, errno = %d. | | ERR-01859 | ERR_SM_KEYVALUE_WRITE_DATAFILE | Cannot write data file <%llX> for Key-Value table <%llX>, errno = %d. | | ERR-01860 | ERR_SM_KEYVALUE_CORRUPTED_DATAFILE | Data file <%llX> is corrupted for Key-Value table <%llX>. | | ERR-01861 | ERR_SM_KEYVALUE_CREATE_INDEXFILE | Cannot create index file <%llX> for Key-Value table <%llX>, errno = %d. | | ERR-01862 | ERR_SM_KEYVALUE_OPEN_INDEXFILE | Cannot open index file <%llX> for Key-Value table <%llX>, errno = %d. | | ERR-01863 | ERR_SM_KEYVALUE_READ_INDEXFILE | Cannot read <.%s> file <%llX> for Key-Value table <%llX>, errno = %d. | | ERR-01864 | ERR_SM_KEYVALUE_WRITE_INDEXFILE | Cannot write <.%s> file <%llX> for Key-Value table <%llX>, errno = %d. | | ERR-01865 | ERR_SM_KEYVALUE_CORRUPTED_INDEXFILE | Index file <%llX> is corrupted for Key-Value table <%llX>. | | ERR-01866 | ERR_SM_KEYVALUE_IOERROR | Cannot perform I/O for Key-Value table <%llX>. | | ERR-01867 | ERR_SM_KEYVALUE_INVALID_PATH_APPENDFILE | Invalid path to append file for Key-Value table <%llX>, errno = %d. | | ERR-01868 | ERR_SM_KEYVALUE_OPEN_APPENDFILE | Cannot open append file for Key-Value table <%llX>, errno = %d. | | ERR-01869 | ERR_SM_KEYVALUE_NO_DATAFILE | RID-based SELECT is not allowed without datafile, Table<%llX>/RID<%llu>. | | ERR-01870 | ERR_SM_KEYVALUE_OPEN_MOUNTED_APPENDFILE | Cannot open append file for mounted Key-Value table <%llX>, errno = %d. | | ERR-01871 | ERR_SM_KEYVALUE_READ_MOUNTED_APPENDFILE | Cannot read append file for mounted Key-Value table <%llX>, errno = %d. | | ERR-01872 | ERR_SM_BACKUP_IN_PROGRESS | Another backup is in progress for table <%llX>. | | ERR-01873 | ERR_SM_KEYVALUE_NO_INDEXFILE | No index-file <%llx> for Key-Value table Table<%llX>. | | ERR-01874 | ERR_SM_KEYVALUE_OPEN_FILE | Cannot open file <%llX> for Key-Value table <%llX> path<%s>, errno = %d. | | ERR-01875 | ERR_SM_KEYVALUE_NO_UNPURGED_NODE | Cannot find unpurged node for Key-Value table <%llX>. | | ERR-01876 | ERR_SM_KEYVALUE_FILE_DECOMPRESS | Failed to use %s to decompress file <%llX> for key-value table <%llx>, error = %d. | | ERR-01877 | ERR_SM_KEYVALUE_NOT_FOUND_STAT_DATA | Tag stat for id[%llu] is not found. | | ERR-01878 | ERR_SM_STAT_WRITE_FILE | Cannot write stat file for Key-Value table <%llX> path<%s> errno = %d. | | ERR-01879 | ERR_SM_STAT_READ_FILE | Cannot read stat file for Key-Value table <%llX> path<%s> errno = %d. | | ERR-01880 | ERR_SM_STAT_OPEN_FILE | Cannot open stat file for Key-Value table <%llX> path<%s>, errno = %d. | | ERR-01881 | ERR_SM_STAT_INVALID_FILE | Stat File Invalid TableID[%llu], TablePath[%s]. | | ERR-01882 | ERR_SM_KEYVALUE_NO_KVINDEXFILE | No kvindex-file <%llx> for Key-Value table Table<%llX>. | | ERR-01883 | ERR_SM_KEYVALUE_INVALID_TIME_VALUE | Value of the time column(<%lld>) must be greater than or equal to <%lld>. | | ERR-01884 | ERR_SM_KEYVALUE_THREAD_STOPPED | keyvalue table<%llx> thread for [%s] stopped. | | ERR-01885 | ERR_SM_KEYVALUE_DATA_CORRUPTED | Data row value is corrupted: required RID<%llu>, value RID<%llu>. | | ERR-01886 | ERR_SM_KEYVALUE_VDATA_CORRUPTED | %s varchar data is corrupted: required VRID<%u>, value VRID<%u>. | | ERR-01887 | ERR_SM_UPDATE_IN_PROGRESS | Another update is in progress for table <%llX>. | | ERR-01900 | ERR_SM_SNAPSHOT_NOT_VALID | Snapshot ID <%s> is invalid. | | ERR-01901 | ERR_SM_SNAPSHOT_NO_TABLE | Cannot snapshot with no table. | | ERR-01902 | ERR_SM_SNAPSHOT_TIMEOUT | Snapshot timed out. | | ERR-01903 | ERR_SM_SNAPSHOT_NOT_EXISTS | Snapshot ID <%s> does not exist. | | ERR-01904 | ERR_SM_SNAPSHOT_ALREADY_EXISTS | Snapshot ID <%s> already exists. | | ERR-01910 | ERR_SM_FREEZE_NO_TABLE | Cannot freeze with no table. | | ERR-01911 | ERR_SM_ALREADY_FROZEN | Snapshot already frozen. | | ERR-01951 | ERR_SM_FUNCTION_CALL | Failed to call function <%s>, errno=%d | | ERR-01952 | ERR_SM_TABLE_RESOURCE_BUSY | Table (0x%llx) resource busy (%s). | ### `ERR-02000`–`ERR-02999` (420) | Code | Symbol | Original Message | |------|------|------| | ERR-02000 | QPE_TEST | Memory allocation error, Error code = %d | | ERR-02001 | ERR_QP_OPEN_META | Error in opening meta. | | ERR-02002 | ERR_QP_EXEC_META | Error in executing meta. | | ERR-02003 | ERR_QP_CLOSE_META | Error in closing meta. | | ERR-02004 | ERR_QP_CRT_HASH | Error in creating hash. (errno=%d) | | ERR-02005 | ERR_QP_ALLOC_MEM | Error in allocating memory. | | ERR-02006 | ERR_QP_HASH_ADD | Error in adding hash. (errno=%d) | | ERR-02007 | ERR_QP_FETCH_META | Error in fetching meta. | | ERR-02008 | ERR_QP_HASH_TRAV | Error in traversing hash. | | ERR-02009 | ERR_QP_MEMORY_INSUFFICIENT | Insufficient parser memory. | | ERR-02010 | ERR_QP_PARSE_ERROR | Syntax error: near token (%s). | | ERR-02011 | ERR_QP_TOKEN_ERROR | Unrecognized token (%s). | | ERR-02012 | ERR_QP_SINGLE_ROW_ERROR | Single row error. Single-row subquery returns more than one row. (NOT USED) | | ERR-02013 | ERR_QP_NEED_GROUPBY_ERROR | A GROUP BY clause is required before HAVING. | | ERR-02014 | ERR_QP_COLUMN_NAME_DUPLICATED | Column name is duplicated: (%s). | | ERR-02015 | ERR_QP_COLUMN_TYPE_INVALID | Invalid column type: (%s). | | ERR-02016 | ERR_QP_NO_TABLE_PROPETY_FOUND | Table property (%s) does not exist. | | ERR-02017 | ERR_QP_NO_TABLE_PROPETY_CONVERT | Error in converting table property. Cannot convert string (%s) to integer. | | ERR-02018 | ERR_QP_NO_TABLE_PROPETY_VALUE_RANGE | Table property value is out of range: (%s). | | ERR-02019 | ERR_QP_VARCHAR_TYPE_SIZE_ERROR | Column size must be specified for a variable-length column type. | | ERR-02020 | ERR_QP_TYPE_SIZE_ZERO | Invalid size specified. Cannot specify type size to (%s). | | ERR-02021 | ERR_QP_CREATE_INDEX_INVALID_BITMAP_DATATYPE | Cannot create bitmap index on data type (%s) | | ERR-02022 | ERR_QP_CREATE_INDEX_INVALID_KEYWORD_DATATYPE | Cannot create keyword index on data type (%s) | | ERR-02023 | ERR_QP_SNPRINTF_ERROR | snprintf function error (%d). | | ERR-02024 | ERR_QP_TABLE_CREATE_DUPLICATE | Table %s already exists. | | ERR-02025 | ERR_QP_TABLE_NO_EXISTS | Table %s does not exist. | | ERR-02026 | ERR_QP_TABLE_INSERT_COLUMN_MISMATCH | The number of insert values does not match the number of columns. | | ERR-02027 | ERR_QP_TABLE_INSERT_COLUMN_INT_CONVERSION | Error in table insert column integer conversion. Insert value conversion to integer error (%s). | | ERR-02028 | ERR_QP_TABLE_INSERT_COLUMN_DOUBLE_CONVERSION | Error in table insert column double conversion. Insert value conversion to double error (%s) | | ERR-02029 | ERR_QP_TABLE_INSERT_COLUMN_TIME_FORMAT | Error in table insert column time format. Insert _arrival_time value conversion error. | | ERR-02030 | ERR_QP_TABLE_INSERT_NO_COLUMN | Column name (%s) does not exist. | | ERR-02031 | ERR_QP_TABLE_RESOURCE_BUSY | Resource busy (%s). | | ERR-02032 | ERR_QP_TYPE_COMPARE_CONVERSION | Type conversion error: error occurred while comparing the values of type (%s) and type (%s). | | ERR-02033 | ERR_QP_TYPE_CONCAT | Cannot concatenate non varchar types. | | ERR-02034 | ERR_QP_TIME_FORMAT | Invalid format of time expression. | | ERR-02035 | ERR_QP_FUNCTION_NO_EXISTS | Function [%s] does not exist. | | ERR-02036 | ERR_QP_FUNCTION_ARG | Function [%s] has an invalid argument. | | ERR-02037 | ERR_QP_FUNCTION_ARG_TYPE | Function [%s] argument data type does not match. | | ERR-02038 | ERR_QP_TABLE_NO_SUCH_FOR_STAR | Table [%s] does not exist. | | ERR-02039 | ERR_QP_TABLE_NO_SPECIFIED_FOR_STAR | No table specified in the target list. | | ERR-02040 | ERR_QP_TIME_RANGE_ERROR | Invalid time range. | | ERR-02041 | ERR_QP_TIME_NEGATIVE_ERROR | Time value must be positive. | | ERR-02042 | ERR_QP_NULL_EXPRESSION | Expression cannot have a NULL value. | | ERR-02043 | ERR_QP_AGGR_WHERE | Group function is not allowed here. | | ERR-02044 | ERR_QP_NO_GROUPBY | Not a GROUP BY expression. | | ERR-02045 | ERR_QP_TYPE_UNKNOWN | Type is not supported(typecode is %u). Internal error. | | ERR-02046 | ERR_QP_BUFFER_SHORTAGE | String buffer is not enough. | | ERR-02047 | ERR_QP_LOCK_BUFFER_SHORTAGE | Lock buffer is not enough. Table counts are too many. | | ERR-02048 | ERR_QP_BIND_COUNT_OVERFLOW | Bind parameter count is overflowed. (max=%u) | | ERR-02049 | ERR_QP_BIND_UNABLE | Cannot apply bind parameter. | | ERR-02050 | ERR_QP_BIND_BUFFER_CORRUPTED | Bind data from client is corrupted. | | ERR-02051 | ERR_QP_BIND_TYPE_UNKNOWN | Bind data type unknown (typecode is %u). | | ERR-02052 | ERR_QP_INSERT_UNABLE_TABLE | Cannot insert data into this table (%s). | | ERR-02053 | ERR_QP_TYPE_VALUE_CONVERSION | Failed to convert type (%s) to type (%s). | | ERR-02054 | ERR_QP_AGGR_ERROR_ON_FUNCTION | Aggregation error on function usage (NOT USED) | | ERR-02055 | ERR_QP_ERROR_ON_INSERT_VALUE | Invalid insert value. | | ERR-02056 | ERR_QP_COLUMN_NAME_NOT_FOUND | Column name (%s) not found. | | ERR-02057 | ERR_QP_SEARCH_STRING_ERROR | Only literal type can be used in SEARCH keyword. | | ERR-02058 | ERR_QP_INDEX_CREATE_DUPLICATE | Index %s already exists | | ERR-02059 | ERR_QP_INDEX_NO_EXISTS | Index %s does not exist | | ERR-02060 | ERR_QP_INDEX_ONLY_ONE_COLUMN | Composite index is not supported. | | ERR-02061 | ERR_QP_DIVIDE_BY_ZERO | Cannot divide a value by zero. | | ERR-02062 | ERR_QP_DATE_CALC_INVALID | Cannot calculate date type. | | ERR-02063 | ERR_QP_SEARCH_TYPE_INVALID | Invalid search type. Search type must be VARCHAR. | | ERR-02064 | ERR_QP_ADD_TIME_FORMAT_ERROR | Invalid time format. (format: "year/mon/day hour:min:sec") | | ERR-02065 | ERR_QP_NO_INDEX_PROPETY_FOUND | Index property (%s) does not exist. | | ERR-02066 | ERR_QP_INDEX_PROPETY_VALUE_INVALID | Invalid index property value: (%s). | | ERR-02067 | ERR_QP_TO_ADDR4_FUNCTION_ARG | Error in TO_ADDR4 function aggregate. Argument type to TO_ADDR4 function must be an integer. | | ERR-02068 | ERR_QP_IPV4_FORMAT | Invalid IPv4 address format (%s). | | ERR-02069 | ERR_QP_INDEX_FOR_INVALID_TABLE | %s index can only be created for %s table. | | ERR-02070 | ERR_QP_INDEX_NEEDED_FOR_SEARCH | Search predicate needs keyword index. | | ERR-02071 | ERR_QP_INDEX_COUNT | Only one index is allowed for a single column. | | ERR-02072 | ERR_QP_DELETE_UNABLE_TABLE | Cannot delete data from this table (%s). | | ERR-02073 | ERR_QP_TABLE_DELETE_CONDITION | Invalid DELETE condition. %s | | ERR-02074 | ERR_QP_TABLE_DELETE_TIME_RANGE | Invalid delete time range. BEFORE time range should be older than present. | | ERR-02075 | ERR_QP_TABLE_DROP_NO_INFO_IN_DB | Table(%s) record does not exist in meta database. | | ERR-02076 | ERR_QP_TABLEID_DROP_NO_INFO_IN_DB | Table(%lld) record does not exist in meta database. | | ERR-02077 | ERR_QP_VARCHAR_SIZE_MAX | Invalid %s size. %s type size cannot be more than %d. | | ERR-02078 | ERR_QP_UNKNOWN_STMT_TYPE | Invalid statement type. Statement type(%d) is unsupported. | | ERR-02079 | ERR_QP_FUNCTION_ARG_COUNT | The number of arguments for function (%s) does not match. | | ERR-02080 | ERR_QP_USER_NOT_EXIST | User (%s) does not exist. | | ERR-02081 | ERR_QP_USER_PASSWORD_ERROR | Invalid username/password. | | ERR-02082 | ERR_QP_USER_ALREADY_EXISTS | User (%s) already exists. | | ERR-02083 | ERR_QP_USER_SELF_DROP | You cannot drop yourself(%s). | | ERR-02084 | ERR_QP_USER_TABLE_EXIST | User drop error. This user's tables still exist. Drop those tables first. | | ERR-02085 | ERR_QP_USER_NO_ALTER_PRIV | The user(%s) does not have alter privileges. | | ERR-02086 | ERR_QP_USER_NO_CONNECT_PRIV | The user(%s) does not have connect privileges. | | ERR-02087 | ERR_QP_USER_NO_PRIV_TABLE_ACCESS | The user does not have access privileges on table(%s.%s). | | ERR-02088 | ERR_QP_ALTER_TABLE_NO_RIGHT | Error in altering table. Only the LOG table can be altered. | | ERR-02089 | ERR_QP_ALTER_TABLE_SAME_COLUMN_EXISTS | Error in altering table. Column name(%s) already exists. | | ERR-02090 | ERR_QP_ALTER_TABLE_MODIFY_TYPE | Error in altering table. Only varchar type can be modified. | | ERR-02091 | ERR_QP_ALTER_TABLE_MODIFY_VARCHAR_SIZE | Error in altering table. Varchar length should be greater than previous value length | | ERR-02092 | ERR_QP_ALTER_TABLE_DROP_BUILTIN_COLUMN | Error in altering table. Column (%s) cannot be dropped. | | ERR-02093 | ERR_QP_ALTER_TABLE_DROP_COLUMN_ON_INDEX | Error in altering table. Column (%s) having index cannot be dropped. | | ERR-02094 | ERR_QP_ALTER_TABLE_DUP_COLUMN | Error in altering table. Column (%s) already exists. | | ERR-02095 | ERR_QP_TRUNCATE_NON_LOG_TABLE | Error in truncating table. Only the LOG table can be truncated. | | ERR-02096 | ERR_QP_TABLE_TRUNCATE_NO_EXISTS | Error in truncating table. Table %s does not exist. | | ERR-02097 | ERR_QP_TABLE_DROP_COLUMN_LIMIT | Error in altering table. The table must have at least one column. | | ERR-02098 | ERR_QP_NOT_EQUJOIN | Error in joining tables. Only equi-join is allowed. | | ERR-02099 | ERR_QP_JOIN_OR | Error in joining tables. The OR condition for a join predicate is not allowed. | | ERR-02100 | ERR_QP_JOIN_FUNCTION_EXPR | Error in joining tables. The join predicate cannot use functions. | | ERR-02101 | ERR_QP_JOIN_PERMUTATION | Error in joining tables. Cannot join without join predicate. | | ERR-02104 | ERR_QP_COLLECTOR_NO_TEMPLATE_EXISTS | The template file (%s) does not exist. | | ERR-02105 | ERR_QP_COLLECTOR_TEMPLATE_FORMAT_INVALID | The template format (%s : %s : %d) is invalid. | | ERR-02109 | ERR_QP_JOIN_LOG_LOG | Cannot join two or more LOG tables. | | ERR-02110 | ERR_QP_KEYWD_MIN_LENGTH | Search condition argument is too short. It needs more than (%d) characters. | | ERR-02111 | ERR_QP_NO_SUCH_COMMAND | Invalid option. | | ERR-02112 | ERR_QP_NO_DISTINCT_GRBY | Cannot use DISTINCT with GROUP BY clause. | | ERR-02113 | ERR_QP_NO_DISTINCT_AGGR | Cannot use DISTINCT with aggregation function. | | ERR-02114 | ERR_QP_FUNCTION_DISTINCT | DISTINCT clause is not allowed here. | | ERR-02115 | ERR_QP_INVALID_COL_NAME | Internal column cannot be modified. | | ERR-02116 | ERR_QP_SEARCH_FILTER | Search predicate must use an index. | | ERR-02117 | ERR_QP_TABLE_NAME_INVALID | DDL on table (%s) is forbidden. | | ERR-02118 | ERR_QP_TABLE_LOCK_ALREADY_INIT | Lock object was already initialized. (Do not use select and append simultaneously in single session.) | | ERR-02119 | ERR_QP_NOT_IMPLEMENTED | This functionality has not been implemented. | | ERR-02120 | ERR_QP_SESSION_ID_INVALID | Invalid session ID (%s). | | ERR-02121 | ERR_QP_SESSION_PRIV_OF_KILL | No privileges to kill the session. | | ERR-02122 | ERR_QP_SESSION_PRIV_OF_CANCEL | No privileges to cancel the session. | | ERR-02123 | ERR_QP_NOT_EXIST_TABLE_ID_META | Table id (%lld) does not exist in meta database. | | ERR-02124 | ERR_QP_NOT_EXIST_COLUMN_ID_META | Column id (%llu) does not exist in table (%llu). | | ERR-02125 | ERR_QP_VARCHAR_TO_DATE_HEURISTIC | Error in converting string (%s) to datetime with heuristic method. Check the default date string format in this session. | | ERR-02126 | ERR_QP_NO_ORDERBY_SUBQ | ORDER BY clause is not allowed in a subquery | | ERR-02127 | ERR_QP_ORDERBY_TERMS | Only integer constants must be used for ORDER BY column position. | | ERR-02128 | ERR_QP_ORDERBY_OOR | ORDER BY column position %d is out of range - should be between 1 and %d. | | ERR-02129 | ERR_QP_GRBY_INT | GROUP BY terms must be integer constants | | ERR-02130 | ERR_QP_NO_GRBY_HAVING | A GROUP BY clause is required before HAVING | | ERR-02131 | ERR_QP_SUBQ_NOT_SINGLE | Single row error. Single-row subquery returns more than one row. | | ERR-02132 | ERR_QP_SUBQ_NOT_ALLOWED | Cannot use subquery on HAVING, ORDER BY and GROUP BY clauses. | | ERR-02133 | ERR_QP_INVALID_SUBQ | Invalid subquery. | | ERR-02134 | ERR_QP_REGEX_MAX_COUNT | Too many REGEXP in WHERE clause. No more than %d REGEXP in WHERE clause. | | ERR-02135 | ERR_QP_WHERE_TYPE | WHERE clause has to return a boolean result. | | ERR-02136 | ERR_QP_TBS_INVALID_TYPE | Invalid tablespace type. | | ERR-02137 | ERR_QP_TBS_TOO_MANY_DISKS | There are too many disks<%ud> for tablespace %s. | | ERR-02138 | ERR_QP_TBS_DISK_INVALID_PARALLEL_IO_VALUE | The PARALLEL_IO value<%d> for the disk<%s> must be higher than <%d>. | | ERR-02139 | ERR_QP_NO_MINMAX_ON_VARCHAR | MINMAX CACHE is not allowed for VARCHAR column(%s). | | ERR-02140 | ERR_QP_TABLE_NOT_SUPPORT_TABLESPACE | This type of tables do not support the tablespace functionality. | | ERR-02141 | ERR_QP_TYPE_COMPARE_NOT_APPLICABLE | Type comparison error. | | ERR-02142 | ERR_QP_NO_AGGR_LOB | Cannot use lob type in the GROUP BY clause. | | ERR-02143 | ERR_QP_NO_ORDER_LOB | Cannot use lob type in the ORDER BY clause. | | ERR-02144 | ERR_QP_OUTERJOIN_LIMIT | Outerjoin permits only 2 tables. | | ERR-02145 | ERR_QP_NOT_NUMBER_STRING | The string cannot be converted to number value.(%s) | | ERR-02146 | ERR_QP_TS_JOIN_LIMIT | Cannot join tables with timeseries function. | | ERR-02147 | ERR_QP_TS_VIEW_LIMIT | Cannot use inline view with timeseries function. | | ERR-02148 | ERR_QP_IPV6_FORMAT | Invalid IPv6 address format.(%s) | | ERR-02149 | ERR_QP_CONTAINS_TYPE_INVALID | Error in executing CONTAINS. Cannot convert from type(%d) to type(%d). | | ERR-02150 | ERR_QP_IP_NETWORK_TYPE_CLASS_MISMATCHED | Network type error. Network Mask length does not match with the column's length.(mask=%s, column=%s) | | ERR-02151 | ERR_QP_NO_MORE_DISK_FOR_EVALUATION | Error in adding disk to tablespace. You cannot use multiple disks for tablespace without valid license. | | ERR-02152 | ERR_QP_PARTITION_PROPERTY_NOT_COMPLETE | Error in setting column property. You should specify a positive value of column property PARTITION_PAGE_COUNT as well as PAGE_VALUE_COUNT. | | ERR-02153 | ERR_QP_UNKNOWN_COLUMN_PROPERTY | Invalid column property name (%s). Specify a valid property name. | | ERR-02154 | ERR_QP_SET_OP_NO_SELECT | Select set operator parsing error. | | ERR-02155 | ERR_QP_UNSURPPORTED_SET_OP | Only UNION ALL set operator is supported. | | ERR-02156 | ERR_QP_SET_OP_TARGET_MISMATCH | Set operator column types do not match at column (%d). | | ERR-02157 | ERR_QP_VALIDATE_INTERNAL | Internal error on validating query | | ERR-02158 | ERR_QP_INVALID_TYPE | Error in evaluating data type. You must specify a valid data type. | | ERR-02159 | ERR_QP_INVALID_BACKUP_RANGE | 'FROM DATETIME' must be earlier than 'TO DATETIME'. | | ERR-02160 | ERR_QP_UNMOUNT_NOT_MOUNTED_TABLE | Error in doing unmount table(%s). You can unmount only mounted tables. | | ERR-02161 | ERR_QP_NO_DDL_ON_MOUTE_MODE | Error in executing DDL. You cannot execute DDL with mounted DB. (*NOT USED*) | | ERR-02162 | ERR_QP_NO_UNMOUTE_DB | Error in doing unmount DB. You cannot umount database which is not mounted. | | ERR-02163 | ERR_QP_WRONG_RESTORE_PATH | Invalid directory path (%s). You should specify a valid path. | | ERR-02164 | ERR_QP_INVALID_ALTER_INDEX_PROPETY | Invalid index property. Property (%s) for index cannot be altered. | | ERR-02165 | ERR_QP_FUNCTION_POS | Function (%s) is not allowed here. | | ERR-02166 | ERR_QP_FUNCTION_ORDER_BY | Cannot use ORDER BY clause with aggregation function. | | ERR-02167 | ERR_QP_FUNCTION_GROUP_CONCAT_WRONG_SEPARATOR | GROUP_CONCAT function error. Separator should be a string constant. | | ERR-02168 | ERR_QP_OPERATOR_ARG_ERROR | Operator argument count or type does not match. | | ERR-02169 | ERR_QP_WRONG_COLUMN_PROPERTY_VALUE | Invalid column property value: (%s) | | ERR-02170 | ERR_QP_NO_ALIAS_IN_TABLE_INLINE_VIEW | Every specified table or inline view in FROM clause must have its own alias. | | ERR-02171 | ERR_QP_PRIMARY_KEY_DUPLICATE_PK_DECL | VOLATILE / LOOKUP / TRANSACTION table cannot have more than one primary key. | | ERR-02172 | ERR_QP_PRIMARY_KEY_INVALID_TABLE | Primary key is allowed only for VOLATILE / LOOKUP / TRANSACTION table. | | ERR-02173 | ERR_QP_VOLATILE_TABLE_INVALID_TYPE | Cannot create columns with data type (%s) in VOLATILE / LOOKUP table. | | ERR-02174 | ERR_QP_INDEX_TARGET_COLUMN_DUPLICATE | The index already exists in the column(%s). | | ERR-02175 | ERR_QP_VTABLE_UPDATE_INVALID_FORM | SET clause must be written as a list of 'column = value' expression. | | ERR-02176 | ERR_QP_VTABLE_UPDATE_TO_PRIMARY_KEY | Cannot update primary key column in SET clause. | | ERR-02177 | ERR_QP_VTABLE_UPDATE_NOT_IN_VOLATILE | ON DUPLICATE UPDATE clause is allowed only in LOOKUP / VOLATILE / TRANSACTION table. | | ERR-02178 | ERR_QP_TABLE_UPDATE_NO_COLUMN | Error in updating table. Column name (%s) does not exist in this table. | | ERR-02179 | ERR_QP_VTABLE_INSERT_WITHOUT_PRIMARY_KEY_VAL | INSERT on a %s table without primary key value cannot be proceeded. | | ERR-02180 | ERR_QP_VTABLE_UPDATE_ON_NO_PRIMARY_KEY | Primary key is mandatory for UPDATE. | | ERR-02181 | ERR_QP_INDEX_WITH_PRIMARY_KEY_PREFIX | Invalid index name starting with (%s) which is the same as primary key index. | | ERR-02182 | ERR_QP_PRIMARY_KEY_INDEX_DROP | You cannot drop the primary key index (%s). | | ERR-02183 | ERR_QP_APPEND_TO_VTABLE_UNSUPPORTED | Append mode for table (%s) is not supported. | | ERR-02184 | ERR_QP_PROPERTY_ON_INVALID_TABLE_TYPE | Specified property value is invalid in %s table. | | ERR-02185 | ERR_QP_MOUNT_DB_DUPLICATED | Invalid database name. This database name is already used for mount. | | ERR-02186 | ERR_QP_MOUNT_DB_INVALID | Invalid database name. | | ERR-02187 | ERR_QP_UNMOUNT_TABLE_IN_ACCESS | Error in unmounting database. Some tables in mounted database are accessed by other transactions | | ERR-02188 | ERR_QP_MOUNT_DB_NOT_FOUND | The database is not mounted. | | ERR-02189 | ERR_QP_DELETE_WHERE_INVALID_TABLE | Error in deleting rows. Only rows in VOLATILE / LOOKUP table can be deleted. | | ERR-02190 | ERR_QP_UPDATE_DELETE_WHERE_INVALID_CONDITION | Invalid UPDATE/DELETE condition. Specify it as (primary key column) = (value) | | ERR-02191 | ERR_QP_DELETE_WHERE_UNSUPPORTED | WHERE clause in DELETE statement is not supported yet. | | ERR-02192 | ERR_QP_KEYWORD_INDEX_TYPE | Index type for keyword index only supports keyword bitmap or keyword LSM. | | ERR-02195 | ERR_QP_BUFFER_OVERFLOW | Buffer size insufficient. | | ERR-02196 | ERR_QP_NO_FILE_TO_LOAD | Error in loading data. File (%s) does not exist. | | ERR-02197 | ERR_QP_LOAD_TABLE_ALREADY_EXISTS | Error in loading data with automatic mode. The table (%s) already exists. | | ERR-02198 | ERR_QP_LOAD_TABLE_NON_EXISTS | Error loading data. Table (%s) does not exist. | | ERR-02199 | ERR_QP_LOAD_TABLE_PARSING_ERROR | CSV parsing error on line %d: [%s]. | | ERR-02200 | ERR_QP_LOAD_TABLE_DELIMITOR_ERROR | [%s] is not a valid string terminator or enclosure. | | ERR-02201 | ERR_QP_LOAD_TABLE_UNKNOWN_AUTOMODE | The automatic loading mode is invalid. | | ERR-02202 | ERR_QP_LOAD_TABLE_HEADER_DETECT_ERROR | Automatic column detection failed because the data is empty or the headers are invalid. | | ERR-02203 | ERR_QP_LOAD_TABLE_UNKNOWN_ENCODINGMODE | Invalid encoding. | | ERR-02204 | ERR_QP_LOAD_TABLE_CHAR_CONVERSION_ERROR | Failed to convert %s to UTF8. | | ERR-02205 | ERR_QP_NO_SUPPORT_DOUBLE_MOD | A modulo operator can be applied only for integer types. | | ERR-02206 | ERR_QP_NO_SUPPORT_TBS_NON_AUTO | Tablespace name cannot be specified in non automode | | ERR-02207 | ERR_QP_SAVE_FILE_ALREADY_EXISTS | Error in saving table into file (%s). File already exists. | | ERR-02208 | ERR_QP_EXPR_TYPE | Expression argument type does not match. | | ERR-02221 | ERR_QP_NO_MANAGER_NAME_SETTED | Manager name is not specified. | | ERR-02222 | ERR_QP_RECEIVE_DIFF_PROTOCOL | Error in read protocol. Send %s protocol, but received %d protocol. | | ERR-02223 | ERR_QP_COLLECTORMANAGER_CONNECT | Unable to establish connection with collectormanager (%s). | | ERR-02224 | ERR_QP_NO_COLLECTOR_NAME_SETTED | Manager name is not specified. | | ERR-02225 | ERR_QP_SET_COLUMN_UNIT_ERROR | Invalid set column unit. | | ERR-02226 | ERR_QP_INVALID_CHARACTER | Invalid character ('%c'). | | ERR-02228 | ERR_QP_UNSUPPORT_PROCEDURE | Invalid procedure (%s). | | ERR-02229 | ERR_QP_INVALID_ARG_VALUE | Invalid argument value for function (%s). | | ERR-02230 | ERR_QP_PROCEDURE_WRONG_NUMBER_OF_ARGUMENTS | Wrong number of arguments in call to '%s'. | | ERR-02231 | ERR_QP_STRCPY_ERROR | strcpy function error (%d). | | ERR-02232 | ERR_QP_CALC_TYPE | Calculation argument type (%s), (%s) error. | | ERR-02233 | ERR_QP_INSERT_VALUE_LOCATION | Error occurred at column (%u): (%s) | | ERR-02234 | ERR_QP_SET_OP_COUNT | Set operator column counts do not match (%d and %d). | | ERR-02235 | ERR_QP_SERIES_BY | SERIES BY clause is not allowed here. | | ERR-02236 | ERR_QP_TOO_MANY_TABLES_IN_JOIN | For a table list in FROM clause, The number of tables should be less than 32. | | ERR-02237 | ERR_QP_INDEX_NOT_CREATED_ON_TABLE | The index <%s> is not an index for the table <%s>. | | ERR-02238 | ERR_QP_NO_JOIN_TYPE | This type of join is not allowed. | | ERR-02239 | ERR_QP_INVALID_USE_AGGR_FUNC | Invalid use of aggregation function. | | ERR-02240 | ERR_QP_INVALID_COLUMN_TYPE_FOR_FETCH | Cannot fetch column with type (%s). | | ERR-02241 | ERR_QP_UNSUPPORTED_JOIN_TABLES | Join between LOG table and fixed table is not supported in Cluster Edition. | | ERR-02242 | ERR_QP_EQUIJOIN_WITH_LOGTABLE_JOIN | Only equality predicates are supported when joining LOG tables in Cluster Edition. | | ERR-02243 | ERR_QP_UNSUPPORTED_ROW_BASED_DELETE | DELETE statement with the number of rows is not supported in Cluster Edition. | | ERR-02246 | ERR_QP_IDENTIFIER_TOO_LONG | Identifier %.*s is too long. | | ERR-02247 | ERR_QP_DATETIME_NOT_PROPER | DATETIME earlier than 1970-01-01 00:00:00 (UTC) is not valid. | | ERR-02248 | ERR_QP_INSUFFICIENT_COLUMN_DEF | Insufficient column definitions. | | ERR-02249 | ERR_QP_TABLE_DELETE_INVALID_COND | Invalid DELETE condition. | | ERR-02250 | ERR_QP_TAGDATA_COMPONENT_DDL_BLOCKED | You cannot execute DDL on compoment table/index of TAGDATA table explictly. | | ERR-02251 | ERR_QP_TAGDATA_DUPLICATE_FLAG | You cannot define columns with duplicate flag (%s) in TAGDATA table. | | ERR-02252 | ERR_QP_TAGDATA_INVALID_TYPE_FOR_FLAG | Invalid column type (%s) for flag (%s) in TAGDATA table. | | ERR-02253 | ERR_QP_TAGDATA_INSUFFICIENT_MANDATORY | Mandatory column definition (PRIMARY KEY / BASE TIME) is missing. | | ERR-02254 | ERR_QP_INVALID_TAGDATA_FLAG_ON_OTHER_TABLE | Column flag (%s) is only allowed for TAG table. | | ERR-02255 | ERR_QP_TAGDATA_INSERT_META_NO_PK | Primary key of TAGDATA table is not defined in metadata. | | ERR-02256 | ERR_QP_TAGDATA_INVALID_META_COLUMN_CLAUSE | Metadata column definition is allowed only in TAGDATA table. | | ERR-02257 | ERR_QP_TAGDATA_INSERT_META_INVALID_TYPE | Metadata insertion is allowed only in TAGDATA table. | | ERR-02258 | ERR_QP_TAGDATA_ALREADY_INSERTED | Metadata key (%.*s) for the TAG table has already been inserted. | | ERR-02259 | ERR_QP_TAGDATA_NOT_FOUND | Metadata of TAGDATA table is not found. (Key = %s) | | ERR-02260 | ERR_QP_TAGDATA_ALLOC_FAILURE | Failed to allocate new metadata of TAGDATA table (Current Size=%llu). | | ERR-02261 | ERR_QP_NO_TAGDATA_METADATA_INSERT_UPDATE | You cannot insert metadata into TAGDATA table with ON DUPLICATE KEY UPDATE clause. | | ERR-02262 | ERR_QP_TAGDATA_DIRECT_DML_BLOCKED | Direct DML on component tables of TAGDATA table is not allowed. | | ERR-02263 | ERR_QP_TAGDATA_MORE_TAGDATA_TABLE | You can create only one TAGDATA table. | | ERR-02264 | ERR_QP_TAGDATA_SCAN_OTHER_COLUMN_IN_ROLLUP | Cannot read a column (%s) in ROLLUP query because it is not a ROLLUP column. | | ERR-02265 | ERR_QP_TAGDATA_SCAN_WITHOUT_KEY_CONDITION | Reading TAGDATA table without primary key condition is not allowed. | | ERR-02266 | ERR_QP_TAGDATA_DELETE_RAW_CONDITION | You cannot delete raw data of TAGDATA table with WHERE condition. | | ERR-02267 | ERR_QP_TAGDATA_UNSUPPORTED_KEY_PREDICATE | Primary key in TAGDATA table should be compared by '=' or 'IN' operation. | | ERR-02268 | ERR_QP_TAGDATA_COMPARE_KEY_ONLY_CONSTANT | Primary key in TAGDATA table should be compared with constant value. | | ERR-02269 | ERR_QP_TAGDATA_OUTERJOIN | Outerjoin on TAGDATA table is not allowed. | | ERR-02270 | ERR_QP_TAGDATA_NAME_VIOLATION | TAGDATA table's name should be 'TAG'. | | ERR-02271 | ERR_QP_TAGDATA_NOT_CONSTANT_PK_VALUE | You must insert key value of TAGDATA table as constant. | | ERR-02272 | ERR_QP_NOT_EXIST_INDEX_ID_META | Index id (%llu) does not exist in meta database. | | ERR-02273 | ERR_QP_TAGDATA_USER_NO_PRIV_DDL | The user does not have privileges on TAGDATA DDL. | | ERR-02274 | ERR_QP_TAGDATA_FREE_FAILURE | Failed to free new metadata of TAGDATA table. | | ERR-02275 | ERR_QP_TAGDATA_INSERT_SELECT_IN_EE | The INSERT SELECT statement to the TAGDATA table is not allowed in enterprise edition. | | ERR-02276 | ERR_QP_TAGDATA_COMPONENT_EXISTS | Component table (%s) of TAGDATA table already exists. | | ERR-02277 | ERR_QP_TAGDATA_COMPONENT_NAME_RESERVED | Table or index name that starts with '_TAG' is reserved. | | ERR-02278 | ERR_QP_UPDATE_INVALID_TABLE_TYPE | UPDATE statement is not allowed for %s. | | ERR-02279 | ERR_QP_TAGDATA_INVALID_PRIMARY_NAME | Invalid tag name insertion to TAGDATA table (name = '%s'). | | ERR-02280 | ERR_QP_TAGDATA_INVALID_BIND_TAGNAME | Invalid tag name insertion due to wrong bind variable. | | ERR-02281 | ERR_QP_DURATION_NOT_APPLICABLE | DURATION clause is not applicable on %s. | | ERR-02282 | ERR_QP_DELETE_ALREADY_DOING | The DELETE statement for table '%s' is already been executed. | | ERR-02283 | ERR_QP_TAGDATA_IN_SUBQUERY_NOT_ALLOWED | IN subquery on TAGDATA table is not allowed. | | ERR-02284 | ERR_QP_INTERNAL_NULL_EXIST | Internal NULL value exists in the condition expression. | | ERR-02285 | ERR_QP_INTERNAL_ERROR | Internal error: %s. | | ERR-02286 | ERR_QP_KV_TABLE_MEMORY_ALLOC | Memory allocation failed while creating TAGDATA table. You may need to decrease TAG_DATA_PART_SIZE in machbase.conf. | | ERR-02287 | ERR_QP_TAGDATA_NAME_TRUNCATED | TAGDATA name value (%s) is too long. | | ERR-02288 | ERR_QP_AGGR_EXPECTED | Aggregate function is expected at (%.*s). | | ERR-02289 | ERR_QP_NON_CONST | Non-constant expression is not allowed for PIVOT values. | | ERR-02290 | ERR_QP_CANNOT_ALTER | %s cannot be altered. | | ERR-02291 | ERR_QP_INVALID_TABLE_NAME_TAG | Table name 'TAG' must be used for TAGDATA table. | | ERR-02292 | ERR_QP_TAGDATA_INVALID_CONSTRAINT_ORDER | The order of columns in TAGDATA table must be (PRIMARY, BASE TIME, SUMMARIZED, other columns, .. ). | | ERR-02293 | ERR_QP_NO_BIND_PARAM_COLUMN | Column meta for bind param[%d] is not available. | | ERR-02294 | ERR_QP_TAGDATA_JOIN | Joining more than one TAGDATA table is not supported. | | ERR-02295 | ERR_QP_INVALID_ORDINAL_NUMBER | Invalid ordinal number ID_COLUMN (%lld) and TIME_COLUMN (%lld). | | ERR-02296 | ERR_QP_INTERPOLATION_ONE_BETWEEN | Interpolation requires only one BETWEEN expression. | | ERR-02297 | ERR_QP_BETWEEN_HAS_INVALID_EXPR | BETWEEN has invalid expression (%s). | | ERR-02298 | ERR_QP_NOT_FACTOR_OF_INTERPOLATION_INTERVAL | FREQUENCE must be a factor of INTERPOLATION_INTERVAL (%lld). | | ERR-02299 | ERR_QP_ONLY_BETWEEN_SUPPORTED | Only BETWEEN condition is supported. | | ERR-02300 | ERR_QP_INSUFFICIENT_COLUMN_FOR_INTERPOLATION | Interpolation column is missing. (%s) | | ERR-02301 | ERR_QP_INSUFFICIENT_PROPERTIES_FOR_INTERPOLATION | Some properties are missing for interpolation. | | ERR-02302 | ERR_QP_INVALID_INTERVAL_INTERPOLATION_PROPERTY | Invalid interpolation interval property: %lld. | | ERR-02303 | ERR_QP_INVALID_ROLLUP_UNIT | You must use higher ROLLUP unit. | | ERR-02304 | ERR_QP_INTERPOLATION_VIEW_LIMIT | Interpolation is not applicable on (%s). | | ERR-02305 | ERR_QP_INTERPOLATION_ONE_TARGET | JOIN is not applicable for interpolation. | | ERR-02306 | ERR_QP_CHEKPOINT_INVALID_SIZE | Interpolation interval value(%lld) should be less than checkpoint interval value(%lld). | | ERR-02307 | ERR_QP_ROLLUPUNIT_INTERVALVALUE | Interpolation interval value(%lld) should be less than ROLLUP unit (%s). | | ERR-02308 | ERR_QP_ROLLUPUNIT_CHECKPOINTVALUE | Checkpoint interval value(%lld) should be less than ROLLUP unit (%s). | | ERR-02309 | ERR_QP_INVALID_INTERPOLATION_DIVIDE | Checkpoint interval value(%lld) should be divide by interpolation value(%lld). | | ERR-02310 | ERR_QP_INVALID_CHECKPOINT_INTERPOLATION_PROPERTY | Invalid interpolation checkpoint property: %lld. | | ERR-02311 | ERR_QP_INVALID_KEYWORD_INTERPOLATION | %s cannot be used in interpolation query. | | ERR-02312 | ERR_QP_NOT_INTERPOLATION_TABLE | Rollup delete can only be done on the Interpolation Tag table. | | ERR-02313 | ERR_QP_ROLLUP_REBUILD_RANGE_ERROR | Unable to execute ROLLUP DELETE with the given range. | | ERR-02314 | ERR_QP_TAG_UNSUPPORT_DURATION_BACKUP | Regular duration backup does not support a backup of the TAG table (Try incremental backup which permits the action on the TAG table). | | ERR-02315 | ERR_QP_FOG_SNAPSHOT_NOT_SUPPORTED | Snapshot is not supported. | | ERR-02316 | ERR_QP_INVALID_EXPR_IN_DURATION | Invalid expression in DURATION clause: %.*s | | ERR-02317 | ERR_QP_FUNCTION_EXECUTION | Function execution failed: %s | | ERR-02318 | ERR_QP_LOOKUP_NODE_CONNECT_FAIL | Cannot connect to the lookup node. | | ERR-02319 | ERR_QP_LOOKUP_NODE_ERROR | Error on Lookup Node | | ERR-02320 | ERR_QP_LOOKUP_NODE_PENDING | Lookup Node is not ready | | ERR-02321 | ERR_QP_LOOKUP_NODE_NIL | No data was found in the lookup node. | | ERR-02322 | ERR_QP_LOOKUP_TABLE_MISSING_PRIMARY_KEY | Mandatory column definition (PRIMARY KEY) is missing. | | ERR-02323 | ERR_QP_EXEC_FUNCTION_NOT_SUPPORTED_TABLE_TYPE | EXEC %s is not supported for %s table type. | | ERR-02324 | ERR_QP_USED_TAG_ID_DATA | Cannot delete tagmeta. there exist data with deleted_tag key. | | ERR-02325 | ERR_QP_INTEGER_OVERFLOW | Integer %s type overflow. | | ERR-02326 | ERR_QP_EDGE_BACKUP_MOUNT_NOT_SUPPORTED | Backup/Mount is not supported. | | ERR-02327 | ERR_QP_PIVOT_IN_ROLLUP_NOT_SUPPORTED | Pivot is not supported in rollup query. | | ERR-02328 | ERR_QP_TAGMETA_INSERT_COUNT_EXCEEDED | Cannot insert a new tag since the number of tags has exceeded MAX_TAG_COUNT(%lld). | | ERR-02329 | ERR_QP_TAGMETA_INSERT_COUNT_EXCEEDED_LIMIT | Cannot insert a new tag since the number of tags has exceeded TAG_COUNT_LIMIT(%lld). | | ERR-02330 | ERR_QP_KV_INSUFFICIENT_MANDATORY | Mandatory column definition (ULONG / DATETIME) is missing. | | ERR-02331 | ERR_QP_RANGE_EXPR | RANGE expression is not applicable on the table (%s). | | ERR-02332 | ERR_QP_UNABLE_CREATE_INDEX_ON_COLUMN | Unable to create an index on the column (%s). | | ERR-02333 | ERR_QP_KV_TABLE_PREDICATE_MAX_OVER | Column (%s) cannot exceed %d. | | ERR-02334 | ERR_QP_TAG_INDEX_NOT_YET_SUPPORTED | Tag Index is not yet supported. | | ERR-02335 | ERR_QP_FAILED_TO_DELETE_ALL | Failed to delete all on this table. It is recommended to use EXEC TABLE_REFRESH(%s). | | ERR-02336 | ERR_QP_CASCADE_ONLY_TAG_TABLE | CASCADE option is not applicable on %s. | | ERR-02337 | ERR_QP_TAGMETA_DUPLICATE_FLAG | Unable to define more than one column attribute (%s). | | ERR-02339 | ERR_QP_TAGMETA_DIFFERENT_SUMMARY_TYPE | The type of %s column (%s) is different from that of VALUE column (%s). | | ERR-02340 | ERR_QP_TAGMETA_NOT_FOUND_SUMMARY_VALUE | SUMMARIZED column does not exist for %s. | | ERR-02341 | ERR_QP_SUMMARY_GREATER_THAN_USL | SUMMARIZED value is greater than UPPER LIMIT. | | ERR-02342 | ERR_QP_SUMMARY_LESS_THAN_LSL | SUMMARIZED value is less than LOWER LIMIT. | | ERR-02343 | ERR_QP_LSL_GREATER_THAN_USL | LOWER LIMIT must not be greater than UPPER LIMIT. | | ERR-02344 | ERR_QP_NOT_NUMERIC_TYPE | Not numeric type. (%s) | | ERR-02345 | ERR_QP_INVALID_TAGMETA_FLAG_ON_OTHER_TABLE | Column flag (%s) is only allowed for TAGMETA table. | | ERR-02346 | ERR_QP_DEFAULT_ONLY_FOR_TYPE_DATETIME | Column type (%s) is not allowed for default value. | | ERR-02347 | ERR_QP_DEFAULT_ONLY_FOR_FLAG_SYSDATE | SYSDATE is only allowed for default value. | | ERR-02348 | ERR_QP_ALTER_SET_PROP_NOT_SUPPORT_ON_CLUSTER | Alter table set %s not support on cluster. | | ERR-02349 | ERR_QP_BIND_VARIABLE_NOT_SUPPORTED_NEW_TAG | Bind variable is not supported for new tag. | | ERR-02350 | ERR_QP_WINDOW_FUNCTION_OVER_EXISTS | The function (%s) requires OVER clause. | | ERR-02351 | ERR_QP_NO_WINDOW_CONTEXT | Window function is allowed only in SELECT list. | | ERR-02352 | ERR_QP_FUNCTION_OVER | OVER clause is not applicable on (%s). | | ERR-02353 | ERR_QP_OVER_INVALID_TYPE | Invalid data type (%s) in OVER clause. | | ERR-02354 | ERR_QP_OVER_CONSTANT | Constant is not allowed in OVER clause. | | ERR-02355 | ERR_QP_TYPE_UNSUPPORTED | Type (%s) is not supported. | | ERR-02356 | ERR_QP_FIRST_DAY_OF_THE_MONTH | Origin must be the first day of the month. | | ERR-02357 | ERR_QP_JOIN_NOT_APPLICABLE | JOIN is not applicable on the table (%s). | | ERR-02358 | ERR_QP_INVALID_METADATA_ALTER_TABLE | When altering a table, the METADATA keyword is only applied to the tag table. | | ERR-02359 | ERR_QP_TAG_TABLE_ONLY_META_CHANGE | Tag table (%s) can only be modified in the metadata area. | | ERR-02360 | ERR_QP_WINDOW_FUNCTION_NOT_ALLOWED | Window function is not allowed with %s. | | ERR-02361 | ERR_QP_TABLE_STRUCTURE_MODIFIED | Table (%d) structure was modified. | | ERR-02362 | ERR_QP_STATEMENT_NOT_SUPPORTED | This statement is not supported. | | ERR-02600 | ERR_QP_WRONG_SEQUENCE_TABLE_TYPE | SEQUENCE property is not applicable in the table. | | ERR-02601 | ERR_QP_INVALID_FUNCTION_IN_SEQUENCE_COLUMN | Invalid function in a SEQUENCE column. NEXTVAL must be used. | | ERR-02602 | ERR_QP_INVALID_NEXTVAL_FUNCTION_QUERY | NEXTVAL is applicable only in INSERT statement. | | ERR-02603 | ERR_QP_INVALID_COLUMN_NEXTVAL | NEXTVAL is applicable only in SEQUENCE columns. | | ERR-02604 | ERR_QP_INVALID_SEQUENCE_COLUMN_DATA_TYPE | Sequence column must be LONG type. | | ERR-02651 | ERR_QP_EXIST_DEPENDENT_ROLLUP_TABLE | Dependent ROLLUP (%s) exists. | | ERR-02652 | ERR_QP_NOT_ROLLUP_TABLE | Not a ROLLUP table. (%s) | | ERR-02653 | ERR_QP_ROLLUP_INTERVAL_GREATER_THAN_SRC_ROLLUP | Rollup interval must be greater than source rollup interval. | | ERR-02654 | ERR_QP_ROLLUP_NOT_FOUND | ROLLUP (%s) is not found. | | ERR-02655 | ERR_QP_ROLLUP_INTERVAL_DIVIDE_REMAINDER_ZERO | Rollup interval source rollup interval Must Divide Zero. | | ERR-02656 | ERR_QP_ROLLUP_INTERVAL_POSITIVE_INTEGER | Rollup interval must positive integer. | | ERR-02657 | ERR_QP_ROLLUP_INTERVAL_SMALLER_THAN_YEAR | Rollup interval must be smaller than year. | | ERR-02658 | ERR_QP_ROLLUP_NOT_ENABLE | ROLLUP is not enabled for %s. | | ERR-02659 | ERR_QP_ROLLUP_MAX_COUNT | Rollup maximum count is 100. | | ERR-02670 | ERR_QP_ROLLUP_SOURCE_USERID | Rollup user ID(%d) is not equal to Source user ID(%d) | | ERR-02671 | ERR_QP_ROLLUP_COLUMN_INVALID_TYPE | Invalid type for ROLLUP column (%s). | | ERR-02672 | ERR_QP_ROLLUP_JSON_PATH_NOT_EXISTS | Json path is not specified on %s. | | ERR-02673 | ERR_QP_ROLLUP_JSON_PATH_EXISTS | Json path is not applicable on %s. | | ERR-02674 | ERR_QP_ROLLUP_NOT_FOUND_COLUMN | ROLLUP query must have a target column. | | ERR-02675 | ERR_QP_CAN_SCAN_ONE_ROLLUP_COLUMN | Cannot use more than one ROLLUP column in a ROLLUP query. | | ERR-02676 | ERR_QP_NOT_TAG_TABLE | Not a TAG table. | | ERR-02677 | ERR_QP_INVALID_ROLLUP_TIME_UNIT | Invalid rollup time unit (%s). | | ERR-02678 | ERR_QP_NEED_SUMMARIZED_COLUMN | WITH ROLLUP requires a SUMMARIZED column. | | ERR-02679 | ERR_QP_AUTO_GENERATE_ROLLUP_FAIL | Failed to create ROLLUP by WITH ROLLUP option. | | ERR-02680 | ERR_QP_PROCESS_ALREADY_START | PROCESS %s (%s) is already started. | | ERR-02681 | ERR_QP_PROCESS_ALREADY_STOP | PROCESS %s (%s) is already stopped. | | ERR-02682 | ERR_QP_ROLLUP_EXT_TYPE_DIFFER | ROLLUP extension type is different. | | ERR-02683 | ERR_QP_TAGDATA_SCAN_OTHER_TIME_COLUMN_IN_ROLLUP | Cannot read a column (%s) in ROLLUP query because it is not a ROLLUP time column. | | ERR-02684 | ERR_QP_NOT_EXIST_DEPENDENT_ROLLUP_TABLE | Dependent ROLLUP table does not exist. | | ERR-02685 | ERR_QP_NO_APPLICABLE_ROLLUP_TABLE | There are no applicable ROLLUP tables. | | ERR-02686 | ERR_QP_RENAME_NO_APPLICABLE_ROLLUP_TABLE | The names of column(%s) associated with ROLLUP cannot be changed. | | ERR-02687 | ERR_QP_ROLLUP_WAKEUP_INTERVAL_SMALLER_THAN_SRC_ROLLUP | Rollup wakeup interval must be same or smaller than rollup interval. | | ERR-02688 | ERR_QP_ROLLUP_WAKEUP_INTERVAL_DIVIDE_REMAINDER_ZERO | Rollup wakeup interval must exactly divide the rollup interval. | | ERR-02689 | ERR_QP_CUSTOM_ROLLUP_FROM_ALIAS_NOT_ALLOWED | Cannot use alias in custom ROLLUP SELECT FROM clause. | | ERR-02690 | ERR_QP_CUSTOM_ROLLUP_OWNER_MISMATCH | Custom ROLLUP source and destination table owners must be same. (source:%s, destination:%s) | | ERR-02691 | ERR_QP_INDEX_TABLE_OWNER_MISMATCH | Index owner and table owner must be same. (index owner:%s, table owner:%s) | | ERR-02692 | ERR_QP_CIRCULAR_VIEW_DEFINITION | Circular view definition is not allowed: (%s). | | ERR-02700 | ERR_QP_DUPLICATE_RETENTION | Policy (%s) already exists. | | ERR-02701 | ERR_QP_NOT_EXISTS_RETENTION | Policy (%s) does not exist. | | ERR-02702 | ERR_QP_EXIST_DEPENDENT_RETENTION_TABLE | Policy (%s) is in use. | | ERR-02703 | ERR_QP_NOT_EXISTS_RETENTIONJOB | Table (%s) has no retention policy. | | ERR-02704 | ERR_QP_DUPLICATE_RETENTIONJOB | Table (%s) already has a retention policy. | | ERR-02705 | ERR_QP_RETENTION_DURATION_RANGE | Retention duration must be longer than 1 day. | | ERR-02706 | ERR_QP_RETENTION_INTERVAL_RANGE | Retention interval must be longer than 1 hour. | | ERR-02707 | ERR_QP_RETENTION_TABLE_TYPE | Retention is not applicable on the table (%s). | | ERR-02708 | ERR_QP_RETENTION_PRIVILEGE | Only SYS user can create or drop RETENTION. | | ERR-02813 | ERR_QP_INVALID_ROLLUP_EXPR | Invalid ROLLUP expression. (Token = %s, Unit = %ld) | | ERR-02814 | ERR_QP_INVALID_ROLLUP_TARGET | Invalid ROLLUP target. BASETIME column of TAGDATA table is the only target. | | ERR-02815 | ERR_QP_DIFFERENT_ROLLUP_EXPR | Different ROLLUP expressions are used in a single SELECT query. | | ERR-02816 | ERR_QP_INVALID_USE_IN_ROLLUP | Only rollup column with aggregate function can be referenced in ROLLUP SELECT query. | | ERR-02817 | ERR_QP_INVALID_ROLLUP_NOT_SELECT | ROLLUP expression must be used in SELECT query. | | ERR-02818 | ERR_QP_UNSUPPORT_ROLLUP_TARGET | Invalid ROLLUP target (%s). | | ERR-02819 | ERR_QP_ROLLUP_RUNNING | ROLLUP thread is running. | | ERR-02820 | ERR_QP_ROLLUP_NOT_RUNNING | ROLLUP thread is not running. | | ERR-02821 | ERR_QP_OPERATION_IN_PROGRESS | Another DDL/DELETE/SNAPSHOT is in progress. | | ERR-02822 | ERR_QP_INVALID_EXPRESSION_IN_ROLLUP_QUERY | Invalid expression in ROLLUP query : %.*s | | ERR-02823 | ERR_QP_ROLLUP_SELECT_FROM | Invalid table in ROLLUP query: %s | | ERR-02824 | ERR_QP_CUSTOM_ROLLUP_FIRST_COLUMN_NOT_TAGNAME | In custom ROLLUP SELECT, first column must be TAG key column (%s). | | ERR-02825 | ERR_QP_INVALID_EXTENDED_COLUMN_ROLLUP_QUERY | Extended column(%s) cannot be used in ROLLUP query. | | ERR-02826 | ERR_QP_CANT_REVOKE | User (%s) can't revoke from table (%s.%s). | | ERR-02827 | ERR_QP_USER_NO_GRANT_PRIV | User does not have grant privileges. | | ERR-02828 | ERR_QP_USER_NO_REVOKE_PRIV | User does not have revoke privileges. | | ERR-02829 | ERR_QP_USER_ONLY_SYS_CAN_DO_CREATE_DROP | Only SYS user can create or drop user. | | ERR-02830 | ERR_QP_USER_NO_PRIV_TABLE_FOR_EACH_CASE | The user does not have (%s) privilege on table(%s.%s). | | ERR-02831 | ERR_QP_USER_NO_GRANT_UPDATE_PRIV_FOR_LOG_TABLE | You can't grant UPDATE privilege on Log Table. | | ERR-02832 | ERR_QP_USER_NO_REVOKE_UPDATE_PRIV_FOR_LOG_TABLE | You can't revoke UPDATE privilege on Log Table. | | ERR-02833 | ERR_QP_USER_SELECT_ONLY_FOR_MOUNT_TABLE | You can only grant SELECT privileges on Mounted database. | | ERR-02834 | ERR_QP_PASSWORD_REUSED | Cannot use new password as previously used. | | ERR-02835 | ERR_QP_USER_NO_PRIV_DATABASE_FOR_EACH_CASE | The user does not have (%s) privilege on database(%s). | | ERR-02837 | ERR_QP_CUSTOM_ROLLUP_NOT_SUPPORTED_IN_CLUSTER | Custom rollup is not supported in cluster edition. | | ERR-02838 | ERR_QP_USER_NO_MOUNT_PRIV | The user(%s) does not have mount privileges. | | ERR-02839 | ERR_QP_DATABASE_NOT_FOUND | Database (%s) does not exist. | | ERR-02840 | ERR_QP_DATABASE_NOT_ACTIVE | Database (%s) is not an active database. | | ERR-02841 | ERR_QP_DATABASE_USE_IN_TRANSACTION | Cannot change the current database while a transaction is active. | | ERR-02842 | ERR_QP_DATABASE_ALREADY_EXISTS | Database (%s) already exists. | | ERR-02843 | ERR_QP_DATABASE_SELF_DROP | Cannot drop current database (%s). | | ERR-02844 | ERR_QP_DATABASE_DEFAULT_DROP | Default database (%s) cannot be dropped. | | ERR-02845 | ERR_QP_DATABASE_READ_ONLY | Database (%s) is read only. | | ERR-02846 | ERR_QP_DATABASE_RESERVED_NAME | Database name (%s) is reserved and cannot be used. | | ERR-02847 | ERR_QP_PREPARED_CATALOG_CHANGED | Prepared statement target database (%s) changed. | ### `ERR-03000`–`ERR-03999` (65) | Code | Symbol | Original Message | |------|------|------| | ERR-03000 | MMP_STMT_OVERFLOWS | Statement ID overflow (Limit = %u, Curr = %u). | | ERR-03001 | MMP_STMT_QUERY_ZERO | Statement query length is zero. | | ERR-03002 | MMT_TASK_POOL_INITIALIZE_ERROR | Task pool initialization error. | | ERR-03003 | MMS_STMT_POOL_INITIALIZE_ERROR | Statement pool initialization error. | | ERR-03004 | MMT_QUEUE_CREATE_ERROR | Queue creation error. | | ERR-03005 | MMS_STMT_ALLOC_ERROR | Statement allocation error. | | ERR-03006 | MMP_META_UNKNOWN_TYPE_ERROR | Unknown meta type error (typecode is %u). Internal error. | | ERR-03007 | MMP_PROTOCOL_BUFFER_INSUFFICIENT | Insufficient protocol buffer size. Increase it. | | ERR-03008 | MMP_PROTOCOL_STATE_INVALID | Invalid protocol state. Check your application again. (Protocol = %s, State = %s) | | ERR-03009 | MMP_EXECUTE_PROTOCOL_DATA_INVALID | Invalid execute protocol data (%s). | | ERR-03010 | MMS_FETCH_PROTOCOL_INSUFFICIENT | Error in fetch protocol: not enough buffer size to execute it. Increase the size. | | ERR-03011 | MMP_SEND_ERROR | Send error. | | ERR-03012 | MMP_MEMORY_ALLOC_ERROR | Memory allocation error. | | ERR-03013 | MMP_STMT_APPEND_TABLE_ZERO | Invalid table name for append table. Table name is omitted. | | ERR-03014 | MMP_APPEND_PROTOCOL_DATA_INVALID | Invalid append protocol data (%s). | | ERR-03015 | MMP_STMT_APPEND_NO_ENDIAN | Endian is not specified for append. Check endian information. | | ERR-03016 | MMP_STMT_APPEND_MAX_COLUMN | Too many columns are specified for append. Cannot append more than %d columns | | ERR-03017 | MMP_STMT_APPEND_MAX_RECORD_SIZE | Too large record size for append. Cannot append more than %d bytes per record. | | ERR-03018 | MMP_STMT_APPEND_MAX_BLOCK_SIZE | The specified maximum block size (%d) was exceeded. Check the application's append data structure. | | ERR-03019 | MMP_STMT_EXPLAIN_PLAN_ERROR | Explain plan error. Use it for SELECT statement only. | | ERR-03020 | MMP_STMT_EXPLAIN_ONLY_DIRECT_EXECUTE | Explain plan is not allowed in prepared mode. | | ERR-03021 | MMP_CONNECT_VERSION_MISMATCHED | Protocol versions do not match: server (%d.%d.%d), client (%d.%d.%d). | | ERR-03022 | MMP_OS_GET_HANDLE_LIMIT_ERROR | Failed to get handle limit from the system. | | ERR-03023 | MMP_OS_CHECK_HANDLE_LIMIT_ERROR | Handle limit(%d) from the system is less than that of property(%d). Tune system handle limit or decrease the property 'HANDLE_LIMIT' | | ERR-03024 | ERR_MM_SESSION_ID_NOT_FOUND | Invalid session ID (%llu). | | ERR-03025 | ERR_MM_SESSION_SELF_OP_ERROR | Not enough privileges to manipulate the session. (%llu) | | ERR-03026 | ERR_MM_SESSION_DIFF_USER_CANCEL | You should log in with the same user name in the target session. Now (%d) Target(%d) | | ERR-03027 | ERR_MM_SESSION_CANCELLED | This statement has been canceled. | | ERR-03028 | ERR_MM_NO_SESSION_PROPETY | Invalid session property name. Name (%s) does not exist. | | ERR-03029 | ERR_MM_SESSION_PROPETY_CONVERT | Error in converting session property (%s). Cannot convert string (%s) to integer. | | ERR-03030 | ERR_MM_SESSION_PROPETY_VALUE_RANGE | Invalid session property value. Check the session value (%s) | | ERR-03031 | ERR_MM_PROTOCOL_BROKEN | Protocol error. | | ERR-03032 | ERR_MM_LICENSE_NO_META | Error in getting license meta. Check DB image and binary. | | ERR-03033 | ERR_MM_LICENSE_OPEN_META | Error in opening meta. | | ERR-03034 | ERR_MM_LICENSE_EXEC_META | Error in executing meta. | | ERR-03035 | ERR_MM_LICENSE_CLOSE_META | Error in closing meta. | | ERR-03036 | ERR_MM_LICENSE_EXPIRED | The license is expired(%s). | | ERR-03037 | ERR_MM_LICENSE_INVALID | The license is invalid or the license file does not exist(%s). | | ERR-03038 | ERR_MM_LICENSE_VIOLATION | License violation detected (%s). contact sales@machbase.com | | ERR-03039 | ERR_MM_SESSION_COUNT_EXCEED | Session count exceeded the maximum (%llu). | | ERR-03040 | ERR_MM_SHUTDOWN_FAIL | Unable to shutdown since the server is busy. | | ERR-03041 | ERR_MM_APPEND_BATCH | AppendBatch error: %s. | | ERR-03042 | ERR_MM_RECOVERY_BEGUN | Recovery in progress. | | ERR-03043 | ERR_MM_EXECARRAY_NOT_FOR_SELECT | Array Execute is not applicable for SELECT query. | | ERR-03044 | MMP_CONNECT_WRONG_TIMEZONE | Invalid TIMEZONE string: %s. | | ERR-03045 | ERR_MM_INVALID_CONTEXT | Invalid context at %s. | | ERR-03046 | ERR_MM_CM_ERROR | Communication module error (rc=%d): [%s]. | | ERR-03047 | ERR_MM_FUNCTION | Failed to call function %s (rc=%d) | | ERR-03048 | ERR_MM_PREPARED_STMT_USER_CHANGED | Prepared statement cannot be used after CONNECT USER. | | ERR-03200 | ERR_MM_SERVER_NOT_RUNNING | Server is not running. | | ERR-03201 | ERR_MM_INVALID_STMT_STATE | Invalid statement state: (%d) | | ERR-03202 | ERR_MM_COLUMN_RANGE | Column index is out of range. | | ERR-03203 | ERR_MM_BUFFER_SIZE_EXCEEDED | The data length exceeded the buffer size. | | ERR-03204 | ERR_MM_APPEND_PARAM_IP_STRING_NULL | Append data ip string is null. | | ERR-03205 | ERR_MM_APPEND_PARAM_DATETIME_STRING_NULL | Append data datetime string(%s) is null. | | ERR-03206 | ERR_MM_INVALID_COLUMN_TYPE | Invalid column type (%d). | | ERR-03207 | ERR_MM_INVALID_STMT_TYPE | Invalid statement type (%d). | | ERR-03208 | ERR_MM_SERVER_THREAD_ERR | Server thread error: %d - %s | | ERR-03209 | ERR_MM_BUSY_STMT_STATE | statement is busy. (%d) | | ERR-03210 | ERR_MM_CONN_INVALID_STATE | This connection already has been already disconnected | | ERR-03211 | ERR_MM_DB_EXIST | Database already exists. | | ERR-03212 | ERR_MM_DB_NOT_EXIST | Database does not exist. | | ERR-03213 | ERR_MM_SERVER_RUNNING | Server is running. | | ERR-03214 | ERR_MM_DBS_OPEN_FAIL | Failed to open dbs(%s) directory. | | ERR-03215 | ERR_MM_ALTER_SESSION | ALTER SESSION statement is not supported. | ### `ERR-04000`–`ERR-04999` (23) | Code | Symbol | Original Message | |------|------|------| | ERR-04000 | CMI_PROTOCOL_MSG_ERROR_IN_CONNECTION | Protocol message error in connection. | | ERR-04001 | CMI_PROTOCOL_LENGTH_ERROR_IN_CONNECTION | Protocol length error in connection (%llu but %llu). | | ERR-04002 | CMI_DOUBLE_CREATE_COMMUNICATION_CHANNEL | Cannot create duplicate communication channels. | | ERR-04003 | CMI_SOCKET_CREATION_ERROR | Socket creation error (%d). | | ERR-04004 | CMI_BIND_ERROR | Socket bind error. Errorcode is (%d) | | ERR-04005 | CMI_LISTEN_ERROR | Listen error (%d). | | ERR-04006 | CMI_POLL_CREATION_ERROR | Poll creation error (%d). | | ERR-04007 | CMI_POLL_ADD_ERROR | Poll add error (%d). | | ERR-04008 | CMI_CONNECTION_ERROR | Creation error (%d). | | ERR-04009 | CMI_SEND_ERROR | Send error (%d). | | ERR-04010 | CMI_RECV_ERROR | Receive error (%d). | | ERR-04011 | CMI_DISPATCH_ERROR | Dispatch error (%d). | | ERR-04012 | CMI_SETSOCKOPT_ERROR | nbp_sock_set_opt() error (%d). | | ERR-04013 | CMI_RECV_RETRY_ERROR | Failed to receive accept data repeatedly in %u milliseconds. | | ERR-04014 | CMI_MEMORY_ALLOC_ERROR | Memory allocation error. | | ERR-04015 | CMI_INVALID_PROTOCOL_ERROR | Receive invalid protocol (%d). | | ERR-04016 | CMI_TIMEDOUT_ERROR | Communication timed out error. (%d) | | ERR-04017 | CMI_SOCKET_CLOSED | Remote socket closed. | | ERR-04018 | CMI_INVALID_BIND_IP_ADDR | BIND_IP_ADDRESS [%s] is invalid | | ERR-04019 | CMI_BIND_ADDR_NOT_AVAILABLE | BIND_IP_ADDRESS [%s] is not available. Errorcode is[%d] | | ERR-04020 | CMI_BIND_PORT_INUSE | Port[%d] is already in use. Errorcode is [%d] | | ERR-04021 | CMI_OS_NOT_SUPPORT_FUNCTION | Function[%s] is not supported in this OS[%s] | | ERR-04999 | ERR_QP_ROLLUP_NOT_SUPPORTED_ON_DISTANCE_AXIS | ROLLUP is not supported on DISTANCE axis TAG table. | ### `ERR-05000`–`ERR-05999` (1) | Code | Symbol | Original Message | |------|------|------| | ERR-05002 | AD_MANAGER_GENERATE_ERROR | msg does not used | ### `ERR-06000`–`ERR-06999` (35) | Code | Symbol | Original Message | |------|------|------| | ERR-06000 | ERR_LM_FUNCTION_EXECUTION | Function execution failed: "%s". | | ERR-06001 | ERR_LM_RESPONSE_FAILED | Response failed: %s | | ERR-06002 | ERR_LM_ACCEPT_TIMEOUT | Accept timeout: "%s:%u". | | ERR-06003 | ERR_LM_SEND_BUFFER_OVERFLOW | Send buffer overflow: "%s". | | ERR-06004 | ERR_LM_COMMAND_EXECUTION_FAILED | Command execution failed: Application-Id = %u, Command-Code = %u. | | ERR-06005 | ERR_LM_UNSUPPORTED_COMMAND | Unsupported command: Application-Id = %u, Command-Code = %u. | | ERR-06006 | ERR_LM_ALREADY_CONNECTED | Already connected: "%s". | | ERR-06007 | ERR_LM_CSTR_TO_INT32_FAILED | Failed to convert string "%s" to int. | | ERR-06008 | ERR_LM_DESTINATION_HOST_TOO_LONG | Destination-Host too long: "%s". | | ERR-06009 | ERR_LM_DISCONNECTED | Disconnected: "%s". | | ERR-06010 | ERR_LM_HOST_NOT_FOUND | Host not found: "%s". | | ERR-06011 | ERR_LM_GROUPED_AVP_TOO_DEEP | Grouped AVP too deep: %d. | | ERR-06012 | ERR_LM_HANDSHAKE_TIMEOUT | Handshake timeout: "%s". | | ERR-06013 | ERR_LM_INITIALIZED | Link manager already initialized. | | ERR-06014 | ERR_LM_INVALID_HEADER | Invalid header: "%s". | | ERR-06015 | ERR_LM_INVALID_HOST | Invalid host: "%s" and "%s". | | ERR-06016 | ERR_LM_INVALID_PORT_NO | Invalid port no: %d. | | ERR-06017 | ERR_LM_MESSAGE_TOO_LONG | Message too long: %d | | ERR-06018 | ERR_LM_MISSING_AVP | Missing AVP: "%s" | | ERR-06019 | ERR_LM_NOT_INITIALIZED | Link manager not initialized. | | ERR-06020 | ERR_LM_NO_OPENED_GROUPED_AVP_FOUND | No opened grouped AVP found. | | ERR-06021 | ERR_LM_NULL_POINTER_ACCESS | NULL pointer access: "%s". | | ERR-06022 | ERR_LM_ORIGIN_HOST_TOO_LONG | Origin-Host too long: "%s". | | ERR-06023 | ERR_LM_REQUIRE_REQUEST_MESSAGE | Require request message. | | ERR-06024 | ERR_LM_SESSION_ID_TOO_LONG | Session-Id too long: "%s". | | ERR-06025 | ERR_LM_CONNECTION_TIMEOUT | Connection timeout: "%s". | | ERR-06026 | ERR_LM_UNABLE_TO_BIND_ADDRESS | Unable to bind address: "%s". | | ERR-06027 | ERR_LM_ABORT_CALLBACK_TIMEOUT | Abort callback: "Timeout". | | ERR-06028 | ERR_LM_ABORT_CALLBACK_DISCONNECTED | Abort callback: "Disconnected". | | ERR-06029 | ERR_LM_ABORT_CALLBACK_SHUTDOWN | Abort callback: "Shutdown". | | ERR-06030 | ERR_LM_NO_MORE_ADDRESS | No more address: "%s". | | ERR-06031 | ERR_LM_HANDSHAKE_FAILED | Handshake failed: "%s". | | ERR-06032 | ERR_LM_PROCESS_MEMORY_LIMIT | Failed to allocate connection (Current Allocate Memory / PROCESS_MAX_SIZE (%llu/%llu)). | | ERR-06033 | ERR_LM_ABORT_CONN_FREED | connection object for (%s) has been freed. please retry. | | ERR-06034 | ERR_LM_ABORT_SEND_RETRY_COUNT_EXHAUSETED | The number of send repetitions has been exhausted. | ### `ERR-07000`–`ERR-07999` (50) | Code | Symbol | Original Message | |------|------|------| | ERR-07000 | ERR_XM_CREATE_HASH | Error in creating hashtable for global metadata. | | ERR-07001 | ERR_XM_OPEN_META | Error in opening meta. Cannot open meta database. | | ERR-07002 | ERR_XM_EXEC_META | Error in executing meta. Cannot execute meta database | | ERR-07003 | ERR_XM_CLOSE_META | Error in closing meta. Cannot close meta database. | | ERR-07004 | ERR_XM_FETCH_META | Error in fetching meta. | | ERR-07005 | ERR_XM_GLOB_OBJECT_NOT_EXISTS_BY_LOID | No global object found. (Local Object ID=%llu, Host=%s) | | ERR-07006 | ERR_XM_GLOB_OBJECT_NOT_EXISTS_BY_GOID | No global object found. (Global Object ID=%llu, Host=%s) | | ERR-07007 | ERR_XM_GLOB_OBJECT_EXISTS | Global object already exists. (Global Object ID=%llu, Host=%s) | | ERR-07008 | ERR_XM_HASH_ADD_FAILURE | Error in hash add (Memory allocation failed). | | ERR-07009 | ERR_XM_STATEMENT_ALREADY_EXISTS | Failed to add query statement due to unfinished one. | | ERR-07010 | ERR_XM_STATEMENT_NO_EXISTS | Failed to find query statement. | | ERR-07011 | ERR_XM_NOT_SUPPORTED_YET | This query type is not supported yet. | | ERR-07012 | ERR_XM_NOT_SUPPORTED_PLANNODE_YET | This plan node (%s) is not supported yet. | | ERR-07013 | ERR_XM_STATEMENT_CANCELLED | Statement is canceled by the broker. | | ERR-07014 | ERR_XM_NODE_INFO_EXISTS | Node information already exists. | | ERR-07015 | ERR_XM_INVALID_MESSAGE | Invalid message from XM: %u | | ERR-07016 | ERR_XM_DDL_ON_WAREHOUSE_NOT_SUPPORTED | DDL/DELETE statement on warehouse node is not supported. | | ERR-07017 | ERR_XM_NOT_SUPPORTED_AGG_FUNC_YET | This aggregate function (%s) is not supported yet. | | ERR-07018 | ERR_XM_STANDBY_INSERT | INSERT/APPEND to warehouse standby is not available. | | ERR-07019 | ERR_XM_UNSUPPORTED_STMT_TYPE | Unsupported query statement type in the Cluster Edition. | | ERR-07020 | ERR_XM_INTERNAL_ERROR | XM internal error (XMART_POINT:%s) | | ERR-07021 | ERR_XM_XMART_TARGET_NOT_NODE_ID | [XM-ART] Targeted node is not valid. (%s) | | ERR-07022 | ERR_XM_ERROR_VIA_ANSWER_MSG | An error occurred after processing a %s message. [Src='%s']: %s | | ERR-07023 | ERR_XM_ERROR_STAFF_ALREADY_GONE | Execution unit from remote note is already gone. | | ERR-07024 | ERR_XM_INVALID_APPEND_ON_WAREHOUSE | APPEND operation on warehouse node is not supported. | | ERR-07025 | ERR_XM_INVALID_NODE_HOSTS | Host information from broker is invalid. Please check coordinator's status. | | ERR-07026 | ERR_XM_CLUSTER_INVALID | Cluster node information is invalid. | | ERR-07027 | ERR_XM_CLUSTER_CHANGED | Cluster node information has changed during query execution. | | ERR-07028 | ERR_XM_CANNOT_EXPLAIN_STAGE | This execution plan does not need to generate stage(s). | | ERR-07029 | ERR_XM_CLUSTER_CONNECTION_ABORT_TIMEOUT | Cluster connection aborted: Time-out | | ERR-07030 | ERR_XM_CLUSTER_CONNECTION_ABORT_LINK_BROKEN | Cluster connection aborted: Disconnected by warehouse. | | ERR-07031 | ERR_XM_BLOCKED_BY_DEACTIVATED_MODE | DML/DDL is disabled in DEACTIVATED mode. | | ERR-07032 | ERR_XM_DELETE_NOT_AVAILABLE | DELETE is not available since a read-only group exists. | | ERR-07033 | ERR_XM_WAREHOUSE_DROPPED_OUT | Participating warehouse has been dropped out. | | ERR-07034 | ERR_XM_INVALID_BROKER_STORED | Broker info has been changed. Please free statement and initalize again. | | ERR-07035 | ERR_XM_WAREHOUSE_DIRECT_DML_NOW_ALLOWED | Direct DML on warehouse is not allowed. | | ERR-07036 | ERR_XM_WAREHOUSE_NOT_AVAILABLE | Warehouse is not available. | | ERR-07037 | ERR_XM_STAGE_MEMORY_LIMIT | Execution stage memory usage exceeded the limit. (used: %llu, maximum: %llu) | | ERR-07038 | ERR_XM_ARCHIVE_INTERNAL_ERROR | XM archiving error occurred. (%s) | | ERR-07039 | ERR_XM_BROKER_DISCONN | Broker (%s) is disconnected. | | ERR-07040 | ERR_XM_BROKER_NOT_LEADER | Only leader broker can execute DML on LOOKUP table. | | ERR-07041 | ERR_XM_BROKER_REMOTE_ERROR | Remote error. (%s) | | ERR-07042 | ERR_XM_RESTORE_LOOKUP_TIMEOUT | LOOKUP table restore timeout: (%s) | | ERR-07043 | ERR_XM_BROKER_NOT_ACTIVE | Broker is not ACTIVE. | | ERR-07044 | ERR_XM_VERSION_NOT_MATCH | XM version does not match. (%s - %s) | | ERR-07045 | ERR_XM_SNAPSHOT_FAIL | Snapshot failed: %s. | | ERR-07046 | ERR_XM_MESSAGE_EXPIRED | Message %d is expired. | | ERR-07047 | ERR_XM_SNAPSHOT_RECOVER_IN_PROGRESS | Snapshot recover is in progress. | | ERR-07048 | ERR_XM_QUEUE_TIMEOUT | Queue timeout. | | ERR-07049 | ERR_XM_VERSION_UNMATCHED | XM version does not match. (%d - %d) | ### `ERR-08000`–`ERR-08999` (109) | Code | Symbol | Original Message | |------|------|------| | ERR-08000 | ERR_CC_FUNCTION_EXECUTION | Function execution failed: "%s". | | ERR-08001 | ERR_CC_BUFFER_OVERRUN | Buffer overrun. | | ERR-08002 | ERR_CC_END_OF_FILE | End of file. | | ERR-08003 | ERR_CC_HEADER_OCCURS_TOO_MANY_TIMES | Header occurs too many times: "%s". | | ERR-08004 | ERR_CC_JSON_DEPTH_OUT_OF_RANGE | JSON depth: Out of range. | | ERR-08005 | ERR_CC_CONNECTION_TIMEOUT | Connection timeout. | | ERR-08006 | ERR_CC_PACKAGE_NOT_FOUND | Package not found: "%s". | | ERR-08007 | ERR_CC_FILE_NAME_MISMATCH | File name mismatch: "%s" and "%s" | | ERR-08008 | ERR_CC_BLOCK_SIZE_OVERRUN | Block size overrun: %llu and %llu | | ERR-08009 | ERR_CC_FILE_SIZE_MISMATCH | File size mismatch: %llu and %llu | | ERR-08010 | ERR_CC_FILE_READ_SIZE_MISMATCH | File read size mismatch: %llu and %llu | | ERR-08011 | ERR_CC_FILE_WRITE_SIZE_MISMATCH | File write size mismatch: %llu and %llu | | ERR-08012 | ERR_CC_NODE_NOT_FOUND | Node not found: "%s" | | ERR-08013 | ERR_CC_NODE_EXIST | Node exist: "%s" | | ERR-08014 | ERR_CC_INVALID_PACKAGE_FILE_SIZE | Invalid package file size: "%s" = %llu / %llu | | ERR-08015 | ERR_CC_UNMATCHED_HOST | Unmatched host: "%s" and "%s" | | ERR-08016 | ERR_CC_DASHBOARD_INITIALIZED | Dashboard initialized | | ERR-08017 | ERR_CC_DASHBOARD_NOT_INITIALIZED | Dashboard is not initialized | | ERR-08018 | ERR_CC_NULL_POINTER_ACCESS | NULL pointer access: "%s". | | ERR-08019 | ERR_CC_STATUS_NOT_FOUND | Status not found: "%s" | | ERR-08020 | ERR_CC_HASH_INSERT_FAILED | Hash insert failed: "%s" | | ERR-08021 | ERR_CC_HASH_DELETE_FAILED | Hash delete failed: "%s" | | ERR-08022 | ERR_CC_HOST_TOO_LONG | Host too long: "%s" | | ERR-08023 | ERR_CC_ACTIVE_TOO_LONG | Active too long: "%s" | | ERR-08024 | ERR_CC_COORDINATOR_HOST_TOO_LONG | Coordinator-Host too long: "%s" | | ERR-08025 | ERR_CC_SPIN_TIMEOUT | Spin timeout | | ERR-08026 | ERR_CC_DDL_DISABLED | DDL disabled: %s | | ERR-08027 | ERR_CC_STATUS_UNINITALIZED | Status uninitialized | | ERR-08028 | ERR_CC_UNSUPPORTED_NODE_TYPE | Unsupported Node-Type: %u | | ERR-08029 | ERR_CC_SEQUENCE_NUMBER_UNINITIALIZED | Sequence number uninitialized | | ERR-08030 | ERR_CC_SEQUENCE_NUMBER_UNMATCHED | Sequence number unmatched: %lld and %lld | | ERR-08031 | ERR_CC_DDL_INCOMPLETED | DDL[%lld] incomplete: [%s] | | ERR-08032 | ERR_CC_INVALID_BROKER_COUNT | Invalid broker count: %lld | | ERR-08033 | ERR_CC_DDL_FAILED | DDL failed | | ERR-08034 | ERR_CC_DDL_SEQUENCE_NOT_FOUND | DDL sequence not found | | ERR-08035 | ERR_CC_INVALID_DDL_STATE | Invalid DDL state: %lld | | ERR-08036 | ERR_CC_INVALID_DDL_RETURNED | Invalid DDL returned: %lld and %lld | | ERR-08037 | ERR_CC_STANDBY_TOO_LONG | Standby too long: "%s" | | ERR-08038 | ERR_CC_INVALID_STATE_CHANGE | Invalid state change: %u => %u | | ERR-08039 | ERR_CC_INVALID_STATE | Invalid state: %u | | ERR-08040 | ERR_CC_INVALID_NODE_TYPE | Invalid Node-Type: %u | | ERR-08041 | ERR_CC_COORDINATOR_INACTIVE | Coordinator inactive | | ERR-08042 | ERR_CC_NOT_LEADER | Only leader can execute DDL. | | ERR-08043 | ERR_CC_DDL_TIMEOUT | DDL timeout | | ERR-08044 | ERR_CC_DDL_ERROR_MESSAGE | %s | | ERR-08045 | ERR_CC_DDL_NOT_FOUND | DDL not found: %llu | | ERR-08046 | ERR_CC_DDL_INCOMPLETNESS | DDL incompleteness: "%s" | | ERR-08047 | ERR_CC_UNSUPPORTED_PACKAGE | Unsupported package: "%s" | | ERR-08048 | ERR_CC_DDL_DISABLED_BY_MODE_CHANGE | DDL disabled by mode change | | ERR-08049 | ERR_CC_FAILED_TO_FORKED_COMMAND | Failed to fork and execute command: %s. Please check deployer's trace log. | | ERR-08050 | ERR_CC_FUNCTION_EXECUTION_WITH_RC | Function execution failed: "%s" (errno=%d). | | ERR-08051 | ERR_CC_DDL_DISABLED_READONLY_GROUP | DDL disabled because a part of group is not normal. | | ERR-08052 | ERR_CC_DDLSYNC_EXECUTE_FAILED_AFTER_RETRY | DDL[%llu] execution during DDL-Sync failed after several attempts. | | ERR-08053 | ERR_CC_INVALID_OPTION | Invalid option (%s). | | ERR-08054 | ERR_CC_GROUP_NOT_FOUND | Group (%s) is not found. | | ERR-08055 | ERR_CC_PORT_CHECK_REQUIRED | Check %s port number (%d). | | ERR-08056 | ERR_CC_DEPLOYER_DISABLED | Deployer is disabled: "%s". | | ERR-08057 | ERR_CC_ONLY_PRIMARY_COORDINATOR_AVAILABLE | Command is not available in the secondary coordinator. | | ERR-08058 | ERR_CC_CLUSTER_SYNC_FAILURE | Cluster synchronization failed. | | ERR-08059 | ERR_CC_INVALID_DECISION_STATE | Invaid decision state: %s | | ERR-08060 | ERR_CC_MISSING_ATTRIBUTE | Missing attribute: %s | | ERR-08061 | ERR_CC_ATTRIBUTE_OCCURS_TOO_MANY_TIMES | Attribute occurs too many times: %s | | ERR-08062 | ERR_CC_EXECUTE_COMMAND_FAILURE | Failed to execute command (%s). | | ERR-08063 | ERR_CC_PACKAGE_ALREADY_EXISTS | Package name or file name already exists (%s = %s). | | ERR-08064 | ERR_CC_HOST_RES_INFO_NOT_FOUND | Host resource info not found: "%s" | | ERR-08065 | ERR_CC_DISK_INFO_NOT_FOUND | Disk info not found: "%s" | | ERR-08066 | ERR_CC_INTEGER_OVERFLOW | Integer overflow. | | ERR-08067 | ERR_CC_COORDINATOR_COUNT_EXCEEDED | The number of coordinators exceeded %d. | | ERR-08068 | ERR_CC_DDL_DISABLED_BY_INITIAL_STATE | DDL disabled since some of nodes are in initial states. | | ERR-08069 | ERR_CC_COORD_ROLE_HANDSHAKE | Coordinator role handshake failed: [%s] | | ERR-08070 | ERR_CC_HOST_RESOURCE_DISABLED | Collecting host resource is disabled. | | ERR-08071 | ERR_CC_REQUEST_FAILED | Request to execute command %s failed. (code=%d) | | ERR-08072 | ERR_CC_CLUSTER_ACTIVATION_FAILED | Cluster activation failed: %lld / %lld. | | ERR-08073 | ERR_CC_ENVIRONMENT_VARIABLE_NOT_SET | Environment (%s) is not set. | | ERR-08074 | ERR_CC_OPTION_DUPLICATED | Option duplicated. | | ERR-08075 | ERR_CC_OPTION_REQUIRED | Option required (%s). | | ERR-08076 | ERR_CC_LOCK_FAILED | Cannot read Lock File! Check $MACHBASE_COORDINATOR_HOME/conf/machbasecoordinator.lock* and Tracelog in $MACHBASE_COORDINATOR_HOME/trc. | | ERR-08077 | ERR_CC_COORDINATOR_RUNNING | Machbase coordinator is running. | | ERR-08078 | ERR_CC_COORDINATOR_NOT_RUNNING | Machbase coordinator is not running. | | ERR-08079 | ERR_CC_COORDINATOR_PHASE1_FAILED | Machbase Coordinator %s Phase1 failed: %s | | ERR-08080 | ERR_CC_COORDINATOR_PHASE2_FAILED | Machbase Coordinator %s Phase2 failed: %s | | ERR-08081 | ERR_CC_COORDINATOR_DEAD | Machbase Coordinator has been DEAD! Check Tracelog in $MACHBASE_COORDINATOR_HOME/trc. | | ERR-08082 | ERR_CC_METADATA_NOT_CREATED | Machbase Coordinator metadata is not created. Check Tracelog in $MACHBASE_COORDINATOR_HOME/trc. | | ERR-08083 | ERR_CC_METADATA_ALREADY_CREATED | Machbase Coordinator metadata is already created. Check Tracelog in $MACHBASE_COORDINATOR_HOME/trc. | | ERR-08084 | ERR_CC_INVALID_PROCESS_ID | Invalid process id. | | ERR-08085 | ERR_CC_OPTION_INIT_FAILED | Option initialization error: %d. | | ERR-08086 | ERR_CC_OPTION_CHECK_FAILED | Option check error: %d. | | ERR-08087 | ERR_CC_OPTION_GET_FAILED | Option retrieval error: %d (%s). | | ERR-08088 | ERR_CC_COMMAND_OPTION_NOT_FOUND | Command option is not found. | | ERR-08089 | ERR_CC_COLLECTING_HOST_RES_FAILED | Failed to collect '%s': %s. | | ERR-08090 | ERR_CC_INVALID_ATTRIBUTE | Invalid attribute: %s | | ERR-08091 | ERR_CC_DDL_RECOVERY_FAILED | DDL recovery failed: %s. | | ERR-08092 | ERR_CC_DESIRED_STATE_NOT_APPLICABLE | Desired state (%s) is not applicable. | | ERR-08093 | ERR_CC_NODE_STILL_RUNNING | %s is still running. | | ERR-08094 | ERR_CC_SNAPSHOT_NOT_EXIST | SNAPSHOT on %s does not exist. | | ERR-08095 | ERR_CC_RECOVER_NON_READONLY | Group %s is not readonly mode. Snapshot recovery works only for a readonly group | | ERR-08096 | ERR_CC_SNAPSHOT_NOT_AVAILABLE | Snapshot is not available: %s | | ERR-08097 | ERR_CC_NOT_SCRAPPED | Warehouse %s is not scrapped. %s only works on a scrapped warehouse. | | ERR-08098 | ERR_CC_MASTER_NOT_FOUND | Cannot add lookup node %s (%s) before adding the lookup master node. | | ERR-08099 | ERR_CC_MASTER_NOT_MONITOR | Lookup monitor node (%s) cannot change the lookup master node. | | ERR-08100 | ERR_CC_SNAPSHOT_FAIL_PUBLISH | Failed to publish SnapshotID to warehouse. | | ERR-08101 | ERR_CC_NOT_READONLY | Group (%s) is not readonly. | | ERR-08102 | ERR_CC_NODE_FIX | Fix node (%s) failed. (refcnt=%d) | | ERR-08103 | ERR_CC_LOOKUP_ALREADY_RUNNING | Lookup node running already. (%s:%d) | | ERR-08104 | ERR_CC_LOOKUP_CONNECT_FAILED | Connect to lookup node failed. (%s:%d) | | ERR-08105 | ERR_CC_LOOKUP_STARTUP_FAILED | Startup lookup node failed. (%s:%d) | | ERR-08106 | ERR_CC_NORMAL_SHUTDOWN | Unable to shutdown warehouse (%s) since it is not INACTIVE status. | | ERR-08107 | ERR_CC_MESSAGE_EXPIRED | Expired message (%llu) received. | | ERR-08108 | ERR_CC_SNAPSHOT_FAIL | Snapshot failed: %s | ### `ERR-09000`–`ERR-09999` (11) | Code | Symbol | Original Message | |------|------|------| | ERR-09000 | ERR_RP_BUFFER_POOL_ITEM_ALLOC_FAIL | Failed to allocate buffer pool item. | | ERR-09001 | ERR_RP_TARGET_FILE_OPEN_FAIL | Failed to open replication target file <Table %llu, FileID %llu, PartID %llu - Level %d Type %d> | | ERR-09002 | ERR_RP_PROTOCOL_ERROR | Invalid protocol received. | | ERR-09003 | ERR_RP_SOCKET_ERROR | Socket write failed. | | ERR-09004 | ERR_RP_APPEND_VALUE_ERROR | Failed to append target table<%llu>. | | ERR-09005 | ERR_RP_VALUE_BUFFER_ALLOC_MEM_FAIL | Failed to allocate value buffer. | | ERR-09006 | ERR_RP_TABLE_CURSOR_OPEN_FAIL | Failed to open table <%llu>'s cursor. | | ERR-09007 | ERR_RP_POLL_REMOVE | Failed to remove poll socket. (%d) | | ERR-09008 | ERR_RP_POLL_DESTROY | Failed to destroy poll socket. (%d) | | ERR-09009 | ERR_RP_CANNOT_REPLICATE2_LARGER | Cannot replicate to larger dbs. | | ERR-09010 | ERR_RP_HOST_NOT_FOUND | Host not found: "%s". | ## Checking Error Codes - Check the error string returned by machsql or the driver. - Check server trace logs under `$MACHBASE_HOME/trc/`. If the cause remains unclear, see [Server Log Analysis](/dbms/operations-configuration-recovery/diagnosis-observability/#log-diagnosis-logs-log-server-logs) and [Checking Failure Indicators](/dbms/operations-configuration-recovery/diagnosis-observability/#monitoring-capacity-failure). --- title: "16.8 AI Agent Reference" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/ language: en kind: section --- # 16.8 AI Agent Reference AI Agent Reference helps AI agents and RAG systems find the correct canonical pages in the Machbase DBMS 8.7 documentation. It links to the authoritative feature documentation rather than redefining SQL syntax, SDK support, or operating procedures. ## Contents | Page | Purpose | |--------|------| | [Agent Guide](./guide-agent/) | Question classification, verification order, and response principles | | [canonical-url-map](./canonical-url-map/) | Canonical documentation URLs by topic | | [task-map](./task-map/) | Reading and verification order by user task | | [support-matrix](./support-matrix/) | Canonical edition, table, and SDK support matrices | | [constraints-index](./constraints-index/) | Canonical constraints and error conditions | | [evidence-map](./evidence-map/) | Evidence selection by claim type | | [terminology-disambiguation](./terminology-disambiguation/) | Clarify easily confused terms | | [sql-generation-rules](./sql-generation-rules/) | Verification rules before generating SQL | | [sdk-api-selection-rules](./sdk-api-selection-rules/) | SDK and API selection order | | [operations-checklist](./operations-checklist/) | Sequence for safe operational responses | | [error-resolution-map](./error-resolution-map/) | Canonical error diagnosis references | | [llms.txt](./llms-txt/) | Concise machine-readable documentation map | | [Full Text and RAG Index](./llms-full-txt-chunk-index/) | Full Markdown and JSON documentation index | ## Machine-readable Outputs - [llms.txt](/kr/llms.txt) - [llms-full.txt](/kr/llms-full.txt) - [llms-chunks.json](/kr/llms-chunks.json) The outputs linked above include only current Korean DBMS documentation. Machbase Neo and archived DBMS 8.5 documentation are excluded. ## Principles 1. Check the server version, edition, table type, and SDK first. 2. Read the canonical feature page together with its support scope. 3. Do not invent unverified syntax, defaults, limits, or error codes. 4. For operational changes, specify the target, impact, recovery method, and completion criteria. 5. Use public canonical URLs in responses. --- title: "16.8.1 Agent Guide" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/guide-agent/ language: en kind: page --- # 16.8.1 Agent Guide This guide defines the sequence for answering Machbase questions from canonical documentation. ## Question Classification | Question Type | First Reference | |----------|------------------| | Installation/upgrades | [Installation, Deployment, and Upgrades](/dbms/installation-deployment-upgrade/) | | Table selection/design | [Table Type Concepts and Selection](/dbms/data-modeling-table-design/) | | SQL syntax/functions | [SQL Reference](/dbms/reference/sql/) | | SDK/integration | [Development and Application Integration](/dbms/development-tools-integration/) | | Support/constraints | [Support Scope and Constraints](/dbms/reference/support-scope-constraints/) | | Operations/recovery | [Operations, Configuration, and Recovery](/dbms/operations-configuration-recovery/) | | Errors/performance | [Troubleshooting](/dbms/troubleshooting/) and [Performance Tuning](/dbms/performance-tuning/) | ## Response Sequence 1. Identify the product version, edition, table type, SDK, and target object in the question. 2. Check Machbase-specific meanings through [Terminology](../terminology-disambiguation/). 3. Check the [Support Matrix](../support-matrix/) and [Constraints Index](../constraints-index/). 4. Verify actual syntax, APIs, and procedures on the canonical page. 5. Include prerequisites, execution, result checks, and cleanup in examples. 6. For uncertain facts, provide the versions, commands, and documentation needed to verify them. ## Evidence and Links - Use canonical URLs on docs.machbase.com in public answers. - Internal issues, commits, or source paths do not replace evidence of public product behavior. - If documents conflict, prioritize current version-specific canonical pages and actual support scope. ## Safety Present queries and diagnosis first. Do not present execution steps for deleting data, restarting servers, terminating sessions, changing settings, or recovery without checking the user's target and authorization scope. --- title: "16.8.2 canonical-url-map" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/canonical-url-map/ language: en kind: page --- # 16.8.2 canonical-url-map These are the main canonical URLs for Machbase DBMS 8.7 documentation. Find detailed pages in each chapter's contents, and prefer the canonical pages below over legacy URLs. ## Getting Started and Concepts | Topic | Canonical URL | |------|---------------| | DBMS manual | `/dbms/` | | Getting started | `/dbms/getting-started/` | | Core concepts | `/dbms/core-concepts/` | | Installation and upgrades | `/dbms/installation-deployment-upgrade/` | | Table type selection | `/dbms/data-modeling-table-design/` | ## Tables and Analytics | Topic | Canonical URL | |------|---------------| | TAG | `/dbms/tag-table-usage/` | | ROLLUP | `/dbms/tag-rollup-usage/` | | LOG | `/dbms/log-table-usage/` | | TRANSACTION | `/dbms/rdb-table-usage/` | | LOOKUP | `/dbms/lookup-table-usage/` | | VOLATILE | `/dbms/volatile-table-usage/` | ## Development, Operations, and Reference | Topic | Canonical URL | |------|---------------| | SDK/API | `/dbms/development-tools-integration/` | | Performance | `/dbms/performance-tuning/` | | Operations and recovery | `/dbms/operations-configuration-recovery/` | | Security | `/dbms/security-access-control/` | | Troubleshooting | `/dbms/troubleshooting/` | | SQL | `/dbms/reference/sql/` | | Configuration | `/dbms/reference/configuration/` | | System catalog | `/dbms/reference/system-catalog/` | | Support scope | `/dbms/reference/support-scope-constraints/` | | Error codes | `/dbms/reference/error-codes/` | ## Machine-readable URLs | Output | Korean | English | |------|--------|------| | Concise map | `/kr/llms.txt` | `/llms.txt` | | Full text | `/kr/llms-full.txt` | `/llms-full.txt` | | Document index | `/kr/llms-chunks.json` | `/llms-chunks.json` | --- title: "16.8.3 task-map" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/task-map/ language: en kind: page --- # 16.8.3 task-map This map links user tasks to canonical reading order and completion criteria. | Task | Verification Order | Completion Check | |------|-----------|-----------| | First installation | [Installation](/dbms/installation-deployment-upgrade/) → [Getting Started](/dbms/getting-started/) | Server status, connection, and sample query | | Table selection | [Selection Criteria](/dbms/data-modeling-table-design/) → Table chapter | Edition, DML, axis, and retention requirements met | | Bulk ingestion | [Common Integration Concepts](/dbms/development-tools-integration/concepts-common/) → SDK page | Success/failure counts and flush verified | | SQL authoring | [SQL Reference](/dbms/reference/sql/) → [Support Scope](/dbms/reference/support-scope-constraints/) | Actual schema and results verified | | SDK selection | [Choosing an Integration Method](/dbms/development-tools-integration/selection-integration-method/) → [SDK Support](/dbms/development-tools-integration/sdk-support-scope/) | Server/SDK versions and APIs match | | Performance diagnosis | [Performance Approach](/dbms/performance-tuning/performance-approach/) → Symptom-specific tuning | Baseline and post-change measurements compared | | Failure diagnosis | [Troubleshooting](/dbms/troubleshooting/) → [Error Codes](/dbms/reference/error-codes/) | Cause, action, and recurrence prevention recorded | | Backup/recovery | [Backup/Recovery](/dbms/operations-configuration-recovery/backup-restore-mount/) | Restore or mounted queries verified | For tasks involving writes, deletion, or restarts, establish the target and impact scope before selecting the procedure. --- title: "16.8.4 support-matrix" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/support-matrix/ language: en kind: page --- # 16.8.4 support-matrix This page identifies the relevant dimensions of a support question and links to current canonical tables. ## Verification Order 1. Check Standard and Cluster scope in the [Edition Support Matrix](/dbms/reference/support-scope-constraints/edition/). 2. Check the target table's SQL and API scope in the [Table Type Support Matrix](/dbms/reference/support-scope-constraints/table-types-type/). 3. Check client APIs and minimum provenance in [SDK Support](/dbms/development-tools-integration/sdk-support-scope/). 4. Check conditions and exceptions in detailed feature support tables. | Feature Group | Canonical Reference | |--------|------| | TAG data UPDATE | [TAG UPDATE Support](/dbms/reference/support-scope-constraints/tag-data-update/) | | ROLLUP | [ROLLUP Support](/dbms/reference/support-scope-constraints/rollup/) | | TRANSACTION | [TRANSACTION Support](/dbms/reference/support-scope-constraints/rdb/) | | Backup/MOUNT | [Backup/MOUNT Support](/dbms/reference/support-scope-constraints/backup-mount/) | | Privileges | [Privilege Support](/dbms/reference/support-scope-constraints/privileges/) | When answering support questions, provide the edition, table type, server and SDK versions, and prerequisites along with `O/△/X`. --- title: "16.8.5 constraints-index" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/constraints-index/ language: en kind: page --- # 16.8.5 constraints-index For constraint questions, check the target object and execution path as well as the feature name. | Constraint Category | Canonical Reference | |-----------|------| | Edition and table type | [Support Scope and Constraints](/dbms/reference/support-scope-constraints/) | | SQL predicates and SET targets | [SQL Syntax Dictionary](/dbms/reference/sql/syntax/) | | TAG | [TAG Constraints and Troubleshooting](/dbms/tag-table-usage/constraints-errors-troubleshooting/) | | ROLLUP | [ROLLUP Constraints and Troubleshooting](/dbms/troubleshooting/rollup/) | | LOG | [LOG Constraints and Troubleshooting](/dbms/log-table-usage/constraints-errors-troubleshooting/) | | TRANSACTION | [TRANSACTION Constraints and Troubleshooting](/dbms/rdb-table-usage/constraints-errors-troubleshooting/) | | LOOKUP | [LOOKUP Constraints and Troubleshooting](/dbms/lookup-table-usage/constraints-errors-troubleshooting/) | | VOLATILE | [VOLATILE Constraints and Troubleshooting](/dbms/volatile-table-usage/constraints-errors-troubleshooting/) | When an error occurs, preserve the complete SQL, schema, edition, server version, and error code, then compare them with the allowed conditions in the canonical reference. --- title: "16.8.6 evidence-map" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/evidence-map/ language: en kind: page --- # 16.8.6 evidence-map Select public evidence appropriate to each claim in the response. | Claim Type | Preferred Evidence | |----------|-----------| | SQL syntax/functions/types | [SQL Reference](/dbms/reference/sql/) | | Edition/table/SDK support | [Support Scope and Constraints](/dbms/reference/support-scope-constraints/) and [SDK Support](/dbms/development-tools-integration/sdk-support-scope/) | | Configuration keys/defaults | [Configuration Reference](/dbms/reference/configuration/) and distribution configuration files | | System status columns | [System Catalog](/dbms/reference/system-catalog/) | | CLI options | [Command-line Tools](/dbms/reference/command-line-tools/) and distribution `--help` | | Error meaning/actions | [Error Codes](/dbms/reference/error-codes/) and [Troubleshooting](/dbms/troubleshooting/) | | Operating procedures | [Operations, Configuration, and Recovery](/dbms/operations-configuration-recovery/) | ## Verification Rules - Preserve version and edition conditions with the evidence. - Do not generalize example results into guarantees or performance claims. - Mark facts absent from public canonical documentation as requiring verification. - Internal development history does not replace public manual links. --- title: "16.8.7 terminology-disambiguation" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/terminology-disambiguation/ language: en kind: page --- # 16.8.7 terminology-disambiguation Verify user terminology in canonical Machbase documentation instead of assuming general database meanings. | Term | Canonical Reference | |------|-------------| | TAG, LOG, LOOKUP, VOLATILE, TRANSACTION | [Core Concepts](/dbms/core-concepts/) and [Table Type Selection](/dbms/data-modeling-table-design/) | | Append and SQL INSERT | [Common Integration Concepts](/dbms/development-tools-integration/concepts-common/) | | ROLLUP | [Using ROLLUP](/dbms/tag-rollup-usage/) | | BASETIME, BASE DISTANCE, SUMMARIZED | [TAG Structure and Schema](/dbms/tag-table-usage/table-structure-schema/) | | AUTH KEY | [Authentication and AUTH KEY](/dbms/security-access-control/authentication-auth-key/) | | Broker, Warehouse | [Edition and Cluster Concepts](/dbms/core-concepts/concepts-edition/) | | database, owner, tablespace | [Multiple Database Operations](/dbms/operations-configuration-recovery/multi-database/) | Preserve product object names and SQL keywords in responses. If the user's general term differs from a Machbase object, clarify the distinction first. --- title: "16.8.8 sql-generation-rules" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/sql-generation-rules/ language: en kind: page --- # 16.8.8 sql-generation-rules Apply the following verification sequence when generating SQL. The [SQL Reference](/dbms/reference/sql/) defines the actual syntax. ## Before Generation 1. Check the server version and edition. 2. Check the target database, owner, table type, and `DESC` output. 3. Verify the statement form in the [SQL Syntax Dictionary](/dbms/reference/sql/syntax/). 4. Verify arguments and return types in the [Function Dictionary](/dbms/reference/sql/functions/). 5. Check edition and table constraints in [Support Scope](/dbms/reference/support-scope-constraints/). ## Generation Rules - Do not assume keywords, functions, hints, or transaction behavior from other DBMSs apply. - Do not replace identifiers with parameter markers. - For time/distance ranges, DELETE, and UPDATE, provide a query to inspect expected target rows first. - Specify `ORDER BY` when result order matters. - Include result checks and cleanup in modification examples. If an error occurs, use the complete error and schema with the [Troubleshooting](/dbms/troubleshooting/) procedure rather than arbitrarily changing syntax. --- title: "16.8.9 sdk-api-selection-rules" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/sdk-api-selection-rules/ language: en kind: page --- # 16.8.9 sdk-api-selection-rules Check requirements and actual support instead of inferring features from an SDK name. ## Selection Order 1. Check language and standard interface requirements in [Choosing an Integration Method](/dbms/development-tools-integration/selection-integration-method/). 2. List requirements for Append, transactions, prepared statements, named binds, metadata, and AUTH KEY. 3. Check support and provenance in [SDK Support](/dbms/development-tools-integration/sdk-support-scope/). 4. Verify installation, connection options, type mappings, and error handling on the selected SDK page. | Environment | Canonical Reference | |------|------| | C/C++ SQLCLI/ODBC | [SQLCLI and ODBC](/dbms/development-tools-integration/cli-odbc/) | | Java | [JDBC](/dbms/development-tools-integration/jdbc/) | | Python | [Python](/dbms/development-tools-integration/python/) | | Node.js·TypeScript | [Node.js / TypeScript](/dbms/development-tools-integration/node-js-typescript/) | | .NET | [.NET Connector](/dbms/development-tools-integration/net-connector/) | | Go | [Go](/dbms/development-tools-integration/go/) | Also check server/SDK version combinations in [Compatibility](/dbms/reference/support-scope-constraints/compatibility-xma-protocol/). --- title: "16.8.10 operations-checklist" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/operations-checklist/ language: en kind: page --- # 16.8.10 operations-checklist Base operational responses on the procedures in [Operations, Configuration, and Recovery](/dbms/operations-configuration-recovery/) and apply the following safety sequence. 1. Identify symptoms, occurrence time, complete errors, and target databases/nodes/tables. 2. Inspect current state read-only with `machadmin -e`, relevant `V$` views, and logs. 3. Distinguish normal operation from failure and provide evidence that a change is needed. 4. Specify change targets, impact, downtime, rollback, and success criteria. 5. Check the user's authorization scope, execute one step at a time, and verify results. Do not automatically suggest server restarts, session termination, data deletion, configuration changes, backup restoration, or cluster node changes as diagnostic commands. Verify commands and SQL in the relevant [operations chapter](/dbms/operations-configuration-recovery/). --- title: "16.8.11 error-resolution-map" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/error-resolution-map/ language: en kind: page --- # 16.8.11 error-resolution-map Preserve the complete error and execution context instead of guessing an error number or cause. ## Diagnosis Order 1. Collect the full `ERR-XXXXX` message, SQL/command, and occurrence time. 2. Record server and SDK versions, edition, target database/owner/table, and connection options. 3. Check the message in the [Error Code Dictionary](/dbms/reference/error-codes/). 4. Apply symptom-specific procedures from [Troubleshooting](/dbms/troubleshooting/). 5. Verify recovery with the same input and validation queries after corrective action. | Symptom | Canonical Reference | |------|------| | Server/authentication/connection | [Server and Connection Issues](/dbms/troubleshooting/server-connection/) | | Ingestion/Append/files | [Ingestion and Loading Issues](/dbms/troubleshooting/item/) | | Queries/performance/memory | [Query and Performance Issues](/dbms/troubleshooting/performance/) | | Backup/recovery | [Backup and Recovery Issues](/dbms/troubleshooting/recovery-backup/) | | Cluster | [Cluster Issues](/dbms/troubleshooting/cluster/) | Do not assign an arbitrary error code from part of a message or recommend a destructive workaround without reproducing the problem. --- title: "16.8.12 llms.txt" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/llms-txt/ language: en kind: page --- # 16.8.12 llms.txt `llms.txt` is a UTF-8 plain-text contents map that helps LLMs quickly find the structure and main canonical pages of the current Machbase DBMS manual. ## URL | Language | URL | |------|-----| | English | [https://docs.machbase.com/llms.txt](/llms.txt) | | Korean | [https://docs.machbase.com/kr/llms.txt](/kr/llms.txt) | The output includes only current `/dbms/` documentation. Machbase Neo, archived DBMS 8.5, drafts, and alias pages are excluded. ## Contents - Product and manual version - Top-level DBMS chapters and canonical URLs - Canonical SQL, SDK, operations, support scope, and error code references - AI Agent Reference - Full-text and JSON index URLs ## Usage 1. Find the question's canonical section in `llms.txt`. 2. For individual Markdown, read `index.md` under that document's URL. 3. For the complete corpus, use [llms-full.txt](../llms-full-txt-chunk-index/). 4. Use `llms-chunks.json` when a crawler needs document-level metadata. `llms.txt` is a navigation index. Verify product facts in the linked current documentation before composing a response. --- title: "16.8.13 Full Text and RAG Document Index" url: https://docs.machbase.com/dbms/reference/ai-agent-reference/llms-full-txt-chunk-index/ language: en kind: page --- # 16.8.13 Full Text and RAG Document Index The current DBMS manual provides full Markdown text and a page-level JSON index. ## Full Text | Language | URL | |------|-----| | English | [llms-full.txt](/llms-full.txt) | | Korean | [llms-full.txt](/kr/llms-full.txt) | Full text concatenates published DBMS pages in navigation weight order. Each page boundary includes the title, language, and canonical URL. The body preserves source Markdown. ## JSON Index | Language | URL | |------|-----| | English | [llms-chunks.json](/llms-chunks.json) | | Korean | [llms-chunks.json](/kr/llms-chunks.json) | Schema version 1 has the following top-level fields. | Field | Description | |------|------| | `schema_version` | JSON contract version; currently `1` | | `product` | `Machbase DBMS` | | `manual_version` | Product version covered by the manual | | `language` | `en` or `kr` | | `document_count` | Size of the `documents` array | | `documents` | Document metadata array | Each document provides `id`, `title`, `url`, `markdown_url`, `kind`, `parent_url`, `weight`, and `last_modified`. JSON does not duplicate the body. Fetch each page's Markdown from `markdown_url` or use `llms-full.txt` as the corpus. ## Chunk Boundaries The current index treats one published page as one document chunk. SQL syntax, SDK tasks, and operating procedures remain on separate pages where possible, so URLs and titles can serve as stable chunk identifiers. Preserve the page `id` when subdividing large dictionary pages. Nondeterministic values such as build time are omitted. Neo, DBMS 8.5, drafts, and alias pages are excluded from both the index and full text.