Search in sources :

Example 71 with Column

use of com.servoy.j2db.persistence.Column in project servoy-client by Servoy.

the class JSDatabaseManager method js_getSQL.

/**
 * Returns the internal SQL which defines the specified (related)foundset.
 * Optionally, the foundset and table filter params can be excluded in the sql (includeFilters=false).
 * Make sure to set the applicable filters when the sql is used in a loadRecords() call.
 * When the founset is in find mode, the find conditions are included in the resulting query.
 *
 * @sample var sql = databaseManager.getSQL(foundset)
 *
 * @param foundsetOrQBSelect The JSFoundset or QBSelect to get the sql for.
 * @param includeFilters include the foundset and table filters.
 *
 * @return String representing the sql of the JSFoundset.
 */
public String js_getSQL(Object foundsetOrQBSelect, boolean includeFilters) throws ServoyException {
    checkAuthorized();
    if (foundsetOrQBSelect instanceof IFoundSetInternal && ((IFoundSetInternal) foundsetOrQBSelect).getTable() != null) {
        try {
            QuerySet querySet = getQuerySet(((IFoundSetInternal) foundsetOrQBSelect).getCurrentStateQuery(true, false), includeFilters);
            StringBuilder sql = new StringBuilder();
            QueryString[] prepares = querySet.getPrepares();
            for (int i = 0; prepares != null && i < prepares.length; i++) {
            // TODO parameters from updates and cleanups
            // sql.append(updates[i].getSql());
            // sql.append("\n"); //$NON-NLS-1$
            }
            sql.append(querySet.getSelect().getSql());
            QueryString[] cleanups = querySet.getCleanups();
            for (int i = 0; cleanups != null && i < cleanups.length; i++) {
            // TODO parameters from updates and cleanups
            // sql.append("\n"); //$NON-NLS-1$
            // sql.append(cleanups[i].getSql());
            }
            return sql.toString();
        } catch (Exception e) {
            Debug.error(e);
        }
    } else if (foundsetOrQBSelect instanceof QBSelect) {
        try {
            QuerySelect select = ((QBSelect) foundsetOrQBSelect).build();
            if (select.getColumns() == null) {
                // no columns, add pk
                // note that QBSelect.build() already returns a clone
                ITable table = application.getFoundSetManager().getTable(select.getTable().getDataSource());
                Iterator<Column> pkIt = ((Table) table).getRowIdentColumns().iterator();
                if (!pkIt.hasNext()) {
                    throw new RepositoryException(ServoyException.InternalCodes.PRIMARY_KEY_NOT_FOUND, new Object[] { table.getName() });
                }
                while (pkIt.hasNext()) {
                    Column c = pkIt.next();
                    select.addColumn(c.queryColumn(select.getTable()));
                }
            }
            QuerySet querySet = getQuerySet(select, includeFilters);
            return querySet.getSelect().getSql();
        } catch (RemoteException e) {
            Debug.error(e);
        }
    }
    return null;
}
Also used : BaseQueryTable(com.servoy.base.query.BaseQueryTable) QueryTable(com.servoy.j2db.query.QueryTable) ITable(com.servoy.j2db.persistence.ITable) Table(com.servoy.j2db.persistence.Table) QueryString(com.servoy.j2db.persistence.QueryString) QuerySet(com.servoy.j2db.persistence.QuerySet) RepositoryException(com.servoy.j2db.persistence.RepositoryException) QuerySelect(com.servoy.j2db.query.QuerySelect) ApplicationException(com.servoy.j2db.ApplicationException) RemoteException(java.rmi.RemoteException) SQLException(java.sql.SQLException) ServoyException(com.servoy.j2db.util.ServoyException) RepositoryException(com.servoy.j2db.persistence.RepositoryException) QBSelect(com.servoy.j2db.querybuilder.impl.QBSelect) QueryColumn(com.servoy.j2db.query.QueryColumn) IBaseColumn(com.servoy.base.persistence.IBaseColumn) Column(com.servoy.j2db.persistence.Column) QBColumn(com.servoy.j2db.querybuilder.impl.QBColumn) Iterator(java.util.Iterator) ITable(com.servoy.j2db.persistence.ITable) NativeObject(org.mozilla.javascript.NativeObject) RemoteException(java.rmi.RemoteException)

Example 72 with Column

use of com.servoy.j2db.persistence.Column in project servoy-client by Servoy.

the class JSDatabaseManager method js_convertToDataSet.

/**
 * @clonedesc js_convertToDataSet(IFoundSetInternal)
 *
 * @sampleas js_convertToDataSet(IFoundSetInternal)
 *
 * @param foundset The foundset to be converted.
 * @param dataproviderNames Array with column names.
 *
 * @return JSDataSet with the data.
 */
