/****************************************************************************** * Copyright (C) 2013 Elaine Tan * * Copyright (C) 2013 Trek Global * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * * by the Free Software Foundation. This program is distributed in the hope * * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * * with this program; if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * *****************************************************************************/ package org.compiere.process; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.logging.Level; import org.compiere.model.MColumn; import org.compiere.model.MIndexColumn; import org.compiere.model.MProcessPara; import org.compiere.model.MTable; import org.compiere.model.MTableIndex; import org.compiere.util.DB; import org.compiere.util.Msg; import org.compiere.util.Trx; /** * Create table index (AD_TableIndex) process * @author Elaine * */ @org.adempiere.base.annotation.Process public class CreateTableIndex extends SvrProcess { /** Table */ private int p_AD_Table_ID = 0; private int countTable = 0; private int countIndex = 0; private int countError = 0; @Override protected void prepare() { ProcessInfoParameter[] para = getParameter(); for (int i = 0; i < para.length; i++) { String name = para[i].getParameterName(); if (para[i].getParameter() == null) ; else if (name.equals("AD_Table_ID")) p_AD_Table_ID = para[i].getParameterAsInt(); else MProcessPara.validateUnknownParameter(getProcessInfo().getAD_Process_ID(), para[i]); } } @Override protected String doIt() throws Exception { if (log.isLoggable(Level.INFO)) log.info("AD_Table_ID=" + p_AD_Table_ID); Trx trx = Trx.get(get_TrxName(), true); DatabaseMetaData md = trx.getConnection().getMetaData(); if (p_AD_Table_ID > 0) { MTable table = new MTable(getCtx(), p_AD_Table_ID, get_TrxName()); if (table != null) processDatabaseTable(md, table); } else processDatabase(md); trx.close(); return Msg.getMsg(getCtx(), "CreateTableIndexProcessResult", new Object[] {countTable, countIndex, countError}); } private void processDatabase(DatabaseMetaData md) throws Exception { String tableName = null; String catalog = DB.getDatabase().getCatalog(); String schema = DB.getDatabase().getSchema(); String[] types = {"TABLE"}; ResultSet rs = md.getTables(catalog, schema, tableName, types); while (rs.next()) { String dbTableName = rs.getString("TABLE_NAME"); if (dbTableName == null) continue; MTable table = MTable.get(getCtx(), dbTableName); if (table != null) // exists in AD_Table processDatabaseTable(md, table); } rs.close(); } private void processDatabaseTable(DatabaseMetaData md, MTable table) throws Exception { Hashtable htIndexes = new Hashtable(); String catalog = DB.getDatabase().getCatalog(); String schema = DB.getDatabase().getSchema(); String tableName = table.getTableName(); if (md.storesUpperCaseIdentifiers()) tableName = tableName.toUpperCase(); else if (md.storesLowerCaseIdentifiers()) tableName = tableName.toLowerCase(); addLog(Msg.getMsg(getCtx(), "CreateTableIndexProcessTable") + tableName); addLog(table.getAD_Table_ID(), null, null, table.toString(), table.get_Table_ID(), table.getAD_Table_ID()); ++countTable; ResultSet rs = md.getIndexInfo(catalog, schema, tableName, false, true); while (rs.next()) { String dbIndexName = rs.getString("INDEX_NAME"); if (dbIndexName == null) continue; String key = dbIndexName.toLowerCase(); DatabaseTableIndex dbTableIndex = htIndexes.get(key); if (dbTableIndex == null) dbTableIndex = new DatabaseTableIndex(dbIndexName, new String[30], true, null); String columnName = rs.getString("COLUMN_NAME"); int pos = (rs.getShort("ORDINAL_POSITION")); if (pos > 0) dbTableIndex.columns[pos-1] = columnName; dbTableIndex.isNonUnique = rs.getBoolean("NON_UNIQUE"); dbTableIndex.ascOrDesc = rs.getString("ASC_OR_DESC"); htIndexes.put(key, dbTableIndex); } rs.close(); if (!htIndexes.isEmpty()) processTableIndex(md, table, htIndexes); htIndexes = null; } private void processTableIndex(DatabaseMetaData md, MTable table, Hashtable htIndexes) throws Exception { String catalog = DB.getDatabase().getCatalog(); String schema = DB.getDatabase().getSchema(); String tableName = table.getTableName(); if (md.storesUpperCaseIdentifiers()) tableName = tableName.toUpperCase(); else if (md.storesLowerCaseIdentifiers()) tableName = tableName.toLowerCase(); ResultSet rs = md.getPrimaryKeys(catalog, schema, tableName); while (rs.next()) { String primaryKeyName = rs.getString("PK_NAME"); String key = primaryKeyName.toLowerCase(); DatabaseTableIndex dbTableIndex = htIndexes.get(key); if (dbTableIndex != null) htIndexes.remove(key); } rs.close(); if (htIndexes.isEmpty()) return; ArrayList tableIndexesToValidate = new ArrayList(); MTableIndex[] tableIndexes = MTableIndex.get(table); for (MTableIndex tableIndex : tableIndexes) { String key = tableIndex.getName().toLowerCase(); DatabaseTableIndex dbTableIndex = htIndexes.get(key); tableIndexesToValidate.add(tableIndex); if (dbTableIndex != null) htIndexes.remove(key); } String getColumnIDSql = "SELECT AD_Column_ID FROM AD_Column WHERE AD_Table_ID = ? AND LOWER(ColumnName) = ?"; Enumeration en = htIndexes.elements(); while (en.hasMoreElements()) { DatabaseTableIndex dbTableIndex = en.nextElement(); addLog(Msg.getMsg(getCtx(), "CreateTableIndexCreateTableIndex") + dbTableIndex.indexName); Trx trx = Trx.get(Trx.createTrxName("CreateTableIndex"), true); trx.setDisplayName(getClass().getName()+"_process_createMTableIndex"); try { MTableIndex tableIndex = new MTableIndex(getCtx(), 0, get_TrxName()); tableIndex.setAD_Table_ID(table.getAD_Table_ID()); tableIndex.setName(dbTableIndex.indexName); tableIndex.setIsUnique(!dbTableIndex.isNonUnique); tableIndex.saveEx(); addLog(tableIndex.getAD_TableIndex_ID(), null, null, tableIndex.toString(), tableIndex.get_Table_ID(), tableIndex.getAD_TableIndex_ID()); for (int i = 0; i < 30; i++) { String dbIndexColumn = dbTableIndex.columns[i]; if (dbIndexColumn == null) break; int AD_Column_ID = DB.getSQLValue(null, getColumnIDSql, table.getAD_Table_ID(), dbIndexColumn.toLowerCase()); String columnName = dbIndexColumn; if (AD_Column_ID > 0) columnName = MColumn.getColumnName(getCtx(), AD_Column_ID); MIndexColumn indexColumn = new MIndexColumn(getCtx(), 0, get_TrxName()); indexColumn.setAD_TableIndex_ID(tableIndex.getAD_TableIndex_ID()); if (AD_Column_ID > 0) indexColumn.setAD_Column_ID(AD_Column_ID); else indexColumn.setColumnSQL(columnName); String ascOrDesc = dbTableIndex.ascOrDesc; if (ascOrDesc != null && ascOrDesc.equals("D")) indexColumn.setColumnSQL(columnName + " DESC"); indexColumn.setSeqNo(i + 1); indexColumn.saveEx(); addLog(indexColumn.getAD_IndexColumn_ID(), null, null, indexColumn.toString(), indexColumn.get_Table_ID(), indexColumn.getAD_IndexColumn_ID()); } if (trx != null) trx.commit(); ++countIndex; } catch (Exception e) { addLog(Msg.getMsg(getCtx(), "Error") + e.getLocalizedMessage()); if (trx != null) trx.rollback(); ++countError; } finally { if (trx != null) trx.close(); } } for (MTableIndex tableIndex : tableIndexesToValidate) { addLog(Msg.getMsg(getCtx(), "CreateTableIndexValidateTableIndex") + tableIndex.getName()); addLog(tableIndex.getAD_TableIndex_ID(), null, null, tableIndex.toString(), tableIndex.get_Table_ID(), tableIndex.getAD_TableIndex_ID()); Trx trx = Trx.get(Trx.createTrxName("ValidateTableIndex"), true); trx.setDisplayName(getClass().getName()+"_process_validateTableIndex"); try { String result = TableIndexValidate.validateTableIndex(getCtx(), tableIndex, trx.getTrxName(), getProcessInfo()); addLog(result); if (trx != null) trx.commit(); ++countIndex; } catch (Exception e) { addLog(Msg.getMsg(getCtx(), "Error") + e.getLocalizedMessage()); if (trx != null) trx.rollback(); ++countError; } finally { if (trx != null) trx.close(); } } } private class DatabaseTableIndex { private String indexName; private String[] columns; private boolean isNonUnique; private String ascOrDesc; private DatabaseTableIndex(String indexName, String[] columns, boolean isNonUnique, String ascOrDesc) { this.indexName = indexName; this.columns = columns; this.isNonUnique = isNonUnique; this.ascOrDesc = ascOrDesc; } } }