## Database structure

Libgda imposes its own structure (based on objects such as tables and views which name starts with an underscore '_') for the meta data database associated to a GdaMetaStore object, but a user can also add its own tables or other database objects. The following diagram shows the tables defined by Libgda for its internal needs:

### Data types

Data types (as reported for example for table's columns) can be one of the following kinds:

- Builtin data types offered by the database engine such as integers, varchar, etc. Those data types are all listed in the "_builtin_data_types" table.

- Database domains: domains are data types with optional constraints (restrictions on the allowed set of values). A domain refers to the base data type from which it is defined (that base data type can also be an array). Those data types are all listed in the "_domains" table.

- User defined data types (which are not part of the SQL standard but featured by some databases such as PostgreSQL) are simple or composed data types based on existing data types (which may also be arrays). Those data types are all listed in the "_udt" table.

- Arrays of any of the previous data types (one or more dimensions). Arrays are not per-se data types, but rather refer to an existing data type. Arrays are described in the "_element_types" table.

Note that the data types which are built in, domains or user defined are all also listed in the "_all_types" view as a convenience.

The impact of that data types' hierarchy is that everytime a data type is referenced (from a table's column definition for example), there will be two attributes for the data type: one named `data_type` which, if not NULL, refers to a data type listed in the "_all_types" view (thus a built in, domain or user defined data type), and one named `array_spec` which, if not NULL, refers to an array, listed in the "_element_types" table. Any of these attributes can be NULL, but they should never be both NULL at the same time.

Single dimension arrays will have the `data_type` attribute referencing a data type in the "_all_types" view (and the `array_spec` attribute set to NULL), whereas multi dimension arrays will have the `data_type` attribute set to NULL and the `array_spec` attribute referencing another tow in the "_element_types" table.

The following diagram illustrates the data types representation and how ther are refered from table's columns, domains, and other database objects which refer to a data type:

### SQL identifiers

Please refer to the SQL identifiers and abstraction section for an overview of how SQL identifiers are handled thoughout Libgda

Considering that each database has its own internal way of representing case insensitive SQL identifiers (for instance PostgreSQL represents them in lower case whereas Oracle represents them in upper case and MySQL represents them in upper or lower case depending on the platform and the configuration), Libgda has chosen by convention to represent case insensitive SQL identifiers in lower case and case sensitive SQL identifiers enclosed between double quotes when storing meta data in GdaMetaStore.

This convention has been made necessary to avoid confusion. To illustrate the problem, let's consider a table named mytable. Without this convention, if that table was in a PostgreSQL database, then the meta data would report it as mytable, and if it was in an ORACLE, it would report it as MYTABLE. Now, a programmer which wants to compare the schemas of the PostgreSQL and Oracle databases has to know that the PostgreSQL's mytable and Oracle's MYTABLE represent in fact the same table which means he needs to know how each database internally stores SQL identifiers, which is not a good choice because it makes the application less portable between database engines. Better let each database provider do the job. Note that things can even get more confusing if MySQL is used because then one needs to figure out on which platform the MySQL server is running and how it's configured, a task which makes an application even less portable.

