Merge branch 'master' into bugs/323006
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
index aecd6a3..341f052 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
@@ -89,8 +89,6 @@
 import java.io.OutputStreamWriter;

 import java.io.Reader;

 import java.io.Writer;

-import java.sql.Blob;

-import java.sql.Clob;

 import java.sql.Connection;

 import java.sql.PreparedStatement;

 import java.sql.ResultSet;

@@ -372,17 +370,15 @@
         resultSet.next();

 

         long size = resultSet.getLong(1);

-        Blob blob = resultSet.getBlob(2);

+        InputStream inputStream = resultSet.getBinaryStream(2);

         if (resultSet.wasNull())

         {

-          Clob clob = resultSet.getClob(3);

-          Reader in = clob.getCharacterStream();

-          IOUtil.copyCharacter(in, new OutputStreamWriter(out), size);

+          Reader reader = resultSet.getCharacterStream(3);

+          IOUtil.copyCharacter(reader, new OutputStreamWriter(out), size);

         }

         else

         {

-          InputStream in = blob.getBinaryStream();

-          IOUtil.copyBinary(in, out, size);

+          IOUtil.copyBinary(inputStream, out, size);

         }

       }

       finally

@@ -416,11 +412,10 @@
         {

           byte[] id = HexUtil.hexToBytes(resultSet.getString(1));

           long size = resultSet.getLong(2);

-          Blob blob = resultSet.getBlob(3);

+          InputStream inputStream = resultSet.getBinaryStream(3);

           if (resultSet.wasNull())

           {

-            Clob clob = resultSet.getClob(4);

-            Reader in = clob.getCharacterStream();

+            Reader in = resultSet.getCharacterStream(4);

             Writer out = handler.handleClob(id, size);

             if (out != null)

             {

@@ -436,13 +431,12 @@
           }

           else

           {

-            InputStream in = blob.getBinaryStream();

             OutputStream out = handler.handleBlob(id, size);

             if (out != null)

             {

               try

               {

-                IOUtil.copyBinary(in, out, size);

+                IOUtil.copyBinary(inputStream, out, size);

               }

               finally

               {

diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java
index c0551e6..d001ac7 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java
@@ -620,6 +620,53 @@
   }

 

   /**

+   * @author Stefan Winkler

+   */

+  public static class TMCharacter2Integer extends AbstractTypeMapping

+  {

+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(

+        ID_PREFIX + ".Character2Integer", EcorePackage.eINSTANCE.getEChar(), DBType.INTEGER));

+

+    public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX

+        + ".CharacterObject2Integer", EcorePackage.eINSTANCE.getECharacterObject(), DBType.INTEGER));

+

+    @Override

+    public Object getResultSetValue(ResultSet resultSet) throws SQLException

+    {

+      int intRepresentation = resultSet.getInt(getField().getName());

+      if (resultSet.wasNull())

+      {

+        return getFeature().isUnsettable() ? CDORevisionData.NIL : null;

+      }

+

+      return Character.valueOf((char)intRepresentation);

+    }

+

+    @Override

+    protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException

+    {

+      stmt.setInt(index, /* (int) */((Character)value).charValue());

+    }

+

+    /**

+     * @author Stefan Winkler

+     */

+    public static class Factory extends AbstractTypeMappingFactory

+    {

+      public Factory(Descriptor descriptor)

+      {

+        super(descriptor);

+      }

+

+      @Override

+      public ITypeMapping create(String description) throws ProductCreationException

+      {

+        return new TMCharacter2Integer();

+      }

+    }

+  }

+

+  /**

    * @author Eike Stepper

    */

   public static class TMByte extends AbstractTypeMapping

diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java
index ccf5f6d..d6de02b 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java
@@ -129,6 +129,8 @@
     container.registerFactory(CoreTypeMappings.TMBytes.FACTORY);

     container.registerFactory(CoreTypeMappings.TMCharacter.FACTORY);

     container.registerFactory(CoreTypeMappings.TMCharacter.FACTORY_OBJECT);

+    container.registerFactory(CoreTypeMappings.TMCharacter2Integer.FACTORY);

+    container.registerFactory(CoreTypeMappings.TMCharacter2Integer.FACTORY_OBJECT);

     container.registerFactory(CoreTypeMappings.TMCustom.FACTORY_VARCHAR);

     container.registerFactory(CoreTypeMappings.TMCustom.FACTORY_CLOB);

     container.registerFactory(CoreTypeMappings.TMCustom.FACTORY_LONG_VARCHAR);

@@ -262,6 +264,7 @@
 

       if (descriptor == null)

       {

+        System.out.println();

         EClassifier type = getEType(feature);

         throw new IllegalStateException(MessageFormat.format(Messages.getString("TypeMappingRegistry.1"), feature

             .getEContainingClass().getName() + "." + feature.getName(),

diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_350137_Test.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_350137_Test.java
new file mode 100644
index 0000000..b803f44
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_350137_Test.java
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *    Stefan Winkler - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.db;
+
+import org.eclipse.emf.cdo.common.model.EMFUtil;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CDOUtil;
+
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * @author Stefan Winkler
+ */
+public class Bugzilla_350137_Test extends AbstractCDOTest
+{
+
+  /**
+   * Just check if an EChar attribute can be stored to the database per default. (PostgreSQL has problems with this).
+   */
+  public void testDefault() throws Exception
+  {
+    EPackage pkg = EMFUtil.createEPackage("Test", "t", "http://cdo.eclipse.org/tests/Bugzilla350137_Test1.ecore");
+    EClass cls = EMFUtil.createEClass(pkg, "foo", false, false);
+
+    @SuppressWarnings("unused")
+    EAttribute att = EMFUtil.createEAttribute(cls, "bar", EcorePackage.eINSTANCE.getEChar());
+
+    if (!isConfig(LEGACY))
+    {
+      CDOUtil.prepareDynamicEPackage(pkg);
+    }
+
+    EObject obj = EcoreUtil.create(cls);
+
+    CDOSession session = openSession();
+    CDOTransaction transaction = session.openTransaction();
+    CDOResource resource = transaction.createResource(getResourcePath("/test"));
+
+    resource.getContents().add(obj);
+    transaction.commit();
+    transaction.close();
+    session.close();
+  }
+
+  /**
+   * Check if an EChar attribute with explicit zero value can be stored to the database per default. (PostgreSQL has
+   * problems with this).
+   */
+  public void testExplicitZero() throws Exception
+  {
+    EPackage pkg = EMFUtil.createEPackage("Test", "t", "http://cdo.eclipse.org/tests/Bugzilla350137_Test2.ecore");
+    EClass cls = EMFUtil.createEClass(pkg, "foo2", false, false);
+
+    EAttribute att = EMFUtil.createEAttribute(cls, "bar", EcorePackage.eINSTANCE.getEChar());
+
+    if (!isConfig(LEGACY))
+    {
+      CDOUtil.prepareDynamicEPackage(pkg);
+    }
+
+    EObject obj = EcoreUtil.create(cls);
+    obj.eSet(att, '\u0000');
+
+    CDOSession session = openSession();
+    CDOTransaction transaction = session.openTransaction();
+    CDOResource resource = transaction.createResource(getResourcePath("/test"));
+
+    resource.getContents().add(obj);
+    transaction.commit();
+    transaction.close();
+    session.close();
+  }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java
index 9948534..1069d84 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java
@@ -38,6 +38,7 @@
     testClasses.add(DBStoreTest.class);

     testClasses.add(CustomTypeMappingTest.class);

     testClasses.add(SQLQueryTest.class);

+		testClasses.add(Bugzilla_350137_Test.class);

 

     super.initTestClasses(testClasses, scenario);

     testClasses.remove(MEMStoreQueryTest.class);

diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/PostgresqlConfig.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/PostgresqlConfig.java
index b30ed03..ce24c02 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/PostgresqlConfig.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/PostgresqlConfig.java
@@ -31,6 +31,12 @@
  */

 public class PostgresqlConfig extends DBConfig

 {

+  private static final String HOSTNAME = "majua02";

+

+  private static final String USER_NAME = "cdo";

+

+  private static final String PASSWORD = USER_NAME;

+

   public static final String DB_ADAPTER_NAME = "Postgresql";

 

   private static final long serialVersionUID = 1L;

@@ -65,10 +71,10 @@
     currentRepositoryName = repoName;

 

     dataSource = new Jdbc3SimpleDataSource();

-    dataSource.setServerName("localhost");

+    dataSource.setServerName(HOSTNAME);

     dataSource.setDatabaseName(currentRepositoryName);

-    dataSource.setUser("sa");

-    dataSource.setPassword("sa");

+    dataSource.setUser(USER_NAME);

+    dataSource.setPassword(PASSWORD);

 

     try

     {

@@ -114,15 +120,11 @@
 

   private DataSource getSetupDataSource()

   {

-    if (setupDataSource == null)

-    {

-      setupDataSource = new Jdbc3SimpleDataSource();

-      setupDataSource.setServerName("localhost");

-      setupDataSource.setDatabaseName(currentRepositoryName);

-      setupDataSource.setUser("sa");

-      setupDataSource.setPassword("sa");

-    }

-

+    setupDataSource = new Jdbc3SimpleDataSource();

+    setupDataSource.setServerName(HOSTNAME);

+    setupDataSource.setDatabaseName(currentRepositoryName);

+    setupDataSource.setUser(USER_NAME);

+    setupDataSource.setPassword(PASSWORD);

     return setupDataSource;

   }

 }

diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/SQLQueryTest.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/SQLQueryTest.java
index 569f296..abb3e41 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/SQLQueryTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/SQLQueryTest.java
@@ -331,8 +331,9 @@
     List<Map<String, Object>> results = query.getResult();

     for (int i = 0; i < NUM_OF_CUSTOMERS; i++)

     {

-      assertEquals("Street " + i, results.get(i).get("STREET"));

-      Object actual = results.get(i).get("CITY");

+      Map<String, Object> result = results.get(i);

+      assertEquals("Street " + i, result.containsKey("STREET") ? result.get("STREET") : result.get("street"));

+      Object actual = result.containsKey("CITY") ? result.get("CITY") : result.get("city");

       if (i == 0)

       {

         assertEquals(null, actual);

@@ -342,7 +343,7 @@
         assertEquals("City " + i, actual);

       }

 

-      assertEquals("" + i, results.get(i).get("NAME"));

+      assertEquals("" + i, result.containsKey("NAME") ? result.get("NAME") : result.get("name"));

     }

   }

 

diff --git a/plugins/org.eclipse.net4j.db.postgresql/src/org/eclipse/net4j/db/postgresql/PostgreSQLAdapter.java b/plugins/org.eclipse.net4j.db.postgresql/src/org/eclipse/net4j/db/postgresql/PostgreSQLAdapter.java
index 8f70a4e..54a3800 100644
--- a/plugins/org.eclipse.net4j.db.postgresql/src/org/eclipse/net4j/db/postgresql/PostgreSQLAdapter.java
+++ b/plugins/org.eclipse.net4j.db.postgresql/src/org/eclipse/net4j/db/postgresql/PostgreSQLAdapter.java
@@ -10,6 +10,8 @@
  *    Eike Stepper - maintenance

  *    Stefan Winkler - Bug 276979

  *    Stefan Winkler - Bug 289445

+ *    Stefan Winker  - Bug 350137

+ *    Victor Roldan Betancort - Bug 323006

  */

 package org.eclipse.net4j.db.postgresql;

 

@@ -98,11 +100,18 @@
     case LONGVARCHAR:

     case VARCHAR:

     case CLOB:

-      return "text"; //$NON-NLS-1$

+      return "text"; //$NON-NLS-1$    

+    case BINARY:

+    case VARBINARY:

+    case LONGVARBINARY:

     case BLOB:

       return "bytea"; //$NON-NLS-1$

     case DOUBLE:

       return "double precision"; //$NON-NLS-1$

+    case BIT:

+      return "boolean"; //$NON-NLS-1$

+    case TINYINT:

+      return "smallint"; //$NON-NLS-1$

     }

 

     return super.getTypeName(field);

@@ -171,9 +180,10 @@
   {

     switch (type)

     {

-    // Due to Bug 289194: [DB] BLOB not correctly handled by PostgreSQL DBAdapter

-    case BLOB:

-      return DBType.VARBINARY;

+    case CHAR:

+      // Due to Bug 350137 (PostgreSQL does not like zeros in strings ...)

+      // SMALLINT won't fit since it only supports 32767 as maximum value, whereas Character.MAX_VALUE is 65535

+      return DBType.INTEGER;

     }

 

     return super.adaptType(type);

diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java
index 683c915..b7b14b8 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java
@@ -20,8 +20,6 @@
 import java.io.IOException;

 import java.io.InputStream;

 import java.io.Reader;

-import java.sql.Blob;

-import java.sql.Clob;

 import java.sql.PreparedStatement;

 import java.sql.ResultSet;

 import java.sql.SQLException;

@@ -464,7 +462,19 @@
     public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)

         throws SQLException, IOException

     {

-      Clob value = resultSet.getClob(column);

+      InputStream inputStream = resultSet.getBinaryStream(column);

+      long length = -1;

+      try

+      {

+        length = resultSet.getClob(column).length();

+      }

+      catch (SQLException ex)

+      {

+        // Postgresql does not have support for Blob/Clob

+        // InputStream.available() returns the actual length

+        length = inputStream.available();

+      }

+

       if (canBeNull)

       {

         if (resultSet.wasNull())

@@ -476,21 +486,18 @@
         out.writeBoolean(true);

       }

 

-      long length = value.length();

-      Reader reader = value.getCharacterStream();

-

       try

       {

         out.writeLong(length);

         while (length-- > 0)

         {

-          int c = reader.read();

+          int c = inputStream.read();

           out.writeChar(c);

         }

       }

       finally

       {

-        IOUtil.close(reader);

+        IOUtil.close(inputStream);

       }

 

       return null;

@@ -806,7 +813,19 @@
     public Object writeValueWithResult(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull)

         throws SQLException, IOException

     {

-      Blob value = resultSet.getBlob(column);

+      InputStream inputStream = resultSet.getBinaryStream(column);

+      long length = -1;

+      try

+      {

+        length = resultSet.getBlob(column).length();

+      }

+      catch (SQLException ex)

+      {

+        // Postgresql does not have support for Blob/Clob

+        // InputStream.available() returns the actual length

+        length = inputStream.available();

+      }

+

       if (canBeNull)

       {

         if (resultSet.wasNull())

@@ -818,21 +837,18 @@
         out.writeBoolean(true);

       }

 

-      long length = value.length();

-      InputStream stream = value.getBinaryStream();

-

       try

       {

         out.writeLong(length);

         while (length-- > 0)

         {

-          int b = stream.read();

+          int b = inputStream.read();

           out.writeByte(b + Byte.MIN_VALUE);

         }

       }

       finally

       {

-        IOUtil.close(stream);

+        IOUtil.close(inputStream);

       }

 

       return null;