public JSDataSet js_convertToDataSet(IFoundSetInternal foundset, String[] dataproviderNames) throws RepositoryException {
    if (foundset == null) {
        return null;
    }
    // $NON-NLS-1$
    String[] dpnames = { "id" };
    ColumnType[] dptypes = { ColumnType.getInstance(IColumnTypes.INTEGER, Integer.MAX_VALUE, 0) };
    List<Object[]> lst = new ArrayList<Object[]>();
    FoundSet fs = (FoundSet) foundset;
    if (fs.getTable() != null) {
        if (dataproviderNames != null) {
            dpnames = dataproviderNames;
        } else {
            dpnames = fs.getSQLSheet().getPKColumnDataProvidersAsArray();
        }
        FoundSetManager fsm = (FoundSetManager) application.getFoundSetManager();
        boolean getInOneQuery = !fs.isInFindMode() && (fs.hadMoreRows() || fs.getSize() > fsm.config.pkChunkSize()) && !fsm.getEditRecordList().hasEditedRecords(fs);
        dptypes = new ColumnType[dpnames.length];
        Table table = fs.getSQLSheet().getTable();
        Map<String, Column> columnMap = new HashMap<String, Column>();
        for (int i = 0; i < dpnames.length; i++) {
            IDataProvider dp = application.getFlattenedSolution().getDataProviderForTable(table, dpnames[i]);
            dptypes[i] = dp == null ? ColumnType.getInstance(0, 0, 0) : ColumnType.getInstance(dp instanceof Column ? ((Column) dp).getType() : dp.getDataProviderType(), dp.getLength(), dp instanceof Column ? ((Column) dp).getScale() : 0);
            if (getInOneQuery) {
                // only columns and data we can get from the foundset (calculations only when stored)
                if (dp instanceof Column) {
                    columnMap.put(dpnames[i], (Column) dp);
                    // Blobs require special resultset handling
                    getInOneQuery = !SQLGenerator.isBlobColumn((Column) dp);
                } else {
                    // aggregates, globals
                    getInOneQuery = fs.containsDataProvider(dpnames[i]);
                }
            }
        }
        if (getInOneQuery && columnMap.size() > 0) {
            // large foundset, query the columns in 1 go
            QuerySelect sqlSelect = AbstractBaseQuery.deepClone(fs.getQuerySelectForReading());
            ArrayList<IQuerySelectValue> cols = new ArrayList<IQuerySelectValue>(columnMap.size());
            ArrayList<String> distinctColumns = new ArrayList<String>(columnMap.size());
            for (String dpname : dpnames) {
                Column column = columnMap.get(dpname);
                if (column != null && !distinctColumns.contains(dpname)) {
                    distinctColumns.add(dpname);
                    cols.add(column.queryColumn(sqlSelect.getTable()));
                }
            }
            boolean hasJoins = sqlSelect.getJoins() != null;
            if (hasJoins) {
                // add pk columns so distinct-in-memory can be used
                List<Column> rowIdentColumns = ((Table) fs.getTable()).getRowIdentColumns();
                for (Column column : rowIdentColumns) {
                    if (!columnMap.containsKey(column.getDataProviderID())) {
                        cols.add(column.queryColumn(sqlSelect.getTable()));
                    }
                }
            }
            sqlSelect.setColumns(cols);
            try {
                SQLSheet sheet = fs.getSQLSheet();
                IConverterManager<IColumnConverter> columnConverterManager = ((FoundSetManager) fs.getFoundSetManager()).getColumnConverterManager();
                SQLStatement trackingInfo = null;
                if (fsm.getEditRecordList().hasAccess(sheet.getTable(), IRepository.TRACKING_VIEWS)) {
                    trackingInfo = new SQLStatement(ISQLActionTypes.SELECT_ACTION, sheet.getServerName(), sheet.getTable().getName(), null, null);
                    trackingInfo.setTrackingData(sqlSelect.getColumnNames(), new Object[][] {}, new Object[][] {}, fsm.getApplication().getUserUID(), fsm.getTrackingInfo(), fsm.getApplication().getClientID());
                }
                IDataSet dataSet = fsm.getDataServer().performQuery(fsm.getApplication().getClientID(), sheet.getServerName(), fsm.getTransactionID(sheet), sqlSelect, null, fsm.getTableFilterParams(sheet.getServerName(), sqlSelect), hasJoins, 0, -1, IDataServer.FOUNDSET_LOAD_QUERY, trackingInfo);
                lst = new ArrayList<Object[]>(dataSet.getRowCount());
                for (int i = 0; i < dataSet.getRowCount(); i++) {
                    Object[] row = new Object[dpnames.length];
                    // may contain more data: pk columns for distinct-in-memory
                    Object[] dataseRow = dataSet.getRow(i);
                    for (int j = 0; j < dpnames.length; j++) {
                        Column column = columnMap.get(dpnames[j]);
                        if (column == null) {
                            // fs.containsDataProvider returned true for this dpname
                            row[j] = fs.getDataProviderValue(dpnames[j]);
                        } else {
                            row[j] = sheet.convertValueToObject(dataseRow[distinctColumns.indexOf(dpnames[j])], sheet.getColumnIndex(dpnames[j]), columnConverterManager);
                        }
                    }
                    lst.add(row);
                }
            } catch (RepositoryException e) {
                throw e;
            } catch (Exception e) {
                Debug.error(e);
                throw new RepositoryException(e.getMessage());
            }
        } else {
            // loop over the records
            for (int i = 0; i < fs.getSize(); i++) {
                IRecordInternal record = fs.getRecord(i);
                Object[] pk = new Object[dpnames.length];
                for (int j = 0; j < dpnames.length; j++) {
                    pk[j] = record.getValue(dpnames[j]);
                }
                lst.add(pk);
            }
        }
    }
    return new JSDataSet(application, BufferedDataSetInternal.createBufferedDataSet(dpnames, dptypes, lst, false));
}
Also used : ColumnType(com.servoy.j2db.query.ColumnType) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) QueryString(com.servoy.j2db.persistence.QueryString) IDataProvider(com.servoy.j2db.persistence.IDataProvider) QueryColumn(com.servoy.j2db.query.QueryColumn) IBaseColumn(com.servoy.base.persistence.IBaseColumn) Column(com.servoy.j2db.persistence.Column) QBColumn(com.servoy.j2db.querybuilder.impl.QBColumn) BaseQueryTable(com.servoy.base.query.BaseQueryTable) QueryTable(com.servoy.j2db.query.QueryTable) ITable(com.servoy.j2db.persistence.ITable) Table(com.servoy.j2db.persistence.Table) IJSFoundSet(com.servoy.base.scripting.api.IJSFoundSet) RepositoryException(com.servoy.j2db.persistence.RepositoryException) QuerySelect(com.servoy.j2db.query.QuerySelect) ApplicationException(com.servoy.j2db.ApplicationException) RemoteException(java.rmi.RemoteException) SQLException(java.sql.SQLException) ServoyException(com.servoy.j2db.util.ServoyException) RepositoryException(com.servoy.j2db.persistence.RepositoryException) NativeObject(org.mozilla.javascript.NativeObject) IQuerySelectValue(com.servoy.j2db.query.IQuerySelectValue)

