SQL/MED
SQL/MED is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:
- Foreign Table
- a transparent access method for external data
- DATALINK
- a special SQL type intended to store URLs in database
Current Status
The implementation of this specification began in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.
Basic features have been merged in PostgreSQL 9.1.
- Make foreign data wrapper functional
- Support FOREIGN TABLEs
contrib/file_fdw is available to retrieve external data from server-side files.
Check out the list of all the foreign data wrappers
Active Work In Progress
Add pgsql_fdw as a contrib module
"pgsql_fdw contrib module" is under proposal at CF 2011-11. The goal of this proposal is to add pgsql_fdw as a contrib module.
Smart planning
- We might have statistics of external data. ANALYZE command would need to have hook to delegate row sampling to each FDW. For this purpose, "Collecting statistics on foreign tables" is under proposal at CF 2011-11. This proposal provides a handler function which allows FDWs to handle ANALYZE commands which are executed for foreign tables. In addition, contrib/file_fdw is enhanced to get sample rows from actual data file and calculate statistics by using existing routines in core.
- set_foreign_size_estimates() have to be enhanced to reflect actual statistics.
JOIN push down
Doing a JOIN (or JOINs) on the remote side would reduce amount of data transferred from external server.
Table partioning
Foreign tables should support inheritance and table partitioning for scale-out clustering. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as partitioned remote function call in PL/Proxy.
Connection caching
Currently, connection caching has not been implemented in order to focus on the FDW API. Ideas below once had been implemented but have since been removed.
Connections to foreign servers are cached and reused during the lifetime of the backend. When a scan of a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache. If the reusable connection is not in cache, then call FdwRoutine.ConnectServer() to create a new connection and store it in the connection cache.
Connections are identified by name. A connection's name is the same as the name of the server which the connection uses.
The pg_foreign_connections view displays all the foreign connections that are available in the current session.
Name | Type | Reference | Description |
---|---|---|---|
connname | Text | name of the connection | |
srvname | Name | pg_foreign_server.srvname | name of the foreign server |
usename | Name | pg_authid.rolname | name of the local role which was used to map the foreign user |
fdwname | Name | pg_foreign_data_wrapper.fdwname | name of the foreign data wrapper which was used to connect to the foreign server |
Finished works
Syntax
In SQL standard, 'CREATE FOREIGN DATA WRAPPER' has a 'LIBRARY' option and FDW routines are exported directly from the library, but another approach like 'CREATE LANGUAGE' would be better because we already have pg_proc, an existing function manager.
-- Register a function that returns FDW handler function set. CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler AS 'MODULE_PATHNAME' LANGUAGE C; -- Create a foreign data wrapper with FDW handler. CREATE FOREIGN DATA WRAPPER postgresql HANDLER postgresql_fdw_handler VALIDATOR postgresql_fdw_validator;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.
-- Create a foreign server. CREATE SERVER remote_postgresql_server FOREIGN DATA WRAPPER postgresql OPTIONS ( host 'somehost', port 5432, dbname 'remotedb' ); -- Create a user mapping. CREATE USER MAPPING FOR postgres SERVER remote_postgresql_server OPTIONS ( user 'someuser', password 'secret' );
These two statements are not changed.
-- Create a foreign table. CREATE FOREIGN TABLE schemaname.tablename ( column_name type_name [ OPTIONS ( ... ) ] [ NOT NULL ], ... ) SERVER remote_postgresql_server OPTIONS ( ... );
Foreign tables can have generic options with OPTIONS syntax.
In the first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy. hackers-ML archive
FDW routines
Version 1
In the SQL standard, FDW routines are designed to have a portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn't seem realistic. Instead, a PostgreSQL-specific and C language-specific routine set would be feasible:
/* FDW interface routines */ typedef struct FdwRoutine { FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user); void (*FreeFSConnection)(FSConnection *conn); void (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel); void (*BeginScan)(ForeignScanState *scanstate); void (*Open)(ForeignScanState *scanstate); void (*Iterate)(ForeignScanState *scanstate); void (*Close)(ForeignScanState *scanstate); void (*ReOpen)(ForeignScanState *scanstate); } FdwRoutine;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOINs on several foreign tables in the same foreign server.
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.
In contrast, ForeignServer and UserMapping are implemented in core.
Version 2
Per discussion and Heikki Linnakangas's proposal, FdwRoutine was changed in some points:
- Add FdwPlan as container of FDW-specific planning information.
- Add FdwExecutionState as container of FD-specific execution information.
- Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection
- Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information. That plan will be passed to BeginScan() to execute the scan.
struct FdwPlan { NodeTag type; /* FdwPlan need copyObject() support for plan caching */ char *explainInfo; /* FDW-specific info shown in EXPLAIN VERBOSE */ double startup_cost; /* Optimizer needs costs for each path */ double total_cost; List *private; /* FDW can store private data as copy-able objects */ }; struct FdwExecutionState { void *private; /* FDW-private data */ }; struct FdwRoutine { #ifdef IN_THE_FUTURE FdwPlan *(*PlanNative)(Oid serverid, char *query); FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query); #endif FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root, RelOptInfo *baserel); FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params); void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot); void (*ReScan)(FdwExecutionState *state); void (*EndScan)(FdwExecutionState *state); };
Version 3
Finally FDW API has been defined in PostgreSQL 9.1 as below:
typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid, PlannerInfo *root, RelOptInfo *baserel); typedef void (*ExplainForeignScan_function) (ForeignScanState *node, struct ExplainState *es); typedef void (*BeginForeignScan_function) (ForeignScanState *node, int eflags); typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node); typedef void (*ReScanForeignScan_function) (ForeignScanState *node); typedef void (*EndForeignScan_function) (ForeignScanState *node); typedef struct FdwRoutine { NodeTag type; PlanForeignScan_function PlanForeignScan; ExplainForeignScan_function ExplainForeignScan; BeginForeignScan_function BeginForeignScan; IterateForeignScan_function IterateForeignScan; ReScanForeignScan_function ReScanForeignScan; EndForeignScan_function EndForeignScan; } FdwRoutine;
In future, more planner hooks may be added to allow FDWs to optimize the query.
Version 4
In 9.2, PlanForeignScan is changed so that FDW can return multiple scan paths per a foreign table, and this change get rid of FdwPlan. Planner chooses appropriate path from paths provided by FDW, and creates only one ForeignScan node which has copy of fdw_private of chosen path. Now PlanForeignScan is responsible to create ForeignScan path node and add it to RelOptInfo (baserel). You can use create_foreignscan_path, which is also changed in 9.2, to create a finished ForeignScan path node.
typedef void (*PlanForeignScan_function) (Oid foreigntableid, PlannerInfo *root, RelOptInfo *baserel);
PlanForeignScan of FDW which doesn't support any pushing down feature would be like this.
void fooPlanForeignScan(Oid foreigntableid, PlannerInfo *root, RelOptInfo *baserel) { double rows; Cost startup_cost, total_cost; List *fdw_private; /* Estimate # of rows returned by this scan */ rows = ...; /* Estimate costs of this scan */ startup_cost = ...; total_cost = ...; /* Store FDW-private information as copy-able objects */ fdw_private = NIL; fdw_private = lappend(fdw_private, makeNode(...)); ... /* Create path node and add it to baserel */ add_path(baserel, (Path *) create_foreignscan_path(root, baserel, rows, /* # of tuples in the table */ startup_cost, /* costs are required */ total_costs, NIL, /* no pathkeys */ NULL, /* no outer rel eigher */ NIL, /* no param clause */ fdw_private)); }
In other FDW functions, fdw_private is available via ForeignScanState.
List *fdw_private; fdw_private = ((ForeignScan *) node->ss.ps.plan)->fdw_private;
On-disk structure
pg_catalog.pg_foreign_data_wrapper
An FDW handler function returns an FDW routine set. A new pseudo type 'fdw_handler' is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog. InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can't be used to define any foreign table. This specification supports usage in which foreign-data wrapper is used as the container of connection information like the past.
CREATE TABLE pg_catalog.pg_foreign_data_wrapper ( fdwname name NOT NULL UNIQUE, fdwowner oid NOT NULL REFERENCES pg_authid (oid), fdwvalidator oid NOT NULL REFERENCES pg_proc (oid), fdwhandler oid NOT NULL REFERENCES pg_proc (oid), fdwacl aclitem[], fdwoptions text[] ) WITH OIDS;
pg_catalog.pg_foreign_table
A foreign table is registered in pg_class with relkind = 'f' (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in which we store the foreign server ID and generic options for the foreign table.
CREATE TABLE pg_catalog.pg_foreign_table ( ftrelid oid PRIMARY KEY REFERENCES pg_class (oid), ftserver oid NOT NULL REFERENCES pg_foreign_server (oid), ftoptions text[] ) WITHOUT OIDS;
Planner and Executor changes
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for this purpose.
Planner
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.
In the planning phase, create_foreignscan_path() calls PlanRelScan() of the related FDW's FdwRoutine for each ForeignScan node. PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.
In future, additional planner hooks might be added for:
- Pass-through mode (one ForeignScan node executes whole query)
- Query optimization such as merging multiple foreign tables into one remote query
To estimate costs as correctly as possible, FDWs might want to have their own statistics. In this step, we don't provide a common mechanism to store statistics. Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE. With such a function, FDWs can update their statistics in their own respective ways.
In version 1, the planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().
typedef struct ForeignScan { Scan scan; bool fsSystemCol; struct FdwPlan *fdwplan; } ForeignScan;
Executor
The Executor module executes ForeignScan nodes with calling FDW routines.
- ExecInitForeignScan()
- Create ForeignScanState for the given ForeignScan plan node.
- Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.
- ExecForeignScan()
- Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.
- If the scan reaches the end, the slot will be empty after Iterate() call.
- ExecForeignReScan()
- Call FdwRoutine.ReScan() to re-initialize scanning.
- ExecEndScan()
- Call FdwRoutine.EndScan() to finalize the foreign scan.
- ExecForeignMarkPos()/ExecForeignRestrPos()
- Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false for ForeignScan. The reason not to support is that they are used to perform merge join, and merge join needs sorted results. If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.
typedef struct ForeignScanState { ScanState ss; struct FdwRoutine *fdwroutine; void *fdw_state; } ForeignScanState;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines. Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state->private.
Per-column FDW option
Similar to other kind of FDW objects, column of a foreign table can have FDW options. This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause for a column, and key/value pairs are stored in attfdwoptions of pg_attribute.
Because of syntax vagueness between "DEFAULT b_expr" and "OPTIONS ( ... )", OPTIONS clause for a column must be specified before any constraints or default value.
Foreign data wrappers
file_fdw
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module. This can be used to read data from files in the server's local file system like COPY FROM
command.
Currently, stdin, although allowed in COPY FROM, is not supported.
Because the FDW read from files on server-side, some security issues should be considered. Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.
using COPY FROM routines
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.
generic options
Information of the source file such as filename are passed via generic options. Options of COPY FROM statement are acceptable, but oids is not supported by file_fdw because it's a legacy feature.
Different from COPY, the force_not_null can be described in per-column generic option with boolean values, not a list of column names.
PostgreSQL
This can be used to connect external postgres servers. It might be able to be integrated with contrib/dblink to share the code and connections. dblink will be installed optionally like as standard contrib modules.
Connection options
The connection options are constructed from FDW options of foreign-data wrapper, foreign server and user mapping, with choosing only connection options because FDW option might include non-connection options such as relname and nspname. Note that non-superuser MUST specify password in FDW options and require password authentication by the foreign server because of security issues.
In current implementation, FDW options of user mappings are visible to users who has SUPERUSER privilege or USAGE privilege on relevant SERVER, because of security issues.
No transaction management
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT. Thus, all SQL statements are executed in each transaction when 'autocommit' was set to 'on'.
Cost estimation
ANALYZE for foreign tables is not supported in 9.0, so we can't store statistics in local PG. One work around is getting EXPLAIN result from remote server, and use its cost values for local planning.
SELECT-clause optimization
Currently SELECT clause is constructed as "SELECT col1, col2, col3, ...". If some of columns are not used at all in the original query, they will be replaced with NULL for optimization. For example, if col2 was unused, SELECT clause will be "SELECT col1, NULL, col3, ...". Main purpose of this optimization is to reduce amount of data transferred from remote server.
WHERE-clause push-down
WHERE clauses in the original query are pushed-down into the reconstructed query sent to the foreign server.
To push-down a condition, it must consist of only the following node types. For this purpose, we check each element in RelOptInfo.baserestrictinfo list. If there are conditions which can't be pushed down, the remote server will send rows without the conditions, and the local server will evaluate the rows and ignore rows which don't satisfy the conditions.
Element | Tag name | Note |
---|---|---|
Constant value | Const | |
Table column reference | Var | |
Array of some type | Array | expression like "'{1, 2, 3}'" |
External parameter | Param | "External" means that "Param.paramkind == PARAM_EXTERNAL" |
Bool expression | BoolExpr | expressions such as "A AND B", "A OR B", "NOT A" |
NULL test | NullTest | expressions like "IS [NOT] NULL" |
Operator | OpExpr | pg_operator.opcode MUST be a IMMUTABLE function |
DISTINCT operator | DistinctExpr | expressions like "A IS DISTINCT FROM B"
pg_operator.opcode MUST be a IMMUTABLE function |
Scalar array operator | ScalarArrayOpExpr | expressions such as "ANY (...)", "ALL (...)"
pg_operator.opcode MUST be a IMMUTABLE function |
Function call | FuncExpr | MUST be a IMMUTABLE function |
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.
Retrieving result tuples
This FDW switches method for retrieving result tuples according to estimated # of result rows.
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan(). Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, are configurable via FDW option of SERVER and/or FOREIGN TABLE. If a option was specified on both object, latter overrides former.
We must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy and some overhead. Another solution is registering cleanup function to resource owner, and release PGresult in that cleanup function. This method has already been used to close libpq connection.
Open questions
There are still several issues in the FDW design and implementation:
- Which should we export foreign connection management functions from?
- Currently
DISCARD ALL
disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.
Resolved questions
- pg_foreign_table.ftoptions vs. pg_class.reloptions
- We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won't use those fields for foreign tables.
- FdwRoutine vs. SETOF record function
- Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.
- fdw_handler vs. function table like pg_am
- FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.
- Which user identifier is appropriate to determine USER MAPPING ?
- Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING. Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option. It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function. Is this an appropriate specification ?
- Locking a foreign table
- Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table. In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes. Should we relax the restriction if the target is a foreign server ? We must consider about recursive locking via table inheritance.
- In 9.1, locking foreign table is not supported.
Supported features
DDL
- ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}
- CREATE FOREIGN TABLE name INHERITS (parent)
- Inherit a plain relation (tableoid system attribute is supported too)
- DROP FOREIGN TABLE
- ALTER FOREIGN TABLE name RENAME TO newname
- ALTER FOREIGN TABLE name RENAME COLUMN column TO newname
- ALTER FOREIGN TABLE name {ADD|DROP} column
- ALTER FOREIGN TABLE name {ADD|DROP} constraint
- Only NOT NULL and CHECK constraints are supported.
- ALTER FOREIGN TABLE name OWNER TO owner
- {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user
- syntax below are valid too:
- {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user
- {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user
- syntax below are valid too:
- CREATE RULE ... TO foreign_table
- COMMENT ON FOREIGN TABLE name IS 'table comment'
- COMMENT ON COLUMN name.column IS 'column comment'
DML
- SELECT statement using:
- multiple foreign-data wrappers
- multiple foreign servers
- multiple foreign tables (JOIN, UNION, Subquery, etc.)
- PREPARE/EXECUTE statement with parameters
- Deny execution of INSERT/UPDATE/DELETE for a foreign table
- Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table
- Lock foreign tables and their children recursively
- Support tableoid system column
- To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.
pg_dump
- dumping schema (definition) of foreign tables
- contents of a foreign table are not dumped because they are not part of the database
- dumping foreign-data wrappers with HANDLER specification
- dumping foreign-data wrappers, servers and user mappings excluding built-in objects
Future improvements
General
- Smart planning
- ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.
- The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same. GENERIC OPTION like cost_factor allow to tell the overhead to planner.
for SQL-based FDWs
- JOINs of two foreign tables in the same server
- They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.
- Optimize SELECT clause
- Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause.
- Support internal parameter
- A certain kind of a plan, i.e. nested loop, generates internal parameter to pass value(s) from parent node to child node. The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query.
- This seems difficult in some cases, because value of internal parameter is determined after fetching tuple from a relation.
- Optimize parameter
- Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.
- Support cursor mode for huge result
- Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once. If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.
- Push-down WHERE clause including CURRENT_TIMESTAMP
- Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.
SQL Conformance
Identifier | Description | Status |
---|---|---|
M004 | Foreign data support | |
M005 | Foreign schema support | |
M006 | GetSQLString routine | |
M007 | TransmitRequest | |
M009 | GetOpts and GetStatistics routines | |
M010 | Foreign data wrapper support | |
M018 | Foreign data wrapper interface routines in Ada | (not planned) |
M019 | Foreign data wrapper interface routines in C | |
M020 | Foreign data wrapper interface routines in COBOL | (not planned) |
M021 | Foreign data wrapper interface routines in Fortran | (not planned) |
M022 | Foreign data wrapper interface routines in MUMPS | (not planned) |
M023 | Foreign data wrapper interface routines in Pascal | (not planned) |
M024 | Foreign data wrapper interface routines in PL/I | (not planned) |
M030 | SQL-server foreign data support | |
M031 | Foreign data wrapper general routines |
Code | Meaning |
---|---|
HV000 | FDW-specific condition |
HV001 | MEMORY ALLOCATION ERROR |
HV002 | DYNAMIC PARAMETER VALUE NEEDED |
HV004 | INVALID DATA TYPE |
HV005 | COLUMN NAME NOT FOUND |
HV006 | INVALID DATA TYPE DESCRIPTORS |
HV007 | INVALID COLUMN NAME |
HV008 | INVALID COLUMN NUMBER |
HV009 | INVALID USE OF NULL POINTER |
HV00A | INVALID STRING FORMAT |
HV00B | INVALID HANDLE |
HV00C | INVALID OPTION INDEX |
HV00D | INVALID OPTION NAME |
HV00J | OPTION NAME NOT FOUND |
HV00K | REPLY HANDLE |
HV00L | UNABLE TO CREATE EXECUTION |
HV00M | UNABLE TO CREATE REPLY |
HV00N | UNABLE TO ESTABLISH CONNECTION |
HV00P | NO SCHEMAS |
HV00Q | SCHEMA NOT FOUND |
HV00R | TABLE NOT FOUND |
HV010 | FUNCTION SEQUENCE ERROR |
HV014 | LIMIT ON NUMBER OF HANDLES EXCEEDED |
HV021 | INCONSISTENT DESCRIPTOR INFORMATION |
HV024 | INVALID ATTRIBUTE VALUE |
HV090 | INVALID STRING LENGTH OR BUFFER LENGTH |
HV091 | INVALID DESCRIPTOR FIELD IDENTIFIER |
0X000 | invalid foreign server specification |
0Y000 | pass-through specific condition |
0Y001 | INVALID CURSOR OPTION |
0Y002 | INVALID CURSOR ALLOCATION |