Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Serverside bug: isUnique-check for setAllowMultiUpdate has wrong logic

    Hi Isomorphic,

    I'm using v10.1p_2016-03-27 and just noticed that the unique-check for setAllowMultiUpdate-Requests consists of two SELECT statements where it could be one and that the 2nd just takes a value from the (random) 1st row.
    See this log:
    Code:
    === 2016-03-30 13:35:26,862 [8-34] INFO  RequestContext - URL: '/builtinds/sc/IDACall', User-Agent: 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0': Moz (Gecko) with Accept-Encoding header
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Connection:keep-alive
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: DNT:1
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Referer:http://127.0.0.1:8888/BuiltInDS.html?gwt.codesvr=127.0.0.1:9997
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Pragma:no-cache
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Accept-Encoding:gzip, deflate
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Cache-Control:no-cache
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Content-Type:application/x-www-form-urlencoded; charset=UTF-8
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Accept-Language:de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Content-Length:828
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Cookie:isc_cState=ready; JSESSIONID=xxre83hp03zd1sbpiz5zx8wq2; GLog=%7B%0A%20%20%20%20trackRPC%3Atrue%2C%20%0A%20%20%20%20isc_pageURL%3A%22http%3A//127.0.0.1%3A8888/BuiltInDS.html%3Fgwt.codesvr%3D127.0.0.1%3A9997%22%2C%20%0A%20%20%20%20isc_pageGUID%3A%2245C1F5C0-A193-481A-9145-F6D2BEBEDFAC%22%2C%20%0A%20%20%20%20priorityDefaults%3A%7B%0A%20%20%20%20%20%20%20%20sgwtInternal%3A1%2C%20%0A%20%20%20%20%20%20%20%20Log%3A4%0A%20%20%20%20%7D%2C%20%0A%20%20%20%20defaultPriority%3A3%2C%20%0A%20%20%20%20left%3A2068%2C%20%0A%20%20%20%20top%3A131%2C%20%0A%20%20%20%20width%3A905%2C%20%0A%20%20%20%20height%3A788%0A%7D
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - Header Name:Value pair: Host:127.0.0.1:8888
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - session exists: xxre83hp03zd1sbpiz5zx8wq2
    === 2016-03-30 13:35:26,862 [8-34] DEBUG IDACall - remote user: null
    === 2016-03-30 13:35:26,864 [8-34] DEBUG XML - Parsed XML from (in memory stream): 1ms
    === 2016-03-30 13:35:26,864 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'transaction'
    === 2016-03-30 13:35:26,864 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'transaction' but null was returned
    === 2016-03-30 13:35:26,864 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'transaction' in the pooling flow
    === 2016-03-30 13:35:26,864 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'Object'
    === 2016-03-30 13:35:26,864 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource 60 of type 'Object' and assigned it to thread qtp448569108-34
    === 2016-03-30 13:35:26,864 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource 60 of type 'Object' in the pooling flow
    === 2016-03-30 13:35:26,864 [8-34] DEBUG PoolableDataSourceFactory - Activated DataSource 60 of type 'Object'
    === 2016-03-30 13:35:26,864 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'List'
    === 2016-03-30 13:35:26,865 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource 61 of type 'List' and assigned it to thread qtp448569108-34
    === 2016-03-30 13:35:26,865 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource 61 of type 'List' in the pooling flow
    === 2016-03-30 13:35:26,865 [8-34] DEBUG PoolableDataSourceFactory - Activated DataSource 61 of type 'List'
    === 2016-03-30 13:35:26,865 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'elem'
    === 2016-03-30 13:35:26,865 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'elem' but null was returned
    === 2016-03-30 13:35:26,865 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'elem' in the pooling flow
    === 2016-03-30 13:35:26,865 [8-34] DEBUG RPCManager - Processing 1 requests.
    === 2016-03-30 13:35:26,865 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'employees'
    === 2016-03-30 13:35:26,865 [8-34] DEBUG PoolableDataSourceFactory - Activated DataSource 46 of type 'employees'
    === 2016-03-30 13:35:26,865 [8-34] DEBUG DSRequest - Caching instance 46 of DS 'employees' from DSRequest.getDataSource()
    === 2016-03-30 13:35:26,865 [8-34] DEBUG DSRequest - Caching instance 46 of DS employees
    === 2016-03-30 13:35:26,866 [8-34] DEBUG RPCManager - Request #1 (DSRequest) payload: {
        values:null,
        operationConfig:{
            dataSource:"employees",
            repo:null,
            operationType:"custom",
            textMatchStyle:"exact"
        },
        appID:"builtinApplication",
        operation:"doRenameEmployeeTo2",
        oldValues:null,
        criteria:{
        }
    }
    === 2016-03-30 13:35:26,866 [8-34] INFO  IDACall - Performing 1 operation(s)
    === 2016-03-30 13:35:26,866 [8-34] DEBUG DeclarativeSecurity - Processing security checks for DataSource null, field null
    === 2016-03-30 13:35:26,866 [8-34] DEBUG DeclarativeSecurity - DataSource employees is not in the pre-checked list, processing...
    === 2016-03-30 13:35:26,866 [8-34] DEBUG DeclarativeSecurity - Processing security checks for DataSource null, field null
    === 2016-03-30 13:35:26,866 [8-34] DEBUG DeclarativeSecurity - Request is not a client request, ignoring security checks.
    === 2016-03-30 13:35:26,866 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'employees'
    === 2016-03-30 13:35:26,866 [8-34] DEBUG PoolableDataSourceFactory - Activated DataSource 49 of type 'employees'
    === 2016-03-30 13:35:26,867 [8-34] DEBUG DSRequest - Caching instance 49 of DS 'employees' from DSRequest.getDataSource()
    === 2016-03-30 13:35:26,867 [8-34] DEBUG DSRequest - Caching instance 49 of DS employees
    === 2016-03-30 13:35:26,867 [8-34] DEBUG DeclarativeSecurity - Processing security checks for DataSource null, field null
    === 2016-03-30 13:35:26,867 [8-34] DEBUG DeclarativeSecurity - Request is not a client request, ignoring security checks.
    === 2016-03-30 13:35:26,867 [8-34] DEBUG ServerObject - Couldn't find a public method named: fetch on class: com.smartgwt.sample.server.listener.Employees
    === 2016-03-30 13:35:26,867 [8-34] DEBUG DataSourceDMI - DataSourceDMI: no public method name: fetch available on class: com.smartgwt.sample.server.listener.Employees - defaulting to builtin operations.
    === 2016-03-30 13:35:26,867 [8-34] DEBUG AppBase - [builtinApplication.null] No userTypes defined, allowing anyone access to all operations for this application
    === 2016-03-30 13:35:26,867 [8-34] DEBUG AppBase - [builtinApplication.null] No public zero-argument method named '_null' found, performing generic datasource operation
    === 2016-03-30 13:35:26,867 [8-34] INFO  SQLDataSource - [builtinApplication.null] Performing fetch operation with
        criteria: {}    values: {}
    === 2016-03-30 13:35:26,867 [8-34] INFO  SQLWhereClause - [builtinApplication.null] empty condition
    === 2016-03-30 13:35:26,867 [8-34] INFO  SQLDataSource - [builtinApplication.null] derived query: SELECT $defaultSelectClause FROM $defaultTableClause WHERE $defaultWhereClause
    === 2016-03-30 13:35:26,868 [8-34] INFO  SQLDataSource - [builtinApplication.null] 49: Executing SQL query on 'HSQLDB': SELECT employeeTable.userOrder, employeeTable.Name, employeeTable.EmployeeId, employeeTable.ReportsTo, employeeTable.Job, employeeTable.Email, employeeTable.EmployeeType, employeeTable.EmployeeStatus, employeeTable.Salary, employeeTable.OrgUnit, employeeTable.Gender, employeeTable.MaritalStatus FROM employeeTable WHERE ('1'='1')
    === 2016-03-30 13:35:26,868 [8-34] DEBUG PoolableSQLConnectionFactory - [builtinApplication.null] DriverManager fetching connection for HSQLDB via jdbc url jdbc:hsqldb:hsql://localhost/isomorphic
    === 2016-03-30 13:35:26,868 [8-34] DEBUG PoolableSQLConnectionFactory - [builtinApplication.null] Passing JDBC URL only to getConnection
    === 2016-03-30 13:35:26,970 [8-34] DEBUG PoolableSQLConnectionFactory - [builtinApplication.null] makeObject() created an unpooled Connection '1611779883'
    === 2016-03-30 13:35:26,970 [8-34] DEBUG SQLConnectionManager - [builtinApplication.null] Borrowed connection '1611779883'
    [B]=== 2016-03-30 13:35:26,970 [8-34] INFO  SQLDriver - [builtinApplication.null] Executing SQL query on 'HSQLDB' using connection '1611779883': SELECT employeeTable.userOrder, employeeTable.Name, employeeTable.EmployeeId, employeeTable.ReportsTo, employeeTable.Job, employeeTable.Email, employeeTable.EmployeeType, employeeTable.EmployeeStatus, employeeTable.Salary, employeeTable.OrgUnit, employeeTable.Gender, employeeTable.MaritalStatus FROM employeeTable WHERE ('1'='1')
    === 2016-03-30 13:35:26,971 [8-34] INFO  DSResponse - DSResponse: List with 115 items[/B]
    === 2016-03-30 13:35:26,971 [8-34] DEBUG DSRequest - About to free up resources for request of type fetch on DataSource employees
    === 2016-03-30 13:35:26,971 [8-34] DEBUG SQLDataSource - About to clear SQLDriver state for DS instance 49
    === 2016-03-30 13:35:26,971 [8-34] DEBUG SQLDriver - Freeing SQLDriver dbConnection 1611779883 for SQLDriver instance 1864992977
    === 2016-03-30 13:35:26,972 [8-34] DEBUG SQLConnectionManager - About to close JDBCConnection with hashcode "1611779883"
    === 2016-03-30 13:35:26,972 [8-34] DEBUG SQLDataSource - About to clear SQLDriver state for DS instance 49
    === 2016-03-30 13:35:26,972 [8-34] DEBUG SQLDataSource - About to clear SQLDriver state for DS instance 49
    === 2016-03-30 13:35:26,972 [8-34] DEBUG PoolableDataSourceFactory - Cleared and passivated DataSource 49 of type 'employees'
    === 2016-03-30 13:35:26,972 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'integer'
    === 2016-03-30 13:35:26,972 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'integer' but null was returned
    === 2016-03-30 13:35:26,972 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'integer' in the pooling flow
    === 2016-03-30 13:35:26,972 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'text'
    === 2016-03-30 13:35:26,972 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'text' but null was returned
    === 2016-03-30 13:35:26,972 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'text' in the pooling flow
    === 2016-03-30 13:35:26,972 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'integer'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'integer' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'integer' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'integer'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'integer' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'integer' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'text'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'text' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'text' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'text'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'text' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'text' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'text'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'text' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'text' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'text'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'text' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'text' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'float'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'float' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'float' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'text'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'text' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'text' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'text'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'text' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'text' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'text'
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Tried to create DataSource  of type 'text' but null was returned
    === 2016-03-30 13:35:26,973 [8-34] DEBUG PoolableDataSourceFactory - Created DataSource null of type 'text' in the pooling flow
    === 2016-03-30 13:35:26,973 [8-34] DEBUG ISCKeyedObjectPool - Borrowing object for 'employees'
    === 2016-03-30 13:35:26,974 [8-34] DEBUG PoolableDataSourceFactory - Activated DataSource 49 of type 'employees'
    === 2016-03-30 13:35:26,974 [8-34] DEBUG DSRequest - Caching instance 49 of DS 'employees' from DSRequest.getDataSource()
    === 2016-03-30 13:35:26,974 [8-34] DEBUG DSRequest - Caching instance 49 of DS employees
    === 2016-03-30 13:35:26,974 [8-34] DEBUG DeclarativeSecurity - Processing security checks for DataSource null, field null
    === 2016-03-30 13:35:26,974 [8-34] DEBUG DeclarativeSecurity - Request is not a client request, ignoring security checks.
    === 2016-03-30 13:35:26,974 [8-34] DEBUG ServerObject - Couldn't find a public method named: fetch on class: com.smartgwt.sample.server.listener.Employees
    === 2016-03-30 13:35:26,974 [8-34] DEBUG DataSourceDMI - DataSourceDMI: no public method name: fetch available on class: com.smartgwt.sample.server.listener.Employees - defaulting to builtin operations.
    === 2016-03-30 13:35:26,974 [8-34] DEBUG AppBase - [builtinApplication.null] No userTypes defined, allowing anyone access to all operations for this application
    === 2016-03-30 13:35:26,974 [8-34] DEBUG AppBase - [builtinApplication.null] No public zero-argument method named '_null' found, performing generic datasource operation
    === 2016-03-30 13:35:26,974 [8-34] INFO  SQLDataSource - [builtinApplication.null] Performing fetch operation with
        outputs: [EmployeeId, Name]    criteria: {_constructor:"AdvancedCriteria",criteria:[{fieldName:"Email",value:"cmadigan@server.com",operator:"iEquals"},{fieldName:"Name",value:"Ralph Brogan",operator:"iEquals"},{criteria:[{fieldName:"EmployeeId",value:null,operator:"notEqual"}],operator:"or"}],operator:"and"}    values: {_constructor:"AdvancedCriteria",criteria:[{fieldName:"Email",value:"cmadigan@server.com",operator:"iEquals"},{fieldName:"Name",value:"Ralph Brogan",operator:"iEquals"},{criteria:[{fieldName:"EmployeeId",value:null,operator:"notEqual"}],operator:"or"}],operator:"and"}
    === 2016-03-30 13:35:26,975 [8-34] INFO  SQLDataSource - [builtinApplication.null] derived query: SELECT $defaultSelectClause FROM $defaultTableClause WHERE $defaultWhereClause
    === 2016-03-30 13:35:26,976 [8-34] INFO  SQLDataSource - [builtinApplication.null] 49: Executing SQL query on 'HSQLDB': SELECT employeeTable.Name, employeeTable.EmployeeId FROM employeeTable WHERE ((LOWER(employeeTable.Email) = LOWER('cmadigan@server.com') AND employeeTable.Email IS NOT NULL) AND (LOWER(employeeTable.Name) = LOWER('ralph brogan') AND employeeTable.Name IS NOT NULL) AND ((employeeTable.EmployeeId IS NOT NULL)))
    === 2016-03-30 13:35:26,976 [8-34] DEBUG PoolableSQLConnectionFactory - [builtinApplication.null] DriverManager fetching connection for HSQLDB via jdbc url jdbc:hsqldb:hsql://localhost/isomorphic
    === 2016-03-30 13:35:26,976 [8-34] DEBUG PoolableSQLConnectionFactory - [builtinApplication.null] Passing JDBC URL only to getConnection
    === 2016-03-30 13:35:27,077 [8-34] DEBUG PoolableSQLConnectionFactory - [builtinApplication.null] makeObject() created an unpooled Connection '1098929166'
    === 2016-03-30 13:35:27,077 [8-34] DEBUG SQLConnectionManager - [builtinApplication.null] Borrowed connection '1098929166'
    [B]=== 2016-03-30 13:35:27,077 [8-34] INFO  SQLDriver - [builtinApplication.null] Executing SQL query on 'HSQLDB' using connection '1098929166': SELECT employeeTable.Name, employeeTable.EmployeeId FROM employeeTable WHERE ((LOWER(employeeTable.Email) = LOWER('cmadigan@server.com') AND employeeTable.Email IS NOT NULL) AND (LOWER(employeeTable.Name) = LOWER('ralph brogan') AND employeeTable.Name IS NOT NULL) AND ((employeeTable.EmployeeId IS NOT NULL)))
    === 2016-03-30 13:35:27,078 [8-34] INFO  DSResponse - DSResponse: List with 0 items[/B]
    === 2016-03-30 13:35:27,078 [8-34] DEBUG DSRequest - About to free up resources for request of type fetch on DataSource employees
    === 2016-03-30 13:35:27,078 [8-34] DEBUG ServerObject - Couldn't find a public method named: update on class: com.smartgwt.sample.server.listener.Employees
    === 2016-03-30 13:35:27,078 [8-34] DEBUG DataSourceDMI - DataSourceDMI: no public method name: update available on class: com.smartgwt.sample.server.listener.Employees - defaulting to builtin operations.
    === 2016-03-30 13:35:27,078 [8-34] DEBUG AppBase - [builtinApplication.null] No userTypes defined, allowing anyone access to all operations for this application
    === 2016-03-30 13:35:27,078 [8-34] DEBUG AppBase - [builtinApplication.null] No public zero-argument method named '_null' found, performing generic datasource operation
    === 2016-03-30 13:35:27,078 [8-34] INFO  SQLDataSource - [builtinApplication.null] Performing update operation with
        criteria: {_constructor:"AdvancedCriteria",criteria:[{fieldName:"Name",value:"Ralph Brogan2",operator:"equals"},{fieldName:"Email",value:"rbrogan@server.com",operator:"equals"}],operator:"and"}    values: {Name:"Ralph Brogan"}
    === 2016-03-30 13:35:27,079 [8-34] DEBUG PoolableSQLConnectionFactory - [builtinApplication.null] DriverManager fetching connection for HSQLDB via jdbc url jdbc:hsqldb:hsql://localhost/isomorphic
    === 2016-03-30 13:35:27,079 [8-34] DEBUG PoolableSQLConnectionFactory - [builtinApplication.null] Passing JDBC URL only to getConnection
    === 2016-03-30 13:35:27,180 [8-34] DEBUG PoolableSQLConnectionFactory - [builtinApplication.null] makeObject() created an unpooled Connection '1762451911'
    === 2016-03-30 13:35:27,180 [8-34] DEBUG SQLConnectionManager - [builtinApplication.null] Borrowed connection '1762451911'
    === 2016-03-30 13:35:27,180 [8-34] DEBUG SQLTransaction - [builtinApplication.null] Started new HSQLDB transaction "1762451911"
    === 2016-03-30 13:35:27,181 [8-34] DEBUG SQLDataSource - [builtinApplication.null] Setting DSRequest as being part of a transaction
    === 2016-03-30 13:35:27,181 [8-34] INFO  SQLDriver - [builtinApplication.null] Executing SQL query on 'HSQLDB' using connection '1762451911': UPDATE employeeTable SET Name='Ralph Brogan' WHERE ((employeeTable.Name = 'Ralph Brogan2' AND employeeTable.Name IS NOT NULL) AND (employeeTable.Email = 'rbrogan@server.com' AND employeeTable.Email IS NOT NULL))
    === 2016-03-30 13:35:27,181 [8-34] WARN  SQLDataSource - [builtinApplication.null] update operation affected no rows
    === 2016-03-30 13:35:27,182 [8-34] DEBUG DSRequest - freeOnExecute is false for request of type update on DataSource employees - not freeing resources!
    === 2016-03-30 13:35:27,182 [8-34] DEBUG DSRequest - About to free up resources for request of type custom on DataSource employees
    === 2016-03-30 13:35:27,182 [8-34] DEBUG DSRequest - Ignoring freeResources call because this is not a primary request!
    === 2016-03-30 13:35:27,182 [8-34] DEBUG RPCManager - Content type for RPC transaction: text/plain; charset=UTF-8
    === 2016-03-30 13:35:27,182 [8-34] DEBUG SQLTransaction - Committing HSQLDB transaction "1762451911"
    === 2016-03-30 13:35:27,182 [8-34] DEBUG SQLTransaction - Committing HSQLDB transaction "1762451911"
    === 2016-03-30 13:35:27,182 [8-34] DEBUG SQLTransaction - Committing HSQLDB transaction "1762451911"
    === 2016-03-30 13:35:27,182 [8-34] DEBUG RPCManager - DMI response, dropExtraFields: false
    === 2016-03-30 13:35:27,182 [8-34] DEBUG DSRequest - Ignoring freeQueueResources call because this is not a primary request!
    === 2016-03-30 13:35:27,182 [8-34] DEBUG SQLTransaction - getConnection() looked for transactional connection for HSQLDB:  hashcode "1762451911"
    === 2016-03-30 13:35:27,182 [8-34] DEBUG SQLTransaction - Ending HSQLDB transaction "1762451911"
    === 2016-03-30 13:35:27,182 [8-34] DEBUG SQLConnectionManager - About to close JDBCConnection with hashcode "1762451911"
    === 2016-03-30 13:35:27,182 [8-34] DEBUG SQLDataSource - About to clear SQLDriver state for DS instance 46
    === 2016-03-30 13:35:27,182 [8-34] DEBUG SQLDataSource - About to clear SQLDriver state for DS instance 46
    === 2016-03-30 13:35:27,183 [8-34] DEBUG SQLDataSource - About to clear SQLDriver state for DS instance 46
    === 2016-03-30 13:35:27,183 [8-34] DEBUG PoolableDataSourceFactory - Cleared and passivated DataSource 46 of type 'employees'
    === 2016-03-30 13:35:27,183 [8-34] DEBUG SQLDataSource - About to clear SQLDriver state for DS instance 49
    === 2016-03-30 13:35:27,183 [8-34] DEBUG SQLDriver - Freeing SQLDriver dbConnection 1098929166 for SQLDriver instance 1864992977
    === 2016-03-30 13:35:27,183 [8-34] DEBUG SQLConnectionManager - About to close JDBCConnection with hashcode "1098929166"
    === 2016-03-30 13:35:27,183 [8-34] DEBUG SQLDataSource - About to clear SQLDriver state for DS instance 49
    === 2016-03-30 13:35:27,183 [8-34] DEBUG SQLDataSource - About to clear SQLDriver state for DS instance 49
    === 2016-03-30 13:35:27,183 [8-34] DEBUG PoolableDataSourceFactory - Cleared and passivated DataSource 49 of type 'employees'
    === 2016-03-30 13:35:27,183 [8-34] DEBUG DSRequest - Ignoring freeResources call because they have already been freed
    === 2016-03-30 13:35:27,183 [8-34] DEBUG DSRequest - Ignoring freeQueueResources call because they have already been freed
    === 2016-03-30 13:35:27,183 [8-34] DEBUG DSRequest - Ignoring freeResources call because they have already been freed
    === 2016-03-30 13:35:27,183 [8-34] DEBUG DSRequest - Ignoring freeQueueResources call because they have already been freed
    === 2016-03-30 13:35:27,183 [8-34] INFO  Compression - /builtinds/sc/IDACall: 159 -> 142 bytes
    I marked two lines above. Why does the first SELECT all rows of the table? Why does the 2nd statement use cmadigan@server.com? This is just the value of one row that happens to be the first by chance.

    This is the testcase:
    BuiltInDS.java:
    Code:
    package com.smartgwt.sample.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.smartgwt.client.core.KeyIdentifier;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.data.Record;
    import com.smartgwt.client.util.Page;
    import com.smartgwt.client.util.PageKeyHandler;
    import com.smartgwt.client.util.SC;
    import com.smartgwt.client.widgets.IButton;
    import com.smartgwt.client.widgets.events.ClickEvent;
    import com.smartgwt.client.widgets.events.ClickHandler;
    import com.smartgwt.client.widgets.layout.VLayout;
    
    public class BuiltInDS implements EntryPoint {
    
        public void onModuleLoad() {
            KeyIdentifier debugKey = new KeyIdentifier();
            debugKey.setCtrlKey(true);
            debugKey.setKeyName("D");
    
            Page.registerKey(debugKey, new PageKeyHandler() {
                public void execute(String keyName) {
                    SC.showConsole();
                }
            });
    
            VLayout mainLayout = new VLayout(20);
            mainLayout.setWidth100();
            mainLayout.setHeight100();
    
            {
                IButton renameEmployeeTo2 = new IButton("Ralph Brogan -> Ralph Brogan2");
                renameEmployeeTo2.setWidth(200);
                renameEmployeeTo2.addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent event) {
                        doRenameEmployeeTo2();
                    }
                });
                mainLayout.addMember(renameEmployeeTo2);
            }
            {
                IButton renameEmployeeToNormal = new IButton("Ralph Brogan2 -> Ralph Brogan");
                renameEmployeeToNormal.setWidth(200);
                renameEmployeeToNormal.addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent event) {
                        doRenameEmployeeToNormal();
                    }
                });
                mainLayout.addMember(renameEmployeeToNormal);
            }
    
            {
                IButton resetViaPK = new IButton("Reset Ralph Brogan via PK");
                resetViaPK.setWidth(200);
                resetViaPK.addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent event) {
                        resetViaPK();
                    }
                });
                mainLayout.addMember(resetViaPK);
            }
            mainLayout.draw();
        }
    
        private void doRenameEmployeeTo2() {
            DataSource.get("employees").performCustomOperation("doRenameEmployeeTo2");
        }
    
        private void doRenameEmployeeToNormal() {
            DataSource.get("employees").performCustomOperation("doRenameEmployeeToNormal");
        }
    
        private void resetViaPK() {
            DataSource.get("employees").updateData(new Record() {
                {
                    setAttribute("EmployeeId", 192);
                    setAttribute("Name", "Ralph Brogan");
                }
            });
        }
    }
    Employees.ds.xml:
    Code:
    <DataSource
        ID="employees"
        serverType="sql"
        tableName="employeeTable"
        recordName="employee"
        testFileName="/examples/shared/ds/test_data/employees.data.xml"
        titleField="Name"
    >
        <fields>
            <field name="userOrder"       title="userOrder"       type="integer"  canEdit="false"    hidden="true"/>
            <field name="Name"            title="Name"            type="text"     length="128">
                     <validators>
                            <validator serverOnly="true" type="isUnique" criteriaFields="Email"></validator>
                        </validators>
            </field>
            <field name="EmployeeId"      title="Employee ID"     type="integer"  primaryKey="true"  required="true"/>
            <field name="ReportsTo"       title="Manager"         type="integer"  required="true" 
                   foreignKey="employees.EmployeeId"  rootValue="1" detail="true"/>
            <field name="Job"             title="Title"           type="text"     length="128"/> 
            <field name="Email"           title="Email"           type="text"     length="128"/>
            <field name="EmployeeType"    title="Employee Type"   type="text"     length="40"/>
            <field name="EmployeeStatus"  title="Status"          type="text"     length="40"/>
            <field name="Salary"          title="Salary"          type="float"/>
            <field name="OrgUnit"         title="Org Unit"        type="text"     length="128"/>
            <field name="Gender"          title="Gender"          type="text"     length="7">
                <valueMap>
                    <value>male</value>
                    <value>female</value>
                </valueMap>
            </field>
            <field name="MaritalStatus"   title="Marital Status"  type="text"     length="10">
                <valueMap>
                    <value>married</value>
                    <value>single</value>
                </valueMap>
            </field>
        </fields>
        <serverObject lookupStyle="new" className="com.smartgwt.sample.server.listener.Employees" />
        <operationBindings>
            <operationBinding operationType="custom" operationId="doRenameEmployeeTo2" serverMethod="doRenameEmployeeTo2" />
            <operationBinding operationType="custom" operationId="doRenameEmployeeToNormal" serverMethod="doRenameEmployeeToNormal" />
        </operationBindings>
    </DataSource>
    Employees.java:
    Code:
    package com.smartgwt.sample.server.listener;
    
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    
    import com.isomorphic.criteria.DefaultOperators;
    import com.isomorphic.criteria.criterion.SimpleCriterion;
    import com.isomorphic.datasource.DSRequest;
    import com.isomorphic.datasource.DSResponse;
    import com.isomorphic.datasource.DataSource;
    
    public class Employees {
        public DSResponse doRenameEmployeeTo2(DSRequest request, HttpServletRequest servletRequest) throws Exception {
            DSRequest updateEmployeeRequest = new DSRequest("employees", DataSource.OP_UPDATE, request.getRPCManager());
            updateEmployeeRequest.setAllowMultiUpdate(true);
            updateEmployeeRequest.addToCriteria(new SimpleCriterion("Name", DefaultOperators.Equals, "Ralph Brogan2"));
            updateEmployeeRequest.addToCriteria(new SimpleCriterion("Email", DefaultOperators.Equals, "rbrogan@server.com"));
            Map<String, String> values = new LinkedHashMap<String, String>();
            values.put("Name", "Ralph Brogan");
            updateEmployeeRequest.setValues(values);
            DSResponse updateEmployeeResponse = updateEmployeeRequest.execute();
            if (updateEmployeeResponse.statusIsError())
                return updateEmployeeResponse;
            return new DSResponse().setSuccess();
        }
    
        public DSResponse doRenameEmployeeToNormal(DSRequest request, HttpServletRequest servletRequest) throws Exception {
            DSRequest updateEmployeeRequest = new DSRequest("employees", DataSource.OP_UPDATE, request.getRPCManager());
            updateEmployeeRequest.setAllowMultiUpdate(true);
            updateEmployeeRequest.addToCriteria(new SimpleCriterion("Name", DefaultOperators.Equals, "Ralph Brogan2"));
            updateEmployeeRequest.addToCriteria(new SimpleCriterion("Email", DefaultOperators.Equals, "rbrogan@server.com"));
            Map<String, String> values = new LinkedHashMap<String, String>();
            values.put("Name", "Ralph Brogan");
            updateEmployeeRequest.setValues(values);
            DSResponse updateEmployeeResponse = updateEmployeeRequest.execute();
            if (updateEmployeeResponse.statusIsError())
                return updateEmployeeResponse;
            return new DSResponse().setSuccess();
        }
    }
    Try button 1+2 to execute the customOperation with the multiUpdate.
    Use the 3rd button to reset the entry if needed.

    For me, if you change the criteriaFields="Email" in the .ds.xml to criteriaFields="EmployeeType", I even get validation errors (these are not guaranteed as they whole behavior is non-deterministic and depends on the data for the 1st row of the 1st SELECT).

    In my opinion the process should be like this (for doRenameEmployeeToNormal), 1st without criteriaFields:
    Code:
    SELECT COUNT(*) cnt FROM employeeTable WHERE Name = 'Ralph Brogan' --new value
            AND NOT --inverted requestCriteria
            (Name = 'Ralph Brogan2' --from criteria
            AND Email = rbrogan@server.com) --from criteria
    
    If this returns 1 (or more, but this should not happen as the value was not unique then, before), the update will violate the constraint iff it targets any rows -> validation error.
    
    Next step:
    SELECT COUNT(*) cnt FROM employeeTable WHERE Name = 'Ralph Brogan2' --from criteria
    AND Email = rbrogan@server.com --from criteria
    If this returns 2 or more, the update would set those rows to "Ralph Brogan" --> not allowed, validation error
    It is more complicated with criteriaFields for the unique-validator:
    Code:
    SELECT Email, COUNT(*) cnt FROM employeeTable WHERE Name = 'Ralph Brogan' --new value
            AND NOT --inverted requestCriteria
            (Name = 'Ralph Brogan2' --from criteria
            AND Email = rbrogan@server.com) --from criteria
    GROUP BY Email --ds.xml criteriaField
    
    Keep DSResponse in memory.
    
    SELECT Email, COUNT(*) cnt FROM employeeTable WHERE Name = 'Ralph Brogan2' --from criteria
    AND Email = rbrogan@server.com --from criteria
    GROUP BY Email --ds.xml criteriaField
    
    Walk though the 1st result and check that the COUNT(*) plus the COUNT(*) for the same key in the other result are <=1.
    It seems that the solution for the criteriaFields-case is more general and would also work for the simpler case.
    As it is unclear how many rows will be SELECTED and processed in the criteriaFields-case (one row per returned criteriaField) and this could potentially be much data, an improvement would be to do in the DB, where it belongs:
    Code:
    SELECT Email, SUM(cnt) cntsum FROM
    (
    --1st statement
    SELECT Email, COUNT(*) cnt FROM employeeTable WHERE Name = 'Ralph Brogan' --new value
            AND NOT --inverted requestCriteria
            (Name = 'Ralph Brogan2' --from criteria
            AND Email = rbrogan@server.com) --from criteria
    GROUP BY Email --ds.xml criteriaField
    UNION ALL
    --2nd statement
    SELECT Email, COUNT(*) cnt FROM employeeTable WHERE Name = 'Ralph Brogan2' --from criteria
    AND Email = rbrogan@server.com --from criteria
    GROUP BY Email --ds.xml criteriaField
    )
    GROUP BY Email --ds.xml criteriaField
    HAVING SUM(cnt) > 1
    If this returns data, the unique validator would be violated.

    I'm pretty sure that this change will require some time which is OK for me as I have a workaround for my code in mind.
    But the way the unique validator behaves currently for setAllowMultiUpdate-Requests is definitely wrong. Perhaps it should be disabled until this gets reworked.

    Best regards
    Blama

    #2
    Hi Isomorphic,

    please check this thread first. It has an easier testcase and handles the case where the update is executed with the PK present.

    Best regards
    Blama

    Comment


      #3
      This issue is fixed and is available in nightly builds since Apr 11 (Monday).

      No more queries without criteria (returning 115 rows in your case) will be performed. isUnique validator behavior is refined and optimized to perform minimum amount of queries to check added/updated record uniqueness. Note this applies to single row updates only, i.e. update operations targeting multiple rows are not supported - isUnique validator will pass without error and a warning will be logged with the exact reason why. isUnique validator docs are updated with this limitation and also suggest using DMI approach to add these custom checks.

      Comment

      Working...
      X