Changeset 7522


Ignore:
Timestamp:
Nov 6, 2018, 3:50:29 PM (4 years ago)
Author:
Nicklas Nordborg
Message:

References #2130: Upgrade 3-rd party libraries

Updated to Hibernate 5.3.7. Except for some API changes and deprecations that is affecting our wrappers around Session, Query, etc. most other things seems to be working. The bug that was reported in #2110 and #2113 seems to be fixed and the workaround has been removed.

Location:
trunk
Files:
11 added
10 deleted
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/.classpath

    r7509 r7522  
    2828  <classpathentry kind="lib" path="lib/dist/javasysmon-0.3.5.jar"/>
    2929  <classpathentry kind="lib" path="lib/dist/slf4j-api-1.7.25.jar"/>
    30   <classpathentry kind="lib" path="lib/dist/hibernate-core-5.2.10.Final.jar"/>
    31   <classpathentry kind="lib" path="lib/dist/hibernate-jpa-2.1-api-1.0.0.Final.jar"/>
    3230  <classpathentry kind="lib" path="lib/dist/parallelgzip-1.0.5.jar"/>
    3331  <classpathentry kind="lib" path="lib/dist/yauaa-2.2.jar"/>
     
    3533  <classpathentry kind="lib" path="lib/dist/bcprov-jdk15on-159.jar"/>
    3634  <classpathentry kind="lib" path="lib/dist/postgresql-42.2.5.jar"/>
     35  <classpathentry kind="lib" path="lib/dist/hibernate-core-5.3.7.Final.jar" sourcepath="D:/Download/Firefox/hibernate-release-5.3.7.Final/project/hibernate-core/src/main/java"/>
     36  <classpathentry kind="lib" path="lib/dist/javax.persistence-api-2.2.jar"/>
    3737  <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
    3838  <classpathentry kind="output" path="xbin"/>
  • trunk/doc/3rd-party-components.txt

    r7518 r7522  
    4040
    4141More info : http://www.hibernate.org/
    42 Version   : 5.2.10
     42Version   : 5.3.7
    4343License   : LGPL (hibernate.license.txt)
    44 Jar files : hibernate-core-5.2.10.Final.jar, hibernate-commons-annotations-5.0.1.Final.jar,
    45             hibernate-jpa-2.1-api-1.0.0.Final.jar,
    46             antlr-2.7.7.jar, dom4j-1.6.1.jar, jandex-2.0.3.Final.jar,
    47             javassist-3.23.1-GA.jar, classmate-1.3.0.jar
    48             jboss-logging-3.3.0.Final.jar, jboss-transaction-api_1.2_spec-1.0.1.Final.jar,
    49             c3p0-0.9.5.2.jar, hibernate-c3p0-5.2.10.Final.jar, mchange-commons-java-0.2.11.jar,
    50             ehcache-2.10.3.jar, hibernate-ehcache-5.2.10.Final.jar,
     44Jar files : hibernate-core-5.3.7.Final.jar, hibernate-commons-annotations-5.0.4.Final.jar,
     45            javax.persistence-api-2.2.jar,
     46            antlr-2.7.7.jar, dom4j-2.1.1.jar, jandex-2.0.5.Final.jar,
     47            javassist-3.23.1-GA.jar, byte-buddy-1.18.17.jar, classmate-1.3.4.jar
     48            jboss-logging-3.3.2.Final.jar, jboss-transaction-api_1.2_spec-1.1.1.Final.jar,
     49            c3p0-0.9.5.2.jar, hibernate-c3p0-5.3.7.Final.jar, mchange-commons-java-0.2.11.jar,
     50            ehcache-2.10.3.jar, hibernate-ehcache-5.3.7.Final.jar,
    5151            slf4j-api.1.7.25.jar, slf4j-log4j12-1.7.25.jar
    5252
  • trunk/src/core/net/sf/basedb/core/AnnotationBatcher.java

    r7381 r7522  
    900900              // We must evict the entity from the Hibernate second-level
    901901              // cache or Hibernate may use the old data
    902               secondLevelCache.evictEntity(itemType.getDataClass(), currentItem.getId());
     902              secondLevelCache.evictEntityData(itemType.getDataClass(), currentItem.getId());
    903903            }
    904904          }
  • trunk/src/core/net/sf/basedb/core/HibernateUtil.java

    r7521 r7522  
    104104import org.hibernate.mapping.PersistentClass;
    105105import org.hibernate.mapping.Table;
    106 import org.hibernate.mapping.SimpleValue;
    107106import org.hibernate.mapping.Index;
    108107import org.hibernate.mapping.Column;
     
    10781077    hibernateColumn.setNullable(column.isNullable());
    10791078    hibernateColumn.setLength(column.getSize());
    1080    
    1081     // Create Hibernate SimpleValue mapping
    1082     SimpleValue hibernateValue = new SimpleValue(metadata);
    1083     hibernateValue.setTypeName(column.getTypeWrapper().getHibernateType().getName());
    1084     hibernateValue.addColumn(hibernateColumn);
     1079    hibernateColumn.setSqlType(dialect.getTypeName(hibernateColumn.getSqlTypeCode(), hibernateColumn.getLength(), hibernateColumn.getPrecision(), hibernateColumn.getScale()));
    10851080   
    10861081    // Add column to Table mapping
     
    18601855
    18611856  /**
    1862     Create a Hibernate query using a stateless session.
    1863   */
    1864   @SuppressWarnings({ "unchecked", "rawtypes" })
    1865   static Query<?> createQuery(StatelessSession session, String hql)
    1866     throws BaseException
    1867   {
    1868     assert session != null : "session == null";
    1869     assert hql != null : "hql == null";
    1870     try
    1871     {
    1872       Query<?> q = session.createQuery(hql);
    1873       q.setFetchSize(getJdbcFetchSize());
    1874       return new EntityQueryWrapper(q);
    1875     }
    1876     catch (HibernateException ex)
    1877     {
    1878       throw new BaseException(ex);
    1879     }
    1880   }
    1881  
    1882   /**
    18831857    Create a Hibernate query using a stateless session and a known return type.
    18841858    @since 3.12
     
    19131887    {
    19141888      NativeQuery<?> q = session.createNativeQuery(sql);
    1915       ((Query<?>)q).setFetchSize(getJdbcFetchSize());
     1889      q.setFetchSize(getJdbcFetchSize());
    19161890      return new NativeQueryWrapper<>(q);
    19171891    }
     
    19461920        q = session.createNativeQuery(sql);
    19471921      }
    1948       ((Query<R>)q).setFetchSize(getJdbcFetchSize());
     1922      q.setFetchSize(getJdbcFetchSize());
    19491923      return new NativeQueryWrapper<>(q);
    19501924    }
     
    19671941    {
    19681942      NativeQuery<?> q = session.createNativeQuery(sql);
    1969       ((Query<?>)q).setFetchSize(getJdbcFetchSize());
     1943      q.setFetchSize(getJdbcFetchSize());
    19701944      return new NativeQueryWrapper<>(q);
    19711945    }
     
    20001974        q = session.createNativeQuery(sql);
    20011975      }
    2002       ((Query<R>)q).setFetchSize(getJdbcFetchSize());
     1976      q.setFetchSize(getJdbcFetchSize());
    20031977      return new NativeQueryWrapper<>(q);
    20041978    }
     
    21402114  }
    21412115
    2142  
    2143   /**
    2144     Get a predefined HQL query using the stateless session.
    2145     @see PredefinedQuery
    2146   */
    2147   static Query<?> getPredefinedQuery(StatelessSession session, String name)
    2148     throws BaseException
    2149   {
    2150     assert session != null : "session == null";
    2151     assert name != null : "name == null";
    2152     return createQuery(session, PredefinedQuery.getQueryString(name));
    2153   }
    2154  
    21552116  /**
    21562117    Get a predefined HQL query with a known return type using the stateless session.
     
    23302291     
    23312292      //  Evict the item from the cache and, in another session, try to load the news item
    2332       sf.getCache().evictEntity(NewsData.class, newsId);
     2293      sf.getCache().evictEntityData(NewsData.class, newsId);
    23332294      session = HibernateUtil.newSession();
    23342295      tx = HibernateUtil.newTransaction(session);
  • trunk/src/core/net/sf/basedb/core/LogControl.java

    r7381 r7522  
    130130 
    131131  /**
    132     Creates a Hibernate HQL query. Use this to get information
    133     from the database that is relevent for the logging implementation.
    134     The query uses the stateless session, which means that there
    135     is no first- or second-level cache and on support for initialization
    136     of proxies. We recommend that queries are used to return
    137     scalar values only, not entities.
    138     @return A Query
    139     @deprecated In 3.12. use {@link #createHqlQuery(String, Class)} instead
    140   */
    141   @Deprecated
    142   public org.hibernate.query.Query<?> createHqlQuery(String hql)
    143   {
    144     return HibernateUtil.createQuery(getSession(), hql);
    145   }
    146  
    147   /**
    148132    Creates a Hibernate HQL query with a known return type. Use this to get information
    149133    from the database that is relevent for the logging implementation.
  • trunk/src/core/net/sf/basedb/core/hibernate/EntityQueryWrapper.java

    r7381 r7522  
    186186  public <P> Query<R> setParameterList(QueryParameter<P> param, Collection<P> values)
    187187  {
    188     if (param.getType().isEntityType()) checkEntityCollection(values);
     188    if (param.getHibernateType().isEntityType()) checkEntityCollection(values);
    189189    return super.setParameterList(param, values);
    190190  }
  • trunk/src/core/net/sf/basedb/core/hibernate/NativeQueryWrapper.java

    r7478 r7522  
    2222package net.sf.basedb.core.hibernate;
    2323
    24 import java.lang.reflect.Field;
     24import java.time.Instant;
     25import java.time.LocalDateTime;
     26import java.time.OffsetDateTime;
     27import java.time.ZonedDateTime;
    2528import java.util.Calendar;
    2629import java.util.Collection;
    2730import java.util.Date;
    28 import java.util.Iterator;
    2931import java.util.List;
    3032import java.util.Map;
    3133
    3234import javax.persistence.FlushModeType;
     35import javax.persistence.LockModeType;
    3336import javax.persistence.Parameter;
    3437import javax.persistence.TemporalType;
     
    4144import org.hibernate.query.NativeQuery;
    4245import org.hibernate.query.QueryParameter;
    43 import org.hibernate.query.internal.AbstractProducedQuery;
    44 import org.hibernate.query.internal.QueryParameterBindingsImpl;
    45 import org.hibernate.query.spi.QueryParameterBinding;
    4646import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
    4747import org.hibernate.type.Type;
     
    434434  {
    435435    query.setParameterList(parameter, values);
    436     clearOldParameterListParameters(parameter.getName());
    437436    return this;
    438437  }
     
    443442  {
    444443    query.setParameterList(name, values);
    445     clearOldParameterListParameters(name);
    446444    return this;
    447445  }
     
    452450  {
    453451    query.setParameterList(name, values, type);
    454     clearOldParameterListParameters(name);
    455452    return this;
    456453  }
     
    460457  {
    461458    query.setParameterList(name, values, type);
    462     clearOldParameterListParameters(name);
    463459    return this;
    464460  }
     
    468464  {
    469465    query.setParameterList(name, values);
    470     clearOldParameterListParameters(name);
    471466    return this;
    472467  }
     
    512507 
    513508 
    514   // Reference to the "QueryParameterBindingsImpl.parameterBindingMap" variable
    515   private Field parameterBindingMap;
    516509 
    517   /**
    518     We need to remove "synthetic" parameters from the "parameterBindingMap".
    519     The parameters are created by Hibernate when a list-type parameter is
    520     specified on a query: name_0, name_1, etc. The problem is that the
    521     "synthetic" parameters are never cleared and if the same query is re-used
    522     with a shorter list, Hibernate will try to set the non-existing parameters
    523     which causes an exception. See http://base.thep.lu.se/ticket/2110
    524     UPDATE: We also need to check for copied parameter (name) in case the list
    525     contained only a single element. See http://base.thep.lu.se/ticket/2113
    526   */
    527   @SuppressWarnings({ "unchecked", "rawtypes" })
    528   private void clearOldParameterListParameters(String parameterName)
    529   {
    530     try
    531     {
    532       if (parameterBindingMap == null)
    533       {
    534         parameterBindingMap = QueryParameterBindingsImpl.class.getDeclaredField("parameterBindingMap");
    535         parameterBindingMap.setAccessible(true);
    536       }
    537      
    538       String prefixOfParametersToRemove = parameterName + "_";
    539       Map<QueryParameter<?>, QueryParameterBinding<?>> m = (Map)parameterBindingMap.get(((AbstractProducedQuery)query).getQueryParameterBindings());
    540       Iterator<QueryParameter<?>> i = m.keySet().iterator();
    541       while (i.hasNext())
    542       {
    543         String name = i.next().getName();
    544         if (name.startsWith(prefixOfParametersToRemove) || name.equals(parameterName))
    545         {
    546           i.remove();
    547         }
    548       }
    549     }
    550     catch (Exception ex)
    551     {
    552       throw new RuntimeException(ex);
    553     }
    554   }
     510 
     511  @Override
     512  public NativeQuery<R> setFirstResult(int firstResult)
     513  {
     514    query.setFirstResult(firstResult);
     515    return this;
     516  }
     517
     518  @Override
     519  public NativeQuery<R> setMaxResults(int maxResults)
     520  {
     521    query.setMaxResults(maxResults);
     522    return this;
     523  }
     524
     525  @Override
     526  public NativeQuery<R> setHint(String name, Object value)
     527  {
     528    query.setHint(name, value);
     529    return this;
     530  }
     531
     532  @Override
     533  public NativeQuery<R> setLockMode(LockModeType lockMode)
     534  {
     535    query.setLockMode(lockMode);
     536    return this;
     537  }
     538
     539  @Override
     540  public NativeQuery<R> setParameter(int position, Instant value, TemporalType type)
     541  {
     542    query.setParameter(position, value, type);
     543    return this;
     544  }
     545
     546  @Override
     547  public NativeQuery<R> setParameter(int position, LocalDateTime value, TemporalType type)
     548  {
     549    query.setParameter(position, value, type);
     550    return this;
     551  }
     552
     553  @Override
     554  public NativeQuery<R> setParameter(int position, OffsetDateTime value, TemporalType type)
     555  {
     556    query.setParameter(position, value, type);
     557    return this;
     558  }
     559
     560  @Override
     561  public NativeQuery<R> setParameter(int position, ZonedDateTime value, TemporalType type)
     562  {
     563    query.setParameter(position, value, type);
     564    return this;
     565  }
     566
     567  @Override
     568  public NativeQuery<R> setParameter(Parameter<Instant> param, Instant value, TemporalType type)
     569  {
     570    query.setParameter(param, value, type);
     571    return this;
     572  }
     573
     574  @Override
     575  public NativeQuery<R> setParameter(Parameter<LocalDateTime> param, LocalDateTime value, TemporalType type)
     576  {
     577    query.setParameter(param, value, type);
     578    return this;
     579  }
     580
     581  @Override
     582  public NativeQuery<R> setParameter(Parameter<OffsetDateTime> param, OffsetDateTime value, TemporalType type)
     583  {
     584    query.setParameter(param, value, type);
     585    return this;
     586  }
     587
     588  @Override
     589  public NativeQuery<R> setParameter(Parameter<ZonedDateTime> param, ZonedDateTime value, TemporalType type)
     590  {
     591    query.setParameter(param, value, type);
     592    return this;
     593  }
     594
     595  @Override
     596  public NativeQuery<R> setParameter(String name, Instant value, TemporalType type)
     597  {
     598    query.setParameter(name, value, type);
     599    return this;
     600  }
     601
     602  @Override
     603  public NativeQuery<R> setParameter(String name, LocalDateTime value, TemporalType type)
     604  {
     605    query.setParameter(name, value, type);
     606    return this;
     607  }
     608
     609  @Override
     610  public NativeQuery<R> setParameter(String name, OffsetDateTime value, TemporalType type)
     611  {
     612    query.setParameter(name, value, type);
     613    return this;
     614  }
     615
     616  @Override
     617  public NativeQuery<R> setParameter(String name, ZonedDateTime value, TemporalType type)
     618  {
     619    query.setParameter(name, value, type);
     620    return this;
     621  }
     622
    555623}
  • trunk/src/core/net/sf/basedb/core/hibernate/QueryWrapper.java

    r7381 r7522  
    849849
    850850  @Override
     851  @Deprecated
    851852  public RowSelection getQueryOptions()
    852853  {
     
    10691070  }
    10701071
     1072  @SuppressWarnings("rawtypes")
     1073  @Override
     1074  @Deprecated
     1075  public org.hibernate.Query<R> setParameterList(int param, Collection values)
     1076  {
     1077    query.setParameterList(param, values);
     1078    return this;
     1079  }
     1080
     1081  @SuppressWarnings("rawtypes")
     1082  @Override
     1083  @Deprecated
     1084  public org.hibernate.Query<R> setParameterList(int param, Collection values, Type type)
     1085  {
     1086    query.setParameterList(param, values, type);
     1087    return this;
     1088  }
     1089
     1090  @Override
     1091  @Deprecated
     1092  public org.hibernate.Query<R> setParameterList(int param, Object[] values, Type type)
     1093  {
     1094    query.setParameterList(param, values, type);
     1095    return this;
     1096  }
     1097
     1098  @Override
     1099  @Deprecated
     1100  public org.hibernate.Query<R> setParameterList(int param, Object[] values)
     1101  {
     1102    query.setParameterList(param, values);
     1103    return this;
     1104  }
     1105
    10711106}
  • trunk/src/core/net/sf/basedb/core/hibernate/SessionWrapper.java

    r7381 r7522  
    173173  }
    174174
    175   @Override
    176   public Query<?> createFilter(Object collection, String queryString)
     175  @SuppressWarnings("deprecation")
     176  @Override
     177  public org.hibernate.Query<?> createFilter(Object collection, String queryString)
    177178    throws HibernateException
    178179  {
  • trunk/src/core/net/sf/basedb/core/hibernate/StatelessSessionWrapper.java

    r7381 r7522  
    146146  */
    147147  @Override
    148   public Query<?> createQuery(String queryString)
     148  @SuppressWarnings("deprecation")
     149  public org.hibernate.Query<?> createQuery(String queryString)
    149150    throws HibernateException
    150151  {
    151     Query<?> q = getCachedQuery(queryString);
    152     if (q == null)
    153     {
    154       q = session.createQuery(queryString);
    155       q.setFetchSize(HibernateUtil.getJdbcFetchSize());
    156       cacheQuery(queryString, q);
    157     }
     152    org.hibernate.Query<?> q = session.createQuery(queryString);
     153    q.setFetchSize(HibernateUtil.getJdbcFetchSize());
    158154    return q;
    159155  }
     
    166162  @Override
    167163  @Deprecated
    168   public NativeQuery<?> createSQLQuery(String queryString)
     164  public org.hibernate.SQLQuery<?> createSQLQuery(String queryString)
    169165    throws HibernateException
    170166  {
    171     Query<?> q = getCachedQuery(queryString);
    172     if (q == null || !(q instanceof NativeQuery))
    173     {
    174       q = session.createSQLQuery(queryString);
    175       q.setFetchSize(HibernateUtil.getJdbcFetchSize());
    176     }
    177     return (NativeQuery<?>)q;
     167    org.hibernate.SQLQuery<?> q = session.createSQLQuery(queryString);
     168    q.setFetchSize(HibernateUtil.getJdbcFetchSize());
     169    return q;
    178170  }
    179171
     
    222214  */
    223215  @Override
    224   public Query<?> getNamedQuery(String queryName)
     216  @SuppressWarnings("deprecation")
     217  public org.hibernate.Query<?> getNamedQuery(String queryName)
    225218    throws HibernateException
    226219  {
    227     Query<?> q = getCachedQuery(queryName);
    228     if (q == null)
    229     {
    230       q = session.getNamedQuery(queryName);
    231       cacheQuery(queryName, q);
    232     }
     220    org.hibernate.Query<?> q = session.getNamedQuery(queryName);
    233221    return q;
    234222  }
  • trunk/src/install/net/sf/basedb/install/InitDB.java

    r7521 r7522  
    215215    String message =
    216216      "--System information-----------------------------\n" +
    217       "BASE     : " + Version.getVersion() + "\n" +
    218       "Database : " + dbUrl + "\n" +
    219       "Dialect  : " + Config.getString("db.dialect") + "\n" +
    220       "JDBC     : " + driverClass + "; " + driverVersion + "\n" +
    221       "Java     : " + properties.getProperty("java.runtime.name") + "; " +
     217      "BASE      : " + Version.getVersion() + "\n" +
     218      "Database  : " + dbUrl + "\n" +
     219      "Dialect   : " + Config.getString("db.dialect") + "\n" +
     220      "JDBC      : " + driverClass + "; " + driverVersion + "\n" +
     221      "Hibernate : " + org.hibernate.Version.getVersionString() + "\n"+
     222      "Java      : " + properties.getProperty("java.runtime.name") + "; " +
    222223        properties.getProperty("java.runtime.version") + "; " +
    223224        properties.getProperty("java.vendor") + "\n" +
    224       "OS       : " + properties.getProperty("os.name") +"; " +
     225      "OS        : " + properties.getProperty("os.name") +"; " +
    225226        properties.getProperty("os.arch") + "; " +
    226227        properties.getProperty("os.version") +"\n" +
  • trunk/src/test/TestUtil.java

    r7521 r7522  
    286286    String message =
    287287      "--System information-----------------------------\n" +
    288       "BASE     : " + Version.getMajor() + "." +
    289         Version.getMinor() + "." + Version.getMaintenance() + Version.getSuffix() + "\n" +
    290       "Database : " + database + "\n" +
    291       "Dialect  : " + Config.getString("db.dialect") + "\n" +
    292       "JDBC     : " + driverClass + "; " + driverVersion + "\n" +
    293       "URL      : " + dbUrl + "\n" +
    294       "Java     : " + properties.getProperty("java.runtime.name") + "; " +
     288      "BASE      : " + Version.getVersion() + "\n" +
     289      "Database  : " + database + "\n" +
     290      "Dialect   : " + Config.getString("db.dialect") + "\n" +
     291      "Hibernate : " + org.hibernate.Version.getVersionString() + "\n"+
     292      "JDBC      : " + driverClass + "; " + driverVersion + "\n" +
     293      "URL       : " + dbUrl + "\n" +
     294      "Java      : " + properties.getProperty("java.runtime.name") + "; " +
    295295        properties.getProperty("java.runtime.version") + "; " +
    296296        properties.getProperty("java.vendor") + "\n" +
    297       "OS       : " + properties.getProperty("os.name") +"; " +
     297      "OS        : " + properties.getProperty("os.name") +"; " +
    298298        properties.getProperty("os.arch") + "; " +
    299299        properties.getProperty("os.version") +"\n" +
  • trunk/src/test/net/sf/basedb/test/TestUtil.java

    r7521 r7522  
    3838import net.sf.basedb.core.DbControl;
    3939import net.sf.basedb.core.SessionControl;
     40import net.sf.basedb.core.Version;
    4041import net.sf.basedb.core.authentication.LoginRequest;
    4142
     
    258259    String message =
    259260      "--System information-----------------------------\n" +
    260       "BASE     : " + Application.getMajorVersion() + "." +
    261         Application.getMinorVersion() + "." +
    262         Application.getMaintenanceVersion() + "\n" +
    263       "Database : " + database + "\n" +
    264       "Dialect  : " + Config.getString("db.dialect") + "\n" +
    265       "JDBC     : " + driverClass + "; " + driverVersion + "\n" +
    266       "URL      : " + dbUrl + "\n" +
    267       "Java     : " + properties.getProperty("java.runtime.name") + "; " +
     261      "BASE      : " + Version.getVersion() + "\n" +
     262      "Database  : " + database + "\n" +
     263      "Dialect   : " + Config.getString("db.dialect") + "\n" +
     264      "Hibernate : " + org.hibernate.Version.getVersionString() + "\n"+
     265      "JDBC      : " + driverClass + "; " + driverVersion + "\n" +
     266      "URL       : " + dbUrl + "\n" +
     267      "Java      : " + properties.getProperty("java.runtime.name") + "; " +
    268268        properties.getProperty("java.runtime.version") + "; " +
    269269        properties.getProperty("java.vendor") + "\n" +
    270       "OS       : " + properties.getProperty("os.name") +"; " +
     270      "OS        : " + properties.getProperty("os.name") +"; " +
    271271        properties.getProperty("os.arch") + "; " +
    272272        properties.getProperty("os.version") +"\n" +
Note: See TracChangeset for help on using the changeset viewer.