You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by da...@apache.org on 2017/08/20 19:16:29 UTC

svn commit: r1805579 [3/7] - in /openoffice/trunk/main: ./ apache-commons/java/lang/ connectivity/ connectivity/java/sdbc_postgresql/ connectivity/java/sdbc_postgresql/src/ connectivity/java/sdbc_postgresql/src/com/ connectivity/java/sdbc_postgresql/sr...

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySetAdapter.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySetAdapter.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySetAdapter.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySetAdapter.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,411 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.comphelper;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.sun.star.beans.Property;
+import com.sun.star.beans.PropertyAttribute;
+import com.sun.star.beans.PropertyChangeEvent;
+import com.sun.star.beans.PropertyVetoException;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XFastPropertySet;
+import com.sun.star.beans.XMultiPropertySet;
+import com.sun.star.beans.XPropertiesChangeListener;
+import com.sun.star.beans.XPropertyChangeListener;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.beans.XPropertySetInfo;
+import com.sun.star.beans.XVetoableChangeListener;
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lib.uno.helper.InterfaceContainer;
+import com.sun.star.lib.uno.helper.MultiTypeInterfaceContainer;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.TypeClass;
+import com.sun.star.uno.XInterface;
+
+public class PropertySetAdapter implements XPropertySet, XFastPropertySet, XMultiPropertySet {
+    private final Object lock;
+    private final Object eventSource;
+    // after registerListeners(), these are read-only:
+    private final Map<String,PropertyData> propertiesByName = new HashMap<String,PropertyData>();
+    private final Map<Integer,PropertyData> propertiesByHandle = new HashMap<Integer,PropertyData>();
+    private int nextHandle = 1;
+    // interface containers are locked internally:
+    protected final MultiTypeInterfaceContainer boundListeners = new MultiTypeInterfaceContainer();
+    protected final MultiTypeInterfaceContainer vetoableListeners = new MultiTypeInterfaceContainer();
+    protected final InterfaceContainer propertiesChangeListeners = new InterfaceContainer();
+    private final PropertySetInfo propertySetInfo = new PropertySetInfo();
+    
+    public static interface PropertyGetter {
+        Object getValue();
+    }
+    
+    public static interface PropertySetter {
+        void setValue(Object value);
+    }
+    
+    private static class PropertyData {
+        Property property;
+        PropertyGetter getter;
+        PropertySetter setter;
+        
+        PropertyData(Property property, PropertyGetter getter, PropertySetter setter) {
+            this.property = property;
+            this.getter = getter;
+            this.setter = setter;
+        }
+    }
+    
+    private static final Comparator<Property> propertyNameComparator = new Comparator<Property>() {
+        @Override
+        public int compare(Property first, Property second) {
+            return first.Name.compareTo(second.Name);
+        }
+    };
+    
+    private class PropertySetInfo implements XPropertySetInfo {
+        @Override
+        public Property[] getProperties() {
+            Property[] properties = new Property[propertiesByName.size()];
+            int next = 0;
+            for (Map.Entry<String,PropertyData> entry : propertiesByName.entrySet()) {
+                properties[next++] = entry.getValue().property;
+            }
+            Arrays.sort(properties, propertyNameComparator);
+            return properties;
+        }
+
+        @Override
+        public Property getPropertyByName(String propertyName) throws UnknownPropertyException {
+            PropertyData propertyData = getPropertyData(propertyName);
+            return propertyData.property;
+        }
+
+        @Override
+        public boolean hasPropertyByName(String propertyName) {
+            return propertiesByName.containsKey(propertyName);
+        }
+    }
+    
+    /**
+     * Creates a new instance.
+     * @param lock the lock that will be held while calling the getters and setters
+     * @param eventSource the com.sun.star.lang.EventObject Source field, to use in events sent to listeners
+     */
+    public PropertySetAdapter(Object lock, Object eventSource) {
+        this.lock = lock;
+        this.eventSource = eventSource;
+    }
+    
+    public void dispose() {
+        // Create an event with this as sender
+        EventObject event = new EventObject(eventSource);
+        
+        // inform all listeners to release this object
+        boundListeners.disposeAndClear(event);
+        vetoableListeners.disposeAndClear(event);
+    }
+    
+    public void registerProperty(String propertyName, int handle, Type type, short attributes,
+            PropertyGetter getter, PropertySetter setter) {
+        Property property = new Property(propertyName, handle, type, attributes);
+        PropertyData propertyData = new PropertyData(property, getter, setter);
+        propertiesByName.put(propertyName, propertyData);
+        propertiesByHandle.put(property.Handle, propertyData);
+    }
+    
+    public void registerProperty(String propertyName, Type type, short attributes,
+            PropertyGetter getter, PropertySetter setter) {
+        int handle;
+        // registerProperty() should only be called from one thread, but just in case:
+        synchronized (lock) {
+            handle = nextHandle++;
+        }
+        registerProperty(propertyName, handle, type, attributes, getter, setter);
+    }
+    
+    @Override
+    public void addPropertyChangeListener(
+            String propertyName, XPropertyChangeListener listener) throws UnknownPropertyException, WrappedTargetException {
+        PropertyData propertyData = getPropertyData(propertyName);
+        if ((propertyData.property.Attributes & PropertyAttribute.BOUND) != 0) {
+            boundListeners.addInterface(propertyName, listener);
+        } // else ignore silently
+    }
+
+    @Override
+    public void addVetoableChangeListener(
+            String propertyName, XVetoableChangeListener listener) throws UnknownPropertyException, WrappedTargetException {
+        PropertyData propertyData = getPropertyData(propertyName);
+        if ((propertyData.property.Attributes & PropertyAttribute.CONSTRAINED) != 0) {
+            vetoableListeners.addInterface(propertyName, listener);
+        } // else ignore silently
+    }
+    
+    @Override
+    public void addPropertiesChangeListener(String[] propertyNames, XPropertiesChangeListener listener) {
+        propertiesChangeListeners.add(listener);
+    }
+
+    @Override
+    public XPropertySetInfo getPropertySetInfo() {
+        return propertySetInfo;
+    }
+
+    private PropertyData getPropertyData(String propertyName) throws UnknownPropertyException {
+        PropertyData propertyData = propertiesByName.get(propertyName);
+        if (propertyData == null) {
+            throw new UnknownPropertyException(propertyName);
+        }
+        return propertyData;
+    }
+    
+    private PropertyData getPropertyData(int handle) throws UnknownPropertyException {
+        PropertyData propertyData = propertiesByHandle.get(handle);
+        if (propertyData == null) {
+            throw new UnknownPropertyException(Integer.toString(handle));
+        }
+        return propertyData;
+    }
+    
+    private Object getPropertyValue(PropertyData propertyData) {
+        Object ret;
+        synchronized (lock) {
+            ret = propertyData.getter.getValue();
+        }
+        
+        // null must not be returned. Either a void any is returned or an any containing
+        // an interface type and a null reference.
+        if (ret == null) {
+            if (propertyData.property.Type.getTypeClass() == TypeClass.INTERFACE) {
+                ret = new Any(propertyData.property.Type, null);
+            } else {
+                ret = new Any(new Type(void.class), null);
+            }
+        }
+        return ret;
+    }
+    
+    @Override
+    public Object getPropertyValue(String propertyName) throws UnknownPropertyException, WrappedTargetException {
+        PropertyData propertyData = getPropertyData(propertyName);
+        return getPropertyValue(propertyData);
+    }
+
+    @Override
+    public Object getFastPropertyValue(int handle) throws UnknownPropertyException, WrappedTargetException {
+        PropertyData propertyData = getPropertyData(handle);
+        return getPropertyValue(propertyData);
+    }
+    
+    @Override
+    public Object[] getPropertyValues(String[] propertyNames) {
+        Object[] values = new Object[propertyNames.length];
+        for (int i = 0; i < propertyNames.length; i++) {
+            Object value = null;
+            try {
+                value = getPropertyValue(propertyNames[i]);
+            } catch (UnknownPropertyException unknownPropertyException) {
+            } catch (WrappedTargetException wrappedTargetException) {
+            }
+            values[i] = value;
+        }
+        return values;
+    }
+
+    @Override
+    public void removePropertyChangeListener(
+            String propertyName, XPropertyChangeListener listener) throws UnknownPropertyException, WrappedTargetException {
+        // check existence:
+        getPropertyData(propertyName);
+        boundListeners.removeInterface(propertyName, listener);
+    }
+
+    @Override
+    public synchronized void removeVetoableChangeListener(
+            String propertyName, XVetoableChangeListener listener) throws UnknownPropertyException, WrappedTargetException {
+        // check existence:
+        getPropertyData(propertyName);
+        vetoableListeners.removeInterface(propertyName, listener);
+    }
+    
+    @Override
+    public void removePropertiesChangeListener(XPropertiesChangeListener listener) {
+        propertiesChangeListeners.remove(listener);
+    }
+
+    @Override
+    public void setPropertyValue(String propertyName, Object value)
+            throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException {
+        PropertyData propertyData = getPropertyData(propertyName);
+        setPropertyValue(propertyData, value);
+    }
+
+    @Override
+    public void setFastPropertyValue(int handle, Object value)
+            throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException {
+        PropertyData propertyData = getPropertyData(handle);
+        setPropertyValue(propertyData, value);
+    }
+
+    private void setPropertyValue(PropertyData propertyData, Object value)
+            throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException {
+        if ((propertyData.property.Attributes & PropertyAttribute.READONLY) != 0) {
+            throw new PropertyVetoException();
+        }
+        // The value may be null only if MAYBEVOID attribute is set         
+        boolean isVoid = false;
+        if (value instanceof Any) {
+            isVoid = ((Any) value).getObject() == null;
+        } else {
+            isVoid = value == null;
+        }
+        if (isVoid && (propertyData.property.Attributes & PropertyAttribute.MAYBEVOID) == 0) { 
+            throw new IllegalArgumentException("The property must have a value; the MAYBEVOID attribute is not set!");
+        }
+
+        // Check if the argument is allowed
+        boolean isValueOk = false;
+        if (value instanceof Any) {
+            isValueOk = checkType(((Any) value).getObject());
+        } else {
+            isValueOk = checkType(value);
+        }
+        if (!isValueOk) {
+            throw new IllegalArgumentException("No valid UNO type");
+        }
+
+        Object[] futureValue = new Object[] { AnyConverter.toObject(propertyData.property.Type, value) };
+        Object[] currentValue = new Object[] { getPropertyValue(propertyData.property.Name) };
+        Property[] properties = new Property[] { propertyData.property };
+        
+        fire(properties, currentValue, futureValue, false);
+        synchronized (lock) {
+            propertyData.setter.setValue(futureValue[0]);
+        }
+        fire(properties, currentValue, futureValue, true);
+    }
+    
+    @Override
+    public void setPropertyValues(String[] propertyNames, Object[] values) throws PropertyVetoException, IllegalArgumentException, WrappedTargetException {
+        for (int i = 0; i < propertyNames.length; i++) {
+            try {
+                setPropertyValue(propertyNames[i], values[i]);
+            } catch (UnknownPropertyException e) {
+                continue;
+            }
+        }
+    }
+
+    private boolean checkType(Object obj) {
+        if (obj == null 
+        || obj instanceof Boolean 
+        || obj instanceof Character
+        || obj instanceof Number
+        || obj instanceof String
+        || obj instanceof XInterface
+        || obj instanceof Type
+        || obj instanceof com.sun.star.uno.Enum
+        || obj.getClass().isArray())
+            return true;
+        return false;
+    }
+    
+    @Override
+    public void firePropertiesChangeEvent(String[] propertyNames, XPropertiesChangeListener listener) {
+        PropertyChangeEvent[] events = new PropertyChangeEvent[propertyNames.length];
+        int eventCount = 0;
+        for (int i = 0; i < propertyNames.length; i++) {
+            try {
+                PropertyData propertyData = getPropertyData(propertyNames[i]);
+                Object value = getPropertyValue(propertyNames[i]);
+                events[eventCount++] = new PropertyChangeEvent(eventSource, propertyNames[i],
+                        false, propertyData.property.Handle, value, value);
+            } catch (UnknownPropertyException unknownPropertyException) {
+            } catch (WrappedTargetException wrappedTargetException) {
+            }
+        }
+        if (eventCount > 0) {
+            if (events.length != eventCount) {
+                PropertyChangeEvent[] tmp = new PropertyChangeEvent[eventCount];
+                System.arraycopy(events, 0, tmp, 0, eventCount);
+                events = tmp;
+            }
+            listener.propertiesChange(events);
+        }
+    }
+    
+    private void fire(Property[] properties, Object[] oldValues, Object[] newValues, boolean hasChanged) throws PropertyVetoException {
+        PropertyChangeEvent[] events = new PropertyChangeEvent[properties.length];
+        int eventCount = 0;
+        for (int i = 0; i < properties.length; i++) {
+            if ((!hasChanged && (properties[i].Attributes & PropertyAttribute.CONSTRAINED) != 0) ||
+                    (hasChanged && (properties[i].Attributes & PropertyAttribute.BOUND) != 0)) {
+                events[eventCount++] = new PropertyChangeEvent(
+                        eventSource, properties[i].Name, false, properties[i].Handle, oldValues[i], newValues[i]);
+            }
+        }
+        for (int i = 0; i < eventCount; i++) {
+            fireListeners(hasChanged, events[i].PropertyName, events[i]);
+            fireListeners(hasChanged, "", events[i]);
+        }
+        if (hasChanged && eventCount > 0) {
+            if (eventCount != events.length) {
+                PropertyChangeEvent[] tmp = new PropertyChangeEvent[eventCount];
+                System.arraycopy(events, 0, tmp, 0, eventCount);
+                events = tmp;
+            }
+            for (Iterator<?> it = propertiesChangeListeners.iterator(); it.hasNext();) {
+                XPropertiesChangeListener listener = (XPropertiesChangeListener) it.next();
+                listener.propertiesChange(events);
+            }
+        }
+    }
+    
+    private void fireListeners(boolean hasChanged, String key, PropertyChangeEvent event) throws PropertyVetoException {
+        InterfaceContainer listeners;
+        if (hasChanged) {
+            listeners = boundListeners.getContainer(key);
+        } else {
+            listeners = vetoableListeners.getContainer(key);
+        }
+        if (listeners != null) {
+            Iterator<?> it = listeners.iterator();
+            while (it.hasNext()) {
+                Object listener = it.next();
+                if (hasChanged) {
+                    ((XPropertyChangeListener)listener).propertyChange(event);
+                } else {
+                    ((XVetoableChangeListener)listener).vetoableChange(event);
+                }
+            }
+        }
+    }
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySetAdapter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ISQLStatementHelper.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ISQLStatementHelper.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ISQLStatementHelper.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ISQLStatementHelper.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,28 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.sdbcx;
+
+import com.sun.star.beans.XPropertySet;
+
+public interface ISQLStatementHelper {
+    void addComment(XPropertySet propertySet, StringBuilder sql);
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ISQLStatementHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OCatalog.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OCatalog.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OCatalog.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OCatalog.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,169 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.sdbcx;
+
+import com.sun.star.container.XNameAccess;
+import com.sun.star.lang.DisposedException;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lib.uno.helper.ComponentBase;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XDatabaseMetaData;
+import com.sun.star.sdbc.XRow;
+import com.sun.star.sdbcx.XGroupsSupplier;
+import com.sun.star.sdbcx.XTablesSupplier;
+import com.sun.star.sdbcx.XUsersSupplier;
+import com.sun.star.sdbcx.XViewsSupplier;
+import com.sun.star.sdbcx.comp.postgresql.util.ComposeRule;
+import com.sun.star.sdbcx.comp.postgresql.util.DbTools;
+
+public abstract class OCatalog extends ComponentBase
+        implements XTablesSupplier, XViewsSupplier, XUsersSupplier, XGroupsSupplier, XServiceInfo {
+
+    private static final String[] services = {
+            "com.sun.star.sdbcx.DatabaseDefinition"
+    };
+    
+    protected final Object lock = new Object();
+    // Deleted on destruction, weakly held by caller:
+    protected OContainer tables;
+    protected OContainer views;
+    protected OContainer groups;
+    protected OContainer users;
+    protected XDatabaseMetaData metadata;
+    
+    public OCatalog(XDatabaseMetaData metadata) {
+        this.metadata = metadata; 
+    }
+    
+    private void checkDisposed() throws DisposedException {
+        if (bInDispose || bDisposed) {
+            throw new DisposedException();
+        }
+    }
+    
+    @Override
+    protected void postDisposing() {
+        synchronized (lock) {
+            if (tables != null) {
+                tables.dispose();
+            }
+            if (views != null) {
+                views.dispose();
+            }
+            if (groups != null) {
+                groups.dispose();
+            }
+            if (users != null) {
+                users.dispose();
+            }
+        }
+    }
+    
+    // XServiceInfo
+    
+    @Override
+    public String getImplementationName() {
+        return "com.sun.star.comp.connectivity.OCatalog";
+    }
+    
+    @Override
+    public String[] getSupportedServiceNames() {
+        return services.clone();
+    }
+    
+    @Override
+    public boolean supportsService(String serviceName) {
+        for (String service : getSupportedServiceNames()) {
+            if (service.equals(serviceName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    // X(Tables/Views/Groups/Users)Supplier
+    
+    @Override
+    public XNameAccess getTables() {
+        checkDisposed();
+        synchronized (lock) {
+            if (tables == null) {
+                tables = refreshTables();
+            }
+            return tables;
+        }
+    }
+    
+    @Override
+    public XNameAccess getViews() {
+        checkDisposed();
+        synchronized (lock) {
+            if (views == null) {
+                views = refreshViews();
+            }
+            return views;            
+        }
+    }
+    
+    @Override
+    public XNameAccess getGroups() {
+        checkDisposed();
+        synchronized (lock) {
+            if (groups == null) {
+                groups = refreshGroups();
+            }
+            return groups;
+        }
+    }
+    
+    @Override
+    public XNameAccess getUsers() {
+        checkDisposed();
+        synchronized (lock) {
+            if (users == null) {
+                users = refreshUsers();
+            }
+            return users;
+        }
+    }
+    
+    protected String buildName(XRow row) throws SQLException {
+        String catalog = row.getString(1);
+        if (row.wasNull()) {
+            catalog = "";
+        }
+        String schema = row.getString(2);
+        if (row.wasNull()) {
+            schema = null;
+        }
+        String table = row.getString(3);
+        if (row.wasNull()) {
+            table = "";
+        }
+        return DbTools.composeTableName(metadata, catalog, schema, table, false, ComposeRule.InDataManipulation);
+    }
+    
+    public abstract OContainer refreshTables();
+    public abstract OContainer refreshViews();
+    public abstract OContainer refreshGroups();
+    public abstract OContainer refreshUsers();
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OCatalog.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumn.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumn.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumn.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumn.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,279 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.sdbcx;
+
+import com.sun.star.beans.PropertyAttribute;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XNamed;
+import com.sun.star.lang.DisposedException;
+import com.sun.star.sdbc.ColumnValue;
+import com.sun.star.sdbcx.XDataDescriptorFactory;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySetAdapter.PropertyGetter;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySetAdapter.PropertySetter;
+import com.sun.star.sdbcx.comp.postgresql.sdbcx.descriptors.SdbcxColumnDescriptor;
+import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds;
+import com.sun.star.uno.Type;
+
+public class OColumn extends ODescriptor implements XNamed, XDataDescriptorFactory {
+    private String typeName;
+    private String description;
+    private String defaultValue;
+    private int isNullable;
+    private int precision;
+    private int scale;
+    private int type;
+    private boolean isAutoIncrement;
+    private boolean isRowVersion;
+    private boolean isCurrency;
+    
+    protected OColumn(final Object lock, final boolean isCaseSensitive) {
+        super(lock, "", isCaseSensitive);
+        this.isNullable = ColumnValue.NULLABLE;
+        this.precision = 0;
+        this.scale = 0;
+        this.type = 0;
+        this.isAutoIncrement = false;
+        this.isRowVersion = false;
+        this.isCurrency = false;
+        registerProperties();
+    }
+    
+    public static OColumn create(final boolean isCaseSensitive) {
+        final Object lock = new Object();
+        return new OColumn(lock, isCaseSensitive);
+    }
+    
+    protected OColumn(
+            final Object lock,
+            final String name,
+            final String typeName,
+            final String defaultValue,
+            final String description,
+            final int isNullable,
+            final int precision,
+            final int scale,
+            final int type,
+            final boolean isAutoIncrement,
+            final boolean isRowVersion,
+            final boolean isCurrency,
+            final boolean isCaseSensitive) {
+        super(lock, name, isCaseSensitive);
+        this.typeName = typeName;
+        this.description = description;
+        this.defaultValue = defaultValue;
+        this.isNullable = isNullable;
+        this.precision = precision;
+        this.scale = scale;
+        this.type = type;
+        this.isAutoIncrement = isAutoIncrement;
+        this.isRowVersion = isRowVersion;
+        this.isCurrency = isCurrency;
+        registerProperties();
+    }
+    
+    public static OColumn create(
+            final String name,
+            final String typeName,
+            final String defaultValue,
+            final String description,
+            final int isNullable,
+            final int precision,
+            final int scale,
+            final int type,
+            final boolean isAutoIncrement,
+            final boolean isRowVersion,
+            final boolean isCurrency,
+            final boolean isCaseSensitive) {
+        final Object lock = new Object();
+        return new OColumn(lock, name, typeName, defaultValue, description,
+                isNullable, precision, scale, type, isAutoIncrement, isRowVersion,
+                isCurrency, isCaseSensitive);
+    }
+    
+    private void registerProperties() {
+        registerProperty(PropertyIds.TYPENAME.name, PropertyIds.TYPENAME.id, Type.STRING, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return typeName;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        typeName = (String) value;
+                    }
+                });
+        registerProperty(PropertyIds.DESCRIPTION.name, PropertyIds.DESCRIPTION.id, Type.STRING, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return description;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        description = (String) value;
+                    }
+                });
+        registerProperty(PropertyIds.DEFAULTVALUE.name, PropertyIds.DEFAULTVALUE.id, Type.STRING, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return defaultValue;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        defaultValue = (String) value;
+                    }
+                });
+        registerProperty(PropertyIds.PRECISION.name, PropertyIds.PRECISION.id, Type.LONG, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return precision;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        precision = (Integer) value;
+                    }
+                });
+        registerProperty(PropertyIds.TYPE.name, PropertyIds.TYPE.id, Type.LONG, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return type;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        type = (Integer) value;
+                    }
+                });
+        registerProperty(PropertyIds.SCALE.name, PropertyIds.SCALE.id, Type.LONG, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return scale;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        scale = (Integer) value;
+                    }
+                });
+        registerProperty(PropertyIds.ISNULLABLE.name, PropertyIds.ISNULLABLE.id, Type.LONG, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return isNullable;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        isNullable = (Integer) value;
+                    }
+                });
+        registerProperty(PropertyIds.ISAUTOINCREMENT.name, PropertyIds.ISAUTOINCREMENT.id, Type.BOOLEAN, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return isAutoIncrement;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        isAutoIncrement = (Boolean) value;
+                    }
+                });
+        registerProperty(PropertyIds.ISROWVERSION.name, PropertyIds.ISROWVERSION.id, Type.BOOLEAN, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return isRowVersion;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        isRowVersion = (Boolean) value;
+                    }
+                });
+        registerProperty(PropertyIds.ISCURRENCY.name, PropertyIds.ISCURRENCY.id, Type.BOOLEAN, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return isCurrency;
+                        
+                    }
+                },
+                new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        isCurrency = (Boolean) value;
+                    }
+                });
+    }
+
+    // XComponent
+    
+    @Override
+    protected void postDisposing() {
+        super.postDisposing();
+    }
+    
+    private void checkDisposed() {
+        if (bDisposed) {
+            throw new DisposedException();
+        }
+    }
+    
+    // XDataDescriptorFactory
+    
+    @Override
+    public XPropertySet createDataDescriptor() {
+        SdbcxColumnDescriptor descriptor = SdbcxColumnDescriptor.create(isCaseSensitive());
+        synchronized (lock) {
+            CompHelper.copyProperties(this, descriptor);
+        }
+        return descriptor;
+    }
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumn.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumnContainer.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumnContainer.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumnContainer.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumnContainer.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,123 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.sdbcx;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.sdbc.ColumnValue;
+import com.sun.star.sdbc.DataType;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XDatabaseMetaData;
+import com.sun.star.sdbcx.comp.postgresql.sdbcx.SqlTableHelper.ColumnDescription;
+import com.sun.star.sdbcx.comp.postgresql.sdbcx.descriptors.SdbcxColumnDescriptor;
+import com.sun.star.sdbcx.comp.postgresql.util.DbTools;
+import com.sun.star.uno.UnoRuntime;
+
+public class OColumnContainer extends OContainer {
+    private OTable table;
+    private XDatabaseMetaData metadata;
+    private Map<String,ColumnDescription> columnDescriptions = new HashMap<>();
+    private Map<String,ExtraColumnInfo> extraColumnInfo = new HashMap<>();
+    
+    /// The XDatabaseMetaData.getColumns() data stored in columnDescriptions doesn't provide everything we need, so this class stores the rest.
+    public static class ExtraColumnInfo {
+        public boolean isAutoIncrement;
+        public boolean isCurrency;
+        public int dataType;
+    }
+    
+    public OColumnContainer(Object lock, boolean isCaseSensitive, List<ColumnDescription> columnDescriptions, OTable table, XDatabaseMetaData metadata) {
+        super(lock, isCaseSensitive, toColumnNames(columnDescriptions));
+        this.table = table;
+        this.metadata = metadata;
+        for (ColumnDescription columnDescription : columnDescriptions) {
+            this.columnDescriptions.put(columnDescription.columnName, columnDescription);
+        }
+    }
+    
+    private static List<String> toColumnNames(List<ColumnDescription> columns) {
+        List<String> columnNames = new ArrayList<>(columns.size());
+        for (ColumnDescription columnDescription : columns) {
+            columnNames.add(columnDescription.columnName);
+        }
+        return columnNames;
+    }
+    
+    @Override
+    public XPropertySet createObject(String name) throws SQLException {
+        boolean queryInfo = true;
+        boolean isAutoIncrement = false;
+        boolean isCurrency = false;
+        int dataType = DataType.OTHER;
+        ExtraColumnInfo columnInfo = extraColumnInfo.get(name);
+        if (columnInfo == null) {
+            String composedName = DbTools.composeTableNameForSelect(metadata.getConnection(), table);
+            extraColumnInfo = DbTools.collectColumnInformation(metadata.getConnection(), composedName, "*");
+            columnInfo = extraColumnInfo.get(name);
+        }
+        if (columnInfo != null) {
+            queryInfo = false;
+            isAutoIncrement = columnInfo.isAutoIncrement;
+            isCurrency = columnInfo.isCurrency;
+            dataType = columnInfo.dataType;
+        }
+        ColumnDescription columnDescription = columnDescriptions.get(name);
+        if (columnDescription != null) {
+            XNameAccess primaryKeyColumns = DbTools.getPrimaryKeyColumns(UnoRuntime.queryInterface(XPropertySet.class, table));
+            int nullable = columnDescription.nullable;
+            if (nullable != ColumnValue.NO_NULLS && primaryKeyColumns != null && primaryKeyColumns.hasByName(name)) {
+                nullable = ColumnValue.NO_NULLS;
+            }
+            return OColumn.create(name, columnDescription.typeName, columnDescription.defaultValue, columnDescription.remarks,
+                    nullable, columnDescription.columnSize, columnDescription.decimalDigits, columnDescription.type,
+                    isAutoIncrement, false, isCurrency, isCaseSensitive());
+        } else {
+            // FIXME: do something like the C++ implementation does?
+            throw new SQLException();
+        }
+    }
+    
+    @Override
+    public XPropertySet createDescriptor() {
+        return SdbcxColumnDescriptor.create(isCaseSensitive());
+    }
+    
+    @Override
+    public void impl_refresh() {
+        extraColumnInfo.clear();
+        table.refreshColumns();
+    }
+    
+    @Override
+    public XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException {
+        return null;
+    }
+    
+    @Override
+    public void dropObject(int index, String name) throws SQLException {
+    }
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumnContainer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OContainer.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OContainer.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OContainer.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OContainer.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,461 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.sdbcx;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.ContainerEvent;
+import com.sun.star.container.ElementExistException;
+import com.sun.star.container.NoSuchElementException;
+import com.sun.star.container.XContainer;
+import com.sun.star.container.XContainerListener;
+import com.sun.star.container.XEnumeration;
+import com.sun.star.container.XEnumerationAccess;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.IndexOutOfBoundsException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lib.uno.helper.InterfaceContainer;
+import com.sun.star.lib.uno.helper.WeakBase;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XColumnLocate;
+import com.sun.star.sdbcx.XAppend;
+import com.sun.star.sdbcx.XDataDescriptorFactory;
+import com.sun.star.sdbcx.XDrop;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.OEnumerationByIndex;
+import com.sun.star.sdbcx.comp.postgresql.util.StandardSQLState;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.util.XRefreshListener;
+import com.sun.star.util.XRefreshable;
+
+public abstract class OContainer extends WeakBase implements
+        XNameAccess, XIndexAccess, XEnumerationAccess,
+        XContainer, XColumnLocate, XRefreshable, XDataDescriptorFactory,
+        XAppend, XDrop, XServiceInfo {
+
+    private static String[] services = new String[] {
+            "com.sun.star.sdbcx.Container"
+    };
+    
+    protected final Object lock;
+    private final boolean isCaseSensitive;
+    private TreeMap<String,HashMap<Long,XPropertySet>> entriesByNameAndId;
+    private ArrayList<PropertyInfo> entriesByIndex;
+    private long nextId;
+    private InterfaceContainer containerListeners = new InterfaceContainer();
+    private InterfaceContainer refreshListeners = new InterfaceContainer();
+
+    /// Names aren't necessarily unique, we have to de-duplicate by id. 
+    private static class PropertyInfo {
+        String name;
+        long id;
+
+        PropertyInfo(String name, long id) {
+            this.name = name;
+            this.id = id;
+        }
+    }
+    
+    private Comparator<String> caseSensitiveComparator = new Comparator<String>() {
+        @Override
+        public int compare(String x, String y) {
+            if (isCaseSensitive) {
+                return x.compareTo(y);
+            } else {
+                return x.compareToIgnoreCase(y);
+            }
+        }
+    };
+
+    public OContainer(Object lock, boolean isCaseSensitive, List<String> names) {
+        this.lock = lock;
+        this.isCaseSensitive = isCaseSensitive;
+        this.entriesByNameAndId = new TreeMap<String,HashMap<Long,XPropertySet>>(caseSensitiveComparator);
+        this.entriesByIndex = new ArrayList<>(names.size());
+        for (String name : names) {
+            HashMap<Long,XPropertySet> entriesById = entriesByNameAndId.get(name);
+            if (entriesById == null) {
+                entriesById = new HashMap<>();
+                entriesByNameAndId.put(name, entriesById);
+            }
+            entriesById.put(nextId, null);
+            
+            entriesByIndex.add(new PropertyInfo(name, nextId));
+            ++nextId;
+        }
+    }
+    
+    // Would be from XComponent ;)
+    
+    public void dispose() {
+        EventObject event = new EventObject(this);
+        containerListeners.disposeAndClear(event);
+        refreshListeners.disposeAndClear(event);
+        
+        synchronized (lock) {
+            for (Map<Long,XPropertySet> entriesById : entriesByNameAndId.values()) {
+                for (XPropertySet propertySet : entriesById.values()) {
+                    CompHelper.disposeComponent(propertySet);
+                }
+            }
+            entriesByNameAndId.clear();
+            entriesByIndex.clear();
+        }
+    }
+
+    // XServiceInfo
+    
+    public String getImplementationName() {
+        return "com.sun.star.sdbcx.VContainer";
+    }
+    
+    @Override
+    public String[] getSupportedServiceNames() {
+        return services.clone();
+    }
+    
+    @Override
+    public boolean supportsService(String serviceName) {
+        for (String service : services) {
+            if (service.equals(serviceName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    // XIndexAccess
+    
+    @Override
+    public Object getByIndex(int index) throws IndexOutOfBoundsException, WrappedTargetException {
+        synchronized (lock) {
+            if (index < 0 || index >= entriesByIndex.size()) {
+                throw new IndexOutOfBoundsException(Integer.toString(index), this);
+            }
+            return getObject(index);
+        }
+    }
+    
+    @Override
+    public int getCount() {
+        synchronized (lock) {
+            return entriesByIndex.size();
+        }
+    }
+    
+    // XNameAccess
+    
+    @Override
+    public boolean hasByName(String name) {
+        synchronized (lock) {
+            return entriesByNameAndId.containsKey(name);
+        }
+    }
+
+    @Override
+    public Object getByName(String name) throws NoSuchElementException, WrappedTargetException {
+        synchronized (lock) {
+            if (!entriesByNameAndId.containsKey(name)) {
+                String error = SharedResources.getInstance().getResourceStringWithSubstitution(
+                        Resources.STR_NO_ELEMENT_NAME, "$name$", name);
+                throw new NoSuchElementException(error, this);
+            }
+            return getObject(indexOf(name));
+        }
+    }
+    
+    @Override
+    public String[] getElementNames() {
+        synchronized (lock) {
+            String[] names = new String[entriesByIndex.size()];
+            int next = 0;
+            for (PropertyInfo propertyInfo : entriesByIndex) {
+                names[next++] = propertyInfo.name;
+            }
+            return names;
+        }
+    }
+    
+    // XRefreshable
+    
+    @Override
+    public void refresh() {
+        Iterator iterator;
+        synchronized (lock) {
+            for (Map<Long,XPropertySet> entriesById : entriesByNameAndId.values()) {
+                for (XPropertySet propertySet : entriesById.values()) {
+                    CompHelper.disposeComponent(propertySet);
+                }
+            }
+            entriesByNameAndId.clear();
+            entriesByIndex.clear();
+
+            impl_refresh();
+            
+            iterator = refreshListeners.iterator();
+        }
+        EventObject event = new EventObject(this);
+        while (iterator.hasNext()) {
+            XRefreshListener listener = (XRefreshListener) iterator.next();
+            listener.refreshed(event);
+        }
+    }
+
+    // XDataDescriptorFactory
+    
+    @Override
+    public XPropertySet createDataDescriptor() {
+        synchronized (lock) {
+            return createDescriptor();
+        }
+    }
+    
+    protected String getNameForObject(XPropertySet object) {
+        try {
+            Object ret = object.getPropertyValue("Name");
+            return AnyConverter.toString(ret);
+        } catch (WrappedTargetException wrappedTargetException) {
+        } catch (UnknownPropertyException unknownPropertyException) {
+        } catch (IllegalArgumentException illegalArgumentException) {
+        }
+        return null;
+    }
+    
+    // XAppend
+    
+    @Override
+    public void appendByDescriptor(XPropertySet descriptor) throws SQLException, ElementExistException {
+        Iterator iterator;
+        ContainerEvent event;
+        synchronized (lock) {
+            String name = getNameForObject(descriptor);
+            
+            if (entriesByNameAndId.containsKey(name)) {
+                throw new ElementExistException(name, this);
+            }
+            
+            XPropertySet newlyCreated = appendObject(name, descriptor);
+            if (newlyCreated == null) {
+                throw new RuntimeException();
+            }
+            
+            name = getNameForObject(newlyCreated);
+            HashMap<Long,XPropertySet> entriesById = entriesByNameAndId.get(name);
+            if (entriesById == null) { // this may happen when the derived class included it itself
+                entriesById = new HashMap<>();
+                entriesById.put(nextId, newlyCreated);
+                entriesByNameAndId.put(name, entriesById);
+                entriesByIndex.add(new PropertyInfo(name, nextId));
+                nextId++;
+            }
+            
+            // notify our container listeners
+            event = new ContainerEvent(this, name, newlyCreated, null);
+            iterator = containerListeners.iterator();
+        }
+        while (iterator.hasNext()) {
+            XContainerListener listener = (XContainerListener) iterator.next();
+            listener.elementInserted(event);
+        }
+        
+    }
+    
+    // XDrop
+    
+    @Override
+    public void dropByName(String name) throws SQLException, NoSuchElementException {
+        synchronized (lock) {
+            if (!entriesByNameAndId.containsKey(name)) {
+                throw new NoSuchElementException(name, this);
+            }
+            dropImpl(indexOf(name));
+        }
+    }
+
+    @Override
+    public void dropByIndex(int index) throws SQLException, IndexOutOfBoundsException {
+        synchronized (lock) {
+            if (index < 0 || index >= entriesByIndex.size()) {
+                throw new IndexOutOfBoundsException(Integer.toString(index), this);
+            }
+            dropImpl(index);
+        }
+    }
+    
+    
+    private void dropImpl(int index) throws SQLException {
+        dropImpl(index, true);
+    }
+
+    private void dropImpl(int index, boolean reallyDrop) throws SQLException {
+        PropertyInfo propertyInfo = entriesByIndex.get(index);
+        if (reallyDrop) {
+            dropObject(index, propertyInfo.name);
+        }
+        HashMap<Long,XPropertySet> entriesById = entriesByNameAndId.get(propertyInfo.name);
+        XPropertySet propertySet = entriesById.remove(propertyInfo.id);
+        if (entriesById.isEmpty()) {
+            entriesByNameAndId.remove(propertyInfo.name);
+        }
+        CompHelper.disposeComponent(propertySet);
+        entriesByIndex.remove(index);
+        
+        ContainerEvent event = new ContainerEvent(this, propertyInfo.name, null, null);
+        for (Iterator iterator = containerListeners.iterator(); iterator.hasNext(); ) {
+            XContainerListener listener = (XContainerListener) iterator.next();
+            listener.elementRemoved(event);
+        }
+    }
+    
+    // XColumnLocate
+    
+    @Override
+    public int findColumn(String name) throws SQLException {
+        if (!entriesByNameAndId.containsKey(name)) {
+            String error = SharedResources.getInstance().getResourceStringWithSubstitution(
+                    Resources.STR_UNKNOWN_COLUMN_NAME, "$columnname$", name);
+            throw new SQLException(error, this, StandardSQLState.SQL_COLUMN_NOT_FOUND.text(), 0, null);
+        }
+        return indexOf(name) + 1; // because columns start at one
+    }
+    
+    
+    // XEnumerationAccess
+    
+    @Override
+    public XEnumeration createEnumeration() {
+        return new OEnumerationByIndex(this);
+    }
+
+    @Override
+    public void addContainerListener(XContainerListener listener) {
+        containerListeners.add(listener);
+    }
+    
+    @Override
+    public void removeContainerListener(XContainerListener listener) {
+        containerListeners.remove(listener);
+    }
+    
+    @Override
+    public Type getElementType() {
+        return new Type(XPropertySet.class);
+    }
+    
+    @Override
+    public boolean hasElements() {
+        synchronized (lock) {
+            return !entriesByNameAndId.isEmpty();
+        }
+    }
+    
+    @Override
+    public void addRefreshListener(XRefreshListener listener) {
+        synchronized (lock) {
+            refreshListeners.add(listener);
+        }
+    }
+    
+    @Override
+    public void removeRefreshListener(XRefreshListener listener) {
+        synchronized (lock) {
+            refreshListeners.remove(listener);
+        }
+    }
+    
+    protected int indexOf(String name) {
+        for (int i = 0; i < entriesByIndex.size(); i++) {
+            if (entriesByIndex.get(i).name.equals(name)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+    
+    protected Object getObject(int index) throws WrappedTargetException {
+        PropertyInfo propertyInfo = entriesByIndex.get(index);
+        HashMap<Long,XPropertySet> entriesById = entriesByNameAndId.get(propertyInfo.name);
+        XPropertySet propertySet = entriesById.get(propertyInfo.id);
+        if (propertySet == null) {
+            try {
+                propertySet = createObject(propertyInfo.name);
+            } catch (SQLException e) {
+                try {
+                    dropImpl(index, false);
+                } catch (Exception ignored) {
+                }
+                throw new WrappedTargetException(e.getMessage(), this, e);
+            }
+            entriesById.put(propertyInfo.id, propertySet);
+        }
+        return propertySet;
+    }
+    
+    protected XPropertySet cloneDescriptor(XPropertySet descriptor) {
+        XPropertySet newDescriptor = createDescriptor();
+        CompHelper.copyProperties(descriptor, newDescriptor);
+        return newDescriptor;
+    }
+    
+    protected boolean isCaseSensitive() {
+        return isCaseSensitive;
+    }
+    
+    // will be called when a object was requested by one of the accessing methods like getByIndex
+    public abstract XPropertySet createObject(final String name) throws SQLException;
+
+    public abstract void dropObject(int index, String name) throws SQLException;
+    
+    // the implementing class should refresh their elements
+    public abstract void impl_refresh();
+    
+    // will be called when a new object should be generated by a call of createDataDescriptor
+    // the returned object is empty will be filled outside and added to the collection
+    public abstract XPropertySet createDescriptor();
+    
+    /** appends an object described by a descriptor, under a given name
+        @param _rForName
+            is the name under which the object should be appended. Guaranteed to not be empty.
+            This is passed for convenience only, since it's the result of a call of
+            getNameForObject for the given descriptor
+        @param descriptor
+            describes the object to append
+        @return
+            the new object which is to be inserted into the collection. This might be the result
+            of a call of <code>createObject( _rForName )</code>, or a clone of the descriptor.
+    */
+    public abstract XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException;
+
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OContainer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ODescriptor.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ODescriptor.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ODescriptor.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ODescriptor.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,76 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.sdbcx;
+
+import com.sun.star.beans.PropertyAttribute;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySet;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySetAdapter.PropertyGetter;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySetAdapter.PropertySetter;
+import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds;
+import com.sun.star.uno.Type;
+
+public class ODescriptor extends PropertySet {
+    private String name;
+    private final boolean isCaseSensitive;
+    protected final Object lock;
+    
+    public ODescriptor(Object lock, String name, boolean isCaseSensitive, boolean isReadOnly) {
+        super(lock);
+        this.lock = lock;
+        this.name = name;
+        this.isCaseSensitive = isCaseSensitive;
+        registerProperties(isReadOnly);
+    }
+
+    public ODescriptor(Object lock, String name, boolean isCaseSensitive) {
+        this(lock, name, isCaseSensitive, true);
+    }
+
+    private void registerProperties(boolean isReadOnly) {
+        registerProperty(PropertyIds.NAME.name, PropertyIds.NAME.id, Type.STRING, isReadOnly ? PropertyAttribute.READONLY : 0,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return name;
+                        
+                    }
+                },
+                isReadOnly ? null : new PropertySetter() {
+                    @Override
+                    public void setValue(Object value) {
+                        name = (String) value;
+                    }
+                });
+    }
+
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    public boolean isCaseSensitive() {
+        return isCaseSensitive;
+    }
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ODescriptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndex.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndex.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndex.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndex.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,121 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.sdbcx;
+
+import java.util.List;
+
+import com.sun.star.beans.PropertyAttribute;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbcx.XColumnsSupplier;
+import com.sun.star.sdbcx.XDataDescriptorFactory;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySetAdapter.PropertyGetter;
+import com.sun.star.sdbcx.comp.postgresql.sdbcx.descriptors.SdbcxIndexDescriptor;
+import com.sun.star.sdbcx.comp.postgresql.util.DbTools;
+import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds;
+import com.sun.star.uno.Type;
+
+public class OIndex extends ODescriptor implements XColumnsSupplier, XDataDescriptorFactory {
+    protected String catalogName;
+    protected boolean isUnique;
+    protected boolean isPrimaryKeyIndex;
+    protected boolean isClustered;
+    private OTable table;
+    private OContainer columns;
+    
+    protected OIndex(Object lock, String name, boolean isCaseSensitive, String catalogName,
+            boolean isUnique, boolean isPrimaryKeyIndex, boolean isClustered, List<String> columnNames, OTable table) {
+        super(lock, name, isCaseSensitive);
+        this.catalogName = catalogName;
+        this.isUnique = isUnique;
+        this.isPrimaryKeyIndex = isPrimaryKeyIndex;
+        this.isClustered = isClustered;
+        this.table = table;
+        columns = new OIndexColumnContainer(lock, this, columnNames);
+        registerProperties();
+    }
+    
+    public static OIndex create(String name, boolean isCaseSensitive, String catalogName,
+            boolean isUnique, boolean isPrimaryKeyIndex, boolean isClustered, List<String> columnNames, OTable table) {
+        final Object lock = new Object();
+        return new OIndex(lock, name, isCaseSensitive, catalogName, isUnique, isPrimaryKeyIndex, isClustered, columnNames, table);
+    }
+    
+    private void registerProperties() {
+        registerProperty(PropertyIds.CATALOG.name, PropertyIds.CATALOG.id, Type.STRING, (short)PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return catalogName;
+                    }
+                }, null);
+        registerProperty(PropertyIds.ISPRIMARYKEYINDEX.name, PropertyIds.ISPRIMARYKEYINDEX.id, Type.BOOLEAN, (short)PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return isPrimaryKeyIndex;
+                    }
+                }, null);
+        registerProperty(PropertyIds.ISCLUSTERED.name, PropertyIds.ISCLUSTERED.id, Type.BOOLEAN, (short)PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return isClustered;
+                    }
+                }, null);
+        registerProperty(PropertyIds.ISUNIQUE.name, PropertyIds.ISUNIQUE.id, Type.BOOLEAN, (short)PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return isUnique;
+                    }
+                }, null);
+    }
+    
+    @Override
+    public XPropertySet createDataDescriptor() {
+        SdbcxIndexDescriptor descriptor = SdbcxIndexDescriptor.create(isCaseSensitive());
+        CompHelper.copyProperties(this, descriptor);
+        try {
+            DbTools.cloneDescriptorColumns(this, descriptor);
+        } catch (SQLException sqlException) {
+        }
+        return descriptor;
+    }
+    
+    @Override
+    public XNameAccess getColumns() {
+        return columns;
+    }
+    
+    public OTable getTable() {
+        return table;
+    }
+
+    @Override
+    public String toString() {
+        return "OIndex [catalogName=" + catalogName + ", isUnique=" + isUnique + ", isPrimaryKeyIndex=" + isPrimaryKeyIndex + ", isClustered=" + isClustered
+                + ", name=" + getName() + "]";
+    }
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndex.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumn.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumn.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumn.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumn.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,96 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.sdbcx;
+
+import com.sun.star.beans.PropertyAttribute;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySetAdapter.PropertyGetter;
+import com.sun.star.sdbcx.comp.postgresql.sdbcx.descriptors.SdbcxIndexColumnDescriptor;
+import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds;
+import com.sun.star.uno.Type;
+
+public class OIndexColumn extends OColumn {
+    protected boolean isAscending;
+    
+    protected OIndexColumn(
+            final Object lock,
+            final boolean isAscending,
+            final String name,
+            final String typeName,
+            final String defaultValue,
+            final String description,
+            final int isNullable,
+            final int precision,
+            final int scale,
+            final int type,
+            final boolean isAutoIncrement,
+            final boolean isRowVersion,
+            final boolean isCurrency,
+            final boolean isCaseSensitive) {
+        super(lock, name, typeName, defaultValue, description, isNullable,
+                precision, scale, type, isAutoIncrement, isRowVersion, isCurrency, isCaseSensitive);
+        this.isAscending = isAscending;
+        registerProperties();
+    }
+    
+    public static OIndexColumn create(
+            final boolean isAscending,
+            final String name,
+            final String typeName,
+            final String defaultValue,
+            final int isNullable,
+            final int precision,
+            final int scale,
+            final int type,
+            final boolean isAutoIncrement,
+            final boolean isRowVersion,
+            final boolean isCurrency,
+            final boolean isCaseSensitive) {
+        final Object lock = new Object();
+        return new OIndexColumn(lock, isAscending, name, typeName,
+                defaultValue, "", isNullable, precision, scale,
+                type, isAutoIncrement, isRowVersion, isCurrency, isCaseSensitive);
+    }
+    
+    private void registerProperties() {
+        registerProperty(PropertyIds.ISASCENDING.name, PropertyIds.ISASCENDING.id, Type.BOOLEAN, PropertyAttribute.READONLY,
+                new PropertyGetter() {
+                    @Override
+                    public Object getValue() {
+                        return isAscending;
+                        
+                    }
+                }, null);
+    }
+    
+    // XDataDescriptorFactory
+    
+    @Override
+    public XPropertySet createDataDescriptor() {
+        SdbcxIndexColumnDescriptor descriptor = SdbcxIndexColumnDescriptor.create(isCaseSensitive());
+        synchronized (lock) {
+            CompHelper.copyProperties(this, descriptor);
+        }
+        return descriptor;
+    }
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumn.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumnContainer.java
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumnContainer.java?rev=1805579&view=auto
==============================================================================
--- openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumnContainer.java (added)
+++ openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumnContainer.java Sun Aug 20 19:16:28 2017
@@ -0,0 +1,121 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package com.sun.star.sdbcx.comp.postgresql.sdbcx;
+
+import java.util.List;
+
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XResultSet;
+import com.sun.star.sdbc.XRow;
+import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper;
+import com.sun.star.sdbcx.comp.postgresql.sdbcx.descriptors.SdbcxIndexColumnDescriptor;
+import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds;
+import com.sun.star.sdbcx.comp.postgresql.util.StandardSQLState;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.UnoRuntime;
+
+public class OIndexColumnContainer extends OContainer {
+    private OIndex index;
+    
+    public OIndexColumnContainer(Object lock, OIndex index, List<String> columnNames) {
+        super(lock, true, columnNames);
+        this.index = index;
+    }
+    
+    @Override
+    public XPropertySet createDescriptor() {
+        return SdbcxIndexColumnDescriptor.create(isCaseSensitive());
+    }
+    
+    @Override
+    public XPropertySet createObject(String name) throws SQLException {
+        try {
+            Object catalog = index.getTable().getPropertyValue(PropertyIds.CATALOGNAME.name);
+            String schema = AnyConverter.toString(index.getTable().getPropertyValue(PropertyIds.SCHEMANAME.name));
+            String table = AnyConverter.toString(index.getTable().getPropertyValue(PropertyIds.NAME.name));
+            
+            boolean isAscending = true;
+            XResultSet results = null;
+            try {
+                results = index.getTable().getConnection().getMetaData().getIndexInfo(catalog, schema, table, false, false);
+                if (results != null) {
+                    XRow row = UnoRuntime.queryInterface(XRow.class, results);
+                    while (results.next()) {
+                        if (row.getString(9).equals(name)) {
+                            isAscending = !row.getString(10).equals("D");
+                        }
+                    }
+                }
+            } finally {
+                CompHelper.disposeComponent(results);
+            }
+            
+            XPropertySet ret = null;
+            results = null;
+            try {
+                results = index.getTable().getConnection().getMetaData().getColumns(catalog, schema, table, name);
+                if (results != null) {
+                    XRow row = UnoRuntime.queryInterface(XRow.class, results);
+                    while (results.next()) {
+                        if (row.getString(4).equals(name)) {
+                            int dataType = row.getInt(5);
+                            String typeName = row.getString(6);
+                            int size = row.getInt(7);
+                            int dec = row.getInt(9);
+                            int nul = row.getInt(11);
+                            String columnDef = row.getString(13);
+                            
+                            ret = OIndexColumn.create(isAscending, name, typeName, columnDef,
+                                    nul, size, dec, dataType, false, false, false, isCaseSensitive());
+                            break;
+                        }
+                    }
+                }
+            } finally {
+                CompHelper.disposeComponent(results);
+            }
+            
+            return ret;
+        } catch (WrappedTargetException | UnknownPropertyException | IllegalArgumentException exception) {
+            throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, exception);
+        } 
+    }
+
+    @Override
+    public void impl_refresh() {
+        // FIXME
+    }
+    
+    @Override
+    public XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException {
+        throw new SQLException("Unsupported");
+    }
+    
+    @Override
+    public void dropObject(int index, String name) throws SQLException {
+        throw new SQLException("Unsupported");
+    }
+}

Propchange: openoffice/trunk/main/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumnContainer.java
------------------------------------------------------------------------------
    svn:eol-style = native