Example 73 with Column

use of com.servoy.j2db.persistence.Column in project servoy-client by Servoy.

the class EditRecordList method stopEditingImpl.

/**
 * This method should only be called through stopEditing(boolean,List<Record>) so that that can call onAutoSaveFailed.
 */
private int stopEditingImpl(final boolean javascriptStop, List<IRecord> recordsToSave, int recursionDepth) {
    if (recursionDepth > 50) {
        fsm.getApplication().reportJSError("stopEditing max recursion exceeded, look if on (or after) record update or inserts  are constantly changing records", new RuntimeException());
        return ISaveConstants.SAVE_FAILED;
    }
    if (ignoreSave) {
        return ISaveConstants.AUTO_SAVE_BLOCKED;
    }
    if (isSavingAll) {
        // we are saving all, no need to save anything more
        return ISaveConstants.STOPPED;
    }
    if (recordsToSave == null && savingRecords.size() > 0) {
        // we are saving some records, cannot call save all now, not supported
        return ISaveConstants.STOPPED;
    }
    if (recordsToSave != null && savingRecords.size() > 0) {
        // make a copy to be sure that removeAll is supported
        recordsToSave = new ArrayList<IRecord>(recordsToSave);
        recordsToSave.removeAll(savingRecords);
    }
    if (recordsToSave != null) {
        boolean hasEditedRecords = false;
        editRecordsLock.lock();
        try {
            for (IRecord record : recordsToSave) {
                if (editedRecords.contains(record)) {
                    hasEditedRecords = true;
                    break;
                }
            }
        } finally {
            editRecordsLock.unlock();
        }
        if (!hasEditedRecords)
            return ISaveConstants.STOPPED;
    }
    // here we can't have a test if editedRecords is empty (and return stop)
    // because for just globals or findstates (or deleted records)
    // we need to pass prepareForSave.
    final List<IRecord> recordsToSaveFinal = recordsToSave;
    if (!fsm.getApplication().isEventDispatchThread()) {
        // only the event dispatch thread can stop an current edit.
        // this is a fix for innerworkings because background aggregate queries seems to also trigger saves
        // $NON-NLS-1$
        Debug.trace("Stop edit postponend because it is not in the event dispatch thread: " + Thread.currentThread().getName());
        // calculations running from lazy table view loading threads may trigger stopEditing
        fsm.getApplication().invokeLater(new Runnable() {

            public void run() {
                // do not stop if the user is editing something else.
                boolean stop;
                editRecordsLock.lock();
                try {
                    stop = editedRecords.size() == 1 && recordsToSaveFinal != null && recordsToSaveFinal.size() == 1 && editedRecords.get(0) == recordsToSaveFinal.get(0);
                } finally {
                    editRecordsLock.unlock();
                }
                if (stop) {
                    stopEditing(javascriptStop, recordsToSaveFinal);
                } else {
                    // $NON-NLS-1$
                    Debug.trace("Stop edit skipped because other records are being edited");
                }
            }
        });
        return ISaveConstants.AUTO_SAVE_BLOCKED;
    }
    int editedRecordsSize;
    try {
        int p = prepareForSave(true);
        if (p != ISaveConstants.STOPPED) {
            return p;
        }
        if (recordsToSave == null) {
            isSavingAll = true;
        } else {
            savingRecords.addAll(recordsToSave);
        }
        // remove any non referenced failed records
        boolean fireChange = false;
        editRecordsLock.lock();
        try {
            if (failedRecords.size() != 0) {
                Iterator<IRecordInternal> it = failedRecords.iterator();
                while (it.hasNext()) {
                    IRecordInternal rec = it.next();
                    if (rec != null) {
                        if (rec.getParentFoundSet() == null) {
                            it.remove();
                        } else if (rec.getParentFoundSet().getRecordIndex(rec) == -1) {
                            it.remove();
                        }
                    }
                }
                if (failedRecords.size() == 0) {
                    fireChange = true;
                }
            }
        } finally {
            editRecordsLock.unlock();
        }
        if (fireChange)
            fireEditChange();
        // remove the unchanged, really calculate when it is a real stop (autosave = true or it is a javascript stop)
        removeUnChangedRecords(autoSave || javascriptStop, true);
        // check if anything left
        int editRecordListSize;
        editRecordsLock.lock();
        try {
            editRecordListSize = editedRecords.size();
            if (editRecordListSize == 0)
                return ISaveConstants.STOPPED;
        } finally {
            editRecordsLock.unlock();
        }
        // cannot stop, its blocked
        if (!autoSave && !javascriptStop) {
            return ISaveConstants.AUTO_SAVE_BLOCKED;
        }
        int failedCount = 0;
        boolean justValidationErrors = false;
        lastStopEditingException = null;
        List<RowUpdateInfo> rowUpdates = new ArrayList<RowUpdateInfo>(editRecordListSize);
        editRecordsLock.lock();
        try {
            if (recordsToSave == null) {
                // if it is a save all, then first filter out all the duplicate rows.
                for (int i = 0; i < editedRecords.size(); i++) {
                    Row toTest = editedRecords.get(i).getRawData();
                    for (int j = editedRecords.size(); --j > i; ) {
                        if (editedRecords.get(j).getRawData() == toTest) {
                            removeEditedRecord(editedRecords.get(j));
                        }
                    }
                }
            }
            Map<IRecordInternal, Integer> processed = new HashMap<IRecordInternal, Integer>();
            for (IRecordInternal tmp = getFirstElement(editedRecords, recordsToSave); tmp != null; tmp = getFirstElement(editedRecords, recordsToSave)) {
                // check if we do not have an infinite recursive loop
                Integer count = processed.get(tmp);
                if (count != null && count.intValue() > 50) {
                    fsm.getApplication().reportJSError("stopEditing max loop counter exceeded on " + tmp.getParentFoundSet().getDataSource() + "/" + tmp.getPKHashKey(), new RuntimeException());
                    return ISaveConstants.SAVE_FAILED;
                }
                processed.put(tmp, Integer.valueOf(count == null ? 1 : (count.intValue() + 1)));
                if (tmp instanceof Record) {
                    Record record = (Record) tmp;
                    // prevent multiple update for the same row (from multiple records)
                    for (int j = 0; j < rowUpdates.size(); j++) {
                        if (rowUpdates.get(j).getRow() == record.getRawData()) {
                            // create a new rowUpdate that contains both updates
                            RowUpdateInfo removed = rowUpdates.remove(j);
                            recordTested.remove(record);
                            // do use the first record, that one must always be leading. (for fire of events)
                            record = removed.getRecord();
                            break;
                        }
                    }
                    try {
                        // test for table events; this may execute table events if the user attached JS methods to them;
                        // the user might add/delete/edit records in the JS - thus invalidating a normal iterator (it)
                        // - edited record list changes; this is why an AllowListModificationIterator is used
                        // Note that the behaviour is different when trigger returns false or when it throws an exception.
                        // when the trigger returns false, record must stay in editedRecords.
                        // this is needed because the trigger may be used as validation to keep the user in the record when autosave=true.
                        // when the trigger throws an exception, the record must move from editedRecords to failedRecords so that in
                        // scripting the failed records can be examined (the thrown value is retrieved via record.exception.getValue())
                        editRecordsLock.unlock();
                        boolean validationErrors = false;
                        try {
                            JSRecordMarkers validateObject = fsm.validateRecord(record, null);
                            if (// throws ServoyException when trigger method throws exception
                            validateObject != null && validateObject.isHasErrors()) {
                                Object[] genericExceptions = validateObject.getGenericExceptions();
                                if (genericExceptions.length > 0) {
                                    // compartible with old code, then those exceptions are catched below.
                                    throw (Exception) genericExceptions[0];
                                }
                                // we always want to process all records, but mark this as a validation error so below the failed records are updated.
                                validationErrors = true;
                                // update the just failed boolean to true, if that is true and there is not really an exception then handleException of application is not called.
                                justValidationErrors = true;
                                failedCount++;
                                if (!failedRecords.contains(record)) {
                                    failedRecords.add(record);
                                }
                                recordTested.remove(record);
                            }
                        } finally {
                            editRecordsLock.lock();
                        }
                        if (!validationErrors) {
                            RowUpdateInfo rowUpdateInfo = getRecordUpdateInfo(record);
                            if (rowUpdateInfo != null) {
                                rowUpdateInfo.setRecord(record);
                                rowUpdates.add(rowUpdateInfo);
                            } else {
                                recordTested.remove(record);
                            }
                        }
                    } catch (ServoyException e) {
                        // $NON-NLS-1$//$NON-NLS-2$
                        log.debug(// $NON-NLS-1$//$NON-NLS-2$
                        "stopEditing(" + javascriptStop + ") encountered an exception - could be expected and treated by solution code or not", e);
                        // trigger method threw exception
                        lastStopEditingException = e;
                        failedCount++;
                        // set latest
                        record.getRawData().setLastException(e);
                        if (!failedRecords.contains(record)) {
                            failedRecords.add(record);
                        }
                        recordTested.remove(record);
                    } catch (Exception e) {
                        // $NON-NLS-1$ //$NON-NLS-2$
                        Debug.error("Not a normal Servoy/Db Exception generated in saving record: " + record + " removing the record", e);
                        recordTested.remove(record);
                    }
                } else {
                    // find state
                    recordTested.remove(tmp);
                }
                editedRecords.remove(tmp);
            }
        } finally {
            editRecordsLock.unlock();
        }
        if (failedCount > 0) {
            placeBackAlreadyProcessedRecords(rowUpdates);
            if (lastStopEditingException == null && justValidationErrors) {
                return ISaveConstants.VALIDATION_FAILED;
            } else {
                if (!(lastStopEditingException instanceof ServoyException)) {
                    lastStopEditingException = new ApplicationException(ServoyException.SAVE_FAILED, lastStopEditingException);
                }
                if (!javascriptStop)
                    // $NON-NLS-1$
                    fsm.getApplication().handleException(// $NON-NLS-1$
                    fsm.getApplication().getI18NMessage("servoy.formPanel.error.saveFormData"), lastStopEditingException);
                return ISaveConstants.SAVE_FAILED;
            }
        }
        if (rowUpdates.size() == 0) {
            fireEditChange();
            if (Debug.tracing()) {
                // $NON-NLS-1$
                Debug.trace("no records to update anymore, failed: " + failedRecords.size());
            }
            return ISaveConstants.STOPPED;
        }
        if (Debug.tracing()) {
            // $NON-NLS-1$ //$NON-NLS-2$
            Debug.trace("Updating/Inserting " + rowUpdates.size() + " records: " + rowUpdates.toString());
        }
        RowUpdateInfo[] infos = rowUpdates.toArray(new RowUpdateInfo[rowUpdates.size()]);
        if (infos.length > 1 && !fsm.config.disableInsertsReorder()) {
            // search if there are new row pks used that are
            // used in records before this record and sort it based on that.
            boolean changed = false;
            List<RowUpdateInfo> al = new ArrayList<RowUpdateInfo>(Arrays.asList(infos));
            int prevI = -1;
            outer: for (int i = al.size(); --i > 0; ) {
                Row row = al.get(i).getRow();
                // only test for new rows and its pks.
                if (row.existInDB())
                    continue;
                String[] pkColumns = row.getRowManager().getSQLSheet().getPKColumnDataProvidersAsArray();
                Object[] pk = row.getPK();
                for (int j = 0; j < pk.length; j++) {
                    Object pkObject = pk[j];
                    // special case if pk was db ident and that value was copied from another row.
                    if (pkObject instanceof DbIdentValue && ((DbIdentValue) pkObject).getRow() != row)
                        continue;
                    for (int k = 0; k < i; k++) {
                        RowUpdateInfo updateInfo = al.get(k);
                        Object[] values = updateInfo.getRow().getRawColumnData();
                        int[] pkIndexes = updateInfo.getFoundSet().getSQLSheet().getPKIndexes();
                        IntHashMap<String> pks = new IntHashMap<String>(pkIndexes.length, 1);
                        for (int pkIndex : pkIndexes) {
                            // $NON-NLS-1$
                            pks.put(pkIndex, "");
                        }
                        for (int l = 0; l < values.length; l++) {
                            // skip all pk column indexes (except from dbidents from other rows, this may need resort). Those shouldn't be resorted
                            if (!(values[l] instanceof DbIdentValue && ((DbIdentValue) values[l]).getRow() != updateInfo.getRow()) && pks.containsKey(l))
                                continue;
                            boolean same = values[l] == pkObject;
                            if (!same && values[l] != null) {
                                Column pkColumn = row.getRowManager().getSQLSheet().getTable().getColumn(pkColumns[j]);
                                if (pkColumn.hasFlag(IBaseColumn.UUID_COLUMN)) {
                                    // same uuids are the same even if not the same object
                                    same = equalObjects(pkObject, values[l], 0, true);
                                }
                            }
                            if (same) {
                                al.add(k, al.remove(i));
                                // watch out for endless loops when 2 records both with pk's point to each other...
                                if (prevI != i) {
                                    prevI = i;
                                    i++;
                                }
                                changed = true;
                                continue outer;
                            }
                        }
                    }
                }
            }
            if (changed) {
                infos = al.toArray(infos);
            }
        }
        ISQLStatement[] statements;
        if (fsm.config.statementBatching() && infos.length > 1) {
            // Merge insert statements insert statements from all info's: multiple info's can share the same statement of the records are batched together on the statement level
            List<ISQLStatement> mergedStatements = new ArrayList<ISQLStatement>(infos.length);
            ISQLStatement prevStatement = null;
            for (RowUpdateInfo rowUpdateInfo : infos) {
                ISQLStatement statement = rowUpdateInfo.getISQLStatement();
                if (statement.getAction() == ISQLActionTypes.INSERT_ACTION && prevStatement != null && prevStatement.getAction() == ISQLActionTypes.INSERT_ACTION && insertStatementsCanBeMerged(prevStatement, statement)) {
                    mergeInsertStatements(prevStatement, statement);
                } else {
                    prevStatement = statement;
                    mergedStatements.add(statement);
                }
            }
            statements = mergedStatements.toArray(new ISQLStatement[mergedStatements.size()]);
        } else {
            statements = stream(infos).map(RowUpdateInfo::getISQLStatement).toArray(ISQLStatement[]::new);
        }
        // TODO if one statement fails in a transaction how do we know which one? and should we rollback all rows in these statements?
        Object[] idents = null;
        try {
            idents = fsm.getDataServer().performUpdates(fsm.getApplication().getClientID(), statements);
        } catch (Exception e) {
            // $NON-NLS-1$//$NON-NLS-2$
            log.debug("stopEditing(" + javascriptStop + ") encountered an exception - could be expected and treated by solution code or not", e);
            lastStopEditingException = e;
            if (!javascriptStop)
                // $NON-NLS-1$
                fsm.getApplication().handleException(// $NON-NLS-1$
                fsm.getApplication().getI18NMessage("servoy.formPanel.error.saveFormData"), new ApplicationException(ServoyException.SAVE_FAILED, lastStopEditingException));
            return ISaveConstants.SAVE_FAILED;
        }
        if (idents.length != infos.length) {
            // $NON-NLS-1$
            Debug.error("Should be of same size!!");
        }
        List<RowUpdateInfo> infosToBePostProcessed = new ArrayList<RowUpdateInfo>();
        Map<FoundSet, List<Record>> foundsetToRecords = new HashMap<FoundSet, List<Record>>();
        Map<FoundSet, List<String>> foundsetToAggregateDeletes = new HashMap<FoundSet, List<String>>();
        List<Runnable> fires = new ArrayList<Runnable>(infos.length);
        // Walk in reverse over it, so that related rows are update in there row manger before they are required by there parents.
        for (int i = infos.length; --i >= 0; ) {
            RowUpdateInfo rowUpdateInfo = infos[i];
            FoundSet foundSet = rowUpdateInfo.getFoundSet();
            Row row = rowUpdateInfo.getRow();
            String oldKey = row.getPKHashKey();
            Record record = rowUpdateInfo.getRecord();
            if (idents != null && idents.length != 0 && idents[i] != null) {
                Object retValue = idents[i];
                if (retValue instanceof Exception) {
                    // $NON-NLS-1$//$NON-NLS-2$
                    log.debug(// $NON-NLS-1$//$NON-NLS-2$
                    "stopEditing(" + javascriptStop + ") encountered an exception - could be expected and treated by solution code or not", (Exception) retValue);
                    lastStopEditingException = (Exception) retValue;
                    failedCount++;
                    if (retValue instanceof ServoyException) {
                        ((ServoyException) retValue).fillScriptStack();
                    }
                    row.setLastException((Exception) retValue);
                    markRecordAsFailed(record);
                    JSRecordMarkers vo = record.getRecordMarkers() != null ? record.getRecordMarkers() : new JSRecordMarkers(record, fsm.getApplication());
                    vo.addGenericException((Exception) retValue);
                    record.setRecordMarkers(vo);
                    continue;
                } else if (retValue instanceof Object[]) {
                    Object[] rowData = (Object[]) retValue;
                    Object[] oldRowData = row.getRawColumnData();
                    if (oldRowData != null) {
                        if (oldRowData.length == rowData.length) {
                            for (int j = 0; j < rowData.length; j++) {
                                if (rowData[j] instanceof BlobMarkerValue) {
                                    rowData[j] = oldRowData[j];
                                }
                                if (oldRowData[j] instanceof DbIdentValue) {
                                    row.setDbIdentValue(rowData[j]);
                                }
                            }
                        } else {
                            Debug.error("Requery data has different length from row data.");
                        }
                    }
                    row.setRollbackData(rowData, Row.ROLLBACK_MODE.UPDATE_CHANGES);
                } else if (!Boolean.TRUE.equals(retValue)) {
                    // is db ident, can only be one column
                    row.setDbIdentValue(retValue);
                }
            }
            editRecordsLock.lock();
            try {
                recordTested.remove(record);
            } finally {
                editRecordsLock.unlock();
            }
            if (!row.existInDB()) {
                // when row was not saved yet row pkhash will be with new value, pksAndRecordsHolder will have initial value
                foundSet.updatePk(record);
            }
            try {
                ISQLStatement statement = rowUpdateInfo.getISQLStatement();
                row.getRowManager().rowUpdated(row, oldKey, foundSet, fires, statement instanceof ITrackingSQLStatement ? ((ITrackingSQLStatement) statement).getChangedColumns() : null);
            } catch (Exception e) {
                // $NON-NLS-1$//$NON-NLS-2$
                log.debug("stopEditing(" + javascriptStop + ") encountered an exception - could be expected and treated by solution code or not", e);
                lastStopEditingException = e;
                failedCount++;
                row.setLastException(e);
                JSRecordMarkers vo = record.getRecordMarkers() != null ? record.getRecordMarkers() : new JSRecordMarkers(record, fsm.getApplication());
                vo.addGenericException(e);
                record.setRecordMarkers(vo);
                editRecordsLock.lock();
                try {
                    if (!failedRecords.contains(record)) {
                        failedRecords.add(record);
                    }
                } finally {
                    editRecordsLock.unlock();
                }
            }
            infosToBePostProcessed.add(infos[i]);
            List<Record> lst = foundsetToRecords.get(foundSet);
            if (lst == null) {
                lst = new ArrayList<Record>(3);
                foundsetToRecords.put(foundSet, lst);
            }
            lst.add(record);
            List<String> aggregates = foundsetToAggregateDeletes.get(foundSet);
            if (aggregates == null) {
                foundsetToAggregateDeletes.put(foundSet, rowUpdateInfo.getAggregatesToRemove());
            } else {
                List<String> toMerge = rowUpdateInfo.getAggregatesToRemove();
                for (int j = 0; j < toMerge.size(); j++) {
                    String aggregate = toMerge.get(j);
                    if (!aggregates.contains(aggregate)) {
                        aggregates.add(aggregate);
                    }
                }
            }
        }
        // run rowmanager fires in reverse order (original order because info's were processed in reverse order) -> first inserted record is fired first
        for (int i = fires.size(); --i >= 0; ) {
            fires.get(i).run();
        }
        // get the size of the edited records before the table events, so that we can look if those events did change records again.
        editedRecordsSize = editedRecords.size();
        Record rowUpdateInfoRecord = null;
        for (RowUpdateInfo rowUpdateInfo : infosToBePostProcessed) {
            try {
                rowUpdateInfoRecord = rowUpdateInfo.getRecord();
                ((FoundSet) rowUpdateInfoRecord.getParentFoundSet()).executeFoundsetTrigger(new Object[] { rowUpdateInfoRecord }, rowUpdateInfo.getISQLStatement().getAction() == ISQLActionTypes.INSERT_ACTION ? StaticContentSpecLoader.PROPERTY_ONAFTERINSERTMETHODID : StaticContentSpecLoader.PROPERTY_ONAFTERUPDATEMETHODID, true);
            } catch (ServoyException e) {
                if (e instanceof DataException && e.getCause() instanceof JavaScriptException) {
                    // trigger method threw exception
                    // $NON-NLS-1$//$NON-NLS-2$
                    log.debug("stopEditing(" + javascriptStop + ") encountered an exception - could be expected and treated by solution code or not", e);
                    lastStopEditingException = e;
                    failedCount++;
                    rowUpdateInfoRecord.getRawData().setLastException(e);
                    JSRecordMarkers vo = rowUpdateInfoRecord.getRecordMarkers() != null ? rowUpdateInfoRecord.getRecordMarkers() : new JSRecordMarkers(rowUpdateInfoRecord, fsm.getApplication());
                    vo.addGenericException(e);
                    rowUpdateInfoRecord.setRecordMarkers(vo);
                    editRecordsLock.lock();
                    try {
                        if (!failedRecords.contains(rowUpdateInfoRecord)) {
                            failedRecords.add(rowUpdateInfoRecord);
                        }
                    } finally {
                        editRecordsLock.unlock();
                    }
                } else {
                    // $NON-NLS-1$
                    fsm.getApplication().handleException("Failed to execute after update/insert trigger.", e);
                }
            }
        }
        for (Map.Entry<FoundSet, List<Record>> entry : foundsetToRecords.entrySet()) {
            FoundSet fs = entry.getKey();
            fs.recordsUpdated(entry.getValue(), foundsetToAggregateDeletes.get(fs));
        }
        boolean shouldFireEditChange;
        editRecordsLock.lock();
        try {
            shouldFireEditChange = editedRecords.size() == 0;
        } finally {
            editRecordsLock.unlock();
        }
        if (shouldFireEditChange) {
            fireEditChange();
        }
        if (failedCount > 0) {
            if (!javascriptStop) {
                lastStopEditingException = new ApplicationException(ServoyException.SAVE_FAILED, lastStopEditingException);
                // $NON-NLS-1$
                fsm.getApplication().handleException(// $NON-NLS-1$
                fsm.getApplication().getI18NMessage("servoy.formPanel.error.saveFormData"), lastStopEditingException);
            }
            return ISaveConstants.SAVE_FAILED;
        }
    } catch (RuntimeException e) {
        if (e instanceof IllegalArgumentException) {
            fsm.getApplication().handleException(null, new ApplicationException(ServoyException.INVALID_INPUT, e));
            return ISaveConstants.SAVE_FAILED;
        } else if (e instanceof IllegalStateException) {
            // $NON-NLS-1$
            fsm.getApplication().handleException(fsm.getApplication().getI18NMessage("servoy.formPanel.error.saveFormData"), e);
            return ISaveConstants.SAVE_FAILED;
        } else {
            Debug.error(e);
            throw e;
        }
    } finally {
        if (recordsToSave == null) {
            isSavingAll = false;
        } else {
            savingRecords.removeAll(recordsToSave);
        }
        fireEvents();
    }
    if (editedRecords.size() != editedRecordsSize && recordsToSave == null) {
        // records where changed by the after insert/update table events, call stop edit again if this was not a specific record save.
        return stopEditingImpl(javascriptStop, null, recursionDepth + 1);
    }
    return ISaveConstants.STOPPED;
}
Also used : HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) IntHashMap(com.servoy.j2db.util.IntHashMap) ArrayList(java.util.ArrayList) ServoyException(com.servoy.j2db.util.ServoyException) IBaseColumn(com.servoy.base.persistence.IBaseColumn) Column(com.servoy.j2db.persistence.Column) DbIdentValue(com.servoy.j2db.dataprocessing.ValueFactory.DbIdentValue) ArrayList(java.util.ArrayList) List(java.util.List) ServoyException(com.servoy.j2db.util.ServoyException) ApplicationException(com.servoy.j2db.ApplicationException) JavaScriptException(org.mozilla.javascript.JavaScriptException) RepositoryException(com.servoy.j2db.persistence.RepositoryException) JavaScriptException(org.mozilla.javascript.JavaScriptException) IntHashMap(com.servoy.j2db.util.IntHashMap) ApplicationException(com.servoy.j2db.ApplicationException) BlobMarkerValue(com.servoy.j2db.dataprocessing.ValueFactory.BlobMarkerValue) NativeObject(org.mozilla.javascript.NativeObject) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) IntHashMap(com.servoy.j2db.util.IntHashMap)