To keep the same example, to build some SQL using the SQL identifier as reported by the meta data (mytable for PostgreSQL and MYTABLE for Oracle), one has either to determine if the SQL identifier needs to be quoted or not (which limits the application's portability), or systematically enquote the SQL identifier which is not something Libgda can impose to application developpers.

### Short and full names

Database objects will have two associated names, the short name and the long name, the difference being the same as machine in a local network being called either by its machine name such as "moon" or by its fully qualified domain name such as "moon.my.network", but applied to databases and schemas. The full name corresponding to the <database>.<schema>.<object_name> or <schema>.<object_name>, and the short name corresponding to the <object_name>.

Short name and full name differ when the schema being accessed is not the schema containing the named database object, in which case the full name must be used. Some database specific features may also alter the differences between the short name and the sull name such as the "search_path" variable for PostgreSQL (which is to a unix PATH variable but for schemas).

### Individual table description

This section individually describes each table.

#### _attributes table

Table to store (key,value) pairs (keys starting with '_' are reserved)

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
att_name | string | Yes | No |
att_value | string |  | No |

#### _information_schema_catalog_name table

Name of the current database (current catalog), has only one row

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
catalog_name | string | Yes | No |

#### _schemata table

List of schemas

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
catalog_name | string | Yes | No | Name of the catalog that contains the schema
schema_name | string | Yes | No |
schema_owner | string |  | Yes | Name of the schema
schema_internal | boolean |  | No | Tells if the schema is specific to the database implementation (and usually can't be modified)

- (catalog_name) references _information_schema_catalog_name(catalog_name)

#### _builtin_data_types table

List of built-in data types such as varchar, int, ...

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
short_type_name | string |  | No | Short name of the data type
full_type_name | string | Yes | No | Full name of the data type
gtype | string |  | Yes |
comments | string |  | Yes |
synonyms | string |  | Yes |
internal | boolean |  | No | Tells if the data type is reserved for the database implementation and should not be used in applications

#### _udt table

User defined data types

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
udt_catalog | string | Yes | No | Name of the catalog that contains the data type
udt_schema | string | Yes | No | Name of the schema that contains the data type
udt_name | string | Yes | No | Name of the data type
udt_gtype | string |  | Yes | GType associated to the data type
udt_comments | string |  | Yes |
udt_short_name | string |  | No |
udt_full_name | string |  | No |
udt_internal | boolean |  | No | Tells if the data type is reserved for the database implementation and should not be used in applications
udt_owner | string |  | Yes |

- (udt_catalog, udt_schema) references _schemata(catalog_name, schema_name)

#### _udt_columns table

List of components for a user defined data type for composed data types (such as a complex number data type which has real and imaginary parts)

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
udt_catalog | string | Yes | No | Name of the catalog that contains the user defined data type for which the column is
udt_schema | string | Yes | No | Name of the schema that contains the user defined data type for which the column is
udt_name | string | Yes | No | Name of the user defined data type for which the column is
udt_column | string | Yes | No | Name of the column (part)
ordinal_position | gint |  | No | Column position, starts at 1
data_type | string |  | Yes | Data type of the column (if the column is an array, then 'array_spec' is set, and this may be NULL)
array_spec | string |  | Yes | Array description if the column is an array
character_maximum_length | gint |  | Yes |
character_octet_length | gint |  | Yes |
numeric_precision | gint |  | Yes |
numeric_scale | gint |  | Yes |
datetime_precision | gint |  | Yes |
character_set_catalog | string |  | Yes |
character_set_schema | string |  | Yes |
character_set_name | string |  | Yes |
collation_catalog | string |  | Yes |
collation_schema | string |  | Yes |
collation_name | string |  | Yes |

- (udt_catalog, udt_schema, udt_name) references _udt(udt_catalog, udt_schema, udt_name)

- (array_spec) references _element_types(specific_name)

#### _enums table

List of possible enumeration labels for enumerations

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
udt_catalog | string | Yes | No | Name of the catalog that contains the ENUM user defined data type
udt_schema | string | Yes | No | Name of the schema that contains the ENUM user defined data type
udt_name | string | Yes | No | Name of the ENUM user defined data type
label | string | Yes | No |
ordinal_position | gint |  | No | Position, starts at 1

- (udt_catalog, udt_schema, udt_name) references _udt(udt_catalog, udt_schema, udt_name)

#### _element_types table

Array specific attributes for array data types

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
specific_name | string | Yes | No | No specific meaning, used as a primary key, and for joining
object_catalog | string |  | No | Name of the catalog that contains the object that uses the array being described
object_schema | string |  | No | Name of the schema that contains the object that uses the array being described
object_name | string |  | No | Name of the object that uses the array being described
object_type | string |  | No | The type of the object that uses the array being described TABLE_COL, DOMAIN, UDT_COL, ROUTINE_COL, ROUTINE_PAR
data_type | string |  | Yes | Base data type of the array (if the base data type is an array, then 'array_spec' is set, and this may be NULL)
array_spec | string |  | Yes | Array description if the base data type is an array
min_cardinality | gint |  | Yes |
max_cardinality | gint |  | Yes |

#### _domains table

List of domains

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
domain_catalog | string | Yes | No | Name of catalog that contains the domain
domain_schema | string | Yes | No | Name of schema that contains the domain
domain_name | string | Yes | No | Name of the domain
data_type | string |  | Yes | Data type of the domain (if the domain is an array, then 'array_spec' is set, and this may be NULL)
array_spec | string |  | Yes | Array description if the domain is an array
domain_gtype | string |  | No |
character_maximum_length | gint |  | Yes |
character_octet_length | gint |  | Yes |
collation_catalog | string |  | Yes | Name of catalog that contains the associated collation
collation_schema | string |  | Yes | Name of schema that contains the associated collation
collation_name | string |  | Yes | Name of the associated collation
character_set_catalog | string |  | Yes | Name of catalog that contains the associated character set
character_set_schema | string |  | Yes | Name of schema that contains the associated character set
character_set_name | string |  | Yes | Name of the associated character set
numeric_precision | gint |  | Yes |
numeric_scale | gint |  | Yes |
domain_default | string |  | Yes |
domain_comments | string |  | Yes |
domain_short_name | string |  | No |
domain_full_name | string |  | No |
domain_internal | boolean |  | No |
domain_owner | string |  | Yes |

- (domain_catalog, domain_schema) references _schemata(catalog_name, schema_name)

- (array_spec) references _element_types(specific_name)

#### _tables table

List of tables (tables, views or other objects which can contain data)

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
table_catalog | string | Yes | No | Name of catalog that contains the table
table_schema | string | Yes | No | Name of schema that contains the table
table_name | string | Yes | No | Name of the table
table_type | string |  | No | Type of table: BASE TABLE, VIEW, LOCAL TEMPORARY, SYSTEM TABLE, GLOBAL TEMPORARY, ALIAS or SYNONYM
is_insertable_into | boolean |  | Yes | Tells if the table's contents can be modified
table_comments | string |  | Yes |
table_short_name | string |  | No |
table_full_name | string |  | No |
table_owner | string |  | Yes |

- (table_catalog, table_schema) references _schemata(catalog_name, schema_name)

#### _views table

List of views and their specific information

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
table_catalog | string | Yes | No | Name of catalog that contains the view
table_schema | string | Yes | No | Name of schema that contains the view
table_name | string | Yes | No | Name of the view
view_definition | string |  | Yes | View as SQL
check_option | string |  | Yes | CASCADE if the statement used to create the view included the WITH CHECK OPTION; otherwise, NONE
is_updatable | boolean |  | Yes | Tells if the view's contents can be modified

- (table_catalog, table_schema, table_name) references _tables(table_catalog, table_schema, table_name)

#### _collations table

List of collations methods

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
collation_catalog | string | Yes | No |
collation_schema | string | Yes | No |
collation_name | string | Yes | No |
collation_comments | string |  | Yes |
collation_short_name | string |  | No |
collation_full_name | string |  | No |

- (collation_catalog, collation_schema) references _schemata(catalog_name, schema_name)

#### _character_sets table

List of character sets

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
character_set_catalog | string | Yes | No |
character_set_schema | string | Yes | No |
character_set_name | string | Yes | No |
default_collate_catalog | string |  | Yes |
default_collate_schema | string |  | Yes |
default_collate_name | string |  | Yes |
character_set_comments | string |  | Yes |
character_set_short_name | string |  | No |
character_set_full_name | string |  | No |

- (character_set_catalog, character_set_schema) references _schemata(catalog_name, schema_name)

- (default_collate_catalog, default_collate_schema, default_collate_name) references _collations(collation_catalog, collation_schema, collation_name)

#### _routines table

List of functions and stored procedures (note: the primary jey for that table is composed of (specific_catalog, specific_schema, specific_name))

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
specific_catalog | string | Yes | No | Specific name of catalog that contains the routine
specific_schema | string | Yes | No | Specific name of schema that contains the routine
specific_name | string | Yes | No | Specific name of the routine (may be mangled for polymorphic routines)
routine_catalog | string |  | Yes | Name of catalog that contains the routine (may be NULL)
routine_schema | string |  | Yes | Name of schema that contains the routine (may be NULL)
routine_name | string |  | No | Name of the routine
routine_type | string |  | Yes | FUNCTION, PROCEDURE, AGGREGATE
return_type | string |  | Yes | Data type returned by the routine (may be NULL if routine does not return any value)
returns_set | boolean |  | No | True if routine returns a set (i.e., multiple values of the specified data type or if data type may vary)
nb_args | gint |  | No | Number of arguments (-1 for variable number of arguments)
routine_body | string |  | Yes | If the routine is an SQL function, then SQL, else EXTERNAL
routine_definition | string |  | Yes | The source text of the routine
external_name | string |  | Yes | If the routine is an external function, then the external name (link symbol) of the function
external_language | string |  | Yes | The language the routine is written in
parameter_style | string |  | Yes | Parameter style (GENERAL, JAVA, SQL, GENERAL WITH NULLS)
is_deterministic | boolean |  | Yes | Tells if the routine returns the same results given the same arguments forever
sql_data_access | string |  | Yes | Whether the routine contains SQL and whether it reads or modifies data (NONE, CONTAINS, READS, MODIFIES)
is_null_call | boolean |  | Yes | Tells if the routine will be called if any one of its arguments is NULL
routine_comments | string |  | Yes |
routine_short_name | string |  | No |
routine_full_name | string |  | No |
routine_owner | string |  | Yes |

- (specific_catalog, specific_schema) references _schemata(catalog_name, schema_name)

#### _triggers table

List of triggers

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
trigger_catalog | string | Yes | No |
trigger_schema | string | Yes | No |
trigger_name | string | Yes | No |
event_manipulation | string | Yes | No | Event that fires the trigger (INSERT, UPDATE, or DELETE)
event_object_catalog | string | Yes | No | Name of the database that contains the table that the trigger is defined on
event_object_schema | string | Yes | No | Name of the schema that contains the table that the trigger is defined on
event_object_table | string | Yes | No | Name of the table that the trigger is defined on
action_statement | string |  | Yes | Statement that is executed by the trigger
action_orientation | string |  | No | Identifies whether the trigger fires once for each processed row or once for each statement (ROW or STATEMENT)
condition_timing | string |  | No | Time at which the trigger fires (BEFORE or AFTER)
trigger_comments | string |  | Yes |
trigger_short_name | string |  | No |
trigger_full_name | string |  | No |

- (trigger_catalog, trigger_schema) references _schemata(catalog_name, schema_name)

- (event_object_catalog, event_object_schema, event_object_table) references _tables(table_catalog, table_schema, table_name)

#### _columns table

List of columns composing tables

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
table_catalog | string | Yes | No |
table_schema | string | Yes | No |
table_name | string | Yes | No |
column_name | string | Yes | No |
ordinal_position | gint |  | No | Column position, starts at 1
column_default | string |  | Yes |
is_nullable | boolean |  | No |
data_type | string |  | Yes | Data type of the column (if the column is an array, then 'array_spec' is set, and this may be NULL)
array_spec | string |  | Yes | Array description if the column is an array
gtype | string |  | No |
character_maximum_length | gint |  | Yes |
character_octet_length | gint |  | Yes |
numeric_precision | gint |  | Yes |
numeric_scale | gint |  | Yes |
datetime_precision | gint |  | Yes |
character_set_catalog | string |  | Yes |
character_set_schema | string |  | Yes |
character_set_name | string |  | Yes |
collation_catalog | string |  | Yes |
collation_schema | string |  | Yes |
collation_name | string |  | Yes |
extra | string |  | Yes | CSV string with: AUTO_INCREMENT
is_updatable | boolean |  | Yes |
column_comments | string |  | Yes |

- (table_catalog, table_schema, table_name) references _tables(table_catalog, table_schema, table_name)

- (character_set_catalog, character_set_schema, character_set_name) references _character_sets(character_set_catalog, character_set_schema, character_set_name)

- (collation_catalog, collation_schema, collation_name) references _collations(collation_catalog, collation_schema, collation_name)

- (array_spec) references _element_types(specific_name)

#### _table_constraints table

List of constraints applied to tables (Check, primary or foreign key, or unique constraints)

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
constraint_catalog | string |  | Yes | Name of the catalog that contains the constraint
constraint_schema | string |  | Yes | Name of the schema that contains the constraint
constraint_name | string | Yes | No |
table_catalog | string | Yes | No |
table_schema | string | Yes | No |
table_name | string | Yes | No |
constraint_type | string |  | No | CHECK, FOREIGN KEY, PRIMARY KEY or UNIQUE
check_clause | string |  | Yes | The check expression if the constraint is a check constraint, NULL otherwise
is_deferrable | boolean |  | Yes |
initially_deferred | boolean |  | Yes |

- (table_catalog, table_schema, table_name) references _tables(table_catalog, table_schema, table_name)

#### _referential_constraints table

List of foreign key constraints, along with some specific attributes

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
table_catalog | string | Yes | No |
table_schema | string | Yes | No |
table_name | string | Yes | No |
constraint_name | string | Yes | No |
ref_table_catalog | string |  | No |
ref_table_schema | string |  | No |
ref_table_name | string |  | No |
ref_constraint_name | string |  | No |
match_option | string |  | Yes | FULL, PARTIAL or NONE
update_rule | string |  | Yes | CASCADE, SET NULL, SET DEFAULT, RESTRICT, NO ACTION or NONE
delete_rule | string |  | Yes | CASCADE, SET NULL, SET DEFAULT, RESTRICT, NO ACTION or NONE

- (table_catalog, table_schema, table_name, constraint_name) references _table_constraints(table_catalog, table_schema, table_name, constraint_name)

- (ref_table_catalog, ref_table_schema, ref_table_name, ref_constraint_name) references _table_constraints(table_catalog, table_schema, table_name, constraint_name)

#### _key_column_usage table

List of primary key constraints and the name of the tables' columns involved

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
table_catalog | string | Yes | No |
table_schema | string | Yes | No |
table_name | string | Yes | No |
constraint_name | string | Yes | No |
column_name | string | Yes | No |
ordinal_position | gint | Yes | No | Ordinal position of the column within the constraint key (count starts at 1)

- (table_catalog, table_schema, table_name, constraint_name) references _table_constraints(table_catalog, table_schema, table_name, constraint_name)

- (table_catalog, table_schema, table_name, column_name) references _columns(table_catalog, table_schema, table_name, column_name)

#### _check_column_usage table

List of check constraints and the name of the tables' columns involved

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
table_catalog | string | Yes | No |
table_schema | string | Yes | No |
table_name | string | Yes | No |
constraint_name | string | Yes | No |
column_name | string | Yes | No |

- (table_catalog, table_schema, table_name, constraint_name) references _table_constraints(table_catalog, table_schema, table_name, constraint_name)

- (table_catalog, table_schema, table_name, column_name) references _columns(table_catalog, table_schema, table_name, column_name)

#### _view_column_usage table

List of the tables' columns involved in a view

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
view_catalog | string | Yes | No |
view_schema | string | Yes | No |
view_name | string | Yes | No |
table_catalog | string | Yes | No |
table_schema | string | Yes | No |
table_name | string | Yes | No |
column_name | string | Yes | No |

- (view_catalog, view_schema, view_name) references _views(table_catalog, table_schema, table_name)

- (table_catalog, table_schema, table_name, column_name) references _columns(table_catalog, table_schema, table_name, column_name)

#### _domain_constraints table

List of constraints applicable to domains

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
constraint_catalog | string |  | Yes | Name of the catalog that contains the constraint
constraint_schema | string |  | Yes | Name of the schema that contains the constraint
constraint_name | string | Yes | No |
domain_catalog | string | Yes | No |
domain_schema | string | Yes | No |
domain_name | string | Yes | No |
check_clause | string |  | Yes |
is_deferrable | boolean |  | Yes |
initially_deferred | boolean |  | Yes |

- (domain_catalog, domain_schema, domain_name) references _domains(domain_catalog, domain_schema, domain_name)

- (constraint_catalog, constraint_schema) references _schemata(catalog_name, schema_name)

#### _parameters table

List of routines' (functions and stored procedures) parameters (may not contain data for some routines which accept any type of parameter)

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
specific_catalog | string | Yes | No |
specific_schema | string | Yes | No |
specific_name | string | Yes | No |
ordinal_position | gint | Yes | No |
parameter_mode | string |  | No |
parameter_name | string |  | Yes |
data_type | string |  | Yes | Data type of the parameter (if the parameter is an array, then 'array_spec' is set, and this may be NULL; can also be NULL if any type of parameter is accepted)
array_spec | string |  | Yes | Array description if the parameter is an array

- (specific_catalog, specific_schema, specific_name) references _routines(specific_catalog, specific_schema, specific_name)

- (array_spec) references _element_types(specific_name)

#### _routine_columns table

List of routines' (functions and stored procedures) returned values' parts (columns) for routines returning composed values

The following table describes the columns:

Column name | Type | Key | Can be NULL | description
--- | --- | --- | --- | ---
specific_catalog | string | Yes | No |
specific_schema | string | Yes | No |
specific_name | string | Yes | No |
column_name | string | Yes | No |
ordinal_position | gint | Yes | Yes |
data_type | string |  | Yes | Data type of the column (if the column is an array, then 'array_spec' is set, and this may be NULL)
array_spec | string |  | Yes | Array description if the column is an array

- (specific_catalog, specific_schema, specific_name) references _routines(specific_catalog, specific_schema, specific_name)

- (array_spec) references _element_types(specific_name)

#### _all_types view

List of all the data types

Definition is:

    SELECT short_type_name AS short_type_name, gtype, full_type_name AS full_type_name, comments, internal AS internal, synonyms,
           NULL AS domain_catalog, NULL AS domain_schema, NULL AS domain_name,
           NULL AS udt_catalog, NULL AS udt_schema, NULL AS udt_name
           FROM _builtin_data_types
    UNION
    SELECT udt_short_name, udt_gtype, udt_full_name, udt_comments, udt_internal, NULL,
           NULL, NULL, NULL, udt_catalog, udt_schema, udt_name FROM _udt
    UNION
    SELECT domain_short_name, domain_gtype, domain_full_name, domain_comments, domain_internal, NULL,
           domain_catalog, domain_schema, domain_name , NULL, NULL, NULL FROM _domains

#### _detailled_fk view

For each foreign key constraint, lists all the tables' columns involved and the constraint name

Definition is:

    SELECT rc.table_catalog as fk_table_catalog, rc.table_schema as fk_table_schema, rc.table_name as fk_table_name, kc1.column_name as fk_column,
          rc.ref_table_catalog as ref_table_catalog, rc.ref_table_schema as ref_table_schema, rc.ref_table_name as ref_table_name, kc2.column_name as ref_column,
          rc.constraint_name as fk_constraint_name, kc1.ordinal_position as ordinal_position
          FROM _referential_constraints rc
          INNER JOIN _key_column_usage kc2 ON (rc.ref_table_catalog=kc2.table_catalog AND rc.ref_table_schema=kc2.table_schema AND rc.ref_table_name=kc2.table_name AND rc.ref_constraint_name=kc2.constraint_name)
          INNER JOIN _key_column_usage kc1 ON (rc.table_catalog=kc1.table_catalog AND rc.table_schema=kc1.table_schema AND rc.table_name=kc1.table_name AND rc.constraint_name=kc1.constraint_name)
          WHERE kc1.ordinal_position = kc2.ordinal_position
          ORDER BY rc.table_catalog, rc.table_schema, rc.table_name, kc1.ordinal_position