From 160e51b93bb98fe50743d64e9e2728ba1e4129b9 Mon Sep 17 00:00:00 2001 From: Pierre Date: Wed, 19 Jun 2024 01:45:02 +0200 Subject: [PATCH] new version 1.4.0 --- README.md | 4 +- README_fr.md | 6 +- .../prrvchr/jdbcdriver/DriverProvider.java | 2 - .../jdbcdriver/DriverProviderMain.java | 6 +- .../jdbcdriver/helper/DBGeneratedKeys.java | 10 +- .../prrvchr/jdbcdriver/helper/DBTools.java | 222 +++++++++++++----- .../jdbcdriver/resultset/CachedResultSet.java | 16 +- .../resultset/ScrollableResultSet.java | 19 +- .../resultset/SensitiveResultSet.java | 10 +- .../prrvchr/jdbcdriver/rowset/RowCatalog.java | 151 ++++++------ .../prrvchr/jdbcdriver/rowset/RowColumn.java | 41 ++-- .../prrvchr/jdbcdriver/rowset/RowHelper.java | 8 +- .../jdbcdriver/rowset/RowSetWriter.java | 31 ++- .../prrvchr/jdbcdriver/rowset/RowTable.java | 195 ++++++++++----- .../prrvchr/uno/sdbc/StatementMain.java | 2 +- 15 files changed, 473 insertions(+), 250 deletions(-) diff --git a/README.md b/README.md index c8520e81..02857652 100644 --- a/README.md +++ b/README.md @@ -520,6 +520,7 @@ Clients using the jdbcDriverOOo driver can access features of the underlying JDB - Changed the implementation of the UNO interface [com.sun.star.sdbc.XGeneratedResultSet][87]. This new implementation supports drivers that do not follow the JDBC API but offer a specific implementation (ie: MariaDB and Derby). To be activated when using odb files created with a previous version, if present, it is necessary to modify the parameter: `Query of generated values` accessible by the menu: **Edit -> Database -> Advanced Settings... -> Generated Values** by the value: `SELECT * FROM %s WHERE %s`. - Added new settings supported by the [Drivers.xcu][91] configuration file. These new parameters allow you to modify the values ​​returned by the drivers regarding the visibility of modifications in the ResultSet (ie: insertion, update and deletion). They also allow you to force SQL mode for the desired modifications in the ResultSet. - Finalized the emulation implementation making any ResultSet modifiable, if the record is unique in this ResultSet. This implementation, using bookmarks, allows the editing of ResultSet coming from **Base Queries**, this simply makes **LibreOffice Base Queries editable**. Queries joining multiple tables are not yet supported and I am open to any technical proposals regarding a possible implementation. +- In order to make the ResultSet returned by the **Trino** driver modifiable and to precede [feature request #22408][120], a search for the primary key will be launched in order to find the first column, of result set, having no duplicates. - To work around [issue #368][120] the HsqlDB driver uses SQL mode updates in ResultSet. - Many fixes and improvements... @@ -640,4 +641,5 @@ Clients using the jdbcDriverOOo driver can access features of the underlying JDB [117]: [118]: [119]: -[120]: +[120]: +[121]: diff --git a/README_fr.md b/README_fr.md index 36b05880..856e89c4 100644 --- a/README_fr.md +++ b/README_fr.md @@ -520,7 +520,8 @@ Les clients utilisant le pilote jdbcDriverOOo peuvent accéder aux fonctionnalit - Modification de l'implémentation de l'interface UNO [com.sun.star.sdbc.XGeneratedResultSet][87]. Cette nouvelle implémentation prend en charge les pilotes qui ne suivent pas l'API JDBC mais proposent une implémentation spécifique (ie: MariaDB et Derby). Pour être activé lors de l'utilisation de fichiers odb créés avec une version précédente, s'il est présent, il est nécessaire de modifier le paramètre : `Requête des valeurs générées` accessible par le menu : **Edition -> Base de données -> Paramètres avancés... -> Valeurs générées** par la valeur : `SELECT * FROM %s WHERE %s`. - Ajout de nouveaux paramètres pris en charge par le fichier de configuration [Drivers.xcu][91]. Ces nouveaux paramètres permettent de modifier les valeurs renvoyées par les pilotes concernant la visibilité des modifications dans les jeux de résultats (ie: insertion, mise à jour et suppression). Ils permettent également de forcer le mode SQL pour les modifications souhaitées dans les jeux de résultats. - Finalisation de l'implémentation de l'émulation rendant tout jeu de résultats modifiable, si l'enregistrement est unique dans ce jeu de résultats. Cette implémentation, utilisant les signets (ie: bookmark), permet l'édition de jeu de résultats provenant de **Requêtes Base**, cela rend tout simplement les **Requêtes LibreOffice Base éditables**. Les requêtes joignant plusieurs tables ne sont pas encore supportées et je suis ouvert à toute proposition technique concernant une éventuelle implémentation. -- Afin de contourner le [dysfonctionnement #368][120] le driver HsqlDB utilise des mises à jour en mode SQL dans les jeux de résultats. +- Afin de rendre modifiables les jeux de résultats retournés par le driver **Trino** et de précéder la [demande d'amélioration #22408][120], une recherche de la clé primaire sera lancée afin de retrouver la première colonne, du jeu de résultats, ayant pas de doublons. +- Afin de contourner le [dysfonctionnement #368][121] le driver HsqlDB utilise des mises à jour en mode SQL dans les jeux de résultats. - De nombreuses corrections et améliorations... ### Que reste-t-il à faire pour la version 1.4.0: @@ -640,4 +641,5 @@ Les clients utilisant le pilote jdbcDriverOOo peuvent accéder aux fonctionnalit [117]: [118]: [119]: -[120]: +[120]: +[121]: diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/DriverProvider.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/DriverProvider.java index 528904cf..dc7c4f5e 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/DriverProvider.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/DriverProvider.java @@ -36,7 +36,6 @@ import com.sun.star.uno.XInterface; import io.github.prrvchr.jdbcdriver.rowset.Row; -import io.github.prrvchr.jdbcdriver.rowset.RowCatalog; import io.github.prrvchr.jdbcdriver.rowset.RowTable; import io.github.prrvchr.uno.helper.ResourceBasedEventLogger; import io.github.prrvchr.uno.sdbc.ConnectionBase; @@ -92,7 +91,6 @@ public String getConnectionUrl(String location, public boolean useSQLUpdate(); public void setGeneratedKeys(Statement statement, - RowCatalog catalog, RowTable table, Row row) throws java.sql.SQLException; diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/DriverProviderMain.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/DriverProviderMain.java index dc765b36..adb5c9cf 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/DriverProviderMain.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/DriverProviderMain.java @@ -55,7 +55,6 @@ import io.github.prrvchr.jdbcdriver.metadata.TypeInfoResultSet; import io.github.prrvchr.jdbcdriver.metadata.TypeInfoRows; import io.github.prrvchr.jdbcdriver.rowset.Row; -import io.github.prrvchr.jdbcdriver.rowset.RowCatalog; import io.github.prrvchr.jdbcdriver.rowset.RowColumn; import io.github.prrvchr.jdbcdriver.rowset.RowHelper; import io.github.prrvchr.jdbcdriver.rowset.RowTable; @@ -244,7 +243,6 @@ public boolean useSQLUpdate() } public void setGeneratedKeys(Statement statement, - RowCatalog catalog, RowTable table, Row row) throws java.sql.SQLException @@ -254,12 +252,12 @@ public void setGeneratedKeys(Statement statement, return; } java.sql.ResultSet result = null; - Map columns = catalog.getColumnNames(table); + Map columns = table.getColumnNames(); if (command.isBlank()) { result = statement.getGeneratedKeys(); } else { - result = DBGeneratedKeys.getGeneratedResult(this, statement, catalog, table, row, columns, command); + result = DBGeneratedKeys.getGeneratedResult(this, statement, table, row, columns, command); } if (result != null) { ResultSetMetaData metadata = result.getMetaData(); diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/helper/DBGeneratedKeys.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/helper/DBGeneratedKeys.java index c00e6f56..8df015cc 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/helper/DBGeneratedKeys.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/helper/DBGeneratedKeys.java @@ -56,25 +56,23 @@ public final static java.sql.ResultSet getGeneratedResult(DriverProvider provide throws SQLException { RowTable table = catalog.getMainTable(); - return getGeneratedKeys(provider, statement, catalog, table, catalog.getColumnNames(table), command); + return getGeneratedKeys(provider, statement, table, table.getColumnNames(), command); } // XXX: Method called from DriverProviderMain.setGeneratedKeys() public final static java.sql.ResultSet getGeneratedResult(DriverProvider provider, java.sql.Statement statement, - RowCatalog catalog, RowTable table, Row row, Map columns, String command) throws SQLException { - return getGeneratedKeys(provider, statement, catalog, table, columns, command); + return getGeneratedKeys(provider, statement, table, columns, command); } private static ResultSet getGeneratedKeys(DriverProvider provider, Statement statement, - RowCatalog catalog, RowTable table, Map columns, String command) @@ -98,7 +96,7 @@ private static ResultSet getGeneratedKeys(DriverProvider provider, // XXX: If it exists, the first auto-increment column of the table concerned by the insertion // XXX: will be attached to the unique value returned by getGeneratedKeys(). else { - column = catalog.getAutoIncrementColumn(table); + column = table.getRowIdentifierColumn(); if (column != null) { // XXX: It is important to preserve the type of the original ResultSet/Table columns keys.put(column, RowHelper.getResultSetValue(result, i, column.getType())); @@ -110,7 +108,7 @@ private static ResultSet getGeneratedKeys(DriverProvider provider, } if (!keys.isEmpty()) { // XXX: If we want to follow the UNO API we must return all the columns of the table - String query = String.format(command, table.getComposedName(provider, true), getPredicates(catalog, keys)); + String query = String.format(command, table.getComposedName(true), getPredicates(table.getCatalog(), keys)); PreparedStatement prepared = provider.getConnection().prepareStatement(query); setPredicates(prepared, keys); // XXX: The statement will be wrapped in order to be closed correctly when closing the ResultSet. diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/helper/DBTools.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/helper/DBTools.java index 74e3b6c3..104f4fa2 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/helper/DBTools.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/helper/DBTools.java @@ -48,6 +48,7 @@ import java.io.InputStream; import java.sql.ResultSetMetaData; import java.sql.RowIdLifetime; +import java.sql.Statement; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Iterator; @@ -104,25 +105,35 @@ public static class NameComponentSupport { boolean useCatalogs; boolean useSchemas; - - NameComponentSupport(boolean useCatalogs, boolean useSchemas) + boolean catalogAtStart; + String catalogSeparator; + String identifierQuote; + + NameComponentSupport(boolean usecatalog, + boolean useschema, + boolean atstart, + String separator, + String quote) { - this.useCatalogs = useCatalogs; - this.useSchemas = useSchemas; + useCatalogs = usecatalog; + useSchemas = useschema; + catalogAtStart = atstart; + catalogSeparator = separator; + identifierQuote = quote; } } public static class NamedComponents { - private String catalog = ""; - private String schema = ""; - private String table = ""; + private String m_Catalog; + private String m_Schema; + private String m_Table; public NamedComponents(String catalog, String schema, String table) { - this.catalog = catalog; - this.schema = schema; - this.table = table; + m_Catalog = catalog; + m_Schema = schema; + m_Table = table; } public NamedComponents() { @@ -130,71 +141,97 @@ public NamedComponents() { // Java DataBaseMetadata specific getter public String getCatalog() { - return catalog.isBlank() ? null : catalog; + return m_Catalog.isBlank() ? null : m_Catalog; } // UNO getter (String can not be null) public String getCatalogName() { - return catalog; + return m_Catalog != null ? m_Catalog : ""; } public void setCatalog(String catalog) { - this.catalog = catalog; + m_Catalog = catalog; } // Java DataBaseMetadata specific getter public String getSchema() { - return schema.isBlank() ? null : schema; + return m_Schema.isBlank() ? null : m_Schema; } + // UNO getter (String can not be null) public String getSchemaName() { - return schema; + return m_Schema != null ? m_Schema : ""; } public void setSchema(String schema) { - this.schema = schema; + m_Schema = schema; } // Java DataBaseMetadata specific getter public String getTable() { - return table; + return m_Table; } public String getTableName() { - return table; + return m_Table; } public void setTable(String table) { - this.table = table; + m_Table = table; } } + public static NamedComponents getNamedComponents(ResultSetMetaData metadata, int index) + throws java.sql.SQLException + { + return new NamedComponents(metadata.getCatalogName(index), metadata.getSchemaName(index), metadata.getTableName(index)); + } + public static NameComponentSupport getNameComponentSupport(DriverProvider provider, ComposeRule rule) { switch (rule) { case InTableDefinitions: return new NameComponentSupport(provider.supportsCatalogsInTableDefinitions(), - provider.supportsSchemasInTableDefinitions()); + provider.supportsSchemasInTableDefinitions(), + provider.isCatalogAtStart(), + provider.getCatalogSeparator(), + provider.getIdentifierQuoteString()); case InIndexDefinitions: return new NameComponentSupport(provider.supportsCatalogsInIndexDefinitions(), - provider.supportsSchemasInIndexDefinitions()); + provider.supportsSchemasInIndexDefinitions(), + provider.isCatalogAtStart(), + provider.getCatalogSeparator(), + provider.getIdentifierQuoteString()); case InDataManipulation: return new NameComponentSupport(provider.supportsCatalogsInDataManipulation(), - provider.supportsSchemasInDataManipulation()); + provider.supportsSchemasInDataManipulation(), + provider.isCatalogAtStart(), + provider.getCatalogSeparator(), + provider.getIdentifierQuoteString()); case InProcedureCalls: return new NameComponentSupport(provider.supportsCatalogsInProcedureCalls(), - provider.supportsSchemasInProcedureCalls()); + provider.supportsSchemasInProcedureCalls(), + provider.isCatalogAtStart(), + provider.getCatalogSeparator(), + provider.getIdentifierQuoteString()); case InPrivilegeDefinitions: return new NameComponentSupport(provider.supportsCatalogsInPrivilegeDefinitions(), - provider.supportsSchemasInPrivilegeDefinitions()); + provider.supportsSchemasInPrivilegeDefinitions(), + provider.isCatalogAtStart(), + provider.getCatalogSeparator(), + provider.getIdentifierQuoteString()); case Complete: - return new NameComponentSupport(true, true); + return new NameComponentSupport(true, + true, + provider.isCatalogAtStart(), + provider.getCatalogSeparator(), + provider.getIdentifierQuoteString()); default: throw new UnsupportedOperationException("Invalid/unknown enum value"); } @@ -228,27 +265,52 @@ public static String composeTableName(DriverProvider provider, ComposeRule rule) throws java.sql.SQLException { - StringBuilder buffer = new StringBuilder(); - NameComponentSupport nameComponentSupport = getNameComponentSupport(provider, rule); + NameComponentSupport support = getNameComponentSupport(provider, rule); + return composeTableName(provider.getStatement(), catalog, schema, table, support, sensitive); + } + + /** compose a complete table name from it's up to three parts, regarding to the database meta data composing rules + * @throws java.sql.SQLException + */ + public static String composeTableName(Statement statement, + NamedComponents component, + NameComponentSupport support, + boolean sensitive) + throws java.sql.SQLException + { + return composeTableName(statement, component.getCatalogName(), component.getSchemaName(), component.getTable(), support, sensitive); + } + /** compose a complete table name from it's up to three parts, regarding to the database meta data composing rules + * @throws java.sql.SQLException + */ + public static String composeTableName(Statement statement, + String catalog, + String schema, + String table, + NameComponentSupport support, + boolean sensitive) + throws java.sql.SQLException + { + StringBuilder buffer = new StringBuilder(); String catalogSeparator = ""; boolean catalogAtStart = true; - if (!catalog.isEmpty() && nameComponentSupport.useCatalogs) { - catalogSeparator = provider.getCatalogSeparator(); - catalogAtStart = provider.isCatalogAtStart(); + if (!catalog.isEmpty() && support.useCatalogs) { + catalogSeparator = support.catalogSeparator; + catalogAtStart = support.catalogAtStart; if (catalogAtStart && !catalogSeparator.isEmpty()) { - buffer.append(enquoteIdentifier(provider, catalog, sensitive)); + buffer.append(enquoteIdentifier(statement, catalog, sensitive)); buffer.append(catalogSeparator); } } - if (!schema.isEmpty() && nameComponentSupport.useSchemas) { - buffer.append(enquoteIdentifier(provider, schema, sensitive)); + if (!schema.isEmpty() && support.useSchemas) { + buffer.append(enquoteIdentifier(statement, schema, sensitive)); buffer.append('.'); } - buffer.append(enquoteIdentifier(provider, table, sensitive)); - if (!catalog.isEmpty() && !catalogAtStart && !catalogSeparator.isEmpty() && nameComponentSupport.useCatalogs) { + buffer.append(enquoteIdentifier(statement, table, sensitive)); + if (!catalog.isEmpty() && !catalogAtStart && !catalogSeparator.isEmpty() && support.useCatalogs) { buffer.append(catalogSeparator); - buffer.append(enquoteIdentifier(provider, catalog, sensitive)); + buffer.append(enquoteIdentifier(statement, catalog, sensitive)); } System.out.println("DataBaseTools.composeTableName(): Name: " + buffer.toString()); return buffer.toString(); @@ -293,6 +355,15 @@ public static String buildName(DriverProvider provider, return doComposeTableName(provider, support, catalog, schema, table, sensitive); } + public static String buildName(Statement statement, + NamedComponents component, + NameComponentSupport support, + boolean sensitive) + throws java.sql.SQLException + { + return doComposeTableName(statement, support, component, sensitive); + } + public static String composeTableName(DriverProvider provider, XPropertySet table, ComposeRule rule, @@ -342,6 +413,7 @@ public static String composeTableName(DriverProvider provider, sensitive); } + public static String doComposeTableName(DriverProvider provider, NameComponentSupport support, String catalog, @@ -349,32 +421,52 @@ public static String doComposeTableName(DriverProvider provider, String table, boolean sensitive) throws java.sql.SQLException + { + return doComposeTableName(provider.getStatement(), support, catalog, schema, table, sensitive); + } + + + public static String doComposeTableName(Statement statement, + NameComponentSupport support, + NamedComponents component, + boolean sensitive) + throws java.sql.SQLException + { + return doComposeTableName(statement, support, component.getCatalog(), component.getSchema(), component.getTable(), sensitive); + } + + public static String doComposeTableName(Statement statement, + NameComponentSupport support, + String catalog, + String schema, + String table, + boolean sensitive) + throws java.sql.SQLException { StringBuilder buffer = new StringBuilder(); - UnoHelper.ensure(!table.isEmpty(), "At least the table name should be non-empty", provider.getLogger()); String catalogSeparator = ""; boolean catalogAtStart = true; if (!catalog.isEmpty() && support.useCatalogs) { - catalogSeparator = provider.getCatalogSeparator(); - catalogAtStart = provider.isCatalogAtStart(); + catalogSeparator = support.catalogSeparator; + catalogAtStart = support.catalogAtStart; if (catalogAtStart && !catalogSeparator.isEmpty()) { - buffer.append(enquoteIdentifier(provider, catalog, sensitive)); + buffer.append(enquoteIdentifier(statement, catalog, sensitive)); buffer.append(catalogSeparator); } } if (!schema.isEmpty() && support.useSchemas) { - buffer.append(enquoteIdentifier(provider, schema, sensitive)); + buffer.append(enquoteIdentifier(statement, schema, sensitive)); buffer.append("."); } - buffer.append(enquoteIdentifier(provider, table, sensitive)); + buffer.append(enquoteIdentifier(statement, table, sensitive)); if (!catalog.isEmpty() && !catalogAtStart && !catalogSeparator.isEmpty() && support.useCatalogs) { buffer.append(catalogSeparator); - buffer.append(enquoteIdentifier(provider, catalog, sensitive)); + buffer.append(enquoteIdentifier(statement, catalog, sensitive)); } return buffer.toString(); } @@ -441,14 +533,23 @@ public static String enquoteIdentifier(DriverProvider provider, String name, boolean sensitive) throws java.sql.SQLException + { + return enquoteIdentifier(provider.getStatement(), name, sensitive); + } + + public static String enquoteIdentifier(Statement statement, + String name, + boolean sensitive) + throws java.sql.SQLException { // XXX: enquoteIdentifier don't support blank string (ie: catalog or schema name can be empty) if (sensitive && !name.isBlank()) { - name = provider.getStatement().enquoteIdentifier(name, sensitive); + name = statement.enquoteIdentifier(name, sensitive); } return name; } + /** quote the given table name (which may contain a catalog and a schema) according to the rules provided by the meta data */ public static String quoteTableName(DriverProvider provider, @@ -478,6 +579,7 @@ public static NamedComponents qualifiedNameComponents(DriverProvider provider, return qualifiedNameComponents(provider, name, rule, false); } + /** split a fully qualified table name (including catalog and schema, if applicable) into its component parts. * @param metadata meta data describing the connection where you got the table name from * @param name fully qualified table name @@ -491,15 +593,30 @@ public static NamedComponents qualifiedNameComponents(DriverProvider provider, boolean unquote) throws java.sql.SQLException { - NamedComponents component = new NamedComponents(); NameComponentSupport support = getNameComponentSupport(provider, rule); - String separator = provider.getCatalogSeparator(); - String buffer = unquote ? unQuoteTableName(provider, name) : name; + return qualifiedNameComponents(provider.getStatement(), name, support, unquote); + } + + /** split a fully qualified table name (including catalog and schema, if applicable) into its component parts. + * @param metadata meta data describing the connection where you got the table name from + * @param name fully qualified table name + * @param rule where do you need the name for + * @param unquote need to unquote the name before? + * @return the NameComponents object with the catalog, schema and table + */ + public static NamedComponents qualifiedNameComponents(Statement statement, + String name, + NameComponentSupport support, + boolean unquote) + throws java.sql.SQLException + { + NamedComponents component = new NamedComponents(); + String buffer = unquote ? unQuoteTableName(support, name) : name; // do we have catalogs ? if (support.useCatalogs) { - if (provider.isCatalogAtStart()) { + if (support.catalogAtStart) { // search for the catalog name at the beginning - int index = buffer.indexOf(separator); + int index = buffer.indexOf(support.catalogSeparator); if (-1 != index) { component.setCatalog(buffer.substring(0, index)); buffer = buffer.substring(index + 1); @@ -507,7 +624,7 @@ public static NamedComponents qualifiedNameComponents(DriverProvider provider, } else { // catalog name at end - int index = buffer.lastIndexOf(separator); + int index = buffer.lastIndexOf(support.catalogSeparator); if (-1 != index) { component.setCatalog(buffer.substring(index + 1)); buffer = buffer.substring(0, index); @@ -528,11 +645,10 @@ public static NamedComponents qualifiedNameComponents(DriverProvider provider, /** unquote the given table name (which may contain a catalog and a schema) */ - public static String unQuoteTableName(DriverProvider provider, + public static String unQuoteTableName(NameComponentSupport support, String name) { - String quote = provider.getIdentifierQuoteString(); - return name.replace(quote, ""); + return name.replace(support.identifierQuote, ""); } /** creates a SQL CREATE VIEW statement diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/CachedResultSet.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/CachedResultSet.java index 3e5a61da..6609f591 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/CachedResultSet.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/CachedResultSet.java @@ -43,6 +43,7 @@ import io.github.prrvchr.jdbcdriver.DriverProvider; import io.github.prrvchr.jdbcdriver.rowset.Row; +import io.github.prrvchr.jdbcdriver.rowset.RowCatalog; import io.github.prrvchr.jdbcdriver.rowset.RowHelper; import io.github.prrvchr.jdbcdriver.rowset.RowSetWriter; @@ -52,11 +53,12 @@ public class CachedResultSet { protected DriverProvider m_Provider; + protected RowCatalog m_Catalog = null; protected int m_MinSize = 10; protected int m_ColumnCount = 0; protected int m_FetchSize; protected String m_Query; - protected boolean m_IsUpdatable = false; + protected boolean m_Insertable = false; // XXX: We need to know when we are on the insert row protected boolean m_OnInsert = false; // XXX: We need to keep the index references of the columns already assigned for insertion @@ -83,9 +85,9 @@ public CachedResultSet(DriverProvider provider, m_IsUpdateVisible = provider.isUpdateVisible(rstype); m_FetchSize = result.getFetchSize(); m_ColumnCount = result.getMetaData().getColumnCount(); - m_IsUpdatable = provider.isResultSetUpdatable(result); + m_Insertable = provider.isResultSetUpdatable(result); m_InsertedColumns = new BitSet(m_ColumnCount); - System.out.println("CachedResultSet() IsUpdatable: " + m_IsUpdatable); + System.out.println("CachedResultSet() Insertable: " + m_Insertable); } @@ -105,7 +107,7 @@ public void insertRow() public void cancelRowUpdates() throws SQLException { - if (m_IsUpdatable) { + if (m_Insertable) { if (isOnInsertRow()) { moveToCurrentRow(); } @@ -122,7 +124,7 @@ public void cancelRowUpdates() public void moveToInsertRow() throws SQLException { - if (m_IsUpdatable) { + if (m_Insertable) { m_Result.moveToInsertRow(); m_InsertedColumns.clear(); } @@ -133,7 +135,7 @@ public void moveToInsertRow() public void moveToCurrentRow() throws SQLException { - if (m_IsUpdatable) { + if (m_Insertable) { m_Result.moveToCurrentRow(); } setInsertMode(false); @@ -579,7 +581,7 @@ protected RowSetWriter getRowSetWriter() throws SQLException { if (m_RowSetWriter == null) { - m_RowSetWriter = new RowSetWriter(m_Provider, m_Result, m_Query); + m_RowSetWriter = new RowSetWriter(m_Provider, m_Catalog, m_Result, m_Query); } return m_RowSetWriter; } diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/ScrollableResultSet.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/ScrollableResultSet.java index 5ae459b3..10e1a1c3 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/ScrollableResultSet.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/ScrollableResultSet.java @@ -47,6 +47,7 @@ import io.github.prrvchr.jdbcdriver.DriverProvider; import io.github.prrvchr.jdbcdriver.rowset.Row; +import io.github.prrvchr.jdbcdriver.rowset.RowCatalog; //XXX: This ResultSet is supposed to emulate a TYPE_SCROLL_SENSITIVE from a TYPE_FORWARD_ONLY @@ -64,6 +65,7 @@ public class ScrollableResultSet private int m_DeletedRow = 0; private int m_InsertedRow = 0; private boolean m_WasNull = false; + private boolean m_Updatable; // The constructor method: public ScrollableResultSet(DriverProvider provider, @@ -72,8 +74,19 @@ public ScrollableResultSet(DriverProvider provider, throws SQLException { super(provider, result, query); - m_IsUpdatable = false; - initCache(result); + try { + m_Insertable = false; + boolean updatable = provider.isResultSetUpdatable(result); + if (!updatable) { + m_Catalog = new RowCatalog(provider, result, query); + updatable = m_Catalog.hasRowIdentifier(); + } + m_Updatable = updatable; + initCache(result); + } + catch (Exception e) { + e.printStackTrace(); + } } @@ -82,7 +95,7 @@ public ScrollableResultSet(DriverProvider provider, public int getConcurrency() throws SQLException { - return ResultSet.CONCUR_UPDATABLE; + return m_Updatable ? ResultSet.CONCUR_UPDATABLE : ResultSet.CONCUR_READ_ONLY; } // XXX: We want to emulate an scollable ResultSet diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/SensitiveResultSet.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/SensitiveResultSet.java index e828d26a..dc4f919b 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/SensitiveResultSet.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/resultset/SensitiveResultSet.java @@ -49,6 +49,7 @@ import io.github.prrvchr.jdbcdriver.DriverProvider; import io.github.prrvchr.jdbcdriver.rowset.Row; +import io.github.prrvchr.jdbcdriver.rowset.RowCatalog; import io.github.prrvchr.jdbcdriver.rowset.RowHelper; @@ -76,6 +77,7 @@ public class SensitiveResultSet private boolean m_RowCountFinal = false; private int m_RowCount = 0; private boolean m_Moved = false; + private boolean m_Updatable = false; private boolean m_Deleted = false; private boolean m_Inserted = false; private boolean m_WasNull = false; @@ -99,6 +101,12 @@ public SensitiveResultSet(DriverProvider provider, m_SQLInsert = provider.useSQLInsert(); m_SQLUpdate = provider.useSQLUpdate(); m_SQLMode = provider.isSQLMode(); + boolean updatable = provider.isResultSetUpdatable(result); + if (!updatable) { + m_Catalog = new RowCatalog(provider, result, query); + updatable = m_Catalog.hasRowIdentifier(); + } + m_Updatable = updatable; internalNext(); } @@ -108,7 +116,7 @@ public SensitiveResultSet(DriverProvider provider, public int getConcurrency() throws SQLException { - return ResultSet.CONCUR_UPDATABLE; + return m_Updatable ? ResultSet.CONCUR_UPDATABLE : ResultSet.CONCUR_READ_ONLY; } // XXX: We want to emulate an scollable ResultSet diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowCatalog.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowCatalog.java index 07e50e5e..ba7491e7 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowCatalog.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowCatalog.java @@ -31,27 +31,26 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.Map; import io.github.prrvchr.jdbcdriver.ComposeRule; import io.github.prrvchr.jdbcdriver.DriverProvider; import io.github.prrvchr.jdbcdriver.helper.DBQueryParser; import io.github.prrvchr.jdbcdriver.helper.DBTools; +import io.github.prrvchr.jdbcdriver.helper.DBTools.NameComponentSupport; import io.github.prrvchr.jdbcdriver.helper.DBTools.NamedComponents; import io.github.prrvchr.jdbcdriver.resultset.ResultSetWrapper; public class RowCatalog - implements Iterable + //implements Iterable { + private Statement m_Statement; private List m_Tables = new ArrayList<>(); - private RowColumn[] m_Columns; private ComposeRule m_Rule = ComposeRule.InDataManipulation; - private NamedComponents m_Component = null; - private String m_SelectCmd = "SELECT * FROM %s WHERE %s"; + private NameComponentSupport m_Support = null; + private String m_SelectCmd = "SELECT * FROM %1$s WHERE %2$s"; + private String m_UniqueCmd = "SELECT %1$s, COUNT(%1$s) FROM %2$s GROUP BY %1$s HAVING COUNT(%1$s) > 1"; private String m_Mark = "?"; private String m_Parameter = "%s = ?"; private String m_And = " AND "; @@ -60,20 +59,20 @@ public class RowCatalog // The constructor method: // XXX: this constructor is called from sdbc.StatementMain.getStatementCatalog() public RowCatalog(DriverProvider provider, - Statement statement, String identifier) throws SQLException { - List columns = new ArrayList<>(); + m_Statement = provider.getStatement(); + m_Support = DBTools.getNameComponentSupport(provider, m_Rule); NamedComponents component = DBTools.qualifiedNameComponents(provider, identifier, m_Rule, true); RowTable table = new RowTable(this, component); try (ResultSet result = provider.getConnection().getMetaData().getColumns(component.getCatalog(), component.getSchema(), component.getTable(), "%")) { while (result.next()) { - columns.add(new RowColumn(table, statement, result)); + table.addColumn(new RowColumn(table, result)); } } m_Tables.add(table); - m_Columns = columns.toArray(new RowColumn[0]); + setRowIdentifier(table); } // XXX: this constructor is called from rowset.RowSetWriter() @@ -82,60 +81,83 @@ public RowCatalog(DriverProvider provider, String query) throws SQLException { - List columns = new ArrayList<>(); - Statement statement = provider.getStatement(); + RowTable table = null; + NamedComponents component = null; + m_Statement = provider.getStatement(); + m_Support = DBTools.getNameComponentSupport(provider, m_Rule); ResultSetMetaData metadata = result.getMetaData(); for (int index = 1; index <= metadata.getColumnCount(); index++) { if (metadata.getTableName(index).isBlank()) { - RowTable table = getTable(provider, query); + table = getTable(component, query); if (table.isValid()) { - columns.add(new RowColumn(provider, table, metadata, index)); + table.addColumn(new RowColumn(provider.getConnection(), table, metadata, index)); } } else { - RowTable table = getTable(metadata, index); + table = getTable(metadata, index); if (table.isValid()) { - columns.add(new RowColumn(table, statement, metadata, index)); + table.addColumn(new RowColumn(table, metadata, index)); } } } - m_Columns = columns.toArray(new RowColumn[0]); + if (table == null) { + throw new SQLException(); + } + setRowIdentifier(table); } - public RowTable getMainTable() + private void setRowIdentifier(RowTable table) throws SQLException { - if (m_Tables.isEmpty()) { - throw new SQLException(); + try (ResultSet result = m_Statement.getConnection().getMetaData().getPrimaryKeys(table.getCatalogName(), table.getSchemaName(), table.getName())) { + while (result.next()) { + String key = result.getString(4); + if (!result.wasNull() && table.hasColumn(key)) { + short index = result.getShort(5); + table.addRowIdentifier(key, index - 1); + } + } + } + if (!table.hasRowIdentifier()) { + table.setDefaultRowIdentifier(); } - return m_Tables.get(0); } - public RowColumn[] getColumns() + public boolean hasRowIdentifier() { - return m_Columns; + for (RowTable table : m_Tables) { + if (table.hasRowIdentifier()) { + return true; + } + } + return false; } - public Map getColumnNames(RowTable table) + public NameComponentSupport getNamedSupport() + throws SQLException { - Map columns = new HashMap<>(); - for (RowColumn column : m_Columns) { - if (column.isColumnOfTable(table)) { - columns.put(column.getName(), column); - } - } - return columns; + return m_Support; } - public Map getColumnIndexes(RowTable table) + public Statement getStatement() + throws SQLException { - Map columns = new HashMap<>(); - for (RowColumn column : m_Columns) { - if (column.isColumnOfTable(table)) { - columns.put(column.getIndex(), column); - } + return m_Statement; + } + + public String enquoteIdentifier(String name) + throws SQLException + { + return m_Statement.enquoteIdentifier(name, true); + } + + public RowTable getMainTable() + throws SQLException + { + if (m_Tables.isEmpty()) { + throw new SQLException(); } - return columns; + return m_Tables.get(0); } public ComposeRule getRule() @@ -163,38 +185,29 @@ public String getSeparator() return m_Separator; } - public PreparedStatement getSelectStatement(DriverProvider provider, - RowTable table) + public PreparedStatement getSelectStatement(RowTable table) throws SQLException { - String query = String.format(m_SelectCmd, table.getComposedName(provider, true), table.getWhereCmd()); - System.out.println("RowCatalog.getSelectStatement() Query: " + query); - return provider.getConnection().prepareStatement(query); + String query = String.format(m_SelectCmd, table.getComposedName(true), table.getWhereCmd()); + return m_Statement.getConnection().prepareStatement(query); } - public ResultSet getSelectResult(DriverProvider provider, - RowTable table, + public ResultSet getSelectResult(RowTable table, Row row) throws SQLException { - PreparedStatement prepared = getSelectStatement(provider, table); + PreparedStatement prepared = getSelectStatement(table); RowHelper.setWhereParameter(prepared, this, table, row); return new ResultSetWrapper(prepared); } - public RowColumn getAutoIncrementColumn(RowTable table) + public String getUniqueQuery() { - for (RowColumn column : m_Columns) { - if (column.isColumnOfTable(table) && column.isAutoIncrement()) { - return column; - } - } - return null; + return m_UniqueCmd; } - @Override - public Iterator iterator() { - return m_Tables.iterator(); + public List getTables() { + return m_Tables; } private RowTable getTable(ResultSetMetaData metadata, @@ -213,11 +226,13 @@ private RowTable getTable(ResultSetMetaData metadata, return table; } - private RowTable getTable(DriverProvider provider, + private RowTable getTable(NamedComponents component, String query) throws SQLException { - NamedComponents component = getNamedComponent(provider, query); + if (component == null) { + component = getNamedComponent(query); + } for (RowTable table : m_Tables) { if (table.isSameTable(component)) { return table; @@ -225,24 +240,20 @@ private RowTable getTable(DriverProvider provider, } RowTable table = new RowTable(this, component); if (table.isValid()) { - System.out.println("RowCatalog.getTable() Table: " + table.getName()); m_Tables.add(table); } return table; } - - private NamedComponents getNamedComponent(DriverProvider provider, - String query) + + private NamedComponents getNamedComponent(String query) throws SQLException { - if (m_Component == null) { - DBQueryParser parser = new DBQueryParser(DBQueryParser.SQL_SELECT, query); - if (parser.hasTable()) { - m_Component = DBTools.qualifiedNameComponents(provider, parser.getTable(), m_Rule, true); - System.out.println("RowCatalog.getNamedComponent() Table: " + parser.getTable()); - } + DBQueryParser parser = new DBQueryParser(DBQueryParser.SQL_SELECT, query); + if (!parser.hasTable()) { + throw new SQLException(); } - return m_Component; + NamedComponents component = DBTools.qualifiedNameComponents(m_Statement, parser.getTable(), m_Support, true); + return component; } diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowColumn.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowColumn.java index 2ffbd177..7aa9491a 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowColumn.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowColumn.java @@ -25,11 +25,9 @@ */ package io.github.prrvchr.jdbcdriver.rowset; +import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; -import java.sql.Statement; - -import io.github.prrvchr.jdbcdriver.DriverProvider; public class RowColumn @@ -43,38 +41,42 @@ public class RowColumn private boolean m_AutoIncrement = false; private String AUTOINCREMENT = "YES"; - // The constructor method: public RowColumn(RowTable table, - Statement statement, + ResultSet result, + int index) + throws java.sql.SQLException + { + this(table, result); + m_Index = index; + } + + public RowColumn(RowTable table, ResultSet result) throws java.sql.SQLException { m_Table = table; m_Name = result.getString(4); - m_Identifier = statement.enquoteIdentifier(m_Name, true); + m_Identifier = table.getCatalog().enquoteIdentifier(m_Name); m_Type = result.getInt(5); m_Index = result.getInt(17); m_AutoIncrement = AUTOINCREMENT.equalsIgnoreCase(result.getString(23)); - m_Table.setKeyColumn(m_Index, m_Identifier, m_Type); } public RowColumn(RowTable table, - Statement statement, ResultSetMetaData metadata, int index) throws java.sql.SQLException { m_Table = table; m_Name = metadata.getColumnName(index); - m_Identifier = statement.enquoteIdentifier(m_Name, true); + m_Identifier = table.getCatalog().enquoteIdentifier(m_Name); m_Type = metadata.getColumnType(index); m_AutoIncrement = metadata.isAutoIncrement(index); - m_Table.setKeyColumn(index, m_Identifier, m_Type); m_Index = index; } - public RowColumn(DriverProvider provider, + public RowColumn(Connection connection, RowTable table, ResultSetMetaData metadata, int index) @@ -82,16 +84,13 @@ public RowColumn(DriverProvider provider, { m_Table = table; m_Name = metadata.getColumnName(index); - System.out.println("RowColumn() Column Name: " + m_Name); - m_Identifier = provider.getStatement().enquoteIdentifier(m_Name, true); - try (ResultSet result = provider.getConnection().getMetaData().getColumns(table.getCatalogName(), table.getSchemaName(), table.getName(), m_Name)) { + m_Identifier = table.getCatalog().enquoteIdentifier(m_Name); + try (ResultSet result = connection.getMetaData().getColumns(table.getCatalogName(), table.getSchemaName(), table.getName(), m_Name)) { if (result.next()) { m_Type = result.getInt(5); m_AutoIncrement = AUTOINCREMENT.equalsIgnoreCase(result.getString(23)); - System.out.println("RowColumn() Column autoincrement: " + m_AutoIncrement); } } - m_Table.setKeyColumn(index, m_Identifier, m_Type); m_Index = index; } @@ -145,14 +144,4 @@ public boolean isAutoIncrement() return m_AutoIncrement; } - public boolean isColumnOfTable(RowTable table) - { - return m_Table.equals(table); - } - - public boolean isKeyColumn() - { - return m_Table.isKeyColumn(m_Index); - } - } diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowHelper.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowHelper.java index c01a650b..0c065a93 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowHelper.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowHelper.java @@ -133,10 +133,10 @@ public static void setWhereParameter(PreparedStatement statement, throws SQLException { int i = offset; - for (int index : table.getKeyIndex()) { - int type = catalog.getColumns()[index - 1].getType(); - Object value = row.getOldColumnObject(index); - RowHelper.setStatementValue(statement, type, i, value); + for (String key : table.getRowIdentifier()) { + RowColumn column = table.getColumn(key); + Object value = row.getOldColumnObject(column.getIndex()); + RowHelper.setStatementValue(statement, column.getType(), i, value); i ++; } } diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowSetWriter.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowSetWriter.java index 6d18f2b6..7da5fbc1 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowSetWriter.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowSetWriter.java @@ -47,26 +47,31 @@ public class RowSetWriter // The constructor method: public RowSetWriter(DriverProvider provider, + RowCatalog catalog, ResultSet result, String query) throws SQLException { m_Provider = provider; - m_Catalog = new RowCatalog(provider, result, query); + // XXX: We can make lazy loading on catalog if ResultSet is updatable + if (catalog == null) { + catalog = new RowCatalog(provider, result, query); + } + m_Catalog = catalog; } public boolean insertRow(Row row) throws SQLException { int status = 0; - for (RowTable table: m_Catalog) { + for (RowTable table: m_Catalog.getTables()) { List columns = getInsertedColumns(table, row); if (!columns.isEmpty()) { try (PreparedStatement statement = getInsertStatement(table, columns)) { setStatementParameter(statement, columns, row); status = statement.executeUpdate(); if (status == 1) { - m_Provider.setGeneratedKeys(statement, m_Catalog, table, row); + m_Provider.setGeneratedKeys(statement, table, row); } } row.clearUpdated(columns, status); @@ -79,7 +84,7 @@ public boolean updateRow(Row row) throws SQLException { int status = 0; - for (RowTable table: m_Catalog) { + for (RowTable table: m_Catalog.getTables()) { status = 0; List columns = getUpdatedColumns(table, row); if (!columns.isEmpty()) { @@ -99,7 +104,7 @@ public boolean deleteRow(Row row) throws SQLException { int status = 0; - for (RowTable table: m_Catalog) { + for (RowTable table: m_Catalog.getTables()) { status = 0; checkForDelete(table, row); try (PreparedStatement statement = getDeleteStatement(table)) { @@ -115,8 +120,8 @@ private List getInsertedColumns(RowTable table, Row row) { List columns = new ArrayList<>(); - for (RowColumn column : m_Catalog.getColumns()) { - if (column.isColumnOfTable(table) && row.isColumnUpdated(column.getIndex())) { + for (RowColumn column : table.getColumns()) { + if (row.isColumnUpdated(column.getIndex())) { columns.add(column); } } @@ -127,8 +132,8 @@ private List getUpdatedColumns(RowTable table, Row row) { List columns = new ArrayList<>(); - for (RowColumn column : m_Catalog.getColumns()) { - if (column.isColumnOfTable(table) && row.isColumnUpdated(column.getIndex())) { + for (RowColumn column : table.getColumns()) { + if (row.isColumnUpdated(column.getIndex())) { columns.add(column); } } @@ -163,7 +168,7 @@ private int getResultRowCount(RowTable table, throws SQLException { int count = 0; - try (PreparedStatement statement = m_Catalog.getSelectStatement(m_Provider, table)) { + try (PreparedStatement statement = m_Catalog.getSelectStatement(table)) { RowHelper.setWhereParameter(statement, m_Catalog, table, row); ResultSet result = statement.executeQuery(); while (result.next()) { @@ -181,7 +186,7 @@ private PreparedStatement getInsertStatement(RowTable table, throws SQLException { PreparedStatement statement = null; - String query = String.format(m_InsertCmd, table.getComposedName(m_Provider, true), getInsertColumns(table, columns), getInsertParameter(table, columns)); + String query = String.format(m_InsertCmd, table.getComposedName(true), getInsertColumns(table, columns), getInsertParameter(table, columns)); System.out.println("RowSetWriter.getInsertStatement() Query: " + query); if (m_Provider.isAutoRetrievingEnabled()) { statement = m_Provider.getConnection().prepareStatement(query, Statement.RETURN_GENERATED_KEYS); @@ -196,7 +201,7 @@ private PreparedStatement getUpdateStatement(RowTable table, List columns) throws SQLException { - String query = String.format(m_UpdateCmd, table.getComposedName(m_Provider, true), getUpdatedColumns(table, columns), table.getWhereCmd()); + String query = String.format(m_UpdateCmd, table.getComposedName(true), getUpdatedColumns(table, columns), table.getWhereCmd()); System.out.println("RowSetWriter.getUpdateStatement() Query: " + query); return m_Provider.getConnection().prepareStatement(query); } @@ -204,7 +209,7 @@ private PreparedStatement getUpdateStatement(RowTable table, private PreparedStatement getDeleteStatement(RowTable table) throws SQLException { - String query = String.format(m_DeleteCmd, table.getComposedName(m_Provider, true), table.getWhereCmd()); + String query = String.format(m_DeleteCmd, table.getComposedName(true), table.getWhereCmd()); System.out.println("RowSetWriter.getDeleteStatement() Query: " + query); return m_Provider.getConnection().prepareStatement(query); } diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowTable.java b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowTable.java index 9ecea86d..af557b7e 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowTable.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/jdbcdriver/rowset/RowTable.java @@ -25,13 +25,14 @@ */ package io.github.prrvchr.jdbcdriver.rowset; +import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import io.github.prrvchr.jdbcdriver.ComposeRule; import io.github.prrvchr.jdbcdriver.DriverProvider; @@ -42,40 +43,35 @@ public class RowTable { - private RowCatalog m_Tables; - private Map m_Keys = new HashMap<>(); - private String m_Catalog = ""; - private String m_Schema = ""; - private String m_Name = ""; + private RowCatalog m_Catalog; + private Map m_Columns = new LinkedHashMap<>(); + private List m_Keys = new ArrayList<>(); + private NamedComponents m_Component; private String m_Where; // The constructor method: public RowTable(DriverProvider provider, - RowCatalog tables, + RowCatalog catalog, String query) throws SQLException { - m_Tables = tables; + m_Catalog = catalog; DBQueryParser parser = new DBQueryParser(DBQueryParser.SQL_SELECT, query); - if (parser.hasTable()) { - ComposeRule rule = ComposeRule.InDataManipulation; - NamedComponents component = DBTools.qualifiedNameComponents(provider, parser.getTable(), rule, true); - m_Catalog = component.getCatalogName(); - m_Schema = component.getSchemaName(); - m_Name = component.getTableName(); + if (!parser.hasTable()) { + throw new SQLException(); } + ComposeRule rule = ComposeRule.InDataManipulation; + m_Component = DBTools.qualifiedNameComponents(provider, parser.getTable(), rule, true); System.out.println("RowTable() 1"); } - public RowTable(RowCatalog tables, + public RowTable(RowCatalog catalog, NamedComponents component) throws SQLException { - m_Tables = tables; - m_Catalog = component.getCatalogName(); - m_Schema = component.getSchemaName(); - m_Name = component.getTableName(); + m_Catalog = catalog; + m_Component = component; System.out.println("RowTable() 1"); } @@ -84,70 +80,150 @@ public RowTable(RowCatalog tables, int index) throws SQLException { - m_Tables = tables; - m_Catalog = metadata.getCatalogName(index); - m_Schema = metadata.getSchemaName(index); - m_Name = metadata.getTableName(index); + m_Catalog = tables; + m_Component = DBTools.getNamedComponents(metadata, index); System.out.println("RowTable() 1"); } + public RowCatalog getCatalog() + { + return m_Catalog; + } + public boolean isValid() { - return !m_Name.isBlank(); + return m_Component.getTable() != null && !m_Component.getTable().isBlank(); } - public String getCatalogName() + public void addColumn(RowColumn column) { - return m_Catalog; + m_Columns.put(column.getName(), column); } - public String getSchemaName() + public boolean hasRowIdentifier() { - return m_Schema; + return !m_Keys.isEmpty(); } - public String getName() + public void addRowIdentifier(String column, int index) { - return m_Name; + m_Keys.add(index, column); } - public String getComposedName(DriverProvider provider, boolean quoted) + public void setDefaultRowIdentifier() throws SQLException { - return DBTools.buildName(provider, m_Catalog, m_Schema, m_Name, m_Tables.getRule(), quoted); + // XXX: We don't know the primary key of this table!!!! + // XXX: First auto-increment column become default row identifier + RowColumn column = getAutoIncrementColumn(); + if (column == null) { + // XXX: Ok we need to find a unique row column... + column = getPseudoIdentifierColumn(); + } + if (column != null) { + m_Keys.add(column.getName()); + } } - public boolean isSameTable(ResultSetMetaData metadata, - int index) + private RowColumn getPseudoIdentifierColumn() throws SQLException { - return m_Catalog.equals(metadata.getCatalogName(index)) && - m_Schema.equals(metadata.getSchemaName(index)) && - m_Name.equals(metadata.getTableName(index)); + RowColumn identifier = null; + String query = m_Catalog.getUniqueQuery(); + for (RowColumn column : m_Columns.values()) { + // We are looking only for certain column type. + if (RowHelper.isValidKeyType(column.getType())) { + String command = String.format(query, column.getIdentifier(), getComposedName(true)); + try (ResultSet result = m_Catalog.getStatement().executeQuery(command)) { + if (!result.next()) { + identifier = column; + break; + } + } + } + } + return identifier; + } + + public List getRowIdentifier() + { + return m_Keys; } - public boolean isSameTable(NamedComponents component) - throws SQLException + public boolean hasColumn(String column) { - return component != null && - m_Catalog.equals(component.getCatalogName()) && - m_Schema.equals(component.getSchemaName()) && - m_Name.equals(component.getTableName()); + return m_Columns.containsKey(column); + } + + public RowColumn getColumn(String column) + { + return m_Columns.get(column); + } + + public Map getColumnNames() + { + return m_Columns; + } + + public RowColumn getRowIdentifierColumn() + { + RowColumn key = null; + if (!m_Keys.isEmpty()) { + key = m_Columns.get(m_Keys.get(0)); + } + else { + key = getAutoIncrementColumn(); + } + return key; } - public void setKeyColumn(int index, String identifier, int type) { - if (RowHelper.isValidKeyType(type)) { - m_Keys.put(index, identifier); + public RowColumn getAutoIncrementColumn() + { + for (RowColumn column : m_Columns.values()) { + if (column.isAutoIncrement()) { + return column; + } } + return null; + } + + public String getCatalogName() + { + return m_Component.getCatalogName(); + } + + public String getSchemaName() + { + return m_Component.getSchemaName(); + } + + public String getName() + { + return m_Component.getTableName(); } - public boolean isKeyColumn(int index) { - return m_Keys.containsKey(index); + public String getComposedName(boolean quoted) + throws SQLException + { + return DBTools.buildName(m_Catalog.getStatement(), m_Component, m_Catalog.getNamedSupport(), quoted); } - public Integer[] getKeyIndex() + public boolean isSameTable(ResultSetMetaData metadata, + int index) + throws SQLException { - return m_Keys.keySet().toArray(new Integer[0]); + return getCatalogName().equals(metadata.getCatalogName(index)) && + getSchemaName().equals(metadata.getSchemaName(index)) && + getName().equals(metadata.getTableName(index)); + } + + public boolean isSameTable(NamedComponents component) + throws SQLException + { + return component != null && + getCatalogName().equals(component.getCatalogName()) && + getSchemaName().equals(component.getSchemaName()) && + getName().equals(component.getTableName()); } public String getWhereCmd() @@ -155,27 +231,27 @@ public String getWhereCmd() { if (m_Where == null) { List columns = new ArrayList<>(); - for (Entry key : m_Keys.entrySet()) { - columns.add(String.format(m_Tables.getParameter(), key.getValue())); + for (String key : m_Keys) { + columns.add(String.format(m_Catalog.getParameter(), m_Columns.get(key).getIdentifier())); } - m_Where = String.join(m_Tables.getAnd(), columns); + m_Where = String.join(m_Catalog.getAnd(), columns); } return m_Where; } public String getSeparator() { - return m_Tables.getSeparator(); + return m_Catalog.getSeparator(); } public String getParameter() { - return m_Tables.getParameter(); + return m_Catalog.getParameter(); } public String getMark() { - return m_Tables.getMark(); + return m_Catalog.getMark(); } public boolean equals(Object object) @@ -189,4 +265,9 @@ public boolean equals(Object object) getName().equals(table.getName()); } + public Collection getColumns() + { + return m_Columns.values(); + } + } diff --git a/source/jdbcDriverOOo/source/io/github/prrvchr/uno/sdbc/StatementMain.java b/source/jdbcDriverOOo/source/io/github/prrvchr/uno/sdbc/StatementMain.java index a1a694b6..dcb9f679 100644 --- a/source/jdbcDriverOOo/source/io/github/prrvchr/uno/sdbc/StatementMain.java +++ b/source/jdbcDriverOOo/source/io/github/prrvchr/uno/sdbc/StatementMain.java @@ -533,7 +533,7 @@ private RowCatalog getStatementCatalog() if (!m_parsed) { DBQueryParser parser = new DBQueryParser(DBQueryParser.SQL_INSERT, m_Sql); if (parser.hasTable()) { - m_Catalog = new RowCatalog(m_Connection.getProvider(), m_Statement, parser.getTable()); + m_Catalog = new RowCatalog(m_Connection.getProvider(), parser.getTable()); } m_parsed = true; }