Search in sources :

Example 11 with QueryTable

use of com.servoy.j2db.query.QueryTable in project servoy-client by Servoy.

the class FoundSetManager method insertToDataSource.

public Object[] insertToDataSource(String name, IDataSet dataSet, ColumnType[] columnTypes, WrappedObjectReference<String[]> pkNames, boolean create, boolean skipOnLoad, String server) throws ServoyException {
    if (name == null) {
        return null;
    }
    WrappedObjectReference<String[]> actualPkNames = pkNames;
    if (actualPkNames == null)
        actualPkNames = new WrappedObjectReference<String[]>(null);
    String dataSource = IServer.VIEW_SERVER.equals(server) ? DataSourceUtils.createViewDataSource(name) : DataSourceUtils.createInmemDataSource(name);
    // initial dataset to use, but can also be set later to a 0 row dataset that is created to match columnNames and columnTypes with an in-mem
    // table definition, if that is available and columns do not match with the initial dataset
    IDataSet fixedDataSet = dataSet;
    List<ColumnType> fixedColumnTypes;
    if (columnTypes == null) {
        ColumnType[] dataSetTypes = BufferedDataSetInternal.getColumnTypeInfo(dataSet);
        fixedColumnTypes = dataSetTypes == null ? null : asList(dataSetTypes);
    } else {
        fixedColumnTypes = asList(columnTypes);
    }
    // get column def from the first in-mem datasource found
    ServoyJSONObject columnsDef = null;
    Iterator<TableNode> tblIte = application.getFlattenedSolution().getTableNodes(dataSource);
    int onLoadMethodId = -1;
    while (tblIte.hasNext()) {
        TableNode tn = tblIte.next();
        if (columnsDef == null)
            columnsDef = tn.getColumns();
        if (onLoadMethodId == -1)
            onLoadMethodId = tn.getOnFoundSetLoadMethodID();
    }
    HashMap<String, ColumnInfoDef> columnInfoDefinitions = null;
    Set<Integer> columnsThatNeedToStringSerialize = null;
    if (columnsDef == null) {
        // if we have array columns, convert values using StringSerializer
        if (containsArrayType(fixedColumnTypes)) {
            columnsThatNeedToStringSerialize = new HashSet<>();
            for (int i = 0; i < fixedColumnTypes.size(); i++) {
                ColumnType columnType = fixedColumnTypes.get(i);
                if (columnType.getSqlType() == Types.ARRAY) {
                    fixedColumnTypes.set(i, ColumnType.getColumnType(IColumnTypes.TEXT));
                    columnsThatNeedToStringSerialize.add(Integer.valueOf(i));
                }
            }
        }
    } else {
        TableDef tableInfo = DatabaseUtils.deserializeTableInfo(columnsDef);
        // column names that are not SEQUENCE_AUTO_ENTER/DATABASE_IDENTITY from table node (columnsDef)
        List<String> inmemColumnNamesThatCanSetData = new ArrayList<>();
        // column types of columns that are not SEQUENCE_AUTO_ENTER/DATABASE_IDENTITY from table node (columnsDef)
        List<ColumnType> inmemColumnTypesForColumnsThatCanSetData = new ArrayList<>();
        // ALL column defs from design time table node (columnsDef)
        columnInfoDefinitions = new HashMap<String, ColumnInfoDef>();
        // pk/rowid column names from design time table node (columnsDef)
        List<String> inmemPKs = new ArrayList<>();
        for (int j = 0; j < tableInfo.columnInfoDefSet.size(); j++) {
            ColumnInfoDef cid = tableInfo.columnInfoDefSet.get(j);
            if (cid.autoEnterType != ColumnInfo.SEQUENCE_AUTO_ENTER || cid.autoEnterSubType != ColumnInfo.DATABASE_IDENTITY) {
                // we only support auto-enter for in-mem tables based on dbident (that is then handled by hsql)
                // that is why we only check for that here; for example, if one would define at design time a
                // uuid generator pk column on an in-mem table, that would not work; it would try to insert null into a non-nullable column
                inmemColumnNamesThatCanSetData.add(cid.name);
                inmemColumnTypesForColumnsThatCanSetData.add(cid.columnType);
            }
            if ((cid.flags & IBaseColumn.IDENT_COLUMNS) != 0) {
                inmemPKs.add(cid.name);
            }
            columnInfoDefinitions.put(cid.name, cid);
            // apply stringserializer on designed datasources
            if (JSONSerializerWrapper.STRING_SERIALIZER_NAME.equals(cid.converterName)) {
                if (columnsThatNeedToStringSerialize == null) {
                    columnsThatNeedToStringSerialize = new HashSet<>();
                }
                columnsThatNeedToStringSerialize.add(Integer.valueOf(j));
            }
        }
        if (actualPkNames.o == null && inmemPKs.size() > 0) {
            actualPkNames.o = inmemPKs.toArray(new String[inmemPKs.size()]);
        }
        if (!asList(dataSet.getColumnNames()).equals(inmemColumnNamesThatCanSetData) || !compareColumnTypes(fixedColumnTypes, inmemColumnTypesForColumnsThatCanSetData)) {
            if (dataSet.getColumnCount() > 0 && /*
													 * do not generate warning if this is just the initial load of a design time inmem table that adds 0 rows
													 * and doesn't care about columns
													 */
            !asList(dataSet.getColumnNames()).equals(inmemColumnNamesThatCanSetData)) {
                Debug.warn("Dataset column names definition does not match inmem table definition for datasource : " + dataSource + " columns of dataset: " + Arrays.toString(dataSet.getColumnNames()) + ", columns of in mem definition: " + inmemColumnNamesThatCanSetData);
            }
            if (fixedColumnTypes != null && !compareColumnTypes(fixedColumnTypes, inmemColumnTypesForColumnsThatCanSetData)) {
                Debug.warn("Dataset column types definition does not match inmem table definition for datasource : " + dataSource + " types of dataset: " + fixedColumnTypes + ", types of in mem definition: " + inmemColumnTypesForColumnsThatCanSetData);
            }
            fixedColumnTypes = inmemColumnTypesForColumnsThatCanSetData;
            fixedDataSet = BufferedDataSetInternal.createBufferedDataSet(inmemColumnNamesThatCanSetData.toArray(new String[inmemColumnNamesThatCanSetData.size()]), fixedColumnTypes.toArray(new ColumnType[fixedColumnTypes.size()]), new ArrayList<Object[]>(), false);
        }
    }
    // - in the else branch above (already defined at design time), columns that are not auto sequences or dbidents; see inmemColumnNames/inmemColumnTypes(which is at this point the same as fixedColumnTypes)
    if (fixedColumnTypes != null && dataSet.getRowCount() > 0 && dataSet.getRow(0).length != fixedColumnTypes.size()) {
        // $NON-NLS-1$
        throw new RepositoryException("Data set rows do not match column count");
    }
    if (columnsThatNeedToStringSerialize != null) {
        replaceValuesWithSerializedString(dataSet, columnsThatNeedToStringSerialize);
    }
    try {
        ITable table = IServer.VIEW_SERVER.equals(server) ? viewDataSources.get(dataSource) : inMemDataSources.get(dataSource);
        if (table == null && !create) {
            throw new RepositoryException("Appending to non-existing datasource: " + dataSource);
        }
        GlobalTransaction gt = getGlobalTransaction();
        String tid = null;
        String serverName = server == null ? (table == null ? IServer.INMEM_SERVER : table.getServerName()) : server;
        if (gt != null) {
            tid = gt.getTransactionID(serverName);
        }
        if (create && table != null) {
            // temp table was used before, delete all data in it
            FoundSet foundSet = (FoundSet) getSharedFoundSet(dataSource);
            foundSet.removeLastFound();
            try {
                QueryDelete delete = new QueryDelete(new QueryTable(table.getSQLName(), table.getDataSource(), table.getCatalog(), table.getSchema(), true));
                SQLStatement deleteStatement = new SQLStatement(ISQLActionTypes.DELETE_ACTION, table.getServerName(), table.getName(), null, tid, delete, null);
                application.getDataServer().performUpdates(application.getClientID(), new ISQLStatement[] { deleteStatement });
            } catch (Exception e) {
                Debug.log(e);
                table = null;
            }
            RowManager element = rowManagers.get(dataSource);
            if (element != null) {
                element.flushAllCachedRows();
            }
        }
        InsertResult insertResult = application.getDataServer().insertDataSet(application.getClientID(), fixedDataSet, dataSource, table == null ? IServer.INMEM_SERVER : table.getServerName(), table == null ? null : table.getName(), /* create temp table when null */
        tid, fixedColumnTypes == null ? null : fixedColumnTypes.toArray(new ColumnType[fixedColumnTypes.size()]), /* inferred from dataset when null */
        actualPkNames.o, columnInfoDefinitions);
        if (insertResult != null) {
            table = insertResult.getTable();
            // do we want to fix that somehow or the caller should just make sure it calls it with the correct column order?
            if (dataSet != fixedDataSet && dataSet.getRowCount() > 0) {
                insertResult = application.getDataServer().insertDataSet(application.getClientID(), dataSet, dataSource, table.getServerName(), table.getName(), tid, columnTypes, /* will be inferred by called method from dataset if null */
                actualPkNames.o, columnInfoDefinitions);
            }
            if (IServer.INMEM_SERVER.equals(serverName)) {
                inMemDataSources.put(dataSource, table);
            } else {
                viewDataSources.put(dataSource, table);
            }
            fireTableEvent(table);
            if (!skipOnLoad && dataSet.getRowCount() == 0 && onLoadMethodId > 0) {
                IFoundSetInternal sharedFoundSet = getSharedFoundSet(dataSource);
                executeFoundsetTriggerReturnFirst(sharedFoundSet.getTable(), new Object[] { DataSourceUtils.getInmemDataSourceName(dataSource) }, StaticContentSpecLoader.PROPERTY_ONFOUNDSETLOADMETHODID, false, (Scriptable) sharedFoundSet);
            }
            if (create) {
                // only refresh when it is a new full load, when adding data to an existing table, it is only applicable to the (shared) foundset
                refreshFoundSetsFromDB(dataSource, null, false);
            }
            return insertResult.getGeneratedPks();
        }
    } catch (RemoteException e) {
        throw new RepositoryException(e);
    }
    return null;
}
Also used : ColumnType(com.servoy.j2db.query.ColumnType) BaseColumnType(com.servoy.base.query.BaseColumnType) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) TableDef(com.servoy.j2db.util.xmlxport.TableDef) ColumnInfoDef(com.servoy.j2db.util.xmlxport.ColumnInfoDef) ITable(com.servoy.j2db.persistence.ITable) WrappedObjectReference(com.servoy.j2db.util.WrappedObjectReference) InsertResult(com.servoy.j2db.dataprocessing.IDataServer.InsertResult) QueryDelete(com.servoy.j2db.query.QueryDelete) RepositoryException(com.servoy.j2db.persistence.RepositoryException) BaseQueryTable(com.servoy.base.query.BaseQueryTable) QueryTable(com.servoy.j2db.query.QueryTable) ServoyException(com.servoy.j2db.util.ServoyException) JavaScriptException(org.mozilla.javascript.JavaScriptException) IOException(java.io.IOException) MarshallException(org.jabsorb.serializer.MarshallException) ApplicationException(com.servoy.j2db.ApplicationException) RemoteException(java.rmi.RemoteException) RepositoryException(com.servoy.j2db.persistence.RepositoryException) ServoyJSONObject(com.servoy.j2db.util.ServoyJSONObject) TableNode(com.servoy.j2db.persistence.TableNode) ServoyJSONObject(com.servoy.j2db.util.ServoyJSONObject) RemoteException(java.rmi.RemoteException)

