/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.dataprocessing; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.servoy.base.query.IBaseSQLCondition; import com.servoy.j2db.IServiceProvider; import com.servoy.j2db.Messages; import com.servoy.j2db.component.ComponentFactory; import com.servoy.j2db.dataprocessing.ValueFactory.DbIdentValue; import com.servoy.j2db.persistence.Column; import com.servoy.j2db.persistence.ColumnInfo; import com.servoy.j2db.persistence.IColumnTypes; import com.servoy.j2db.persistence.IServer; import com.servoy.j2db.persistence.Relation; import com.servoy.j2db.persistence.RepositoryException; import com.servoy.j2db.persistence.ScriptCalculation; import com.servoy.j2db.persistence.ScriptMethod; import com.servoy.j2db.persistence.Table; import com.servoy.j2db.query.ISQLQuery; import com.servoy.j2db.query.Placeholder; import com.servoy.j2db.query.QueryDelete; import com.servoy.j2db.query.QueryInsert; import com.servoy.j2db.query.QuerySelect; import com.servoy.j2db.query.QueryUpdate; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.Pair; import com.servoy.j2db.util.SafeArrayList; import com.servoy.j2db.util.ScopesUtils; import com.servoy.j2db.util.ServoyException; import com.servoy.j2db.util.UUID; import com.servoy.j2db.util.Utils; /** * Place holder for the sqlstatement needed by the foundset generated by the SQLGenerator * * @author jblok */ public class SQLSheet { public static final int SELECT = 0;//select based on pimary key public static final int DELETE = 1; public static final int INSERT = 2; public static final int UPDATE = 3; public static final int RELATED_SELECT = 6; //select based on foreign key static int sheetIDCounter = 0;//for debugging only private final String connectionName; private final SafeArrayList<SQLDescription> sql; private final Map<Relation, SQLSheet> nonGlobalRelatedSQLSheets;//relation -> SQLSheet private Map<String, Integer> columnIndexes;//dataproviderID -> columnIndex private final int sheetID; private final Table table; private List<SortColumn> defaultSort; private final Map<String, SQLDescription> relatedForeignSQLAccess; private Map<String, Integer> allCalculationsTypes; //dataproviderID -> type private final IServiceProvider application; public SQLSheet(IServiceProvider app, String connectionName, Table table)//for root { this.table = table; this.connectionName = connectionName; this.application = app; sql = new SafeArrayList<SQLDescription>(); nonGlobalRelatedSQLSheets = new ConcurrentHashMap<Relation, SQLSheet>(); relatedForeignSQLAccess = new ConcurrentHashMap<String, SQLDescription>(); sheetID = ++sheetIDCounter; flush(app, null); } /** * This regenerates the calculations when a change to them happens in the developer. So only used when developing the solution. */ public void flush(IServiceProvider app, Relation relation) { if (relation != null) { nonGlobalRelatedSQLSheets.remove(relation); relatedForeignSQLAccess.remove(relation.getName()); } else { // regenerate all cached calculations: allCalculationsTypes = new HashMap<String, Integer>(8); if (table != null) { Iterator< ? > it4 = app.getFlattenedSolution().getScriptCalculations(table, false); while (it4.hasNext()) { ScriptCalculation sp = (ScriptCalculation)it4.next(); allCalculationsTypes.put(sp.getDataProviderID(), new Integer(sp.getDataProviderType())); } } } } VariableInfo getCalculationOrColumnVariableInfo(String dataProviderID, int columnIndex) { if (columnIndex != -1) { Column c = table.getColumn(dataProviderID); if (c == null) Debug.error("getCalculationOrColumnVariableInfo: Cannot get colum with DP " + dataProviderID + " and columnIndex " + columnIndex + " for table " + table.getDataSource()); return new VariableInfo(c.getType(), c.getLength(), c.getFlags()); } Integer retVal = allCalculationsTypes.get(dataProviderID); return new VariableInfo((retVal != null ? retVal.intValue() : 0), Integer.MAX_VALUE /* allow unlimited value for unstored calcs */, Column.NORMAL_COLUMN); } public boolean containsCalculation(String dataProviderID) { return allCalculationsTypes.containsKey(dataProviderID); } public Iterator<String> getAllCalculationNames() { return allCalculationsTypes.keySet().iterator(); } public List<String> getStoredCalculationNames() { List<String> storedCalcs = new ArrayList<String>(); for (String calc : allCalculationsTypes.keySet()) { if (getDataProviderIDsColumnMap().containsKey(calc)) { storedCalcs.add(calc); } } return storedCalcs; } Map<String, Object> getAllUnstoredCalculationNamesWithNoValue() { Map< ? , Integer> columns = getDataProviderIDsColumnMap(); HashMap<String, Object> retval = new HashMap<String, Object>(5); Iterator<String> it = allCalculationsTypes.keySet().iterator(); while (it.hasNext()) { String dp = it.next(); if (!columns.containsKey(dp)) { retval.put(dp, Row.UNINITIALIZED); } } return retval; } public Table getTable() { return table; } public Object[] getDuplicateRecordData(IServiceProvider app, Row toDuplicateRow) { Object[] toDuplicate = toDuplicateRow.getRawColumnData(); SQLDescription desc = getSQLDescription(SELECT); List< ? > list = desc.getDataProviderIDsDilivery(); Object[] array = new Object[toDuplicate.length]; if (list.size() != array.length) throw new IllegalArgumentException("Data to duplicate MUST be created with (help) of this sheet"); //$NON-NLS-1$ for (int i = 0; i < toDuplicate.length; i++) { Object obj = toDuplicate[i]; if (obj instanceof ValueFactory.BlobMarkerValue) { obj = toDuplicateRow.getValue(i); } else if (obj instanceof ValueFactory.DbIdentValue && ((DbIdentValue)obj).getRow() == toDuplicateRow) { // only create a new db ident value if that db ident value belongs to the duplicated row (== pk db ident instead a a relation db ident that has to be kept!) obj = ValueFactory.createDbIdentValue(); } array[i] = obj; try { Column c = table.getColumn((String)list.get(i)); ColumnInfo ci = c.getColumnInfo(); if (c.isDBIdentity()) { array[i] = ValueFactory.createDbIdentValue(); } else if (ci != null && ci.hasSequence()) { array[i] = c.getNewRecordValue(app); } if (ci != null && ci.hasSystemValue()) { array[i] = c.getNewRecordValue(app); } } catch (Exception ex) { Debug.error(ex); } } return array; } /** * Returns raw (not using column converters) row data for a new record * @param app * @param fs * @return */ Object[] getNewRowData(IServiceProvider app, FoundSet fs) { Object[][] creationArgs = null; SQLDescription desc = getSQLDescription(SELECT); //INSERT List< ? > list = desc.getDataProviderIDsDilivery();// RequiredDataProviderIDs(); Column[] fcols = null; Relation relation = null; String relationName = fs.getRelationName(); if (relationName != null) { try { relation = app.getFlattenedSolution().getRelation(relationName); if (relation != null) { fcols = relation.getForeignColumns(); QuerySelect creationSQLString = fs.getCreationSqlSelect(); Placeholder ph = creationSQLString.getPlaceholder(SQLGenerator.createRelationKeyPlaceholderKey(creationSQLString.getTable(), relation.getName())); if (ph != null && ph.isSet()) { // a matrix as wide as the relation keys and 1 deep creationArgs = (Object[][])ph.getValue(); } } } catch (RepositoryException e) { Debug.error(e); } } Object[] array = new Object[list.size()]; for (int i = 0; i < list.size(); i++) { try { boolean filled = false; Column c = table.getColumn((String)list.get(i)); if (c.isDBIdentity()) { array[i] = ValueFactory.createDbIdentValue(); filled = true; } else { ColumnInfo ci = c.getColumnInfo(); if (c.getRowIdentType() != Column.NORMAL_COLUMN && ci != null && ci.hasSequence()) { //this is here for safety, it can happen that a form has (unwanted) still a related foundset which is created by relation based on primary key array[i] = c.getNewRecordValue(app); filled = true; } else { if (creationArgs != null && creationArgs.length != 0 && fcols != null) //created via relation, so fill the foreign key with foreign value { for (int j = 0; j < fcols.length; j++) { if (c.equals(fcols[j]) && ((relation.getOperators()[j] & IBaseSQLCondition.OPERATOR_MASK) == IBaseSQLCondition.EQUALS_OPERATOR)) { // creationArgs is a matrix as wide as the relation keys and 1 deep array[i] = creationArgs[j][0]; filled = true; break; } } } } } if (!filled) { array[i] = c.getNewRecordValue(app); } } catch (Exception ex) { Debug.error(ex); } } return array; } void processCopyValues(IRecordInternal s) { SQLDescription desc = getSQLDescription(SELECT); if (desc == null) { return; } List< ? > list = desc.getDataProviderIDsDilivery(); for (int i = 0; i < list.size(); i++) { try { String id = (String)list.get(i); Column c = table.getColumn(id); if (c != null) { ColumnInfo ci = c.getColumnInfo(); if (ci != null && ci.getAutoEnterType() == ColumnInfo.LOOKUP_VALUE_AUTO_ENTER) { String lookupDataProviderID = ci.getLookupValue(); Object obj = s.getValue(lookupDataProviderID); if (ScopesUtils.isVariableScope(lookupDataProviderID) && !s.has(lookupDataProviderID)) { ScriptMethod globalScriptMethod = application.getFlattenedSolution().getScriptMethod(null, lookupDataProviderID); if (globalScriptMethod != null) { try { obj = application.getScriptEngine().getScopesScope().executeGlobalFunction(globalScriptMethod.getScopeName(), globalScriptMethod.getName(), null, false, false); } catch (Exception e) { Debug.error(e); } } } // Protect to writing null to null-protected columns. An exception gets written in the log. if (!((obj == null) && !c.getAllowNull())) s.setValue(id, obj, false); } } } catch (Exception ex) { Debug.error(ex); } } } Object convertObjectToValue(String dataProviderID, Object obj, IConverterManager<IColumnConverter> columnConverterManager, IColumnValidatorManager columnValidatorManager) { Object convertedValue = obj; int columnIndex = getColumnIndex(dataProviderID); VariableInfo variableInfo = getCalculationOrColumnVariableInfo(dataProviderID, columnIndex); if (columnIndex >= 0) { ConverterInfo converterInfo = getColumnConverterInfo(columnIndex); if (converterInfo != null) { IColumnConverter conv = columnConverterManager.getConverter(converterInfo.converterName); if (conv == null) { throw new IllegalStateException(Messages.getString("servoy.error.converterNotFound", new Object[] { converterInfo.converterName })); //$NON-NLS-1$ } try { convertedValue = conv.convertFromObject(converterInfo.props, variableInfo.type, convertedValue); } catch (Exception e) { throw new IllegalArgumentException( Messages.getString( "servoy.record.error.settingDataprovider", new Object[] { dataProviderID, Column.getDisplayTypeString(variableInfo.type), convertedValue }), e); //$NON-NLS-1$ } int valueLen = Column.getObjectSize(convertedValue, variableInfo.type); if (valueLen > 0 && variableInfo.length > 0 && valueLen > variableInfo.length) // insufficient space to save value { throw new IllegalArgumentException( Messages.getString( "servoy.record.error.columnSizeTooSmall", new Object[] { dataProviderID, Column.getDisplayTypeString(variableInfo.type), convertedValue })); //$NON-NLS-1$ } } Pair<String, Map<String, String>> validatorInfo = getColumnValidatorInfo(columnIndex); if (validatorInfo != null) { IColumnValidator validator = columnValidatorManager.getValidator(validatorInfo.getLeft()); if (validator == null) { throw new IllegalStateException(Messages.getString("servoy.error.validatorNotFound", new Object[] { validatorInfo.getLeft() })); //$NON-NLS-1$ } try { validator.validate(validatorInfo.getRight(), convertedValue); } catch (IllegalArgumentException e) { String msg = Messages.getString("servoy.record.error.validation", new Object[] { dataProviderID, convertedValue }); //$NON-NLS-1$ if (e.getMessage() != null && e.getMessage().length() != 0) msg += ' ' + e.getMessage(); throw new IllegalArgumentException(msg); } } if ((variableInfo.flags & Column.UUID_COLUMN) != 0) { // this is a UUID column, convert from UUID UUID uuid = Utils.getAsUUID(convertedValue, false); if (uuid != null) { switch (Column.mapToDefaultType(variableInfo.type)) { case IColumnTypes.TEXT : convertedValue = uuid.toString(); break; case IColumnTypes.MEDIA : convertedValue = uuid.toBytes(); break; } } } } if (variableInfo.type != IColumnTypes.MEDIA || (variableInfo.flags & Column.UUID_COLUMN) != 0) { try { convertedValue = Column.getAsRightType(variableInfo.type, variableInfo.flags, convertedValue, null, variableInfo.length, null, true); // dont use timezone here, should only be done in ui related stuff } catch (Exception e) { Debug.error(e); throw new IllegalArgumentException(Messages.getString( "servoy.record.error.settingDataprovider", new Object[] { dataProviderID, Column.getDisplayTypeString(variableInfo.type), convertedValue })); //$NON-NLS-1$ } } return convertedValue; } /** * Convert the raw value using the column converters when configured. * @param val * @param columnIndex * @param sheet * @param columnConverterManager * @return */ Object convertValueToObject(Object val, int columnIndex, IConverterManager<IColumnConverter> columnConverterManager) { Object value = val; // check if column uses a converter if (columnIndex >= 0) { String dataProviderID = getColumnNames()[columnIndex]; VariableInfo variableInfo = getCalculationOrColumnVariableInfo(dataProviderID, columnIndex); if ((variableInfo.flags & Column.UUID_COLUMN) != 0) { // this is a UUID column, first convert to UUID (could be string or byte array (media)) - so we can get/use it as a valid uuid string value = Utils.getAsUUID(value, false); } ConverterInfo converterInfo = getColumnConverterInfo(columnIndex); if (converterInfo != null) { IColumnConverter conv = columnConverterManager.getConverter(converterInfo.converterName); if (conv != null) { try { value = conv.convertToObject(converterInfo.props, variableInfo.type, value); } catch (Exception e) { Debug.error(e); throw new IllegalArgumentException(Messages.getString( "servoy.record.error.gettingDataprovider", new Object[] { dataProviderID, Column.getDisplayTypeString(variableInfo.type) }), e); //$NON-NLS-1$ } } else { throw new IllegalArgumentException(Messages.getString( "servoy.record.error.gettingDataprovider", new Object[] { dataProviderID, Column.getDisplayTypeString(variableInfo.type) })); //$NON-NLS-1$ } } } return value; } void addSelect(QuerySelect select, List<String> dataProviderIDsDilivery, List<String> requiredDataProviderIDs, List<String> oldRequiredDataProviderIDs) { sql.set(SELECT, new SQLDescription(select, dataProviderIDsDilivery, requiredDataProviderIDs, oldRequiredDataProviderIDs)); } void addInsert(QueryInsert insert, List<String> requiredDataProviderIDs) { sql.set(INSERT, new SQLDescription(insert, null, requiredDataProviderIDs, null)); } void addUpdate(QueryUpdate update, List<String> requiredDataProviderIDs, List<String> oldRequiredDataProviderIDs) { sql.set(UPDATE, new SQLDescription(update, null, requiredDataProviderIDs, oldRequiredDataProviderIDs)); } void addDelete(QueryDelete delete, List<String> oldRequiredDataProviderIDs) { sql.set(DELETE, new SQLDescription(delete, null, null, oldRequiredDataProviderIDs)); } void addRelatedSelect(String relationName, QuerySelect sqlQuery, List<String> dataProviderIDsDilivery, List<String> requiredDataProviderIDs, List<String> oldRequiredDataProviderIDs) { relatedForeignSQLAccess.put(relationName, new SQLDescription(sqlQuery, dataProviderIDsDilivery, requiredDataProviderIDs, oldRequiredDataProviderIDs)); } public String getServerName() { return connectionName; } SQLSheet getRelatedSQLSheet(Relation relation, SQLGenerator generator) throws ServoyException { SQLSheet retval = nonGlobalRelatedSQLSheets.get(relation); if (retval == null) { if (relation.isParentRef()) { retval = this; } else { retval = generator.getCachedTableSQLSheet(relation.getForeignDataSource()); generator.makeRelatedSQL(retval, relation); } nonGlobalRelatedSQLSheets.put(relation, retval); } return retval; } public List<SortColumn> getDefaultPKSort() { if (table == null) { return null; } if (defaultSort == null) { List<SortColumn> ds = null; if (table.getRowIdentColumns().size() > 1) { // find a match with an index List<SortColumn>[] indexes = table.getIndexes(); for (int i = 0; ds == null && indexes != null && i < indexes.length; i++) { List<SortColumn> index = indexes[i]; List<Column> rowIdentColumnsCopy = new ArrayList<Column>(table.getRowIdentColumns()); boolean match = index.size() == rowIdentColumnsCopy.size(); for (int c = 0; match && c < index.size(); c++) { match = rowIdentColumnsCopy.remove(index.get(c).getColumn()); } if (match) { ds = index; } } } if (ds == null) // no match on index { ds = new ArrayList<SortColumn>(table.getRowIdentColumns().size()); // get key columns in db defined order for (Column column : table.getColumns()) { if (table.getRowIdentColumns().contains(column)) { ds.add(new SortColumn(column)); } } } defaultSort = ds; } return defaultSort; } public SQLSheet getRelatedSheet(Relation relation, SQLGenerator generator) { try { if (relation != null && !relation.isGlobal()) { return getRelatedSQLSheet(relation, generator); } } catch (ServoyException e) { Debug.error("cant get related sheet " + relation, e); //$NON-NLS-1$ } return null; } public ISQLQuery getSQL(int type) { if (sql == null) return null; if (type < sql.size()) { SQLDescription desc = sql.get(type); if (desc != null) { return desc.getSQLQuery(); } } return null; } public Map< ? , Integer> getDataProviderIDsColumnMap() { if (columnIndexes == null) { Map<String, Integer> cols = new HashMap<String, Integer>(32); SQLDescription desc = sql.get(SELECT); if (desc != null) { List<String> dataProviderIDsDilivery = desc.getDataProviderIDsDilivery(); for (int i = 0; i < dataProviderIDsDilivery.size(); i++) { cols.put(dataProviderIDsDilivery.get(i), new Integer(i)); } } columnIndexes = cols; } return columnIndexes; } //used by subsummaryfoundset public void setDataProviderIDsColumnMap(HashMap<String, Integer> indexes) { if (columnIndexes != null) throw new IllegalStateException("cannot set the indexes when they are already set and used from other rootsets"); //$NON-NLS-1$ columnIndexes = indexes; } /** * Get the column index based on a dataProviderID * * @param dataProviderID the dataprovider index to retrieve * @return the index (-1 if not found) */ public int getColumnIndex(String dataProviderID) { Integer index = getDataProviderIDsColumnMap().get(dataProviderID); if (index == null) { return -1; } return index.intValue(); } private String[] allNames; public String[] getColumnNames() { if (allNames == null) { SQLDescription desc = sql.get(SELECT); // not based on a table if (desc == null) { allNames = new String[0]; } else { List< ? > dataProviderIDsDilivery = desc.getDataProviderIDsDilivery(); allNames = dataProviderIDsDilivery.toArray(new String[dataProviderIDsDilivery.size()]); } } return allNames; } public SQLDescription getSQLDescription(int sqlType) { return sql.get(sqlType); } public SQLDescription getRelatedSQLDescription(String relationName) { return relatedForeignSQLAccess.get(relationName); } private int[] sheetPKindexes; int[] getPKIndexes() { if (sheetPKindexes == null) { SQLSheet.SQLDescription desc = getSQLDescription(SQLSheet.UPDATE); List< ? > list = desc.getOldRequiredDataProviderIDs(); //==pk int[] pis = new int[list.size()]; for (int i = 0; i < list.size(); i++) { String id = (String)list.get(i); pis[i] = getColumnIndex(id); if (pis[i] == -1) { throw new IllegalStateException("Could not find PK index for column " + id + " in sheet " + this); //$NON-NLS-1$ //$NON-NLS-2$ } } sheetPKindexes = pis; } return sheetPKindexes; } private Integer sheetIdentIndex; /** * Find the index of an identity column. This may be a non-pk column. * * @return identity column index, -1 if not found */ int getIdentIndex() { if (sheetIdentIndex == null) { SQLSheet.SQLDescription desc = getSQLDescription(SQLSheet.UPDATE); List< ? > list = desc.getRequiredDataProviderIDs(); for (int i = 0; sheetIdentIndex == null && i < list.size(); i++) { String dataProviderID = (String)list.get(i); Column c = table.getColumn(dataProviderID); if (c.isDBIdentity()) { sheetIdentIndex = new Integer(i); } } if (sheetIdentIndex == null) { sheetIdentIndex = new Integer(-1); } } return sheetIdentIndex.intValue(); } private String[] sheetPKColumns = null; public String[] getPKColumnDataProvidersAsArray() { if (sheetPKColumns == null) { SQLSheet.SQLDescription desc = getSQLDescription(SQLSheet.UPDATE); List< ? > list = desc.getOldRequiredDataProviderIDs(); //==pk String[] spks = new String[list.size()]; for (int i = 0; i < list.size(); i++) { String id = (String)list.get(i); spks[i] = id; } sheetPKColumns = spks; } return sheetPKColumns; } public int getSheetID() { return sheetID; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("SQLSheet [" + sheetID + "]\n"); //$NON-NLS-1$ //$NON-NLS-2$ int type = 0; Iterator<SQLDescription> it = sql.iterator(); while (it.hasNext()) { SQLDescription element = it.next(); sb.append("SQL [" + type + "] " + element + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ type++; } Iterator< ? > it2 = relatedForeignSQLAccess.entrySet().iterator(); while (it2.hasNext()) { Map.Entry< ? , ? > entry = (Map.Entry< ? , ? >)it2.next(); SQLDescription element = (SQLDescription)entry.getValue(); sb.append("Related SQL [relation: " + entry.getKey() + "] " + element + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ type++; } return sb.toString(); } class SQLDescription { private final ISQLQuery sqlQuery; private final List<String> dataProviderIDsDilivery; private final List<String> requiredDataProviderIDs; private final List<String> oldRequiredDataProviderIDs; SQLDescription(ISQLQuery sqlQuery, List<String> dataProviderIDsDilivery, List<String> requiredDataProviderIDs, List<String> oldRequiredDataProviderIDs) { this.dataProviderIDsDilivery = dataProviderIDsDilivery; this.requiredDataProviderIDs = requiredDataProviderIDs; this.oldRequiredDataProviderIDs = oldRequiredDataProviderIDs; this.sqlQuery = sqlQuery; } public ISQLQuery getSQLQuery() { return sqlQuery; } public List<String> getDataProviderIDsDilivery() { return dataProviderIDsDilivery; } public List<String> getRequiredDataProviderIDs() { return requiredDataProviderIDs; } public List<String> getOldRequiredDataProviderIDs() { return oldRequiredDataProviderIDs; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getSQLQuery()); sb.append(" ["); //$NON-NLS-1$ sb.append((dataProviderIDsDilivery != null ? dataProviderIDsDilivery.size() : 0)); sb.append(","); //$NON-NLS-1$ sb.append((requiredDataProviderIDs != null ? requiredDataProviderIDs.size() : 0)); sb.append(","); //$NON-NLS-1$ sb.append((oldRequiredDataProviderIDs != null ? oldRequiredDataProviderIDs.size() : 0)); sb.append("]"); //$NON-NLS-1$ return sb.toString(); } } private HashMap<String, QuerySelect> aggregate; private HashMap<String, Collection<String>> aggregate_dataproviders; void addAggregate(String name, String dataProviderIDToAggregate, QuerySelect sqlSelect) { if (aggregate == null) { aggregate = new HashMap<String, QuerySelect>(3); aggregate_dataproviders = new HashMap<String, Collection<String>>(3); } aggregate.put(name, sqlSelect); Collection<String> aggregates = aggregate_dataproviders.get(dataProviderIDToAggregate); if (aggregates == null) { aggregates = new ArrayList<String>(); aggregate_dataproviders.put(dataProviderIDToAggregate, aggregates); } aggregates.add(name); //lowercase is only safety ,due to bad impl earlier } Map<String, QuerySelect> getAggregates() { return aggregate; } public boolean isUsedByAggregate(String dataProviderIDToAggregate) { if (aggregate_dataproviders == null) return false; return (aggregate_dataproviders.containsKey(dataProviderIDToAggregate)); } public Collection<String> getAggregateName(String dataProviderIDToAggregate) //reverse lookup { if (aggregate_dataproviders == null) return null; return aggregate_dataproviders.get(dataProviderIDToAggregate); } public boolean containsAggregate(String name) { if (aggregate == null || name == null) return false; return aggregate.containsKey(name); } public String[] getAggregateNames() { if (aggregate == null) return new String[0]; String[] retval = new String[aggregate.size()]; aggregate.keySet().toArray(retval); return retval; } public String[] getCalculationNames() { String[] retval = new String[allCalculationsTypes.size()]; allCalculationsTypes.keySet().toArray(retval); return retval; } private ConverterInfo[] converterInfos; public ConverterInfo getColumnConverterInfo(String dataProviderID) { return getColumnConverterInfo(getColumnIndex(dataProviderID)); } public ConverterInfo getColumnConverterInfo(int columnIndex) { if (converterInfos == null) { SQLDescription desc = sql.get(SELECT); List<String> dataProviderIDsDilivery = desc.getDataProviderIDsDilivery(); ConverterInfo[] cis = new ConverterInfo[dataProviderIDsDilivery.size()]; for (int i = 0; i < dataProviderIDsDilivery.size(); i++) { String cdp = dataProviderIDsDilivery.get(i); Column c = table.getColumn(cdp); ColumnInfo ci = c.getColumnInfo(); if (ci != null && ci.getConverterName() != null && ci.getConverterName().trim().length() != 0) { Map<String, String> props = null; try { props = ComponentFactory.<String> parseJSonProperties(ci.getConverterProperties()); } catch (IOException e) { Debug.error("Could not parse column converter properties", e); } cis[i] = new ConverterInfo(ci.getConverterName(), props); } } converterInfos = cis; } if (columnIndex < 0 || columnIndex >= converterInfos.length) { return null; } return converterInfos[columnIndex]; } private Pair<String, Map<String, String>>[] validatorInfos; public Pair<String, Map<String, String>> getColumnValidatorInfo(int columnIndex) { if (validatorInfos == null) { SQLDescription desc = sql.get(SELECT); List< ? > dataProviderIDsDilivery = desc.getDataProviderIDsDilivery(); @SuppressWarnings("unchecked") Pair<String, Map<String, String>>[] vis = new Pair[dataProviderIDsDilivery.size()]; int i = 0; Iterator< ? > it = dataProviderIDsDilivery.iterator(); while (it.hasNext()) { String cdp = (String)it.next(); Column c = table.getColumn(cdp); ColumnInfo ci = c.getColumnInfo(); if (ci != null && ci.getValidatorName() != null && ci.getValidatorName().trim().length() != 0) { Map<String, String> parsedValidatorProperties = null; try { parsedValidatorProperties = ComponentFactory.parseJSonProperties(ci.getValidatorProperties()); } catch (IOException e) { Debug.error(e); } vis[i] = new Pair<String, Map<String, String>>(ci.getValidatorName(), parsedValidatorProperties); } i++; } validatorInfos = vis; } return validatorInfos[columnIndex]; } public static boolean isOracleServer(IServer server) { try { return (server.getDatabaseProductName().toLowerCase().indexOf("oracle") != -1); //$NON-NLS-1$ } catch (Exception e) { return false; } } /** * Struct class for variable info * * @author rgansevles * */ public class VariableInfo { public final int type; public final int length; public final int flags; public VariableInfo(int type, int length, int flags) { this.type = type; this.length = length; this.flags = flags; } } public static class ConverterInfo { public final String converterName; public final Map<String, String> props; public ConverterInfo(String converterName, Map<String, String> props) { this.converterName = converterName; this.props = props; } } }