Example 74 with Column

use of com.servoy.j2db.persistence.Column in project servoy-client by Servoy.

the class DBValueList method getDisplayFormat.

private String[] getDisplayFormat() {
    if (table != null && hasRealValues()) {
        String[] displayFormats = new String[3];
        boolean hasDisplayFormats = false;
        Column col1 = table.getColumn(valueList.getDataProviderID1());
        if (col1 != null && col1.getColumnInfo() != null) {
            displayFormats[0] = col1.getColumnInfo().getDefaultFormat();
            hasDisplayFormats = displayFormats[0] != null;
        }
        Column col2 = table.getColumn(valueList.getDataProviderID2());
        if (col2 != null && col2.getColumnInfo() != null) {
            displayFormats[1] = col2.getColumnInfo().getDefaultFormat();
            hasDisplayFormats = displayFormats[1] != null;
        }
        Column col3 = table.getColumn(valueList.getDataProviderID3());
        if (col3 != null && col3.getColumnInfo() != null) {
            displayFormats[2] = col3.getColumnInfo().getDefaultFormat();
            hasDisplayFormats = displayFormats[2] != null;
        }
        return hasDisplayFormats ? displayFormats : null;
    }
    return null;
}
Also used : Column(com.servoy.j2db.persistence.Column)

Example 75 with Column