Example 12 with QueryTable

use of com.servoy.j2db.query.QueryTable in project servoy-client by Servoy.

the class FoundSetManager method createDataSourceFromQuery.

public String createDataSourceFromQuery(String name, String serverName, ISQLSelect sqlSelect, boolean useTableFilters, int maxNumberOfRowsToRetrieve, int[] types, String[] pkNames) throws ServoyException {
    if (name == null) {
        return null;
    }
    try {
        String queryTid = getTransactionID(serverName);
        String dataSource = DataSourceUtils.createInmemDataSource(name);
        ITable table = inMemDataSources.get(dataSource);
        GlobalTransaction gt = getGlobalTransaction();
        String targetTid = null;
        String targetServerName = table == null ? IServer.INMEM_SERVER : table.getServerName();
        if (gt != null) {
            targetTid = gt.getTransactionID(targetServerName);
        }
        if (table != null) {
            // temp table was used before, delete all data in it
            FoundSet foundSet = (FoundSet) getSharedFoundSet(dataSource);
            foundSet.removeLastFound();
            try {
                QueryDelete delete = new QueryDelete(new QueryTable(table.getSQLName(), table.getDataSource(), table.getCatalog(), table.getSchema(), true));
                SQLStatement deleteStatement = new SQLStatement(ISQLActionTypes.DELETE_ACTION, table.getServerName(), table.getName(), null, targetTid, delete, null);
                application.getDataServer().performUpdates(application.getClientID(), new ISQLStatement[] { deleteStatement });
            } catch (Exception e) {
                Debug.log(e);
                table = null;
            }
        }
        table = application.getDataServer().insertQueryResult(application.getClientID(), serverName, queryTid, sqlSelect, useTableFilters ? getTableFilterParams(serverName, sqlSelect) : null, false, 0, maxNumberOfRowsToRetrieve, IDataServer.CUSTOM_QUERY, dataSource, table == null ? IServer.INMEM_SERVER : table.getServerName(), table == null ? null : table.getName(), /* create temp table when null */
        targetTid, ColumnType.getColumnTypes(types), pkNames);
        if (table != null) {
            inMemDataSources.put(dataSource, table);
            fireTableEvent(table);
            refreshFoundSetsFromDB(dataSource, null, false);
            return dataSource;
        }
    } catch (RemoteException e) {
        throw new RepositoryException(e);
    }
    return null;
}
Also used : QueryDelete(com.servoy.j2db.query.QueryDelete) ITable(com.servoy.j2db.persistence.ITable) RepositoryException(com.servoy.j2db.persistence.RepositoryException) RemoteException(java.rmi.RemoteException) BaseQueryTable(com.servoy.base.query.BaseQueryTable) QueryTable(com.servoy.j2db.query.QueryTable) ServoyException(com.servoy.j2db.util.ServoyException) JavaScriptException(org.mozilla.javascript.JavaScriptException) IOException(java.io.IOException) MarshallException(org.jabsorb.serializer.MarshallException) ApplicationException(com.servoy.j2db.ApplicationException) RemoteException(java.rmi.RemoteException) RepositoryException(com.servoy.j2db.persistence.RepositoryException)

