/* Copyright 2011 Jose Maria Arranz Santamaria Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package jepl.impl.query; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Map; import jepl.impl.JEPLConnectionImpl; import jepl.impl.JEPLDataSourceImpl; import jepl.impl.nonjta.android.JEPLNonJTAConnectionSQLDroidImpl; /** * * @author jmarranz */ public class JEPLUpdateColumnPropertyInfoList { public JEPLUpdateColumnPropertyInfo[] columnArray; public JEPLUpdateColumnPropertyInfoList(JEPLConnectionImpl jcon,String tableNameLowerCase,Map<String,JEPLBeanPropertyDescriptorImpl> propertyMap) throws SQLException { // http://tutorials.jenkov.com/jdbc/databasemetadata.html#listing-columns-in-a-table // http://www.herongyang.com/JDBC/sqljdbc-jar-Column-List.html JEPLDataSourceImpl jds = jcon.getJEPLDataSourceImpl(); Connection con = jcon.getConnection(); DatabaseMetaData dbMetaData = con.getMetaData(); boolean sqlDroid = (jcon instanceof JEPLNonJTAConnectionSQLDroidImpl); // Android, SQLite y SQLDroid como driver String catalog = null; String schemaPattern = null; String columnNamePattern = null; ResultSet result = dbMetaData.getColumns(catalog, schemaPattern, tableNameLowerCase, columnNamePattern); ArrayList<String> columnNameList = new ArrayList<String>(); ArrayList<Boolean> autoIncColumnList = new ArrayList<Boolean>(); ArrayList<Boolean> generatedColumnList = new ArrayList<Boolean>(); while(result.next()) { String columnNameLowerCase = result.getString("COLUMN_NAME").toLowerCase(); columnNameList.add(columnNameLowerCase); Boolean autoIncrement = sqlDroid ? autoIncrement = Boolean.FALSE /* Por ahora */ : "YES".equals(result.getString("IS_AUTOINCREMENT")); autoIncColumnList.add(autoIncrement); Boolean generatedColumn; if (jds.generatedColumnMetadataIsSupported) { try { // IS_GENERATEDCOLUMN se define en Java 1.7 // Pero en Java 7 (1.7) aunque sea con compatibilidad 1.6 si el driver lo soporta IS_GENERATEDCOLUMN funciona generatedColumn = "YES".equals(result.getString("IS_GENERATEDCOLUMN")); } catch(Exception ex) { generatedColumn = Boolean.FALSE; // El driver no lo soporta jds.generatedColumnMetadataIsSupported = false; } } else generatedColumn = Boolean.FALSE; generatedColumnList.add(generatedColumn); } result.close(); int cols = columnNameList.size(); this.columnArray = new JEPLUpdateColumnPropertyInfo[cols]; for(int i = 0; i < cols; i++) { JEPLUpdateColumnPropertyInfo columnPropInfo = new JEPLUpdateColumnPropertyInfo(); columnPropInfo.columnDesc.setName( columnNameList.get(i) ); columnPropInfo.columnDesc.setAutoIncrement( autoIncColumnList.get(i) ); columnPropInfo.columnDesc.setGenerated( generatedColumnList.get(i) ); columnArray[i] = columnPropInfo; } result = dbMetaData.getPrimaryKeys(catalog, schemaPattern, tableNameLowerCase); while(result.next()) { String keyColumnNameLowerCase = result.getString("COLUMN_NAME").toLowerCase(); for(JEPLUpdateColumnPropertyInfo prop : columnArray) { String currColumnNameLowcase = JEPLUpdateColumnPropertyInfo.getColumnName(prop.columnDesc); if (keyColumnNameLowerCase.equals(currColumnNameLowcase)) { if (sqlDroid) // Lo normal es que sólo haya una clave primaria, como haya más la hemos liado { Boolean autoIncrement = getAutoIncrementInSQLDroid(con,tableNameLowerCase); prop.columnDesc.setAutoIncrement(autoIncrement); } prop.columnDesc.setPrimaryKey(true); // Si no pasa por aquí será false break; } } } result.close(); if (sqlDroid) { getForeignKeyListInSQLDroid(con,tableNameLowerCase,columnArray); } else { result = dbMetaData.getImportedKeys(catalog, schemaPattern, tableNameLowerCase); // Foreign keys while (result.next()) { String keyColumnNameLowerCase = result.getString("FKCOLUMN_NAME").toLowerCase(); for (JEPLUpdateColumnPropertyInfo prop : columnArray) { String currColumnNameLowcase = JEPLUpdateColumnPropertyInfo.getColumnName(prop.columnDesc); if (keyColumnNameLowerCase.equals(currColumnNameLowcase)) { prop.columnDesc.setImportedKey(true); // Si no pasa por aquí será false break; } } } result.close(); } for (JEPLUpdateColumnPropertyInfo columnPropInfo : columnArray) { String columnNameLowerCase = JEPLUpdateColumnPropertyInfo.getColumnName(columnPropInfo.columnDesc); JEPLBeanPropertyDescriptorImpl beanProp = propertyMap.get(columnNameLowerCase); if (beanProp != null) { Method getter = beanProp.getReadMethod(); columnPropInfo.getter = getter; } } } private static boolean getAutoIncrementInSQLDroid(Connection con,String tableNameLowerCase) throws SQLException { // http://stackoverflow.com/questions/18694393/how-could-you-get-if-a-table-is-autoincrement-or-not-from-the-metadata-of-an-sql // Recuerda que el executeUpdate() en SQLDroid funciona mal, usamos un ResultSet PreparedStatement stmt = con.prepareStatement("SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND LOWER(name) = '" + tableNameLowerCase + "' AND sql LIKE '%AUTOINCREMENT%' " ); ResultSet rs = stmt.executeQuery(); rs.next(); boolean result = rs.getInt(1) == 1; rs.close(); stmt.close(); return result; } private static void getForeignKeyListInSQLDroid(Connection con,String tableNameLowerCase,JEPLUpdateColumnPropertyInfo[] columnArray) throws SQLException { // Por desgracia la v1.0.3 no tiene definida getImportedKeys, está en la versión de desarrollo // https://github.com/SQLDroid/SQLDroid/blob/master/src/main/java/org/sqldroid/SQLDroidDatabaseMetaData.java // https://www.sqlite.org/pragma.html#pragma_foreign_key_list PreparedStatement stmt = con.prepareStatement("PRAGMA foreign_key_list(" + tableNameLowerCase + ")" ); ResultSet rs = stmt.executeQuery(); while (rs.next()) { String keyColumnNameLowerCase = rs.getString( 4 ).toLowerCase(); for (JEPLUpdateColumnPropertyInfo prop : columnArray) { String currColumnNameLowcase = JEPLUpdateColumnPropertyInfo.getColumnName(prop.columnDesc); if (keyColumnNameLowerCase.equals(currColumnNameLowcase)) { prop.columnDesc.setImportedKey(true); // Si no pasa por aquí será false break; } } } rs.close(); stmt.close(); } }