use of com.servoy.j2db.persistence.Column in project servoy-client by Servoy.

the class JSDatabaseManager method convertFoundSet.

public FoundSet convertFoundSet(Object foundset, Object related) throws ServoyException {
    checkAuthorized();
    if (foundset instanceof FoundSet && ((FoundSet) foundset).getTable() != null) {
        FoundSet fs_old = (FoundSet) foundset;
        try {
            String relationName;
            if (related instanceof RelatedFoundSet) {
                relationName = ((RelatedFoundSet) related).getRelationName();
            } else if (related instanceof String) {
                relationName = (String) related;
            } else {
                // $NON-NLS-1$
                Debug.warn("convertFoundSet: invalid argument " + related);
                return null;
            }
            Relation relation = application.getFlattenedSolution().getRelation(relationName);
            if (relation == null || relation.isMultiServer() || fs_old.getTable() == null || !fs_old.getTable().equals(application.getFlattenedSolution().getTable(relation.getPrimaryDataSource()))) {
                // $NON-NLS-1$
                Debug.warn("convertFoundSet: cannot use relation " + relationName);
                return null;
            }
            ITable ft = application.getFlattenedSolution().getTable(relation.getForeignDataSource());
            FoundSet fs_new = (FoundSet) application.getFoundSetManager().getNewFoundSet(ft, null, application.getFoundSetManager().getDefaultPKSortColumns(ft.getDataSource()));
            QuerySelect sql = fs_old.getPksAndRecords().getQuerySelectForModification();
            SQLSheet sheet_new = fs_old.getSQLSheet().getRelatedSheet(relation, ((FoundSetManager) application.getFoundSetManager()).getSQLGenerator());
            if (sheet_new != null) {
                BaseQueryTable oldTable = sql.getTable();
                ISQLTableJoin join = (ISQLTableJoin) sql.getJoin(oldTable, relation.getName());
                if (join == null) {
                    join = SQLGenerator.createJoin(application.getFlattenedSolution(), relation, oldTable, new QueryTable(ft.getSQLName(), ft.getDataSource(), ft.getCatalog(), ft.getSchema()), true, fs_old);
                    sql.addJoin(join);
                }
                BaseQueryTable mainTable = join.getForeignTable();
                // invert the join
                sql.setTable(mainTable);
                // $NON-NLS-1$
                join.invert("INVERTED." + join.getName());
                // set the columns to be the PKs from the related table
                ArrayList<IQuerySelectValue> pkColumns = new ArrayList<IQuerySelectValue>();
                Iterator<Column> pks = sheet_new.getTable().getRowIdentColumns().iterator();
                while (pks.hasNext()) {
                    Column column = pks.next();
                    pkColumns.add(column.queryColumn(mainTable));
                }
                sql.setColumns(pkColumns);
                // sorting will be on the original columns, when distinct is set, this will conflict with the related pk columns
                sql.setDistinct(false);
                fs_new.setSQLSelect(sql);
                return fs_new;
            }
        } catch (Exception e) {
            Debug.error(e);
        }
    }
    return null;
}
Also used : ArrayList(java.util.ArrayList) IJSFoundSet(com.servoy.base.scripting.api.IJSFoundSet) QueryString(com.servoy.j2db.persistence.QueryString) QuerySelect(com.servoy.j2db.query.QuerySelect) BaseQueryTable(com.servoy.base.query.BaseQueryTable) QueryTable(com.servoy.j2db.query.QueryTable) ApplicationException(com.servoy.j2db.ApplicationException) RemoteException(java.rmi.RemoteException) SQLException(java.sql.SQLException) ServoyException(com.servoy.j2db.util.ServoyException) RepositoryException(com.servoy.j2db.persistence.RepositoryException) Relation(com.servoy.j2db.persistence.Relation) BaseQueryTable(com.servoy.base.query.BaseQueryTable) ISQLTableJoin(com.servoy.j2db.query.ISQLTableJoin) QueryColumn(com.servoy.j2db.query.QueryColumn) IBaseColumn(com.servoy.base.persistence.IBaseColumn) Column(com.servoy.j2db.persistence.Column) QBColumn(com.servoy.j2db.querybuilder.impl.QBColumn) ITable(com.servoy.j2db.persistence.ITable) IQuerySelectValue(com.servoy.j2db.query.IQuerySelectValue)

