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;
}
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;
}
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();
}
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;
}
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));
}
}
}
Aggregations