Example 13 with QueryTable

use of com.servoy.j2db.query.QueryTable in project servoy-client by Servoy.

the class FoundSetManager method hasTableFiltersWithJoins.

/**
 * Check if table filters for the query are defined that have joins.
 *
 * @param serverName
 * @param sql
 * @return
 */
public boolean hasTableFiltersWithJoins(String serverName, IQueryElement sql) {
    final List<TableFilter> serverFilters = tableFilterParams.get(serverName);
    if (serverFilters == null) {
        return false;
    }
    // get the sql table names in the query
    // find the filters for the tables found in the query
    final AtomicBoolean hasTableFiltersWithJoins = new AtomicBoolean(false);
    sql.acceptVisitor(new IVisitor() {

        private final Set<String> tableSqlNames = new HashSet<String>();

        public Object visit(Object o) {
            if (o instanceof QueryTable && ((QueryTable) o).getName() != null && tableSqlNames.add(((QueryTable) o).getName())) {
                QueryTable qTable = (QueryTable) o;
                for (TableFilter filter : serverFilters) {
                    if (Utils.stringSafeEquals(filter.getTableSQLName(), qTable.getName())) {
                        if (filter.getTableFilterdefinition() instanceof QueryTableFilterdefinition) {
                            List<ISQLJoin> joins = ((QueryTableFilterdefinition) filter.getTableFilterdefinition()).getQuerySelect().getJoins();
                            if (joins != null && !joins.isEmpty()) {
                                hasTableFiltersWithJoins.set(true);
                                return new VisitorResult(o, false);
                            }
                        }
                    }
                }
            }
            return o;
        }
    });
    return hasTableFiltersWithJoins.get();
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) IVisitor(com.servoy.j2db.util.visitor.IVisitor) ServoyJSONObject(com.servoy.j2db.util.ServoyJSONObject) Arrays.asList(java.util.Arrays.asList) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) List(java.util.List) SortedList(com.servoy.j2db.util.SortedList) Collectors.toList(java.util.stream.Collectors.toList) BaseQueryTable(com.servoy.base.query.BaseQueryTable) QueryTable(com.servoy.j2db.query.QueryTable) HashSet(java.util.HashSet)