Aggregations

Column (com.servoy.j2db.persistence.Column)76 QueryColumn (com.servoy.j2db.query.QueryColumn)44 IColumn (com.servoy.j2db.persistence.IColumn)37 RepositoryException (com.servoy.j2db.persistence.RepositoryException)32 IBaseColumn (com.servoy.base.persistence.IBaseColumn)31 QuerySelect (com.servoy.j2db.query.QuerySelect)29 ArrayList (java.util.ArrayList)29 QueryTable (com.servoy.j2db.query.QueryTable)27 ITable (com.servoy.j2db.persistence.ITable)23 BaseQueryTable (com.servoy.base.query.BaseQueryTable)22 Table (com.servoy.j2db.persistence.Table)22 ServoyException (com.servoy.j2db.util.ServoyException)21 SafeArrayList (com.servoy.j2db.util.SafeArrayList)19 IQuerySelectValue (com.servoy.j2db.query.IQuerySelectValue)18 RemoteException (java.rmi.RemoteException)17 ColumnInfo (com.servoy.j2db.persistence.ColumnInfo)16 BaseQueryColumn (com.servoy.base.query.BaseQueryColumn)14 IDataProvider (com.servoy.j2db.persistence.IDataProvider)12 Relation (com.servoy.j2db.persistence.Relation)12 Placeholder (com.servoy.j2db.query.Placeholder)12