1- // SPDX-FileCopyrightText: Copyright 2001-2024 Firebird development team and individual contributors
2- // SPDX-FileCopyrightText: Copyright 2022-2024 Mark Rotteveel
1+ // SPDX-FileCopyrightText: Copyright 2001-2025 Firebird development team and individual contributors
2+ // SPDX-FileCopyrightText: Copyright 2022-2025 Mark Rotteveel
33// SPDX-License-Identifier: LGPL-2.1-or-later
44package org .firebirdsql .jdbc .metadata ;
55
1010
1111import java .sql .ResultSet ;
1212import java .sql .SQLException ;
13+ import java .util .ArrayList ;
1314
1415import static org .firebirdsql .gds .ISCConstants .SQL_SHORT ;
1516import static org .firebirdsql .gds .ISCConstants .SQL_VARYING ;
2223 * @author Mark Rotteveel
2324 * @since 5
2425 */
25- public final class GetPrimaryKeys extends AbstractMetadataMethod {
26+ public abstract class GetPrimaryKeys extends AbstractMetadataMethod {
2627
2728 private static final String COLUMNINFO = "COLUMNINFO" ;
2829
@@ -36,42 +37,25 @@ public final class GetPrimaryKeys extends AbstractMetadataMethod {
3637 .at (6 ).simple (SQL_VARYING , OBJECT_NAME_LENGTH , "JB_PK_INDEX_NAME" , COLUMNINFO ).addField ()
3738 .toRowDescriptor ();
3839
39- private static final String GET_PRIMARY_KEYS_START = """
40- select
41- RC.RDB$RELATION_NAME as TABLE_NAME,
42- ISGMT.RDB$FIELD_NAME as COLUMN_NAME,
43- ISGMT.RDB$FIELD_POSITION + 1 as KEY_SEQ,
44- RC.RDB$CONSTRAINT_NAME as PK_NAME,
45- RC.RDB$INDEX_NAME as JB_PK_INDEX_NAME
46- from RDB$RELATION_CONSTRAINTS RC
47- inner join RDB$INDEX_SEGMENTS ISGMT
48- on RC.RDB$INDEX_NAME = ISGMT.RDB$INDEX_NAME
49- where RC.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY'
50- and\s """ ;
51-
52- private static final String GET_PRIMARY_KEYS_END = "\n order by ISGMT.RDB$FIELD_NAME " ;
53-
5440 private GetPrimaryKeys (DbMetadataMediator mediator ) {
5541 super (ROW_DESCRIPTOR , mediator );
5642 }
5743
58- public ResultSet getPrimaryKeys (String table ) throws SQLException {
44+ public final ResultSet getPrimaryKeys (String schema , String table ) throws SQLException {
5945 if (isNullOrEmpty (table )) {
6046 return createEmpty ();
6147 }
62- Clause tableClause = Clause .equalsClause ("RC.RDB$RELATION_NAME" , table );
63- String sql = GET_PRIMARY_KEYS_START
64- + tableClause .getCondition (false )
65- + GET_PRIMARY_KEYS_END ;
66- MetadataQuery metadataQuery = new MetadataQuery (sql , Clause .parameters (tableClause ));
48+ MetadataQuery metadataQuery = createGetPrimaryKeysQuery (schema , table );
6749 return createMetaDataResultSet (metadataQuery );
6850 }
6951
52+ abstract MetadataQuery createGetPrimaryKeysQuery (String schema , String table );
53+
7054 @ Override
7155 RowValue createMetadataRow (ResultSet rs , RowValueBuilder valueBuilder ) throws SQLException {
7256 return valueBuilder
7357 .at (0 ).set (null )
74- .at (1 ).set ( null )
58+ .at (1 ).setString ( rs . getString ( "TABLE_SCHEM" ) )
7559 .at (2 ).setString (rs .getString ("TABLE_NAME" ))
7660 .at (3 ).setString (rs .getString ("COLUMN_NAME" ))
7761 .at (4 ).setShort (rs .getShort ("KEY_SEQ" ))
@@ -81,6 +65,99 @@ RowValue createMetadataRow(ResultSet rs, RowValueBuilder valueBuilder) throws SQ
8165 }
8266
8367 public static GetPrimaryKeys create (DbMetadataMediator mediator ) {
84- return new GetPrimaryKeys (mediator );
68+ // NOTE: Indirection through static method prevents unnecessary classloading
69+ if (mediator .getFirebirdSupportInfo ().isVersionEqualOrAbove (6 )) {
70+ return FB6 .createInstance (mediator );
71+ } else {
72+ return FB5 .createInstance (mediator );
73+ }
8574 }
75+
76+ /**
77+ * Implementation for Firebird 5.0 and older.
78+ */
79+ private static final class FB5 extends GetPrimaryKeys {
80+
81+ private static final String GET_PRIMARY_KEYS_START_5 = """
82+ select
83+ cast(null as char(1)) as TABLE_SCHEM,
84+ RC.RDB$RELATION_NAME as TABLE_NAME,
85+ ISGMT.RDB$FIELD_NAME as COLUMN_NAME,
86+ ISGMT.RDB$FIELD_POSITION + 1 as KEY_SEQ,
87+ RC.RDB$CONSTRAINT_NAME as PK_NAME,
88+ RC.RDB$INDEX_NAME as JB_PK_INDEX_NAME
89+ from RDB$RELATION_CONSTRAINTS RC
90+ inner join RDB$INDEX_SEGMENTS ISGMT
91+ on RC.RDB$INDEX_NAME = ISGMT.RDB$INDEX_NAME
92+ where RC.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY'
93+ and\s """ ;
94+
95+ private static final String GET_PRIMARY_KEYS_END_5 = "\n order by ISGMT.RDB$FIELD_NAME" ;
96+
97+ private FB5 (DbMetadataMediator mediator ) {
98+ super (mediator );
99+ }
100+
101+ private static GetPrimaryKeys createInstance (DbMetadataMediator mediator ) {
102+ return new FB5 (mediator );
103+ }
104+
105+ @ Override
106+ MetadataQuery createGetPrimaryKeysQuery (String schema , String table ) {
107+ Clause tableClause = Clause .equalsClause ("RC.RDB$RELATION_NAME" , table );
108+ String sql = GET_PRIMARY_KEYS_START_5
109+ + tableClause .getCondition (false )
110+ + GET_PRIMARY_KEYS_END_5 ;
111+ return new MetadataQuery (sql , Clause .parameters (tableClause ));
112+ }
113+
114+ }
115+
116+ /**
117+ * Implementation for Firebird 6.0 and higher.
118+ */
119+ private static final class FB6 extends GetPrimaryKeys {
120+
121+ private static final String GET_PRIMARY_KEYS_START_6 = """
122+ select
123+ trim(trailing from RC.RDB$SCHEMA_NAME) as TABLE_SCHEM,
124+ trim(trailing from RC.RDB$RELATION_NAME) as TABLE_NAME,
125+ trim(trailing from ISGMT.RDB$FIELD_NAME) as COLUMN_NAME,
126+ ISGMT.RDB$FIELD_POSITION + 1 as KEY_SEQ,
127+ trim(trailing from RC.RDB$CONSTRAINT_NAME) as PK_NAME,
128+ trim(trailing from RC.RDB$INDEX_NAME) as JB_PK_INDEX_NAME
129+ from SYSTEM.RDB$RELATION_CONSTRAINTS RC
130+ inner join SYSTEM.RDB$INDEX_SEGMENTS ISGMT
131+ on RC.RDB$SCHEMA_NAME = ISGMT.RDB$SCHEMA_NAME and RC.RDB$INDEX_NAME = ISGMT.RDB$INDEX_NAME
132+ where RC.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY'
133+ and\s """ ;
134+
135+ // For consistent order (e.g. for tests), we're also sorting on schema name.
136+ // JDBC specifies that the result set is sorted on COLUMN_NAME, so we can't sort on schema first
137+ private static final String GET_PRIMARY_KEYS_END_6 = "\n order by ISGMT.RDB$FIELD_NAME, ISGMT.RDB$SCHEMA_NAME" ;
138+
139+ private FB6 (DbMetadataMediator mediator ) {
140+ super (mediator );
141+ }
142+
143+ private static GetPrimaryKeys createInstance (DbMetadataMediator mediator ) {
144+ return new FB6 (mediator );
145+ }
146+
147+ @ Override
148+ MetadataQuery createGetPrimaryKeysQuery (String schema , String table ) {
149+ var clauses = new ArrayList <Clause >(2 );
150+ if (schema != null ) {
151+ // NOTE: empty string will return no rows as required ("" retrieves those without a schema)
152+ clauses .add (Clause .equalsClause ("RC.RDB$SCHEMA_NAME" , schema ));
153+ }
154+ clauses .add (Clause .equalsClause ("RC.RDB$RELATION_NAME" , table ));
155+ String sql = GET_PRIMARY_KEYS_START_6
156+ + Clause .conjunction (clauses )
157+ + GET_PRIMARY_KEYS_END_6 ;
158+ return new MetadataQuery (sql , Clause .parameters (clauses ));
159+ }
160+
161+ }
162+
86163}
0 commit comments