Example 14 with QueryTable

use of com.servoy.j2db.query.QueryTable in project servoy-client by Servoy.

the class SQLGenerator method getPKSelectSqlSelect.

/*
 * _____________________________________________________________ The methods below belong to this class
 */
// SQL pk(s) select for foundset,concatenating those strings will always deliver a executable SQL
// Note: removeUnusedJoins must be false when the resulting query is changed afterwards (like adding columns)
QuerySelect getPKSelectSqlSelect(IGlobalValueEntry provider, Table table, QuerySelect oldSQLQuery, List<IRecordInternal> findStates, boolean reduce, IDataSet omitPKs, List<SortColumn> orderByFields, boolean removeUnusedJoins) throws ServoyException {
    if (table == null) {
        throw new RepositoryException(ServoyException.InternalCodes.TABLE_NOT_FOUND);
    }
    QuerySelect retval;
    if (oldSQLQuery != null) {
        retval = deepClone(oldSQLQuery);
        retval.setGroupBy(null);
        // will be generated based on foundset sorting
        if (orderByFields != null)
            retval.clearSorts();
        // remove all servoy conditions, except filter, search and relation
        for (String conditionName : retval.getConditionNames()) {
            if (conditionName.startsWith(SERVOY_CONDITION_PREFIX) && !(CONDITION_FILTER.equals(conditionName) || CONDITION_SEARCH.equals(conditionName) || CONDITION_RELATION.equals(conditionName))) {
                retval.setCondition(conditionName, null);
            }
        }
    } else {
        retval = new QuerySelect(new QueryTable(table.getSQLName(), table.getDataSource(), table.getCatalog(), table.getSchema()));
    }
    // Example:-select pk1,pk2 from tablename1 where ((fieldname1 like '%abcd%') or ((fieldname2 like '%xyz%')) (retrieve max 200 rows)
    ArrayList<IQuerySelectValue> pkQueryColumns = new ArrayList<IQuerySelectValue>(3);
    ArrayList<Column> pkColumns = new ArrayList<Column>(3);
    // getPrimaryKeys from table
    Iterator<Column> pks = table.getRowIdentColumns().iterator();
    // make select
    if (!pks.hasNext()) {
        throw new RepositoryException(ServoyException.InternalCodes.PRIMARY_KEY_NOT_FOUND, new Object[] { table.getName() });
    }
    while (pks.hasNext()) {
        Column column = pks.next();
        pkColumns.add(column);
        pkQueryColumns.add(column.queryColumn(retval.getTable()));
    }
    retval.setColumns(pkQueryColumns);
    if (omitPKs != null && omitPKs.getRowCount() != 0) {
        // omit is rebuild each time
        retval.setCondition(CONDITION_OMIT, createSetConditionFromPKs(IBaseSQLCondition.NOT_OPERATOR, pkQueryColumns.toArray(new QueryColumn[pkQueryColumns.size()]), pkColumns, omitPKs));
    } else if (oldSQLQuery != null) {
        retval.setCondition(CONDITION_OMIT, oldSQLQuery.getConditionClone(CONDITION_OMIT));
    }
    if (// new
    findStates != null && findStates.size() != 0) {
        ISQLCondition moreWhere = null;
        for (IRecordInternal obj : findStates) {
            if (obj instanceof FindState) {
                moreWhere = OrCondition.or(moreWhere, createConditionFromFindState((FindState) obj, retval, provider, pkQueryColumns));
            }
        }
        if (moreWhere != null) {
            if (reduce) {
                retval.addCondition(CONDITION_SEARCH, moreWhere);
            } else {
                retval.addConditionOr(CONDITION_SEARCH, moreWhere);
            }
            if (retval.getJoins() != null) {
                // check if the search condition has an or-condition
                final boolean[] hasOr = { false };
                retval.getCondition(CONDITION_SEARCH).acceptVisitor(new IVisitor() {

                    public Object visit(Object o) {
                        if (o instanceof OrCondition && ((OrCondition) o).getConditions().size() > 1) {
                            hasOr[0] = true;
                            return new VisitorResult(o, false);
                        }
                        return o;
                    }
                });
                if (hasOr[0]) {
                    // override join type to left outer join, a related OR-search should not make the result set smaller
                    for (ISQLJoin join : retval.getJoins()) {
                        if (join instanceof QueryJoin && ((QueryJoin) join).getJoinType() == IQueryConstants.INNER_JOIN) {
                            ((QueryJoin) join).setJoinType(IQueryConstants.LEFT_OUTER_JOIN);
                        }
                    }
                }
            }
        }
    }
    // make orderby
    if (orderByFields != null || retval.getSorts() == null) {
        List<SortColumn> orderBy = orderByFields == null ? new ArrayList<SortColumn>(3) : orderByFields;
        if (orderBy.size() == 0) {
            for (Column pkColumn : pkColumns) {
                orderBy.add(new SortColumn(pkColumn));
            }
        }
        addSorts(retval, retval.getTable(), provider, table, orderBy, true, false);
    }
    if (removeUnusedJoins) {
        // remove unneeded joins, some may have been added because of a previous sort and are no longer needed.
        retval.removeUnusedJoins(false);
    }
    // 1 do not remove sort or groupby test, will cause invalid queries
    // 1 this one causes error and can not be fixed,
    // 1 if (joinswherepart.length() != 0 && !sortIsRelated && groupbyKeyword == STRING_EMPTY && table.getPrimaryKeyCount() == 1)
    // 1 sql select distinct(s_contacts.contactsid) from s_contacts,s_companies where s_contacts.company_id = s_companies.company_id order by s_contacts.surname  ERROR:  For SELECT DISTINCT, ORDER BY expressions must appear in target list
    // retval may have set distinct and plainPKSelect flag based on previous sort columns, make sure to reset first
    retval.setDistinct(false);
    retval.setPlainPKSelect(false);
    if (// if joined pks comes back multiple times
    retval.getJoins() != null && retval.getColumns().size() == 1 && isDistinctAllowed(retval.getColumns(), retval.getSorts())) {
        retval.setDistinct(true);
    } else if (// plain pk select
    retval.getJoins() == null && retval.getColumns().size() == pkColumns.size()) {
        retval.setPlainPKSelect(true);
    }
    return retval;
}
Also used : IVisitor(com.servoy.j2db.util.visitor.IVisitor) ArrayList(java.util.ArrayList) SafeArrayList(com.servoy.j2db.util.SafeArrayList) QueryJoin(com.servoy.j2db.query.QueryJoin) RepositoryException(com.servoy.j2db.persistence.RepositoryException) ISQLJoin(com.servoy.j2db.query.ISQLJoin) QuerySelect(com.servoy.j2db.query.QuerySelect) ISQLCondition(com.servoy.j2db.query.ISQLCondition) BaseQueryTable(com.servoy.base.query.BaseQueryTable) QueryTable(com.servoy.j2db.query.QueryTable) RelatedFindState(com.servoy.j2db.dataprocessing.FindState.RelatedFindState) QueryColumn(com.servoy.j2db.query.QueryColumn) BaseQueryColumn(com.servoy.base.query.BaseQueryColumn) IColumn(com.servoy.j2db.persistence.IColumn) Column(com.servoy.j2db.persistence.Column) OrCondition(com.servoy.j2db.query.OrCondition) IQuerySelectValue(com.servoy.j2db.query.IQuerySelectValue)

Example 15 with QueryTable

use of com.servoy.j2db.query.QueryTable in project servoy-client by Servoy.

the class SQLGenerator method addSorts.

public void addSorts(QuerySelect sqlSelect, BaseQueryTable selectTable, IGlobalValueEntry provider, ITable table, List<SortColumn> orderByFields, boolean includeRelated, boolean permanentJoins) throws RepositoryException {
    List<Column> unusedRowidentColumns = new ArrayList<Column>(table.getRowIdentColumns());
    for (int i = 0; orderByFields != null && i < orderByFields.size(); i++) {
        SortColumn sc = orderByFields.get(i);
        // can be column or aggregate
        IColumn column = sc.getColumn();
        if (column.getDataProviderType() == MEDIA && (column.getFlags() & (IDENT_COLUMNS | UUID_COLUMN)) == 0) {
            // skip cannot sort blob columns
            continue;
        }
        SortOptions sortOptions = application.getFoundSetManager().getSortOptions(sc.getColumn());
        Relation[] relations = sc.getRelations();
        // compare on server objects, relation.foreignServerName may be different in case of duplicates
        boolean doRelatedJoin = (includeRelated && relations != null);
        if (doRelatedJoin) {
            FlattenedSolution fs = application.getFlattenedSolution();
            for (Relation relation : relations) {
                if (relation.isMultiServer() && !fs.getTable(relation.getForeignDataSource()).getServerName().equals(table.getServerName())) {
                    doRelatedJoin = false;
                    break;
                }
            }
        }
        if (doRelatedJoin) // related sort, cannot join across multiple servers
        {
            BaseQueryTable primaryQtable = selectTable;
            BaseQueryTable foreignQtable = null;
            for (Relation relation : relations) {
                // join must be re-created as it is possible to have globals involved;
                // first remove, then create it
                ISQLTableJoin join = (ISQLTableJoin) sqlSelect.getJoin(primaryQtable, relation.getName());
                if (join != null)
                    sqlSelect.getJoins().remove(join);
                if (join == null) {
                    ITable foreignTable = application.getFlattenedSolution().getTable(relation.getForeignDataSource());
                    foreignQtable = new QueryTable(foreignTable.getSQLName(), foreignTable.getDataSource(), foreignTable.getCatalog(), foreignTable.getSchema());
                } else {
                    foreignQtable = join.getForeignTable();
                }
                sqlSelect.addJoin(createJoin(application.getFlattenedSolution(), relation, primaryQtable, foreignQtable, permanentJoins, provider));
                primaryQtable = foreignQtable;
            }
            IQuerySelectValue queryColumn;
            if (column instanceof Column) {
                queryColumn = ((Column) column).queryColumn(foreignQtable);
                unusedRowidentColumns.remove(column);
            } else if (column instanceof AggregateVariable) {
                AggregateVariable aggregate = (AggregateVariable) column;
                queryColumn = new QueryAggregate(aggregate.getType(), new QueryColumn(foreignQtable, -1, aggregate.getColumnNameToAggregate(), aggregate.getDataProviderType(), aggregate.getLength(), 0, null, aggregate.getFlags()), aggregate.getName());
                // there has to be a group-by clause for all selected fields
                List<IQuerySelectValue> columns = sqlSelect.getColumns();
                for (IQuerySelectValue selectVal : columns) {
                    List<IQuerySelectValue> groupBy = sqlSelect.getGroupBy();
                    if (selectVal instanceof QueryColumn && (groupBy == null || !groupBy.contains(selectVal))) {
                        sqlSelect.addGroupBy(selectVal);
                    }
                }
                // if the aggregate has not been selected yet, add it and skip it in the result
                QueryAggregate skippedAggregate = new QueryAggregate(aggregate.getType(), QueryAggregate.ALL, new QueryColumn(foreignQtable, -1, aggregate.getColumnNameToAggregate(), aggregate.getDataProviderType(), aggregate.getLength(), 0, null, aggregate.getFlags()), aggregate.getName(), null, true);
                if (!columns.contains(skippedAggregate)) {
                    sqlSelect.addColumn(skippedAggregate);
                }
            } else {
                // $NON-NLS-1$
                Debug.log("Skipping sort on unexpected related column type " + column.getClass());
                continue;
            }
            sqlSelect.addSort(new QuerySort(queryColumn, sc.getSortOrder() == ASCENDING, sortOptions));
        } else {
            // make sure an invalid sort is not possible
            if (column instanceof Column && column.getTable().getName().equals(table.getName())) {
                sqlSelect.addSort(new QuerySort(((Column) column).queryColumn(selectTable), sc.getSortOrder() == ASCENDING, sortOptions));
                unusedRowidentColumns.remove(column);
            } else {
                // $NON-NLS-1$ //$NON-NLS-2$
                Debug.log("Skipping sort on unrelated column " + column.getName() + '.' + column.getTable().getName() + " for table " + table.getName());
            }
        }
    }
    // Make sure pk is part of the sort, in case of non-unique sort columns, the sorted result may not be the same in each fetch
    if (enforcePkInSort) {
        for (Column column : unusedRowidentColumns) {
            SortOptions sortOptions = application.getFoundSetManager().getSortOptions(column);
            sqlSelect.addSort(new QuerySort(column.queryColumn(selectTable), true, sortOptions));
        }
    }
}
Also used : QueryAggregate(com.servoy.j2db.query.QueryAggregate) ArrayList(java.util.ArrayList) SafeArrayList(com.servoy.j2db.util.SafeArrayList) FlattenedSolution(com.servoy.j2db.FlattenedSolution) AggregateVariable(com.servoy.j2db.persistence.AggregateVariable) BaseQueryTable(com.servoy.base.query.BaseQueryTable) QueryTable(com.servoy.j2db.query.QueryTable) Relation(com.servoy.j2db.persistence.Relation) IRelation(com.servoy.j2db.persistence.IRelation) BaseQueryTable(com.servoy.base.query.BaseQueryTable) QueryColumn(com.servoy.j2db.query.QueryColumn) BaseQueryColumn(com.servoy.base.query.BaseQueryColumn) IColumn(com.servoy.j2db.persistence.IColumn) Column(com.servoy.j2db.persistence.Column) IColumn(com.servoy.j2db.persistence.IColumn) ISQLTableJoin(com.servoy.j2db.query.ISQLTableJoin) QueryColumn(com.servoy.j2db.query.QueryColumn) BaseQueryColumn(com.servoy.base.query.BaseQueryColumn) QuerySort(com.servoy.j2db.query.QuerySort) IQuerySort(com.servoy.j2db.query.IQuerySort) ITable(com.servoy.j2db.persistence.ITable) List(java.util.List) ArrayList(java.util.ArrayList) SafeArrayList(com.servoy.j2db.util.SafeArrayList) Collectors.toList(java.util.stream.Collectors.toList) SortOptions(com.servoy.j2db.query.SortOptions) IQuerySelectValue(com.servoy.j2db.query.IQuerySelectValue)

Aggregations

QueryTable (com.servoy.j2db.query.QueryTable)35 BaseQueryTable (com.servoy.base.query.BaseQueryTable)22 QueryColumn (com.servoy.j2db.query.QueryColumn)22 QuerySelect (com.servoy.j2db.query.QuerySelect)19 Column (com.servoy.j2db.persistence.Column)18 ArrayList (java.util.ArrayList)18 ITable (com.servoy.j2db.persistence.ITable)15 RepositoryException (com.servoy.j2db.persistence.RepositoryException)13 IColumn (com.servoy.j2db.persistence.IColumn)12 BaseQueryColumn (com.servoy.base.query.BaseQueryColumn)10 Table (com.servoy.j2db.persistence.Table)10 IQuerySelectValue (com.servoy.j2db.query.IQuerySelectValue)9 SafeArrayList (com.servoy.j2db.util.SafeArrayList)9 ServoyException (com.servoy.j2db.util.ServoyException)9 RemoteException (java.rmi.RemoteException)9 CompareCondition (com.servoy.j2db.query.CompareCondition)8 QueryDelete (com.servoy.j2db.query.QueryDelete)8 ApplicationException (com.servoy.j2db.ApplicationException)7 SetCondition (com.servoy.j2db.query.SetCondition)7 ISQLTableJoin (com.servoy.j2db.query.ISQLTableJoin)6