diff options
author | Damjan Jovanovic <damjan@apache.org> | 2017-08-20 19:16:28 +0000 |
---|---|---|
committer | Damjan Jovanovic <damjan@apache.org> | 2017-08-20 19:16:28 +0000 |
commit | 330392f87e90e4345273d42425b3ffc735281a7c (patch) | |
tree | fd3296aa82cf4ba3bcc659cd3776c1df3083bdb0 /connectivity | |
parent | 6dd83d1c6c5c580d14ca3d0458be4020603ba118 (diff) |
#i127350# - Table design: can't change length of Postgresql char types
Add the initial version of a new SDBC driver, for the PostgreSQL database.
Also its build changes: since it needs Apache Commons Lang version 3,
get configure.ac to check for that, and get that to always build,
just like our driver does.
Patch by: me
Notes
Notes:
prefer: e28033fdfad9750ebe96885b9514adee629acf88
Diffstat (limited to 'connectivity')
64 files changed, 11210 insertions, 2 deletions
diff --git a/connectivity/java/sdbc_postgresql/build.xml b/connectivity/java/sdbc_postgresql/build.xml new file mode 100644 index 000000000000..42f8b5d33970 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/build.xml @@ -0,0 +1,249 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--*********************************************************** + * + * 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. + * + ***********************************************************--> + + +<project name="sdbc_postgresql" default="main" basedir="."> + + <!-- ================================================================= --> + <!-- settings --> + <!-- ================================================================= --> + + <!-- global properties --> + <property file="../../../ant.properties"/> + <!-- version info --> + <property file="../../../solenv/inc/minor.mk"/> + + <!-- name of this sub target used in recursive builds --> + <property name="target" value="sdbc_postgresql"/> + + <!-- name of jar file created, without .jar extension --> + <property name="jarname" value="sdbc_postgresql"/> + + <!-- relative path to project directory --> + <property name="prj" value="../.."/> + + <!-- build output directory --> + <!-- FIXME: there are also extremely rare/obsolete dbcs/bndchk/truetime/hbtoolkit cases in main/solenv/inc/settings.mk --> + <condition property="out" value="${prj}/${OUTPATH}.cap"> + <isset property="${profile}"/> + </condition> + <condition property="out" value="${prj}/${OUTPATH}.pro"> + <isset property="${PRODUCT}"/> + </condition> + <property name="out" value="${prj}/${OUTPATH}"/> + + <!-- build directories --> + <property name="build.dir" value="${out}"/> + <property name="build.class" value="${build.dir}/class/${target}"/> + <property name="build.misc" value="${build.dir}/misc/${target}"/> + + <!-- start of java source code package structure --> + <property name="java.dir" value="src"/> + + <!-- define how to handle CLASSPATH environment --> + <property name="build.sysclasspath" value="ignore"/> + + <!-- classpath settings for compile and javadoc tasks --> + <condition property="jar-class-path" value="${COMMONS_LANG_JAR}" else="commons-lang3-3.3.jar"> + <equals arg1="${SYSTEM_APACHE_COMMONS}" arg2="YES"/> + </condition> + <condition property="commons-lang-jar" value="${COMMONS_LANG_JAR}" else="${OUTDIR}/bin/commons-lang3-3.3.jar"> + <equals arg1="${SYSTEM_APACHE_COMMONS}" arg2="YES"/> + </condition> + <path id="classpath"> + <pathelement location="${OUTDIR}/bin/juh.jar"/> + <pathelement location="${OUTDIR}/bin/jurt.jar"/> + <pathelement location="${OUTDIR}/bin/ridl.jar"/> + <pathelement location="${OUTDIR}/bin/unoil.jar"/> + <!-- 3rd party libs --> + <pathelement location="${commons-lang-jar}"/> + </path> + + <!-- name to display in documentation --> + <property name="docname" value="sdbc_postgresql"/> + + <!-- set "modern" java compiler --> + <property name="build.compiler" value="modern"/> + + <!-- set wether we want to compile with debug information --> + <property name="debug" value="on"/> + + <!-- set wether we want to compile with optimisation --> + <property name="optimize" value="off"/> + + <!-- set wether we want to compile with or without deprecation --> + <property name="deprecation" value="on"/> + + <target name="info"> + <echo message="--------------------"/> + <echo message="${target}"/> + <echo message="--------------------"/> + </target> + + <!-- ================================================================= --> + <!-- custom targets --> + <!-- ================================================================= --> + + <!-- the main target, called in recursive builds --> + <target name="main" depends="info,prepare,compile,jar,javadoc,zipdoc"/> + + <!-- prepare output directories --> + <target name="prepare"> + <mkdir dir="${build.dir}"/> + <mkdir dir="${build.dir}/doc/${target}"/> + <mkdir dir="${build.class}"/> + <mkdir dir="${build.misc}"/> + </target> + + + <target name="res" depends="prepare"> + <copy todir="${build.class}"> + <fileset dir="${java.dir}"> + <include name="**/*.properties"/> + <include name="**/*.css"/> + <include name="**/*.dtd"/> + <include name="**/*.form"/> + <include name="**/*.gif "/> + <include name="**/*.htm"/> + <include name="**/*.html"/> + <include name="**/*.js"/> + <include name="**/*.mod"/> + <include name="**/*.sql"/> + <include name="**/*.xml"/> + <include name="**/*.xsl"/> + <include name="**/*.map"/> + + </fileset> + </copy> + </target> + + + <target name="compile" depends="prepare,res"> + <javac destdir="${build.class}" + debug="${debug}" + debuglevel="lines,vars,source" + deprecation="${deprecation}" + optimize="${optimize}" + classpathref="classpath"> + <src path="${java.dir}"/> + <include name="**/*.java"/> + </javac> + </target> + + <!-- check if javadoc is up to date --> + <target name="javadoc_check" depends="prepare" if="build.dir"> + <uptodate property="javadocBuild.notRequired" value="true" + targetfile="${build.dir}/doc/${target}/${target}_javadoc.zip"> + <srcfiles dir="${java.dir}" includes="**/*.java"/> + </uptodate> + </target> + + <!-- generate java documentation --> + <target name="javadoc" depends="prepare,javadoc_check,compile" + unless="javadocBuild.notRequired" + if="build.dir"> + + <javadoc destdir="${build.dir}/doc/${target}/javadoc" + verbose="false" + author="false" + nodeprecated="true" + nodeprecatedlist="true" + use="true" + Doctitle="${docname}" + windowtitle="${docname}" + classpathref="classpath"> + + <packageset dir="${java.dir}" defaultexcludes="yes"> + <include name="com/**"/> + <include name="org/**"/> + </packageset> + + <link offline="true" href="http://java.sun.com/j2se/1.4.2/docs/api" + packagelistLoc="${common.doc}/jdk1.4.2"/> + <link offline="true" + href="http://java.sun.com/products/servlet/2.3/javadoc" + packagelistLoc="${common.doc}/servlet2.3"/> + <link offline="true" + href="http://logging.apache.org/log4j/docs/api" + packagelistLoc="${common.doc}/log4j-1.2.8"/> + <link offline="true" + href="http://java.sun.com/products/javabeans/glasgow/javadocs" + packagelistLoc="${common.doc}/jaf-1.0.2"/> + <link offline="true" + href="http://java.sun.com/products/javamail/javadocs" + packagelistLoc="${common.doc}/javamail-1.3.1"/> + <link offline="true" + href="http://ws.apache.org/soap/docs" + packagelistLoc="${common.doc}/soap-2.3.1"/> + + <bottom><i>Copyright &#169; 2004 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303 USA</i></bottom> + <header>${docname}</header> + + </javadoc> + </target> + + <!-- zip documentation and store in build/doc/${target} --> + <target name="zipdoc" depends="javadoc" if="build.dir" unless="javadocBuild.notRequired"> + <zip zipfile="${build.dir}/doc/${target}/${target}_javadoc.zip" + basedir="${build.dir}/doc/${target}/javadoc" + update="true"/> + </target> + + <!-- clean up --> + <target name="clean" depends="prepare"> + <delete dir="${build.class}" includeEmptyDirs="true"/> + <delete dir="${build.dir}/doc/${target}" includeEmptyDirs="true"/> + </target> + + <!-- create jar file --> + <target name="jar" depends="prepare,compile" if="build.class"> + <jar jarfile="${build.class}/${jarname}.jar" + basedir="${build.class}"> + <manifest> + <attribute name="Class-Path" value="${jar-class-path} juh.jar jurt.jar ridl.jar unoil.jar"/> + <attribute name="Solar-Version" value="${RSCREVISION}"/> + <attribute name="RegistrationClassName" value="com.sun.star.sdbcx.comp.postgresql.PostgresqlDriver"/> + <attribute name="Sealed" value="true"/> + <attribute name="UNO-Type-Path" value=""/> + </manifest> + <include name="**/*.class"/> + <include name="**/*.properties"/> + <include name="**/*.css"/> + <include name="**/*.dtd"/> + <include name="**/*.form"/> + <include name="**/*.gif "/> + <include name="**/*.htm"/> + <include name="**/*.html"/> + <include name="**/*.js"/> + <include name="**/*.mod"/> + <include name="**/*.sql"/> + <include name="**/*.xml"/> + <include name="**/*.xsl"/> + <include name="**/*.map"/> + </jar> + </target> + + <target name="test" depends="prepare"> + </target> + +</project> + diff --git a/connectivity/java/sdbc_postgresql/makefile.mk b/connectivity/java/sdbc_postgresql/makefile.mk new file mode 100644 index 000000000000..bab2fc72a123 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/makefile.mk @@ -0,0 +1,50 @@ +#************************************************************** +# +# 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. +# +#************************************************************** + + + +PRJ=..$/.. +PRJNAME=connectivity +TARGET=sdbc_postgresql + +# --- Settings ----------------------------------------------------- + +.INCLUDE : $(PRJ)$/makefile.pmk +.INCLUDE : $(PRJ)$/version.mk + +.IF defined(debug) || defined(DEBUG) +ANTDEBUG=true +.ELSE +ANTDEBUG=off +.ENDIF + +ANT_FLAGS+=-Dantdebug=$(ANTDEBUG) + +# --- Targets ------------------------------------------------------ +.INCLUDE : $(PRJ)$/target.pmk + +ALLTAR: ANTBUILD $(MISC)/postgresql.component + +$(MISC)/postgresql.component .ERRREMOVE : $(SOLARENV)/bin/createcomponent.xslt \ + postgresql.component + $(XSLTPROC) --nonet --stringparam uri '$(COMPONENTPREFIX_URE_JAVA)sdbc_postgresql.jar' \ + -o $@ $(SOLARENV)/bin/createcomponent.xslt postgresql.component + diff --git a/connectivity/java/sdbc_postgresql/postgresql.component b/connectivity/java/sdbc_postgresql/postgresql.component new file mode 100644 index 000000000000..d1f0ce6f85b0 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/postgresql.component @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--*********************************************************** + * + * 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. + * + ***********************************************************--> + + + +<component loader="com.sun.star.loader.Java2" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.sdbcx.comp.postgresql.PostgresqlDriver"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/java/sdbc_postgresql/sdbc_postgresql.xcu b/connectivity/java/sdbc_postgresql/sdbc_postgresql.xcu new file mode 100644 index 000000000000..38db83c28bb8 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/sdbc_postgresql.xcu @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--*********************************************************** + * + * 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. + * + ***********************************************************--> + + +<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <node oor:name="Installed"> + <node oor:name="sdbc:postgresql:jdbc:*" oor:op="replace"> + <prop oor:name="Driver"> + <value>com.sun.star.sdbcx.comp.postgresql.PostgresqlDriver</value> + </prop> + <prop oor:name="DriverTypeDisplayName" oor:type="xs:string"> + <value xml:lang="en-US">PostgreSQL</value> + </prop> + <node oor:name="Properties"> + <node oor:name="JavaDriverClass" oor:op="replace"> + <prop oor:name="Value" oor:type="xs:string"> + <value>org.postgresql.Driver</value> + </prop> + </node> + </node> + <node oor:name="Features"> + </node> + <node oor:name="MetaData"> + <node oor:name="SupportsBrowsing" oor:op="replace"> + <prop oor:name="Value" oor:type="xs:boolean"> + <value>true</value> + </prop> + </node> + <node oor:name="SupportsTableCreation" oor:op="replace"> + <prop oor:name="Value" oor:type="xs:boolean"> + <value>true</value> + </prop> + </node> + <node oor:name="UseJava" oor:op="replace"> + <prop oor:name="Value" oor:type="xs:boolean"> + <value>true</value> + </prop> + </node> + <node oor:name="Authentication" oor:op="replace"> + <prop oor:name="Value" oor:type="xs:string"> + <value>UserPassword</value> + </prop> + </node> + <node oor:name="SupportsColumnDescription" oor:op="replace"> + <prop oor:name="Value" oor:type="xs:boolean"> + <value>true</value> + </prop> + </node> + </node> + </node> + </node> +</oor:component-data> diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlCatalog.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlCatalog.java new file mode 100644 index 000000000000..638b8f31c947 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlCatalog.java @@ -0,0 +1,90 @@ +/************************************************************** + * + * 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; + +import java.util.ArrayList; +import java.util.List; + +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.OCatalog; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OContainer; +import com.sun.star.uno.Any; +import com.sun.star.uno.UnoRuntime; + +public class PostgresqlCatalog extends OCatalog { + public PostgresqlCatalog(PostgresqlConnection connection) throws SQLException { + super(connection.getMetaData()); + } + + @Override + public OContainer refreshTables() { + XResultSet results = null; + try { + // Using { "VIEW", "TABLE", "%" } shows INFORMATION_SCHEMA and others, but it also shows indexes :-( + results = metadata.getTables(Any.VOID, "%", "%", new String[] { "VIEW", "TABLE" }); + XRow row = UnoRuntime.queryInterface(XRow.class, results); + List<String> names = new ArrayList<>(); + while (results.next()) { + String name = buildName(row); + System.out.println("Table " + name); + names.add(name); + } + return new PostgresqlTables(lock, metadata, this, names); + } catch (SQLException sqlException) { + } finally { + CompHelper.disposeComponent(results); + } + return null; + } + + @Override + public OContainer refreshViews() { + XResultSet results = null; + try { + results = metadata.getTables(Any.VOID, "%", "%", new String[] { "VIEW" }); + XRow row = UnoRuntime.queryInterface(XRow.class, results); + List<String> names = new ArrayList<>(); + while (results.next()) { + String name = buildName(row); + names.add(name); + } + return new PostgresqlTables(lock, metadata, this, names); + } catch (SQLException sqlException) { + } finally { + CompHelper.disposeComponent(results); + } + return null; + } + + @Override + public OContainer refreshGroups() { + return null; + } + + @Override + public OContainer refreshUsers() { + return null; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlConnection.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlConnection.java new file mode 100644 index 000000000000..8e1d554d7805 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlConnection.java @@ -0,0 +1,198 @@ +/************************************************************** + * + * 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; + +import java.util.HashSet; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.sun.star.container.XNameAccess; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.EventObject; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XEventListener; +import com.sun.star.lib.uno.helper.ComponentBase; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbc.XDatabaseMetaData; +import com.sun.star.sdbc.XPreparedStatement; +import com.sun.star.sdbc.XStatement; +import com.sun.star.sdbc.XWarningsSupplier; +import com.sun.star.uno.UnoRuntime; + +public class PostgresqlConnection extends ComponentBase implements XConnection, XWarningsSupplier, XEventListener { + private XConnection impl; + private XComponent implComponent; + private XWarningsSupplier implWarningsSupplier; + private String url; + private AtomicBoolean isDisposed = new AtomicBoolean(false); + private HashSet<XComponent> statements = new HashSet<>(); + + public PostgresqlConnection(XConnection impl, String url) { + this.impl = impl; + implComponent = UnoRuntime.queryInterface(XComponent.class, impl); + implWarningsSupplier = UnoRuntime.queryInterface(XWarningsSupplier.class, impl); + this.url = url; + } + + // XComponent: + + @Override + protected synchronized void postDisposing() { + isDisposed.set(true); + implComponent.dispose(); + for (XComponent pgStatement : statements) { + try { + pgStatement.dispose(); + } catch (DisposedException disposedException) { + } + } + }; + + private void checkDisposed() throws DisposedException { + if (isDisposed.get()) { + throw new DisposedException(); + } + } + + // XEventListener: + + public synchronized void disposing(EventObject source) { + statements.remove(source.Source); + } + + // XWarningsSupplier: + + public void clearWarnings() throws SQLException { + checkDisposed(); + implWarningsSupplier.clearWarnings(); + } + + public Object getWarnings() throws SQLException { + checkDisposed(); + return implWarningsSupplier.getWarnings(); + } + + // XConnection: + + public void close() throws SQLException { + dispose(); + } + + public void commit() throws SQLException { + checkDisposed(); + impl.commit(); + } + + public synchronized XStatement createStatement() throws SQLException { + checkDisposed(); + PostgresqlStatement pgStatement = new PostgresqlStatement(impl.createStatement(), this); + statements.add(pgStatement); + pgStatement.addEventListener(this); + return pgStatement; + } + + public boolean getAutoCommit() throws SQLException { + checkDisposed(); + return impl.getAutoCommit(); + } + + public String getCatalog() throws SQLException { + checkDisposed(); + return impl.getCatalog(); + } + + public XDatabaseMetaData getMetaData() throws SQLException { + checkDisposed(); + return new PostgresqlDatabaseMetadata(impl.getMetaData(), this, url); + } + + public int getTransactionIsolation() throws SQLException { + checkDisposed(); + return impl.getTransactionIsolation(); + } + + public XNameAccess getTypeMap() throws SQLException { + checkDisposed(); + return impl.getTypeMap(); + } + + public boolean isClosed() throws SQLException { + checkDisposed(); + return impl.isClosed(); + } + + public boolean isReadOnly() throws SQLException { + checkDisposed(); + return impl.isReadOnly(); + } + + public String nativeSQL(String arg0) throws SQLException { + checkDisposed(); + return impl.nativeSQL(arg0); + } + + public synchronized XPreparedStatement prepareCall(String arg0) throws SQLException { + checkDisposed(); + PostgresqlPreparedStatement pgStatement = new PostgresqlPreparedStatement(impl.prepareCall(arg0), this); + statements.add(pgStatement); + pgStatement.addEventListener(this); + return pgStatement; + } + + public synchronized XPreparedStatement prepareStatement(String arg0) throws SQLException { + checkDisposed(); + PostgresqlPreparedStatement pgStatement = new PostgresqlPreparedStatement(impl.prepareStatement(arg0), this); + statements.add(pgStatement); + pgStatement.addEventListener(this); + return pgStatement; + } + + public void rollback() throws SQLException { + checkDisposed(); + impl.rollback(); + } + + public void setAutoCommit(boolean arg0) throws SQLException { + checkDisposed(); + impl.setAutoCommit(arg0); + } + + public void setCatalog(String arg0) throws SQLException { + checkDisposed(); + impl.setCatalog(arg0); + } + + public void setReadOnly(boolean arg0) throws SQLException { + checkDisposed(); + impl.setReadOnly(arg0); + } + + public void setTransactionIsolation(int arg0) throws SQLException { + checkDisposed(); + impl.setTransactionIsolation(arg0); + } + + public void setTypeMap(XNameAccess arg0) throws SQLException { + checkDisposed(); + impl.setTypeMap(arg0); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlDatabaseMetadata.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlDatabaseMetadata.java new file mode 100644 index 000000000000..3e0b24064362 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlDatabaseMetadata.java @@ -0,0 +1,752 @@ +/************************************************************** + * + * 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; + +import java.util.ArrayList; + +import com.sun.star.lib.uno.helper.WeakBase; +import com.sun.star.sdbc.DataType; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbc.XDatabaseMetaData; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XRow; +import com.sun.star.sdbcx.comp.postgresql.util.DatabaseMetaDataResultSet; +import com.sun.star.sdbcx.comp.postgresql.util.ORowSetValue; +import com.sun.star.uno.UnoRuntime; + +public class PostgresqlDatabaseMetadata extends WeakBase implements XDatabaseMetaData { + private XDatabaseMetaData impl; + private XConnection connection; + private String url; + + public PostgresqlDatabaseMetadata(XDatabaseMetaData impl, XConnection connection, String url) { + this.impl = impl; + this.connection = connection; + this.url = url; + } + + public boolean allProceduresAreCallable() throws SQLException { + return impl.allProceduresAreCallable(); + } + + public boolean allTablesAreSelectable() throws SQLException { + return impl.allTablesAreSelectable(); + } + + public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + return impl.dataDefinitionCausesTransactionCommit(); + } + + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return impl.dataDefinitionIgnoredInTransactions(); + } + + public boolean deletesAreDetected(int arg0) throws SQLException { + return impl.deletesAreDetected(arg0); + } + + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return impl.doesMaxRowSizeIncludeBlobs(); + } + + public XResultSet getBestRowIdentifier(Object arg0, String arg1, String arg2, int arg3, boolean arg4) throws SQLException { + return new PostgresqlResultSet(impl.getBestRowIdentifier(arg0, arg1, arg2, arg3, arg4), null); + } + + public String getCatalogSeparator() throws SQLException { + return impl.getCatalogSeparator(); + } + + public String getCatalogTerm() throws SQLException { + return impl.getCatalogTerm(); + } + + public XResultSet getCatalogs() throws SQLException { + return new PostgresqlResultSet(impl.getCatalogs(), null); + } + + public XResultSet getColumnPrivileges(Object arg0, String arg1, String arg2, String arg3) throws SQLException { + return new PostgresqlResultSet(impl.getColumnPrivileges(arg0, arg1, arg2, arg3), null); + } + + public XResultSet getColumns(Object arg0, String arg1, String arg2, String arg3) throws SQLException { + XResultSet results = impl.getColumns(arg0, arg1, arg2, arg3); + XRow row = UnoRuntime.queryInterface(XRow.class, results); + ArrayList<ORowSetValue[]> table = new ArrayList<>(); + while (results.next()) { + String tableCat = row.getString(1); + String tableSchem = row.getString(2); + String tableName = row.getString(3); + String columnName = row.getString(4); + short dataType = row.getShort(5); + String typeName = row.getString(6); + int columnSize = row.getInt(7); + int bufferLength = row.getInt(8); // FIXME: is it int? + int decimalDigits = row.getInt(9); + int numPrecRadix = row.getInt(10); + int nullable = row.getInt(11); + String remarks = row.getString(12); + String columnDef = row.getString(13); + int sqlDataType = row.getInt(14); + int sqlDateTimeSub = row.getInt(15); + int charOctetLength = row.getInt(16); + int ordinalPosition = row.getInt(17); + String isNullable = row.getString(18); + + if (dataType == DataType.BIT) { + if (typeName.equals("bool")) { + dataType = DataType.BOOLEAN; + } + } + + ORowSetValue[] rowOut = new ORowSetValue[18]; + rowOut[0] = new ORowSetValue(tableCat); + rowOut[1] = new ORowSetValue(tableSchem); + rowOut[2] = new ORowSetValue(tableName); + rowOut[3] = new ORowSetValue(columnName); + rowOut[4] = new ORowSetValue(dataType); + rowOut[5] = new ORowSetValue(typeName); + rowOut[6] = new ORowSetValue(columnSize); + rowOut[7] = new ORowSetValue(bufferLength); + rowOut[8] = new ORowSetValue(decimalDigits); + rowOut[9] = new ORowSetValue(numPrecRadix); + rowOut[10] = new ORowSetValue(nullable); + rowOut[11] = new ORowSetValue(remarks); + rowOut[12] = new ORowSetValue(columnDef); + rowOut[13] = new ORowSetValue(sqlDataType); + rowOut[14] = new ORowSetValue(sqlDateTimeSub); + rowOut[15] = new ORowSetValue(charOctetLength); + rowOut[16] = new ORowSetValue(ordinalPosition); + rowOut[17] = new ORowSetValue(isNullable); + table.add(rowOut); + } + return new DatabaseMetaDataResultSet(results, table); + } + + public XConnection getConnection() throws SQLException { + return connection; + } + + public XResultSet getCrossReference(Object arg0, String arg1, String arg2, Object arg3, String arg4, String arg5) throws SQLException { + return new PostgresqlResultSet(impl.getCrossReference(arg0, arg1, arg2, arg3, arg4, arg5), null); + } + + public String getDatabaseProductName() throws SQLException { + return impl.getDatabaseProductName(); + } + + public String getDatabaseProductVersion() throws SQLException { + return impl.getDatabaseProductVersion(); + } + + public int getDefaultTransactionIsolation() throws SQLException { + return impl.getDefaultTransactionIsolation(); + } + + public int getDriverMajorVersion() { + return impl.getDriverMajorVersion(); + } + + public int getDriverMinorVersion() { + return impl.getDriverMinorVersion(); + } + + public String getDriverName() throws SQLException { + return impl.getDriverName(); + } + + public String getDriverVersion() throws SQLException { + return impl.getDriverVersion(); + } + + public XResultSet getExportedKeys(Object arg0, String arg1, String arg2) throws SQLException { + return new PostgresqlResultSet(impl.getExportedKeys(arg0, arg1, arg2), null); + } + + public String getExtraNameCharacters() throws SQLException { + return impl.getExtraNameCharacters(); + } + + public String getIdentifierQuoteString() throws SQLException { + return impl.getIdentifierQuoteString(); + } + + public XResultSet getImportedKeys(Object arg0, String arg1, String arg2) throws SQLException { + return new PostgresqlResultSet(impl.getImportedKeys(arg0, arg1, arg2), null); + } + + public XResultSet getIndexInfo(Object arg0, String arg1, String arg2, boolean arg3, boolean arg4) throws SQLException { + return new PostgresqlResultSet(impl.getIndexInfo(arg0, arg1, arg2, arg3, arg4), null); + } + + public int getMaxBinaryLiteralLength() throws SQLException { + return impl.getMaxBinaryLiteralLength(); + } + + public int getMaxCatalogNameLength() throws SQLException { + return impl.getMaxCatalogNameLength(); + } + + public int getMaxCharLiteralLength() throws SQLException { + return impl.getMaxCharLiteralLength(); + } + + public int getMaxColumnNameLength() throws SQLException { + return impl.getMaxColumnNameLength(); + } + + public int getMaxColumnsInGroupBy() throws SQLException { + return impl.getMaxColumnsInGroupBy(); + } + + public int getMaxColumnsInIndex() throws SQLException { + return impl.getMaxColumnsInIndex(); + } + + public int getMaxColumnsInOrderBy() throws SQLException { + return impl.getMaxColumnsInOrderBy(); + } + + public int getMaxColumnsInSelect() throws SQLException { + return impl.getMaxColumnsInSelect(); + } + + public int getMaxColumnsInTable() throws SQLException { + return impl.getMaxColumnsInTable(); + } + + public int getMaxConnections() throws SQLException { + return impl.getMaxConnections(); + } + + public int getMaxCursorNameLength() throws SQLException { + return impl.getMaxCursorNameLength(); + } + + public int getMaxIndexLength() throws SQLException { + return impl.getMaxIndexLength(); + } + + public int getMaxProcedureNameLength() throws SQLException { + return impl.getMaxProcedureNameLength(); + } + + public int getMaxRowSize() throws SQLException { + return impl.getMaxRowSize(); + } + + public int getMaxSchemaNameLength() throws SQLException { + return impl.getMaxSchemaNameLength(); + } + + public int getMaxStatementLength() throws SQLException { + return impl.getMaxStatementLength(); + } + + public int getMaxStatements() throws SQLException { + return impl.getMaxStatements(); + } + + public int getMaxTableNameLength() throws SQLException { + return impl.getMaxTableNameLength(); + } + + public int getMaxTablesInSelect() throws SQLException { + return impl.getMaxTablesInSelect(); + } + + public int getMaxUserNameLength() throws SQLException { + return impl.getMaxUserNameLength(); + } + + public String getNumericFunctions() throws SQLException { + return impl.getNumericFunctions(); + } + + public XResultSet getPrimaryKeys(Object arg0, String arg1, String arg2) throws SQLException { + return new PostgresqlResultSet(impl.getPrimaryKeys(arg0, arg1, arg2), null); + } + + public XResultSet getProcedureColumns(Object arg0, String arg1, String arg2, String arg3) throws SQLException { + return new PostgresqlResultSet(impl.getProcedureColumns(arg0, arg1, arg2, arg3), null); + } + + public String getProcedureTerm() throws SQLException { + return impl.getProcedureTerm(); + } + + public XResultSet getProcedures(Object arg0, String arg1, String arg2) throws SQLException { + return new PostgresqlResultSet(impl.getProcedures(arg0, arg1, arg2), null); + } + + public String getSQLKeywords() throws SQLException { + return impl.getSQLKeywords(); + } + + public String getSchemaTerm() throws SQLException { + return impl.getSchemaTerm(); + } + + public XResultSet getSchemas() throws SQLException { + return new PostgresqlResultSet(impl.getSchemas(), null); + } + + public String getSearchStringEscape() throws SQLException { + return impl.getSearchStringEscape(); + } + + public String getStringFunctions() throws SQLException { + return impl.getStringFunctions(); + } + + public String getSystemFunctions() throws SQLException { + return impl.getSystemFunctions(); + } + + public XResultSet getTablePrivileges(Object arg0, String arg1, String arg2) throws SQLException { + return new PostgresqlResultSet(impl.getTablePrivileges(arg0, arg1, arg2), null); + } + + public XResultSet getTableTypes() throws SQLException { + return new PostgresqlResultSet(impl.getTableTypes(), null); + } + + public XResultSet getTables(Object arg0, String arg1, String arg2, String[] arg3) throws SQLException { + return new PostgresqlResultSet(impl.getTables(arg0, arg1, arg2, arg3), null); + } + + public String getTimeDateFunctions() throws SQLException { + return impl.getTimeDateFunctions(); + } + + public XResultSet getTypeInfo() throws SQLException { + XResultSet results = impl.getTypeInfo(); + XRow row = UnoRuntime.queryInterface(XRow.class, results); + ArrayList<ORowSetValue[]> table = new ArrayList<>(); + while (results.next()) { + String typeName = row.getString(1); + short dataType = row.getShort(2); + int precision = row.getInt(3); + String literalPrefix = row.getString(4); + String literalSuffix = row.getString(5); + String createParams = row.getString(6); + short nullable = row.getShort(7); + boolean caseSensitive = row.getBoolean(8); + short searchable = row.getShort(9); + boolean unsignedAttribute = row.getBoolean(10); + boolean fixedPrecScale = row.getBoolean(11); + boolean autoIncrement = row.getBoolean(12); + String localTypeName = row.getString(13); + short minimumScale = row.getShort(14); + short maximumScale = row.getShort(15); + int sqlDataType = row.getInt(16); + int sqlDateTimeSub = row.getInt(17); + int numPrecRadix = row.getInt(18); + + if (dataType == DataType.BIT) { + if (typeName.equals("bit")) { + // but the editor sees multi-bit columns as single bit + // and single bit can't be edited either: syntax error + createParams = "length"; + } else if (typeName.equals("bool")) { + dataType = DataType.BOOLEAN; + } + } + if ((dataType == DataType.CHAR || dataType == DataType.VARCHAR)) { + precision = 10485760; + createParams = "length"; + } + + ORowSetValue[] rowOut = new ORowSetValue[18]; + rowOut[0] = new ORowSetValue(typeName); + rowOut[1] = new ORowSetValue(dataType); + rowOut[2] = new ORowSetValue(precision); + rowOut[3] = new ORowSetValue(literalPrefix); + rowOut[4] = new ORowSetValue(literalSuffix); + rowOut[5] = new ORowSetValue(createParams); + rowOut[6] = new ORowSetValue(nullable); + rowOut[7] = new ORowSetValue(caseSensitive); + rowOut[8] = new ORowSetValue(searchable); + rowOut[9] = new ORowSetValue(unsignedAttribute); + rowOut[10] = new ORowSetValue(fixedPrecScale); + rowOut[11] = new ORowSetValue(autoIncrement); + rowOut[12] = new ORowSetValue(localTypeName); + rowOut[13] = new ORowSetValue(minimumScale); + rowOut[14] = new ORowSetValue(maximumScale); + rowOut[15] = new ORowSetValue(sqlDataType); + rowOut[16] = new ORowSetValue(sqlDateTimeSub); + rowOut[17] = new ORowSetValue(numPrecRadix); + table.add(rowOut); + //System.out.println(String.format("type %s, data type %d, SQL type %d, precision %d, createParams %s", typeName, dataType, sqlDataType, precision, createParams)); + } + return new DatabaseMetaDataResultSet(results, table); + } + + public XResultSet getUDTs(Object arg0, String arg1, String arg2, int[] arg3) throws SQLException { + return new PostgresqlResultSet(impl.getUDTs(arg0, arg1, arg2, arg3), null); + } + + public String getURL() throws SQLException { + return url; + } + + public String getUserName() throws SQLException { + return impl.getUserName(); + } + + public XResultSet getVersionColumns(Object arg0, String arg1, String arg2) throws SQLException { + return new PostgresqlResultSet(impl.getVersionColumns(arg0, arg1, arg2), null); + } + + public boolean insertsAreDetected(int arg0) throws SQLException { + return impl.insertsAreDetected(arg0); + } + + public boolean isCatalogAtStart() throws SQLException { + return impl.isCatalogAtStart(); + } + + public boolean isReadOnly() throws SQLException { + return impl.isReadOnly(); + } + + public boolean nullPlusNonNullIsNull() throws SQLException { + return impl.nullPlusNonNullIsNull(); + } + + public boolean nullsAreSortedAtEnd() throws SQLException { + return impl.nullsAreSortedAtEnd(); + } + + public boolean nullsAreSortedAtStart() throws SQLException { + return impl.nullsAreSortedAtStart(); + } + + public boolean nullsAreSortedHigh() throws SQLException { + return impl.nullsAreSortedHigh(); + } + + public boolean nullsAreSortedLow() throws SQLException { + return impl.nullsAreSortedLow(); + } + + public boolean othersDeletesAreVisible(int arg0) throws SQLException { + return impl.othersDeletesAreVisible(arg0); + } + + public boolean othersInsertsAreVisible(int arg0) throws SQLException { + return impl.othersInsertsAreVisible(arg0); + } + + public boolean othersUpdatesAreVisible(int arg0) throws SQLException { + return impl.othersUpdatesAreVisible(arg0); + } + + public boolean ownDeletesAreVisible(int arg0) throws SQLException { + return impl.ownDeletesAreVisible(arg0); + } + + public boolean ownInsertsAreVisible(int arg0) throws SQLException { + return impl.ownInsertsAreVisible(arg0); + } + + public boolean ownUpdatesAreVisible(int arg0) throws SQLException { + return impl.ownUpdatesAreVisible(arg0); + } + + public boolean storesLowerCaseIdentifiers() throws SQLException { + return impl.storesLowerCaseIdentifiers(); + } + + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return impl.storesLowerCaseQuotedIdentifiers(); + } + + public boolean storesMixedCaseIdentifiers() throws SQLException { + return impl.storesMixedCaseIdentifiers(); + } + + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return impl.storesMixedCaseQuotedIdentifiers(); + } + + public boolean storesUpperCaseIdentifiers() throws SQLException { + return impl.storesUpperCaseIdentifiers(); + } + + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return impl.storesUpperCaseQuotedIdentifiers(); + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return impl.supportsANSI92EntryLevelSQL(); + } + + public boolean supportsANSI92FullSQL() throws SQLException { + return impl.supportsANSI92FullSQL(); + } + + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return impl.supportsANSI92IntermediateSQL(); + } + + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return impl.supportsAlterTableWithAddColumn(); + } + + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return impl.supportsAlterTableWithDropColumn(); + } + + public boolean supportsBatchUpdates() throws SQLException { + return impl.supportsBatchUpdates(); + } + + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return impl.supportsCatalogsInDataManipulation(); + } + + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return impl.supportsCatalogsInIndexDefinitions(); + } + + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return impl.supportsCatalogsInPrivilegeDefinitions(); + } + + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return impl.supportsCatalogsInProcedureCalls(); + } + + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return impl.supportsCatalogsInTableDefinitions(); + } + + public boolean supportsColumnAliasing() throws SQLException { + return impl.supportsColumnAliasing(); + } + + public boolean supportsConvert(int arg0, int arg1) throws SQLException { + return impl.supportsConvert(arg0, arg1); + } + + public boolean supportsCoreSQLGrammar() throws SQLException { + return impl.supportsCoreSQLGrammar(); + } + + public boolean supportsCorrelatedSubqueries() throws SQLException { + return impl.supportsCorrelatedSubqueries(); + } + + public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + return impl.supportsDataDefinitionAndDataManipulationTransactions(); + } + + public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + return impl.supportsDataManipulationTransactionsOnly(); + } + + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return impl.supportsDifferentTableCorrelationNames(); + } + + public boolean supportsExpressionsInOrderBy() throws SQLException { + return impl.supportsExpressionsInOrderBy(); + } + + public boolean supportsExtendedSQLGrammar() throws SQLException { + return impl.supportsExtendedSQLGrammar(); + } + + public boolean supportsFullOuterJoins() throws SQLException { + return impl.supportsFullOuterJoins(); + } + + public boolean supportsGroupBy() throws SQLException { + return impl.supportsGroupBy(); + } + + public boolean supportsGroupByBeyondSelect() throws SQLException { + return impl.supportsGroupByBeyondSelect(); + } + + public boolean supportsGroupByUnrelated() throws SQLException { + return impl.supportsGroupByUnrelated(); + } + + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return impl.supportsIntegrityEnhancementFacility(); + } + + public boolean supportsLikeEscapeClause() throws SQLException { + return impl.supportsLikeEscapeClause(); + } + + public boolean supportsLimitedOuterJoins() throws SQLException { + return impl.supportsLimitedOuterJoins(); + } + + public boolean supportsMinimumSQLGrammar() throws SQLException { + return impl.supportsMinimumSQLGrammar(); + } + + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return impl.supportsMixedCaseIdentifiers(); + } + + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return impl.supportsMixedCaseQuotedIdentifiers(); + } + + public boolean supportsMultipleResultSets() throws SQLException { + return impl.supportsMultipleResultSets(); + } + + public boolean supportsMultipleTransactions() throws SQLException { + return impl.supportsMultipleTransactions(); + } + + public boolean supportsNonNullableColumns() throws SQLException { + return impl.supportsNonNullableColumns(); + } + + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return impl.supportsOpenCursorsAcrossCommit(); + } + + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return impl.supportsOpenCursorsAcrossRollback(); + } + + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return impl.supportsOpenStatementsAcrossCommit(); + } + + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return impl.supportsOpenStatementsAcrossRollback(); + } + + public boolean supportsOrderByUnrelated() throws SQLException { + return impl.supportsOrderByUnrelated(); + } + + public boolean supportsOuterJoins() throws SQLException { + return impl.supportsOuterJoins(); + } + + public boolean supportsPositionedDelete() throws SQLException { + return impl.supportsPositionedDelete(); + } + + public boolean supportsPositionedUpdate() throws SQLException { + return impl.supportsPositionedUpdate(); + } + + public boolean supportsResultSetConcurrency(int arg0, int arg1) throws SQLException { + return impl.supportsResultSetConcurrency(arg0, arg1); + } + + public boolean supportsResultSetType(int arg0) throws SQLException { + return impl.supportsResultSetType(arg0); + } + + public boolean supportsSchemasInDataManipulation() throws SQLException { + return impl.supportsSchemasInDataManipulation(); + } + + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return impl.supportsSchemasInIndexDefinitions(); + } + + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return impl.supportsSchemasInPrivilegeDefinitions(); + } + + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return impl.supportsSchemasInProcedureCalls(); + } + + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return impl.supportsSchemasInTableDefinitions(); + } + + public boolean supportsSelectForUpdate() throws SQLException { + return impl.supportsSelectForUpdate(); + } + + public boolean supportsStoredProcedures() throws SQLException { + return impl.supportsStoredProcedures(); + } + + public boolean supportsSubqueriesInComparisons() throws SQLException { + return impl.supportsSubqueriesInComparisons(); + } + + public boolean supportsSubqueriesInExists() throws SQLException { + return impl.supportsSubqueriesInExists(); + } + + public boolean supportsSubqueriesInIns() throws SQLException { + return impl.supportsSubqueriesInIns(); + } + + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return impl.supportsSubqueriesInQuantifieds(); + } + + public boolean supportsTableCorrelationNames() throws SQLException { + return impl.supportsTableCorrelationNames(); + } + + public boolean supportsTransactionIsolationLevel(int arg0) throws SQLException { + return impl.supportsTransactionIsolationLevel(arg0); + } + + public boolean supportsTransactions() throws SQLException { + return impl.supportsTransactions(); + } + + public boolean supportsTypeConversion() throws SQLException { + return impl.supportsTypeConversion(); + } + + public boolean supportsUnion() throws SQLException { + return impl.supportsUnion(); + } + + public boolean supportsUnionAll() throws SQLException { + return impl.supportsUnionAll(); + } + + public boolean updatesAreDetected(int arg0) throws SQLException { + return impl.updatesAreDetected(arg0); + } + + public boolean usesLocalFilePerTable() throws SQLException { + return impl.usesLocalFilePerTable(); + } + + public boolean usesLocalFiles() throws SQLException { + return impl.usesLocalFiles(); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlDriver.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlDriver.java new file mode 100644 index 000000000000..43fd434f2037 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlDriver.java @@ -0,0 +1,199 @@ +/************************************************************** + * + * 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; + +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.sun.star.beans.PropertyValue; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.XServiceInfo; +import com.sun.star.lang.XSingleComponentFactory; +import com.sun.star.lib.uno.helper.ComponentBase; +import com.sun.star.lib.uno.helper.Factory; +import com.sun.star.sdbc.DriverPropertyInfo; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbc.XDriver; +import com.sun.star.sdbc.XDriverManager; +import com.sun.star.sdbcx.XDataDefinitionSupplier; +import com.sun.star.sdbcx.XTablesSupplier; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.SharedResources; +import com.sun.star.sdbcx.comp.postgresql.util.StandardSQLState; +import com.sun.star.uno.Exception; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; + +public class PostgresqlDriver extends ComponentBase implements XServiceInfo, XDriver, XDataDefinitionSupplier { + private static String[] services = new String[] { + "com.sun.star.sdbc.Driver", + "com.sun.star.sdbcx.Driver" + }; + private XComponentContext componentContext; + private AtomicBoolean isDisposed = new AtomicBoolean(false); + + public static XSingleComponentFactory __getComponentFactory(String implName) { + XSingleComponentFactory xSingleComponentFactory = null; + if (implName.equals(getImplementationNameStatic())) { + xSingleComponentFactory = Factory.createComponentFactory(PostgresqlDriver.class, + getImplementationNameStatic(), services); + } + return xSingleComponentFactory; + } + + public PostgresqlDriver(XComponentContext componentContext) { + this.componentContext = componentContext; + SharedResources.registerClient(componentContext); + } + + private static String getImplementationNameStatic() { + return PostgresqlDriver.class.getName(); + } + + // XComponent: + + @Override + protected void postDisposing() { + isDisposed.set(true); + componentContext = null; + SharedResources.revokeClient(); + } + + private void checkDisposed() throws DisposedException { + if (isDisposed.get()) { + throw new DisposedException(); + } + } + + // XServiceInfo: + + @Override + public String getImplementationName() { + return getImplementationNameStatic(); + } + + @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; + } + + // XDriver: + + @Override + public boolean acceptsURL(String url) throws SQLException { + return url.startsWith("sdbc:postgresql:jdbc:"); + } + + @Override + public XConnection connect(String url, PropertyValue[] info) throws SQLException { + checkDisposed(); + XConnection connection = null; + if (acceptsURL(url)) { + String jdbcUrl = transformUrl(url); + System.out.println("Using SDBC URL " + url + " and JDBC URL " + jdbcUrl); + + try { + Object driverManagerObject = componentContext.getServiceManager().createInstanceWithContext( + "com.sun.star.sdbc.DriverManager", componentContext); + XDriverManager driverManager = UnoRuntime.queryInterface(XDriverManager.class, driverManagerObject); + + ArrayList<PropertyValue> properties = new ArrayList<>(); + boolean haveJavaClass = false; + for (PropertyValue property : info) { + if (property.Name.equals("JavaDriverClass")) { + haveJavaClass = true; + } + properties.add(property); + } + if (!haveJavaClass) { + PropertyValue javaClassProperty = new PropertyValue(); + javaClassProperty.Name = "JavaDriverClass"; + javaClassProperty.Value = "org.postgresql.Driver"; + properties.add(javaClassProperty); + } + PropertyValue[] jdbcInfo = properties.toArray(new PropertyValue[properties.size()]); + + connection = driverManager.getConnectionWithInfo(jdbcUrl, jdbcInfo); + if (connection != null) { + connection = new PostgresqlConnection(connection, url); + } + } catch (SQLException sqlException) { + throw sqlException; + } catch (Exception exception) { + throw new SQLException(exception.getMessage(), this, StandardSQLState.SQL_UNABLE_TO_CONNECT.text(), 0, exception); + } + } + return connection; + } + + @Override + public int getMajorVersion() { + return 1; + } + + @Override + public int getMinorVersion() { + return 0; + } + + @Override + public DriverPropertyInfo[] getPropertyInfo(String url, PropertyValue[] info) throws SQLException { + if (!acceptsURL(url)) { + return new DriverPropertyInfo[0]; + } + return new DriverPropertyInfo [] { + new DriverPropertyInfo("JavaClassName", "The JDBC driver class name.", true, + "com.postgresql.Driver", new String[0]), + }; + } + + private static String transformUrl(String url) { + // 012345678901234567890 + // sdbc:postgresql:jdbc: + return "jdbc:postgresql:" + url.substring(21); + } + + // XDataDefinitionSupplier: + + public XTablesSupplier getDataDefinitionByConnection(XConnection connection) throws SQLException { + checkDisposed(); + return new PostgresqlCatalog((PostgresqlConnection)connection); + } + + public XTablesSupplier getDataDefinitionByURL(String url, PropertyValue[] info) throws SQLException { + checkDisposed(); + if (!acceptsURL(url)) { + throw new SQLException(); // FIXME + } + return getDataDefinitionByConnection(connect(url, info)); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlPreparedStatement.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlPreparedStatement.java new file mode 100644 index 000000000000..ff4b99684a5a --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlPreparedStatement.java @@ -0,0 +1,348 @@ +/************************************************************** + * + * 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; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +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.io.XInputStream; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lib.uno.helper.ComponentBase; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XArray; +import com.sun.star.sdbc.XBlob; +import com.sun.star.sdbc.XClob; +import com.sun.star.sdbc.XCloseable; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbc.XMultipleResults; +import com.sun.star.sdbc.XParameters; +import com.sun.star.sdbc.XPreparedBatchExecution; +import com.sun.star.sdbc.XPreparedStatement; +import com.sun.star.sdbc.XRef; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XResultSetMetaData; +import com.sun.star.sdbc.XResultSetMetaDataSupplier; +import com.sun.star.sdbc.XWarningsSupplier; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.Date; +import com.sun.star.util.DateTime; +import com.sun.star.util.Time; +import com.sun.star.util.XCancellable; + +public class PostgresqlPreparedStatement extends ComponentBase + implements XPreparedStatement, XCloseable, XPropertySet, XCancellable, XResultSetMetaDataSupplier, XParameters, XPreparedBatchExecution, + XWarningsSupplier, XMultipleResults { + + private XPreparedStatement impl; + private XCloseable implCloseable; + private XPropertySet implPropertySet; + private XCancellable implCancellable; + private XResultSetMetaDataSupplier implResultSetMetaDataSupplier; + private XParameters implParameters; + private XPreparedBatchExecution implPreparedBatchExecution; + private XWarningsSupplier implWarningsSupplier; + private XMultipleResults implMultipleResults; + private XConnection connection; + private AtomicBoolean isDisposed = new AtomicBoolean(false); + + public PostgresqlPreparedStatement(XPreparedStatement impl, XConnection connection) { + this.impl = impl; + this.implCloseable = UnoRuntime.queryInterface(XCloseable.class, impl); + this.implPropertySet = UnoRuntime.queryInterface(XPropertySet.class, impl); + this.implCancellable = UnoRuntime.queryInterface(XCancellable.class, impl); + this.implResultSetMetaDataSupplier = UnoRuntime.queryInterface(XResultSetMetaDataSupplier.class, impl); + this.implParameters = UnoRuntime.queryInterface(XParameters.class, impl); + this.implPreparedBatchExecution = UnoRuntime.queryInterface(XPreparedBatchExecution.class, impl); + this.implWarningsSupplier = UnoRuntime.queryInterface(XWarningsSupplier.class, impl); + this.implMultipleResults = UnoRuntime.queryInterface(XMultipleResults.class, impl); + this.connection = connection; + } + + // XComponentBase: + + @Override + protected void postDisposing() { + isDisposed.set(true); + try { + implCloseable.close(); + } catch (SQLException sqlException) { + } + } + + private void checkDisposed() { + if (isDisposed.get()) { + throw new DisposedException(); + } + } + + // XPreparedStatement: + + public boolean execute() throws SQLException { + checkDisposed(); + return impl.execute(); + } + + public XResultSet executeQuery() throws SQLException { + checkDisposed(); + return new PostgresqlResultSet(impl.executeQuery(), this); + } + + public int executeUpdate() throws SQLException { + checkDisposed(); + return impl.executeUpdate(); + } + + public XConnection getConnection() throws SQLException { + checkDisposed(); + return connection; + } + + // XCloseable: + + public void close() throws SQLException { + dispose(); + } + + // XPropertySet: + + public void addPropertyChangeListener(String arg0, XPropertyChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.addPropertyChangeListener(arg0, arg1); + } + + public void addVetoableChangeListener(String arg0, XVetoableChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.addVetoableChangeListener(arg0, arg1); + } + + public XPropertySetInfo getPropertySetInfo() { + checkDisposed(); + return implPropertySet.getPropertySetInfo(); + } + + public Object getPropertyValue(String arg0) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + return implPropertySet.getPropertyValue(arg0); + } + + public void removePropertyChangeListener(String arg0, XPropertyChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.removePropertyChangeListener(arg0, arg1); + } + + public void removeVetoableChangeListener(String arg0, XVetoableChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.removeVetoableChangeListener(arg0, arg1); + } + + public void setPropertyValue(String arg0, Object arg1) + throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException { + checkDisposed(); + implPropertySet.setPropertyValue(arg0, arg1); + } + + // XCancellable: + + public void cancel() { + checkDisposed(); + implCancellable.cancel(); + } + + // XResultSetMetaDataSupplier: + + public XResultSetMetaData getMetaData() throws SQLException { + checkDisposed(); + return new PostgresqlResultSetMetaData(implResultSetMetaDataSupplier.getMetaData()); + } + + // XParameters: + + public void clearParameters() throws SQLException { + checkDisposed(); + implParameters.clearParameters(); + } + + public void setArray(int arg0, XArray arg1) throws SQLException { + checkDisposed(); + implParameters.setArray(arg0, arg1); + } + + public void setBinaryStream(int arg0, XInputStream arg1, int arg2) throws SQLException { + checkDisposed(); + implParameters.setBinaryStream(arg0, arg1, arg2); + } + + public void setBlob(int arg0, XBlob arg1) throws SQLException { + checkDisposed(); + implParameters.setBlob(arg0, arg1); + } + + public void setBoolean(int arg0, boolean arg1) throws SQLException { + checkDisposed(); + implParameters.setBoolean(arg0, arg1); + } + + public void setByte(int arg0, byte arg1) throws SQLException { + checkDisposed(); + implParameters.setByte(arg0, arg1); + } + + public void setBytes(int arg0, byte[] arg1) throws SQLException { + checkDisposed(); + implParameters.setBytes(arg0, arg1); + } + + public void setCharacterStream(int arg0, XInputStream arg1, int arg2) throws SQLException { + checkDisposed(); + implParameters.setCharacterStream(arg0, arg1, arg2); + } + + public void setClob(int arg0, XClob arg1) throws SQLException { + checkDisposed(); + implParameters.setClob(arg0, arg1); + } + + public void setDate(int arg0, Date arg1) throws SQLException { + checkDisposed(); + implParameters.setDate(arg0, arg1); + } + + public void setDouble(int arg0, double arg1) throws SQLException { + checkDisposed(); + implParameters.setDouble(arg0, arg1); + } + + public void setFloat(int arg0, float arg1) throws SQLException { + checkDisposed(); + implParameters.setFloat(arg0, arg1); + } + + public void setInt(int arg0, int arg1) throws SQLException { + checkDisposed(); + implParameters.setInt(arg0, arg1); + } + + public void setLong(int arg0, long arg1) throws SQLException { + checkDisposed(); + implParameters.setLong(arg0, arg1); + } + + public void setNull(int arg0, int arg1) throws SQLException { + checkDisposed(); + implParameters.setNull(arg0, arg1); + } + + public void setObject(int arg0, Object arg1) throws SQLException { + checkDisposed(); + implParameters.setObject(arg0, arg1); + } + + public void setObjectNull(int arg0, int arg1, String arg2) throws SQLException { + checkDisposed(); + implParameters.setObjectNull(arg0, arg1, arg2); + } + + public void setObjectWithInfo(int arg0, Object arg1, int arg2, int arg3) throws SQLException { + checkDisposed(); + implParameters.setObjectWithInfo(arg0, arg1, arg2, arg3); + } + + public void setRef(int arg0, XRef arg1) throws SQLException { + checkDisposed(); + implParameters.setRef(arg0, arg1); + } + + public void setShort(int arg0, short arg1) throws SQLException { + checkDisposed(); + implParameters.setShort(arg0, arg1); + } + + public void setString(int arg0, String arg1) throws SQLException { + checkDisposed(); + implParameters.setString(arg0, arg1); + } + + public void setTime(int arg0, Time arg1) throws SQLException { + checkDisposed(); + implParameters.setTime(arg0, arg1); + } + + public void setTimestamp(int arg0, DateTime arg1) throws SQLException { + checkDisposed(); + implParameters.setTimestamp(arg0, arg1); + } + + // XPreparedBatchExecution: + + public void addBatch() throws SQLException { + checkDisposed(); + implPreparedBatchExecution.addBatch(); + } + + public void clearBatch() throws SQLException { + checkDisposed(); + implPreparedBatchExecution.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + checkDisposed(); + return implPreparedBatchExecution.executeBatch(); + } + + // XWarningsSupplier: + + public void clearWarnings() throws SQLException { + checkDisposed(); + implWarningsSupplier.clearWarnings(); + } + + public Object getWarnings() throws SQLException { + checkDisposed(); + return implWarningsSupplier.getWarnings(); + } + + // XMultipleResults: + + public boolean getMoreResults() throws SQLException { + checkDisposed(); + return implMultipleResults.getMoreResults(); + } + + public XResultSet getResultSet() throws SQLException { + checkDisposed(); + return new PostgresqlResultSet(implMultipleResults.getResultSet(), this); + } + + public int getUpdateCount() throws SQLException { + checkDisposed(); + return implMultipleResults.getUpdateCount(); + } + + +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlResultSet.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlResultSet.java new file mode 100644 index 000000000000..1ba5d62cbedb --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlResultSet.java @@ -0,0 +1,495 @@ +/************************************************************** + * + * 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; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +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.container.XNameAccess; +import com.sun.star.io.XInputStream; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lib.uno.helper.ComponentBase; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XArray; +import com.sun.star.sdbc.XBlob; +import com.sun.star.sdbc.XClob; +import com.sun.star.sdbc.XCloseable; +import com.sun.star.sdbc.XColumnLocate; +import com.sun.star.sdbc.XRef; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XResultSetMetaData; +import com.sun.star.sdbc.XResultSetMetaDataSupplier; +import com.sun.star.sdbc.XResultSetUpdate; +import com.sun.star.sdbc.XRow; +import com.sun.star.sdbc.XRowUpdate; +import com.sun.star.sdbc.XWarningsSupplier; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.Date; +import com.sun.star.util.DateTime; +import com.sun.star.util.Time; +import com.sun.star.util.XCancellable; + +public class PostgresqlResultSet extends ComponentBase + implements XResultSet, XRow, XResultSetMetaDataSupplier, XCancellable, XWarningsSupplier, XResultSetUpdate, + XRowUpdate, XCloseable, XColumnLocate, XPropertySet { + + private XResultSet impl; + private XRow implRow; + private XResultSetMetaDataSupplier implResultSetMetaDataSupplier; + private XCancellable implCancellable; + private XWarningsSupplier implWarningsSupplier; + private XResultSetUpdate implResultSetUpdate; + private XRowUpdate implRowUpdate; + private XCloseable implCloseable; + private XColumnLocate implColumnLocate; + private XPropertySet implPropertySet; + private Object statement; + private AtomicBoolean isDisposed = new AtomicBoolean(false); + + public PostgresqlResultSet(XResultSet impl, Object statement) { + this.impl = impl; + this.implRow = UnoRuntime.queryInterface(XRow.class, impl); + this.implResultSetMetaDataSupplier = UnoRuntime.queryInterface(XResultSetMetaDataSupplier.class, impl); + this.implCancellable = UnoRuntime.queryInterface(XCancellable.class, impl); + this.implWarningsSupplier = UnoRuntime.queryInterface(XWarningsSupplier.class, impl); + this.implResultSetUpdate = UnoRuntime.queryInterface(XResultSetUpdate.class, impl); + this.implRowUpdate = UnoRuntime.queryInterface(XRowUpdate.class, impl); + this.implCloseable = UnoRuntime.queryInterface(XCloseable.class, impl); + this.implColumnLocate = UnoRuntime.queryInterface(XColumnLocate.class, impl); + this.implPropertySet = UnoRuntime.queryInterface(XPropertySet.class, impl); + this.statement = statement; + } + + // XComponent: + + @Override + protected synchronized void postDisposing() { + isDisposed.set(true); + try { + implCloseable.close(); + } catch (SQLException sqlException) { + } + }; + + private void checkDisposed() throws DisposedException { + if (isDisposed.get()) { + throw new DisposedException(); + } + } + + // XCloseable: + + public void close() throws SQLException { + dispose(); + } + + // XResultSet: + + public boolean absolute(int arg0) throws SQLException { + checkDisposed(); + return impl.absolute(arg0); + } + + public void afterLast() throws SQLException { + checkDisposed(); + impl.afterLast(); + } + + public void beforeFirst() throws SQLException { + checkDisposed(); + impl.beforeFirst(); + } + + public boolean first() throws SQLException { + checkDisposed(); + return impl.first(); + } + + public int getRow() throws SQLException { + checkDisposed(); + return impl.getRow(); + } + + public Object getStatement() throws SQLException { + checkDisposed(); + return statement; + } + + public boolean isAfterLast() throws SQLException { + checkDisposed(); + return impl.isAfterLast(); + } + + public boolean isBeforeFirst() throws SQLException { + checkDisposed(); + return impl.isBeforeFirst(); + } + + public boolean isFirst() throws SQLException { + checkDisposed(); + return impl.isFirst(); + } + + public boolean isLast() throws SQLException { + checkDisposed(); + return impl.isLast(); + } + + public boolean last() throws SQLException { + checkDisposed(); + return impl.last(); + } + + public boolean next() throws SQLException { + checkDisposed(); + return impl.next(); + } + + public boolean previous() throws SQLException { + checkDisposed(); + return impl.previous(); + } + + public void refreshRow() throws SQLException { + checkDisposed(); + impl.refreshRow(); + } + + public boolean relative(int arg0) throws SQLException { + checkDisposed(); + return impl.relative(arg0); + } + + public boolean rowDeleted() throws SQLException { + checkDisposed(); + return impl.rowDeleted(); + } + + public boolean rowInserted() throws SQLException { + checkDisposed(); + return impl.rowInserted(); + } + + public boolean rowUpdated() throws SQLException { + checkDisposed(); + return impl.rowUpdated(); + } + + // XRow: + + public XArray getArray(int arg0) throws SQLException { + checkDisposed(); + return implRow.getArray(arg0); + } + + public XInputStream getBinaryStream(int arg0) throws SQLException { + checkDisposed(); + return implRow.getBinaryStream(arg0); + } + + public XBlob getBlob(int arg0) throws SQLException { + checkDisposed(); + return implRow.getBlob(arg0); + } + + public boolean getBoolean(int arg0) throws SQLException { + checkDisposed(); + return implRow.getBoolean(arg0); + } + + public byte getByte(int arg0) throws SQLException { + checkDisposed(); + return implRow.getByte(arg0); + } + + public byte[] getBytes(int arg0) throws SQLException { + checkDisposed(); + return implRow.getBytes(arg0); + } + + public XInputStream getCharacterStream(int arg0) throws SQLException { + checkDisposed(); + return implRow.getCharacterStream(arg0); + } + + public XClob getClob(int arg0) throws SQLException { + checkDisposed(); + return implRow.getClob(arg0); + } + + public Date getDate(int arg0) throws SQLException { + checkDisposed(); + return implRow.getDate(arg0); + } + + public double getDouble(int arg0) throws SQLException { + checkDisposed(); + return implRow.getDouble(arg0); + } + + public float getFloat(int arg0) throws SQLException { + checkDisposed(); + return implRow.getFloat(arg0); + } + + public int getInt(int arg0) throws SQLException { + checkDisposed(); + return implRow.getInt(arg0); + } + + public long getLong(int arg0) throws SQLException { + checkDisposed(); + return implRow.getLong(arg0); + } + + public Object getObject(int arg0, XNameAccess arg1) throws SQLException { + checkDisposed(); + return implRow.getObject(arg0, arg1); + } + + public XRef getRef(int arg0) throws SQLException { + checkDisposed(); + return implRow.getRef(arg0); + } + + public short getShort(int arg0) throws SQLException { + checkDisposed(); + return implRow.getShort(arg0); + } + + public String getString(int arg0) throws SQLException { + checkDisposed(); + return implRow.getString(arg0); + } + + public Time getTime(int arg0) throws SQLException { + checkDisposed(); + return implRow.getTime(arg0); + } + + public DateTime getTimestamp(int arg0) throws SQLException { + checkDisposed(); + return implRow.getTimestamp(arg0); + } + + public boolean wasNull() throws SQLException { + checkDisposed(); + return implRow.wasNull(); + } + + // XResultSetMetaDataSupplier: + + public XResultSetMetaData getMetaData() throws SQLException { + checkDisposed(); + return new PostgresqlResultSetMetaData(implResultSetMetaDataSupplier.getMetaData()); + } + + // XCancellable: + + public void cancel() { + checkDisposed(); + implCancellable.cancel(); + } + + // XWarningsSupplier: + + public void clearWarnings() throws SQLException { + checkDisposed(); + implWarningsSupplier.clearWarnings(); + } + + public Object getWarnings() throws SQLException { + checkDisposed(); + return implWarningsSupplier.getWarnings(); + } + + // XResultSetUpdate: + + public void cancelRowUpdates() throws SQLException { + checkDisposed(); + implResultSetUpdate.cancelRowUpdates(); + } + + public void deleteRow() throws SQLException { + checkDisposed(); + implResultSetUpdate.deleteRow(); + } + + public void insertRow() throws SQLException { + checkDisposed(); + implResultSetUpdate.insertRow(); + } + + public void moveToCurrentRow() throws SQLException { + checkDisposed(); + implResultSetUpdate.moveToCurrentRow(); + } + + public void moveToInsertRow() throws SQLException { + checkDisposed(); + implResultSetUpdate.moveToInsertRow(); + } + + public void updateRow() throws SQLException { + checkDisposed(); + implResultSetUpdate.updateRow(); + } + + // XRowUpdate: + + public void updateBinaryStream(int arg0, XInputStream arg1, int arg2) throws SQLException { + checkDisposed(); + implRowUpdate.updateBinaryStream(arg0, arg1, arg2); + } + + public void updateBoolean(int arg0, boolean arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateBoolean(arg0, arg1); + } + + public void updateByte(int arg0, byte arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateByte(arg0, arg1); + } + + public void updateBytes(int arg0, byte[] arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateBytes(arg0, arg1); + } + + public void updateCharacterStream(int arg0, XInputStream arg1, int arg2) throws SQLException { + checkDisposed(); + implRowUpdate.updateCharacterStream(arg0, arg1, arg2); + } + + public void updateDate(int arg0, Date arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateDate(arg0, arg1); + } + + public void updateDouble(int arg0, double arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateDouble(arg0, arg1); + } + + public void updateFloat(int arg0, float arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateFloat(arg0, arg1); + } + + public void updateInt(int arg0, int arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateInt(arg0, arg1); + } + + public void updateLong(int arg0, long arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateLong(arg0, arg1); + } + + public void updateNull(int arg0) throws SQLException { + checkDisposed(); + implRowUpdate.updateNull(arg0); + } + + public void updateNumericObject(int arg0, Object arg1, int arg2) throws SQLException { + checkDisposed(); + implRowUpdate.updateNumericObject(arg0, arg1, arg2); + } + + public void updateObject(int arg0, Object arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateObject(arg0, arg1); + } + + public void updateShort(int arg0, short arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateShort(arg0, arg1); + } + + public void updateString(int arg0, String arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateString(arg0, arg1); + } + + public void updateTime(int arg0, Time arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateTime(arg0, arg1); + } + + public void updateTimestamp(int arg0, DateTime arg1) throws SQLException { + checkDisposed(); + implRowUpdate.updateTimestamp(arg0, arg1); + } + + // XColumnLocate: + + public int findColumn(String arg0) throws SQLException { + checkDisposed(); + return implColumnLocate.findColumn(arg0); + } + + // XPropertySet: + + public void addPropertyChangeListener(String arg0, XPropertyChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.addPropertyChangeListener(arg0, arg1); + } + + public void addVetoableChangeListener(String arg0, XVetoableChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.addVetoableChangeListener(arg0, arg1); + } + + public XPropertySetInfo getPropertySetInfo() { + checkDisposed(); + return implPropertySet.getPropertySetInfo(); + } + + public Object getPropertyValue(String arg0) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + return implPropertySet.getPropertyValue(arg0); + } + + public void removePropertyChangeListener(String arg0, XPropertyChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.removePropertyChangeListener(arg0, arg1); + } + + public void removeVetoableChangeListener(String arg0, XVetoableChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.removeVetoableChangeListener(arg0, arg1); + } + + public void setPropertyValue(String arg0, Object arg1) + throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException { + checkDisposed(); + implPropertySet.setPropertyValue(arg0, arg1); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlResultSetMetaData.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlResultSetMetaData.java new file mode 100644 index 000000000000..cb54880787f6 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlResultSetMetaData.java @@ -0,0 +1,127 @@ +/************************************************************** + * + * 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; + +import com.sun.star.lib.uno.helper.WeakBase; +import com.sun.star.sdbc.DataType; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XResultSetMetaData; + +public class PostgresqlResultSetMetaData extends WeakBase implements XResultSetMetaData { + + private XResultSetMetaData impl; + + public PostgresqlResultSetMetaData(XResultSetMetaData impl) { + this.impl = impl; + } + + public String getCatalogName(int arg0) throws SQLException { + return impl.getCatalogName(arg0); + } + + public int getColumnCount() throws SQLException { + return impl.getColumnCount(); + } + + public int getColumnDisplaySize(int arg0) throws SQLException { + return impl.getColumnDisplaySize(arg0); + } + + public String getColumnLabel(int arg0) throws SQLException { + return impl.getColumnLabel(arg0); + } + + public String getColumnName(int arg0) throws SQLException { + return impl.getColumnName(arg0); + } + + public String getColumnServiceName(int arg0) throws SQLException { + return impl.getColumnServiceName(arg0); + } + + public int getColumnType(int column) throws SQLException { + int columnType = impl.getColumnType(column); + if (columnType == DataType.BIT) { + String columnName = getColumnTypeName(column); + if (columnName.equals("bool")) { + columnType = DataType.BOOLEAN; + } + } + return columnType; + } + + public String getColumnTypeName(int column) throws SQLException { + return impl.getColumnTypeName(column); + } + + public int getPrecision(int arg0) throws SQLException { + return impl.getPrecision(arg0); + } + + public int getScale(int arg0) throws SQLException { + return impl.getScale(arg0); + } + + public String getSchemaName(int arg0) throws SQLException { + return impl.getSchemaName(arg0); + } + + public String getTableName(int arg0) throws SQLException { + return impl.getTableName(arg0); + } + + public boolean isAutoIncrement(int arg0) throws SQLException { + return impl.isAutoIncrement(arg0); + } + + public boolean isCaseSensitive(int arg0) throws SQLException { + return impl.isCaseSensitive(arg0); + } + + public boolean isCurrency(int arg0) throws SQLException { + return impl.isCurrency(arg0); + } + + public boolean isDefinitelyWritable(int arg0) throws SQLException { + return impl.isDefinitelyWritable(arg0); + } + + public int isNullable(int arg0) throws SQLException { + return impl.isNullable(arg0); + } + + public boolean isReadOnly(int arg0) throws SQLException { + return impl.isReadOnly(arg0); + } + + public boolean isSearchable(int arg0) throws SQLException { + return impl.isSearchable(arg0); + } + + public boolean isSigned(int arg0) throws SQLException { + return impl.isSigned(arg0); + } + + public boolean isWritable(int arg0) throws SQLException { + return impl.isWritable(arg0); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlStatement.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlStatement.java new file mode 100644 index 000000000000..462e10f23399 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlStatement.java @@ -0,0 +1,188 @@ +/************************************************************** + * + * 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; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +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.DisposedException; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lib.uno.helper.ComponentBase; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XCloseable; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbc.XMultipleResults; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XStatement; +import com.sun.star.sdbc.XWarningsSupplier; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.XCancellable; + +public class PostgresqlStatement extends ComponentBase + implements XCloseable, XPropertySet, XCancellable, XStatement, XWarningsSupplier, XMultipleResults { + + private XStatement impl; + private XCloseable implCloseable; + private XPropertySet implPropertySet; + private XCancellable implCancellable; + private XWarningsSupplier implWarningsSupplier; + private XMultipleResults implMultipleResults; + private XConnection connection; + private AtomicBoolean isDisposed = new AtomicBoolean(false); + + public PostgresqlStatement(XStatement impl, XConnection connection) { + this.impl = impl; + this.implCloseable = UnoRuntime.queryInterface(XCloseable.class, impl); + this.implPropertySet = UnoRuntime.queryInterface(XPropertySet.class, impl); + this.implCancellable = UnoRuntime.queryInterface(XCancellable.class, impl); + this.implWarningsSupplier = UnoRuntime.queryInterface(XWarningsSupplier.class, impl); + this.implMultipleResults = UnoRuntime.queryInterface(XMultipleResults.class, impl); + this.connection = connection; + } + + // XComponentBase: + + @Override + protected void postDisposing() { + isDisposed.set(true); + try { + implCloseable.close(); + } catch (SQLException sqlException) { + } + } + + private void checkDisposed() throws DisposedException { + if (isDisposed.get()) { + throw new DisposedException(); + } + } + + // XStatement: + + public boolean execute(String arg0) throws SQLException { + checkDisposed(); + System.out.println(arg0); + return impl.execute(arg0); + } + + public XResultSet executeQuery(String arg0) throws SQLException { + checkDisposed(); + XResultSet results = impl.executeQuery(arg0); + return new PostgresqlResultSet(results, this); + } + + public int executeUpdate(String arg0) throws SQLException { + checkDisposed(); + return impl.executeUpdate(arg0); + } + + public XConnection getConnection() throws SQLException { + checkDisposed(); + return connection; + } + + // XCloseable: + + public void close() throws SQLException { + dispose(); + } + + // XPropertySet: + + public void addPropertyChangeListener(String arg0, XPropertyChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.addPropertyChangeListener(arg0, arg1); + } + + public void addVetoableChangeListener(String arg0, XVetoableChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.addVetoableChangeListener(arg0, arg1); + } + + public XPropertySetInfo getPropertySetInfo() { + checkDisposed(); + return implPropertySet.getPropertySetInfo(); + } + + public Object getPropertyValue(String arg0) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + return implPropertySet.getPropertyValue(arg0); + } + + public void removePropertyChangeListener(String arg0, XPropertyChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.removePropertyChangeListener(arg0, arg1); + } + + public void removeVetoableChangeListener(String arg0, XVetoableChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.removeVetoableChangeListener(arg0, arg1); + } + + public void setPropertyValue(String arg0, Object arg1) + throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException { + checkDisposed(); + implPropertySet.setPropertyValue(arg0, arg1); + } + + // XCancellable: + + public void cancel() { + checkDisposed(); + implCancellable.cancel(); + } + + // XWarningsSupplier: + + public void clearWarnings() throws SQLException { + checkDisposed(); + implWarningsSupplier.clearWarnings(); + } + + public Object getWarnings() throws SQLException { + checkDisposed(); + return implWarningsSupplier.getWarnings(); + } + + // XMultipleResults: + + public boolean getMoreResults() throws SQLException { + checkDisposed(); + return implMultipleResults.getMoreResults(); + } + + public XResultSet getResultSet() throws SQLException { + checkDisposed(); + return new PostgresqlResultSet(implMultipleResults.getResultSet(), this); + } + + public int getUpdateCount() throws SQLException { + checkDisposed(); + return implMultipleResults.getUpdateCount(); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlTable.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlTable.java new file mode 100644 index 000000000000..426bded92625 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlTable.java @@ -0,0 +1,125 @@ +/************************************************************** + * + * 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; + +import java.util.List; +import java.util.Map; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.ElementExistException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.IndexOutOfBoundsException; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OColumnContainer; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OContainer; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OIndexContainer; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OKey; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OKeyContainer; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OTable; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.SqlTableHelper; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.SqlTableHelper.ColumnDescription; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.descriptors.SdbcxTableDescriptor; + +public class PostgresqlTable extends OTable { + private PostgresqlTable(Object lock, XConnection connection, OContainer tables, String name, + String catalogName, String schemaName, String description, String type) { + super(lock, name, true, connection, tables); + super.catalogName = catalogName; + super.schemaName = schemaName; + super.description = description; + super.type = type; + } + + public static PostgresqlTable create(XConnection connection, OContainer tables, String name, + String catalogName, String schemaName, String description, String type) { + Object lock = new Object(); + return new PostgresqlTable(lock, connection, tables, name, catalogName, schemaName, description, type); + } + + @Override + public XPropertySet createDataDescriptor() { + SdbcxTableDescriptor descriptor = SdbcxTableDescriptor.create(true); + synchronized (lock) { + CompHelper.copyProperties(this, descriptor); + } + return descriptor; + } + + @Override + public void setName(String name) { + // TODO Auto-generated method stub + + } + + @Override + public void rename(String name) throws SQLException, ElementExistException { + // TODO Auto-generated method stub + + } + + @Override + public void alterColumnByIndex(int index, XPropertySet descriptor) throws SQLException, IndexOutOfBoundsException { + // TODO Auto-generated method stub + + } + + @Override + public void alterColumnByName(String name, XPropertySet descriptor) throws SQLException, NoSuchElementException { + // TODO Auto-generated method stub + + } + + @Override + protected OContainer refreshColumns() { + try { + List<ColumnDescription> columns = new SqlTableHelper().readColumns(getConnection().getMetaData(), catalogName, schemaName, getName()); + return new OColumnContainer(lock, isCaseSensitive(), columns, this, getConnection().getMetaData()); + } catch (SQLException sqlException) { + return null; + } + } + + @Override + protected OContainer refreshIndexes() { + try { + List<String> indexes = new SqlTableHelper().readIndexes(getConnection().getMetaData(), catalogName, schemaName, getName(), this); + return new OIndexContainer(lock, indexes, isCaseSensitive(), this); + } catch (SQLException sqlException) { + return null; + } + } + + @Override + protected OContainer refreshKeys() { + try { + Map<String, OKey> keys = new SqlTableHelper().readKeys( + getConnection().getMetaData(), catalogName, schemaName, getName(), isCaseSensitive(), this); + return OKeyContainer.create(isCaseSensitive(), keys, this); + } catch (SQLException sqlException) { + return null; + } + } + + +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlTables.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlTables.java new file mode 100644 index 000000000000..7591f7974153 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/PostgresqlTables.java @@ -0,0 +1,151 @@ +/************************************************************** + * + * 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; + +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.IndexOutOfBoundsException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XDatabaseMetaData; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XRow; +import com.sun.star.sdbc.XStatement; +import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OContainer; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.descriptors.SdbcxTableDescriptor; +import com.sun.star.sdbcx.comp.postgresql.util.ComposeRule; +import com.sun.star.sdbcx.comp.postgresql.util.DbTools; +import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds; +import com.sun.star.sdbcx.comp.postgresql.util.StandardSQLState; +import com.sun.star.sdbcx.comp.postgresql.util.DbTools.NameComponents; +import com.sun.star.uno.Any; +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.UnoRuntime; + +public class PostgresqlTables extends OContainer { + private XDatabaseMetaData metadata; + private PostgresqlCatalog catalog; + + public PostgresqlTables(Object lock, XDatabaseMetaData metadata, PostgresqlCatalog catalog, List<String> names) { + super(lock, true, names); + this.metadata = metadata; + this.catalog = catalog; + } + + @Override + public XPropertySet createObject(String name) throws SQLException { + NameComponents nameComponents = DbTools.qualifiedNameComponents(metadata, name, ComposeRule.InDataManipulation); + Object queryCatalog = nameComponents.getCatalog().isEmpty() ? Any.VOID : nameComponents.getCatalog(); + XPropertySet ret = null; + XResultSet results = null; + try { + results = metadata.getTables( + queryCatalog, nameComponents.getSchema(), nameComponents.getTable(), new String[] { "VIEW", "TABLE", "%" }); + if (results != null) { + XRow row = UnoRuntime.queryInterface(XRow.class, results); + if (results.next()) { + String type = row.getString(4); + String remarks = row.getString(5); + ret = PostgresqlTable.create(metadata.getConnection(), this, nameComponents.getTable(), + nameComponents.getCatalog(), nameComponents.getSchema(), remarks, type); + } + } + } finally { + CompHelper.disposeComponent(results); + } + return ret; + + } + + @Override + public void dropObject(int index, String name) throws SQLException { + try { + Object object = getObject(index); + + NameComponents nameComponents = DbTools.qualifiedNameComponents(metadata, name, ComposeRule.InDataManipulation); + + boolean isView = false; + XPropertySet propertySet = UnoRuntime.queryInterface(XPropertySet.class, object); + if (propertySet != null) { + isView = AnyConverter.toString(propertySet.getPropertyValue(PropertyIds.TYPE.name)).equals("VIEW"); + } + + String composedName = DbTools.composeTableName(metadata, nameComponents.getCatalog(), nameComponents.getSchema(), nameComponents.getTable(), + true, ComposeRule.InDataManipulation); + String sql = String.format("DROP %s %s", isView ? "VIEW" : "TABLE", composedName); + + XStatement statement = null; + try { + statement = metadata.getConnection().createStatement(); + statement.execute(sql); + } finally { + CompHelper.disposeComponent(statement); + } + // FIXME: delete it from our views + } catch (IllegalArgumentException illegalArgumentException) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, illegalArgumentException); + } catch (UnknownPropertyException unknownPropertyException) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, unknownPropertyException); + } catch (WrappedTargetException wrappedTargetException) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, wrappedTargetException); + } + } + + @Override + public void impl_refresh() { + catalog.refreshTables(); + } + + @Override + public XPropertySet createDescriptor() { + return SdbcxTableDescriptor.create(true); + } + + @Override + public XPropertySet appendObject(String name, XPropertySet descriptor) throws SQLException { + createTable(descriptor); + return createObject(name); + } + + void createTable(XPropertySet descriptor) throws SQLException { + XStatement statement = null; + try { + String sql = DbTools.createSqlCreateTableStatement(descriptor, metadata.getConnection(), null, "(M,D)"); + statement = metadata.getConnection().createStatement(); + statement.execute(sql); + } catch (IndexOutOfBoundsException indexOutOfBoundsException) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, indexOutOfBoundsException); + } catch (IllegalArgumentException illegalArgumentException) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, illegalArgumentException); + } catch (UnknownPropertyException unknownPropertyException) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, unknownPropertyException); + } catch (WrappedTargetException wrappedTargetException) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, wrappedTargetException); + } finally { + CompHelper.disposeComponent(statement); + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/CompHelper.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/CompHelper.java new file mode 100644 index 000000000000..27ac3439e2ba --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/CompHelper.java @@ -0,0 +1,74 @@ +/************************************************************** + * + * 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 com.sun.star.beans.Property; +import com.sun.star.beans.PropertyAttribute; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertySetInfo; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XServiceInfo; +import com.sun.star.uno.UnoRuntime; + +public class CompHelper { + /** + * If the given parameter is an XComponent, calls dispose() on it. + * @param object the UNO interface to try dispose; may be null. + */ + public static void disposeComponent(final Object object) { + final XComponent component = UnoRuntime.queryInterface(XComponent.class, object); + if (component != null) { + component.dispose(); + } + } + + public static void copyProperties(final XPropertySet src, final XPropertySet dst) { + if (src == null || dst == null) { + return; + } + + XPropertySetInfo srcPropertySetInfo = src.getPropertySetInfo(); + XPropertySetInfo dstPropertySetInfo = dst.getPropertySetInfo(); + + for (Property srcProperty : srcPropertySetInfo.getProperties()) { + if (dstPropertySetInfo.hasPropertyByName(srcProperty.Name)) { + try { + Property dstProperty = dstPropertySetInfo.getPropertyByName(srcProperty.Name); + if ((dstProperty.Attributes & PropertyAttribute.READONLY) == 0) { + Object value = src.getPropertyValue(srcProperty.Name); + if ((dstProperty.Attributes & PropertyAttribute.MAYBEVOID) == 0 || value != null) { + dst.setPropertyValue(srcProperty.Name, value); + } + } + } catch (Exception e) { + String error = "Could not copy property '" + srcProperty.Name + + "' to the destination set"; + XServiceInfo serviceInfo = UnoRuntime.queryInterface(XServiceInfo.class, dst); + if (serviceInfo != null) { + error += " (a '" + serviceInfo.getImplementationName() + "' implementation)"; + } + + } + } + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/OArrayEnumeration.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/OArrayEnumeration.java new file mode 100644 index 000000000000..aa24b3154bee --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/OArrayEnumeration.java @@ -0,0 +1,55 @@ +/************************************************************** + * + * 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 com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XEnumeration; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lib.uno.helper.WeakBase; + +public class OArrayEnumeration extends WeakBase implements XEnumeration { + private Object[] elements; + private int position; + + public OArrayEnumeration(Object[] elements) { + this.elements = elements; + } + + @Override + public boolean hasMoreElements() { + synchronized (this) { + return position < elements.length; + } + } + + @Override + public Object nextElement() + throws NoSuchElementException, WrappedTargetException { + synchronized (this) { + if (position < elements.length) { + return elements[position++]; + } else { + throw new NoSuchElementException(); + } + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/OEnumerationByIndex.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/OEnumerationByIndex.java new file mode 100644 index 000000000000..5af79235e4b0 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/OEnumerationByIndex.java @@ -0,0 +1,118 @@ +/************************************************************** + * + * 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 com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XEnumeration; +import com.sun.star.container.XIndexAccess; +import com.sun.star.lang.EventObject; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XEventListener; +import com.sun.star.lib.uno.helper.WeakBase; +import com.sun.star.uno.UnoRuntime; + +public class OEnumerationByIndex extends WeakBase implements XEnumeration, XEventListener { + private XIndexAccess collection; + private int position; + boolean isListening; + + public OEnumerationByIndex(XIndexAccess collection) { + this.collection = collection; + startDisposeListening(); + } + + @Override + public void disposing(EventObject event) { + synchronized (this) { + if (event.Source == collection) { + collection = null; + } + } + } + + @Override + public boolean hasMoreElements() { + synchronized (this) { + if (collection != null) { + if (position < collection.getCount()) { + return true; + } else { + stopDisposeListening(); + collection = null; + } + } + return false; + } + } + + @Override + public Object nextElement() + throws NoSuchElementException, WrappedTargetException { + Object value = null; + synchronized (this) { + if (collection != null) { + if (position < collection.getCount()) { + try { + value = collection.getByIndex(position++); + } catch (com.sun.star.lang.IndexOutOfBoundsException indexOutOfBoundsException) { + // can't happen + } + } + if (position >= collection.getCount()) { + stopDisposeListening(); + collection = null; + } + } + } + if (value == null) { + throw new NoSuchElementException(); + } + return value; + } + + private void startDisposeListening() { + synchronized (this) { + if (isListening) { + return; + } + XComponent component = UnoRuntime.queryInterface(XComponent.class, collection); + if (component != null) { + component.addEventListener(this); + isListening = true; + } + } + } + + private void stopDisposeListening() { + synchronized (this) { + if (!isListening) { + return; + } + XComponent component = UnoRuntime.queryInterface(XComponent.class, collection); + if (component != null) { + component.removeEventListener(this); + isListening = false; + } + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/OEnumerationByName.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/OEnumerationByName.java new file mode 100644 index 000000000000..155c8e5227e8 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/OEnumerationByName.java @@ -0,0 +1,116 @@ +/************************************************************** + * + * 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 com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XEnumeration; +import com.sun.star.container.XNameAccess; +import com.sun.star.lang.EventObject; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XEventListener; +import com.sun.star.lib.uno.helper.WeakBase; +import com.sun.star.uno.UnoRuntime; + +public class OEnumerationByName extends WeakBase implements XEnumeration, XEventListener { + private String[] names; + private int position; + private XNameAccess collection; + private boolean isListening; + + public OEnumerationByName(XNameAccess collection) { + this.collection = collection; + names = collection.getElementNames(); + startDisposeListening(); + } + + @Override + public void disposing(EventObject event) { + synchronized (this) { + if (event.Source == collection) { + collection = null; + } + } + } + + @Override + public boolean hasMoreElements() { + synchronized (this) { + if (collection != null) { + if (position < names.length) { + return true; + } else { + stopDisposeListening(); + collection = null; + } + } + return false; + } + } + + @Override + public Object nextElement() + throws NoSuchElementException, WrappedTargetException { + Object value = null; + synchronized (this) { + if (collection != null) { + if (position < names.length) { + value = collection.getByName(names[position++]); + } + if (position >= names.length) { + stopDisposeListening(); + collection = null; + } + } + } + if (value == null) { + throw new NoSuchElementException(); + } + return value; + } + + private void startDisposeListening() { + synchronized (this) { + if (isListening) { + return; + } + XComponent component = UnoRuntime.queryInterface(XComponent.class, collection); + if (component != null) { + component.addEventListener(this); + isListening = true; + } + } + } + + private void stopDisposeListening() { + synchronized (this) { + if (!isListening) { + return; + } + XComponent component = UnoRuntime.queryInterface(XComponent.class, collection); + if (component != null) { + component.removeEventListener(this); + isListening = false; + } + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySet.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySet.java new file mode 100644 index 000000000000..a49a2dd6b4e5 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySet.java @@ -0,0 +1,160 @@ +/************************************************************** + * + * 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 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.DisposedException; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lib.uno.helper.ComponentBase; +import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySetAdapter.PropertyGetter; +import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySetAdapter.PropertySetter; +import com.sun.star.uno.Type; + +public class PropertySet extends ComponentBase implements XPropertySet, XFastPropertySet, XMultiPropertySet { + private final PropertySetAdapter impl; + + protected PropertySet(Object lock) { + impl = new PropertySetAdapter(lock, this); + } + + @Override + protected void postDisposing() { + impl.dispose(); + } + + public void registerProperty(String propertyName, int handle, Type type, short attributes, PropertyGetter getter, PropertySetter setter) { + impl.registerProperty(propertyName, handle, type, attributes, getter, setter); + } + + public void registerProperty(String propertyName, Type type, short attributes, PropertyGetter getter, PropertySetter setter) { + impl.registerProperty(propertyName, type, attributes, getter, setter); + } + + public void addPropertyChangeListener(String propertyName, XPropertyChangeListener listener) throws UnknownPropertyException, WrappedTargetException { + // only add listeners if you are not disposed + if (!bInDispose && !bDisposed) { + impl.addPropertyChangeListener(propertyName, listener); + } + } + + public void addVetoableChangeListener(String propertyName, XVetoableChangeListener listener) throws UnknownPropertyException, WrappedTargetException { + // only add listeners if you are not disposed + if (!bInDispose && !bDisposed) { + impl.addVetoableChangeListener(propertyName, listener); + } + } + + public void addPropertiesChangeListener(String[] propertyNames, XPropertiesChangeListener listener) { + // only add listeners if you are not disposed + if (!bInDispose && !bDisposed) { + impl.addPropertiesChangeListener(propertyNames, listener); + } + } + + public XPropertySetInfo getPropertySetInfo() { + return impl.getPropertySetInfo(); + } + + public Object getPropertyValue(String propertyName) throws UnknownPropertyException, WrappedTargetException { + if (bInDispose || bDisposed) { + throw new DisposedException("Component is already disposed"); + } + return impl.getPropertyValue(propertyName); + } + + @Override + public Object getFastPropertyValue(int handle) throws UnknownPropertyException, WrappedTargetException { + if (bInDispose || bDisposed) { + throw new DisposedException("Component is already disposed"); + } + return impl.getFastPropertyValue(handle); + } + + public Object[] getPropertyValues(String[] propertyNames) { + if (bInDispose || bDisposed) { + throw new DisposedException("Component is already disposed"); + } + return impl.getPropertyValues(propertyNames); + } + + public void removePropertyChangeListener(String propertyName, XPropertyChangeListener listener) throws UnknownPropertyException, WrappedTargetException { + // all listeners are automatically released in a dispose call + if (!bInDispose && !bDisposed) { + impl.removePropertyChangeListener(propertyName, listener); + } + } + + public void removeVetoableChangeListener(String propertyName, XVetoableChangeListener listener) throws UnknownPropertyException, WrappedTargetException { + // all listeners are automatically released in a dispose call + if (!bInDispose && !bDisposed) { + impl.removeVetoableChangeListener(propertyName, listener); + } + } + + public void removePropertiesChangeListener(XPropertiesChangeListener listener) { + // all listeners are automatically released in a dispose call + if (!bInDispose && !bDisposed) { + impl.removePropertiesChangeListener(listener); + } + } + + public void setPropertyValue(String propertyName, Object value) + throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException { + if (bInDispose || bDisposed) { + throw new DisposedException("Component is already disposed"); + } + impl.setPropertyValue(propertyName, value); + } + + public void setFastPropertyValue(int handle, Object value) + throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException { + if (bInDispose || bDisposed) { + throw new DisposedException("Component is already disposed"); + } + impl.setFastPropertyValue(handle, value); + } + + public void setPropertyValues(String[] propertyNames, Object[] values) throws PropertyVetoException, IllegalArgumentException, WrappedTargetException { + if (bInDispose || bDisposed) { + throw new DisposedException("Component is already disposed"); + } + impl.setPropertyValues(propertyNames, values); + } + + public void firePropertiesChangeEvent(String[] propertyNames, XPropertiesChangeListener listener) { + if (bInDispose || bDisposed) { + throw new DisposedException("Component is already disposed"); + } + impl.firePropertiesChangeEvent(propertyNames, listener); + } + + +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySetAdapter.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySetAdapter.java new file mode 100644 index 000000000000..03de4f065cc4 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/comphelper/PropertySetAdapter.java @@ -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); + } + } + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ISQLStatementHelper.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ISQLStatementHelper.java new file mode 100644 index 000000000000..52fbf7f466ca --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ISQLStatementHelper.java @@ -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); +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OCatalog.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OCatalog.java new file mode 100644 index 000000000000..aba5c1fb3d0b --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OCatalog.java @@ -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(); +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumn.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumn.java new file mode 100644 index 000000000000..04850d76bfc7 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumn.java @@ -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; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumnContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumnContainer.java new file mode 100644 index 000000000000..a50aa31f1f3a --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OColumnContainer.java @@ -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 { + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OContainer.java new file mode 100644 index 000000000000..9f0ed55e2e04 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OContainer.java @@ -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; + +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ODescriptor.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ODescriptor.java new file mode 100644 index 000000000000..d885eae09611 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/ODescriptor.java @@ -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; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndex.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndex.java new file mode 100644 index 000000000000..e2d2c2df2a02 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndex.java @@ -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() + "]"; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumn.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumn.java new file mode 100644 index 000000000000..7c29d2ec6d1e --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumn.java @@ -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; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumnContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumnContainer.java new file mode 100644 index 000000000000..5e6db41bed7b --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexColumnContainer.java @@ -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"); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexContainer.java new file mode 100644 index 000000000000..c5109335a616 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OIndexContainer.java @@ -0,0 +1,208 @@ +/************************************************************** + * + * 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.List; + +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.XIndexAccess; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.IndexOutOfBoundsException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.sdbc.IndexType; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbc.XDatabaseMetaData; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XRow; +import com.sun.star.sdbc.XStatement; +import com.sun.star.sdbcx.XColumnsSupplier; +import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.descriptors.SdbcxIndexDescriptor; +import com.sun.star.sdbcx.comp.postgresql.util.ComposeRule; +import com.sun.star.sdbcx.comp.postgresql.util.DbTools; +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 OIndexContainer extends OContainer { + protected OTable table; + + public OIndexContainer(Object lock, List<String> names, boolean isCaseSensitive, OTable table) { + super(lock, isCaseSensitive, names); + this.table = table; + } + + @Override + public XPropertySet createDescriptor() { + return SdbcxIndexDescriptor.create(isCaseSensitive()); + } + + @Override + public XPropertySet createObject(String name) throws SQLException { + try { + XConnection connection = table.getConnection(); + if (connection == null) { + return null; + } + + XPropertySet ret = null; + String qualifier = ""; + String subname; + int len = name.indexOf('.'); + if (len >= 0) { + qualifier = name.substring(0, len); + subname = name.substring(len + 1); + } else { + subname = name; + } + + Object catalog = table.getPropertyValue(PropertyIds.CATALOGNAME.name); + String schemaName = AnyConverter.toString(table.getPropertyValue(PropertyIds.SCHEMANAME.name)); + String tableName = AnyConverter.toString(table.getPropertyValue(PropertyIds.NAME.name)); + XResultSet results = null; + try { + results = connection.getMetaData().getIndexInfo(catalog, schemaName, tableName, false, false); + if (results != null) { + XRow row = UnoRuntime.queryInterface(XRow.class, results); + boolean found = false; + boolean isUnique = false; + int clustered = -1; + boolean isPrimaryKeyIndex = false; + ArrayList<String> columnNames = new ArrayList<>(); + while (results.next()) { + isUnique = !row.getBoolean(4); + if ((qualifier.isEmpty() || row.getString(5).equals(qualifier)) && row.getString(6).equals(subname)) { + found = true; + clustered = row.getShort(7); + isPrimaryKeyIndex = isPrimaryKeyIndex(connection.getMetaData(), catalog, schemaName, tableName, subname); + String columnName = row.getString(9); + if (!row.wasNull()) { + columnNames.add(columnName); + } + } + } + if (found) { + ret = OIndex.create(subname, isCaseSensitive(), qualifier, isUnique, isPrimaryKeyIndex, clustered == IndexType.CLUSTERED, + columnNames, table); + } + } + } finally { + CompHelper.disposeComponent(results); + } + return ret; + } catch (WrappedTargetException | UnknownPropertyException | IllegalArgumentException exception) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, exception); + } + } + + private static boolean isPrimaryKeyIndex(XDatabaseMetaData metadata, Object catalog, String schema, String table, String name) throws SQLException { + XResultSet results = null; + try { + results = metadata.getPrimaryKeys(catalog, schema, table); + if (results != null) { + XRow row = UnoRuntime.queryInterface(XRow.class, results); + if (results.next()) { // there can be only one primary key + return row.getString(6).equals(name); + } + } + return false; + } finally { + CompHelper.disposeComponent(results); + } + } + + @Override + public XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException { + try { + XConnection connection = table.getConnection(); + if (connection == null) { + return null; + } + String quote = connection.getMetaData().getIdentifierQuoteString(); + boolean isUnique = AnyConverter.toBoolean(descriptor.getPropertyValue(PropertyIds.ISUNIQUE.name)); + String composedName = DbTools.composeTableName(connection.getMetaData(), table, ComposeRule.InIndexDefinitions, false, false, true); + StringBuilder columnsText = new StringBuilder(); + String separator = ""; + XColumnsSupplier columnsSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, descriptor); + XIndexAccess columns = UnoRuntime.queryInterface(XIndexAccess.class, columnsSupplier.getColumns()); + for (int i = 0; i < columns.getCount(); i++) { + columnsText.append(separator); + separator = ", "; + XPropertySet column = AnyConverter.toObject(XPropertySet.class, columns.getByIndex(i)); + columnsText.append(DbTools.quoteName(quote, AnyConverter.toString(column.getPropertyValue(PropertyIds.NAME.name)))); + // FIXME: ::dbtools::getBooleanDataSourceSetting( m_pTable->getConnection(), "AddIndexAppendix" ); + boolean isAscending = AnyConverter.toBoolean(column.getPropertyValue(PropertyIds.ISASCENDING.name)); + columnsText.append(isAscending ? " ASC" : " DESC"); + } + String sql = String.format("CREATE %s INDEX %s ON %s (%s)", + isUnique ? "UNIQUE" : "", + _rForName.isEmpty() ? "" : DbTools.quoteName(quote, _rForName), + composedName, + columnsText.toString()); + XStatement statement = null; + try { + statement = connection.createStatement(); + statement.execute(sql); + } finally { + CompHelper.disposeComponent(statement); + } + return createObject(_rForName); + } catch (WrappedTargetException | UnknownPropertyException | IllegalArgumentException | IndexOutOfBoundsException exception) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, exception); + } + } + + @Override + public void dropObject(int index, String elementName) throws SQLException { + XConnection connection = table.getConnection(); + if (connection == null) { + return; + } + String name; + String schema = ""; + int len = elementName.indexOf('.'); + if (len >= 0) { + schema = elementName.substring(0, len); + } + name = elementName.substring(len + 1); + + String composedName = DbTools.composeTableName(connection.getMetaData(), table, ComposeRule.InTableDefinitions, false, false, true); + String indexName = DbTools.composeTableName(connection.getMetaData(), "", schema, name, true, ComposeRule.InIndexDefinitions); + String sql = String.format("DROP INDEX %s ON %s", indexName, composedName); + XStatement statement = null; + try { + statement = connection.createStatement(); + statement.execute(sql); + } finally { + CompHelper.disposeComponent(statement); + } + } + + @Override + public void impl_refresh() { + // FIXME + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKey.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKey.java new file mode 100644 index 000000000000..6ebae316be41 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKey.java @@ -0,0 +1,150 @@ +/************************************************************** + * + * 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.lang.DisposedException; +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.SdbcxKeyDescriptor; +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 OKey extends ODescriptor + implements XDataDescriptorFactory, XColumnsSupplier { + + protected OTable table; + protected String referencedTable; + protected int type; + protected int updateRule; + protected int deleteRule; + + private OContainer columns; + + protected OKey(Object lock, boolean isCaseSensitive) { + super(lock, "", isCaseSensitive); + registerProperties(); + } + + protected OKey(Object lock, String name, boolean isCaseSensitive, String referencedTable, int type, + int updateRule, int deleteRule, List<String> columnNames, OTable table) { + super(lock, name, isCaseSensitive); + this.referencedTable = referencedTable; + this.type = type; + this.updateRule = updateRule; + this.deleteRule = deleteRule; + this.table = table; + registerProperties(); + columns = new OKeyColumnContainer(lock, this, columnNames); + } + + public static OKey create(String name, boolean isCaseSensitive, String referencedTable, int type, + int updateRule, int deleteRule, List<String> columnNames, OTable table) { + final Object lock = new Object(); + return new OKey(lock, name, isCaseSensitive, referencedTable, type, updateRule, deleteRule, columnNames, table); + } + + private void registerProperties() { + registerProperty(PropertyIds.REFERENCEDTABLE.name, PropertyIds.REFERENCEDTABLE.id, Type.STRING, (short)PropertyAttribute.READONLY, + new PropertyGetter() { + @Override + public Object getValue() { + return referencedTable; + + } + }, null); + registerProperty(PropertyIds.TYPE.name, PropertyIds.TYPE.id, Type.LONG, (short)PropertyAttribute.READONLY, + new PropertyGetter() { + @Override + public Object getValue() { + return type; + + } + }, null); + registerProperty(PropertyIds.UPDATERULE.name, PropertyIds.UPDATERULE.id, Type.LONG, (short)PropertyAttribute.READONLY, + new PropertyGetter() { + @Override + public Object getValue() { + return updateRule; + + } + }, null); + registerProperty(PropertyIds.DELETERULE.name, PropertyIds.DELETERULE.id, Type.LONG, (short)PropertyAttribute.READONLY, + new PropertyGetter() { + @Override + public Object getValue() { + return deleteRule; + + } + }, null); + } + + // XComponent + + private void checkDisposed() { + if (bDisposed) { + throw new DisposedException(); + } + } + + // XColumnsSupplier + + @Override + public XNameAccess getColumns() { + synchronized (lock) { + checkDisposed(); + return columns; + } + } + + // XDataDescriptionFactory + + public XPropertySet createDataDescriptor() { + SdbcxKeyDescriptor descriptor = SdbcxKeyDescriptor.create(isCaseSensitive()); + CompHelper.copyProperties(this, descriptor); + try { + DbTools.cloneDescriptorColumns(this, descriptor); + } catch (SQLException sqlException) { + } + return descriptor; + } + + public OTable getTable() { + return table; + } + + @Override + public String toString() { + return "OKey [referencedTable=" + referencedTable + ", type=" + type + ", updateRule=" + updateRule + ", deleteRule=" + deleteRule + + ", name=" + getName() + "]"; + } + + +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKeyColumn.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKeyColumn.java new file mode 100644 index 000000000000..d7f409f882d0 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKeyColumn.java @@ -0,0 +1,101 @@ +/************************************************************** + * + * 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.SdbcxKeyColumnDescriptor; +import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds; +import com.sun.star.uno.Type; + +public class OKeyColumn extends OColumn { + protected String referencedColumn; + + protected OKeyColumn(Object lock, boolean isCaseSensitive) { + super(lock, isCaseSensitive); + registerProperties(); + } + + protected OKeyColumn( + final Object lock, + final String referencedColumn, + 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.referencedColumn = referencedColumn; + registerProperties(); + } + + public static OKeyColumn create( + final String referencedColumn, + 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 OKeyColumn(lock, referencedColumn, name, typeName, + defaultValue, "", isNullable, precision, scale, + type, isAutoIncrement, isRowVersion, isCurrency, isCaseSensitive); + } + + private void registerProperties() { + registerProperty(PropertyIds.RELATEDCOLUMN.name, PropertyIds.RELATEDCOLUMN.id, Type.STRING, PropertyAttribute.READONLY, + new PropertyGetter() { + @Override + public Object getValue() { + return referencedColumn; + + } + }, null); + } + + // XDataDescriptorFactory + + @Override + public XPropertySet createDataDescriptor() { + SdbcxKeyColumnDescriptor descriptor = SdbcxKeyColumnDescriptor.create(isCaseSensitive()); + synchronized (lock) { + CompHelper.copyProperties(this, descriptor); + } + return descriptor; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKeyColumnContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKeyColumnContainer.java new file mode 100644 index 000000000000..0fc5aa495589 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKeyColumnContainer.java @@ -0,0 +1,115 @@ +/************************************************************** + * + * 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.sdbcx.descriptors.SdbcxKeyColumnDescriptor; +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 OKeyColumnContainer extends OContainer { + private OKey key; + + public OKeyColumnContainer(Object lock, OKey key, List<String> columnNames) { + super(lock, true, columnNames); + this.key = key; + } + + @Override + public XPropertySet createDescriptor() { + return SdbcxKeyColumnDescriptor.create(isCaseSensitive()); + } + + @Override + public XPropertySet createObject(String name) throws SQLException { + try { + XPropertySet tableProperties = UnoRuntime.queryInterface(XPropertySet.class, key.getTable()); + Object catalog = tableProperties.getPropertyValue(PropertyIds.CATALOGNAME.name); + String schema = AnyConverter.toString(tableProperties.getPropertyValue(PropertyIds.SCHEMANAME.name)); + String table = AnyConverter.toString(tableProperties.getPropertyValue(PropertyIds.NAME.name)); + + XResultSet results = key.getTable().getConnection().getMetaData().getImportedKeys(catalog, schema, table); + String refColumnName = ""; + if (results != null) { + XRow row = UnoRuntime.queryInterface(XRow.class, results); + while (results.next()) { + if (row.getString(8).equals(name) && key.getName().equals(row.getString(12))) { + refColumnName = row.getString(4); + break; + } + } + } + + XPropertySet ret = null; + // now describe the column name and set its related column + results = key.getTable().getConnection().getMetaData().getColumns(catalog, schema, table, name); + if (results != null) { + XRow row = UnoRuntime.queryInterface(XRow.class, results); + if (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 = ""; + try { + columnDef = row.getString(13); + } catch (SQLException sqlException) { + // sometimes we get an error when asking for this param + } + ret = OKeyColumn.create(refColumnName, name, typeName, + columnDef, nul, size, dec, dataType, false, false, false, isCaseSensitive()); + + } + } + } + return ret; + } catch (WrappedTargetException | UnknownPropertyException | IllegalArgumentException exception) { + throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, exception); + } + } + + @Override + public void impl_refresh() { + } + + @Override + public XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException { + throw new SQLException("Cannot change a key's columns, please delete and re-create the key instead"); + } + + @Override + public void dropObject(int index, String name) throws SQLException { + throw new SQLException("Cannot change a key's columns, please delete and re-create the key instead"); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKeyContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKeyContainer.java new file mode 100644 index 000000000000..d00f9018a115 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OKeyContainer.java @@ -0,0 +1,277 @@ +/************************************************************** + * + * 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.Arrays; +import java.util.List; +import java.util.Map; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.XIndexAccess; +import com.sun.star.container.XNamed; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.IndexOutOfBoundsException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.sdbc.KeyRule; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XRow; +import com.sun.star.sdbc.XStatement; +import com.sun.star.sdbcx.KeyType; +import com.sun.star.sdbcx.XColumnsSupplier; +import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.descriptors.SdbcxKeyDescriptor; +import com.sun.star.sdbcx.comp.postgresql.util.ComposeRule; +import com.sun.star.sdbcx.comp.postgresql.util.DbTools; +import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds; +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.UnoRuntime; + +public class OKeyContainer extends OContainer { + private OTable table; + private Map<String,OKey> keys; + + protected OKeyContainer(Object lock, boolean isCaseSensitive, List<String> names, Map<String,OKey> keys, OTable table) { + super(lock, isCaseSensitive, names); + System.out.println("Keys.size()=" + keys.size()); + for (Map.Entry<String,OKey> entry : keys.entrySet()) { + System.out.println(entry.getKey() + " => " + entry.getValue().referencedTable); + XIndexAccess cols = UnoRuntime.queryInterface(XIndexAccess.class, entry.getValue().getColumns()); + try { + System.out.println("" + cols.getCount() + " columns:"); + for (int i =0; i < cols.getCount(); i++) { + System.out.println(" " + AnyConverter.toObject(XNamed.class, cols.getByIndex(i)).getName()); + } + } catch (WrappedTargetException wrappedTargetException) { + wrappedTargetException.printStackTrace(); + } catch (IndexOutOfBoundsException indexOutOfBoundsException) { + indexOutOfBoundsException.printStackTrace(); + } catch (IllegalArgumentException argumentException) { + argumentException.printStackTrace(); + } + } + this.keys = keys; + this.table = table; + } + + public static OKeyContainer create(boolean isCaseSensitive, Map<String,OKey> keys, OTable table) { + final Object lock = new Object(); + String[] names = new String[keys.size()]; + keys.keySet().toArray(names); + return new OKeyContainer(lock, isCaseSensitive, Arrays.asList(names), keys, table); + } + + @Override + public XPropertySet createDescriptor() { + return SdbcxKeyDescriptor.create(isCaseSensitive()); + } + + @Override + public XPropertySet createObject(String name) throws SQLException { + OKey ret = null; + + if (!name.isEmpty()) { + ret = keys.get(name); + } + + if (ret == null) { // we have a primary key with a system name + // FIXME: so why was this exactly the same? + ret = keys.get(name); + } + + return ret; + } + + @Override + public void impl_refresh() { + //throw new NotImplementedException(""); + } + + @Override + public XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException { + XConnection connection = table.getConnection(); + if (connection == null) { + return null; + } + try { + int keyType = AnyConverter.toInt(descriptor.getPropertyValue(PropertyIds.TYPE.name)); + int updateRule = 0; + int deleteRule = 0; + String referencedName = ""; + if (keyType == KeyType.FOREIGN) { + referencedName = AnyConverter.toString(descriptor.getPropertyValue(PropertyIds.UPDATERULE.name)); + updateRule = AnyConverter.toInt(descriptor.getPropertyValue(PropertyIds.UPDATERULE.name)); + deleteRule = AnyConverter.toInt(descriptor.getPropertyValue(PropertyIds.DELETERULE.name)); + } + + String quote = connection.getMetaData().getIdentifierQuoteString(); + String tableName = DbTools.composeTableName(connection.getMetaData(), table, ComposeRule.InTableDefinitions, false, false, true); + + String keyTypeString; + if (keyType == KeyType.PRIMARY) { + keyTypeString = "PRIMARY KEY"; + } else if (keyType == KeyType.FOREIGN) { + keyTypeString = "FOREIGN KEY"; + } else { + throw new SQLException(); + } + + StringBuilder columnsText = new StringBuilder(); + XColumnsSupplier columnsSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, descriptor); + XIndexAccess columns = UnoRuntime.queryInterface(XIndexAccess.class, columnsSupplier.getColumns()); + String separator = ""; + for (int i = 0; i < columns.getCount(); i++) { + columnsText.append(separator); + separator = ","; + XPropertySet columnProperties = AnyConverter.toObject(XPropertySet.class, columns.getByIndex(i)); + columnsText.append(DbTools.quoteName(quote, AnyConverter.toString(columnProperties.getPropertyValue(PropertyIds.NAME.name)))); + } + + String sql = String.format("ALTER TABLE %s ADD %s (%s)", tableName, keyTypeString, columnsText.toString()); + + if (keyType == KeyType.FOREIGN) { + String quotedTableName = DbTools.quoteTableName(connection.getMetaData(), referencedName, ComposeRule.InTableDefinitions); + StringBuilder relatedColumns = new StringBuilder(); + separator = ""; + for (int i = 0; i < columns.getCount(); i++) { + relatedColumns.append(separator); + separator = ","; + XPropertySet columnProperties = AnyConverter.toObject(XPropertySet.class, columns.getByIndex(i)); + relatedColumns.append(DbTools.quoteName(quote, AnyConverter.toString(columnProperties.getPropertyValue(PropertyIds.RELATEDCOLUMN.name)))); + } + sql += String.format(" REFERENCES %s (%s)%s%s", quotedTableName, relatedColumns.toString(), + getKeyRuleString(true, updateRule), getKeyRuleString(false, deleteRule)); + } + XStatement statement = null; + try { + statement = connection.createStatement(); + statement.execute(sql); + } finally { + CompHelper.disposeComponent(statement); + } + + // find the name which the database gave the new key + String newName = _rForName; + try { + String schema = AnyConverter.toString(this.table.getPropertyValue(PropertyIds.SCHEMANAME.name)); + String table = AnyConverter.toString(this.table.getPropertyValue(PropertyIds.TABLENAME.name)); + XResultSet results = null; + try { + final int column; + if (keyType == KeyType.FOREIGN) { + results = connection.getMetaData().getImportedKeys(this.table.getPropertyValue(PropertyIds.CATALOGNAME.name), schema, table); + column = 12; + } else { + results = connection.getMetaData().getPrimaryKeys(this.table.getPropertyValue(PropertyIds.CATALOGNAME.name), schema, table); + column = 6; + } + if (results != null) { + XRow row = UnoRuntime.queryInterface(XRow.class, results); + while (results.next()) { + String name = row.getString(column); + if (!hasByName(name)) { // this name wasn't inserted yet so it must be the new one + descriptor.setPropertyValue(PropertyIds.NAME.name, name); + newName = name; + break; + } + } + } + } finally { + CompHelper.disposeComponent(results); + } + } catch (SQLException sqlException) { + } + keys.put(newName, OKey.create(newName, isCaseSensitive(), referencedName, keyType, updateRule, deleteRule, new ArrayList<String>(), table)); + return createObject(newName); + } catch (WrappedTargetException wrappedTargetException) { + } catch (UnknownPropertyException unknownPropertyException) { + } catch (IllegalArgumentException illegalArgumentException) { + } catch (IndexOutOfBoundsException indexOutOfBoundsException) { + } catch (PropertyVetoException propertyVetoException) { + } + return null; + } + + protected String getKeyRuleString(boolean isUpdate, int rule) { + String keyRule = ""; + switch (rule) { + case KeyRule.CASCADE: + keyRule = isUpdate ? " ON UPDATE CASCADE " : " ON DELETE CASCADE "; + break; + case KeyRule.RESTRICT: + keyRule = isUpdate ? " ON UPDATE RESTRICT " : " ON DELETE RESTRICT "; + break; + case KeyRule.SET_NULL: + keyRule = isUpdate ? " ON UPDATE SET NULL " : " ON DELETE SET NULL "; + break; + case KeyRule.SET_DEFAULT: + keyRule = isUpdate ? " ON UPDATE SET DEFAULT " : " ON DELETE SET DEFAULT "; + break; + } + return keyRule; + } + + @Override + public void dropObject(int index, String name) throws SQLException { + XConnection connection = table.getConnection(); + if (connection == null) { + return; + } + try { + XPropertySet key = AnyConverter.toObject(XPropertySet.class, getObject(index)); + String tableName = DbTools.composeTableName(connection.getMetaData(), table, + ComposeRule.InTableDefinitions, false, false, true); + final int keyType; + if (key != null) { + keyType = AnyConverter.toInt(key.getPropertyValue(PropertyIds.TYPE.name)); + } else { + keyType = KeyType.PRIMARY; + } + final String sql; + if (keyType == KeyType.PRIMARY) { + sql = String.format("ALTER TABLE %s DROP PRIMARY KEY", tableName); + } else { + sql = String.format("ALTER TABLE %s %s %s", tableName, getDropForeignKey(), + DbTools.quoteName(connection.getMetaData().getIdentifierQuoteString(), name)); + } + XStatement statement = null; + try { + statement = connection.createStatement(); + statement.execute(sql); + } finally { + CompHelper.disposeComponent(statement); + } + } catch (IllegalArgumentException illegalArgumentException) { + + } catch (WrappedTargetException wrappedTargetException) { + } catch (UnknownPropertyException unknownPropertyException) { + } + } + + public String getDropForeignKey() { + return "DROP CONSTRAINT"; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OTable.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OTable.java new file mode 100644 index 000000000000..118d54fa25aa --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OTable.java @@ -0,0 +1,187 @@ +/************************************************************** + * + * 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.container.XIndexAccess; +import com.sun.star.container.XNameAccess; +import com.sun.star.container.XNamed; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.XServiceInfo; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbcx.XAlterTable; +import com.sun.star.sdbcx.XColumnsSupplier; +import com.sun.star.sdbcx.XDataDescriptorFactory; +import com.sun.star.sdbcx.XIndexesSupplier; +import com.sun.star.sdbcx.XKeysSupplier; +import com.sun.star.sdbcx.XRename; +import com.sun.star.sdbcx.comp.postgresql.comphelper.PropertySetAdapter.PropertyGetter; +import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds; +import com.sun.star.uno.Type; + +public abstract class OTable extends ODescriptor + implements XColumnsSupplier, XKeysSupplier, XNamed, XServiceInfo, XDataDescriptorFactory, + XIndexesSupplier, XRename, XAlterTable { + + private static String[] services = { + "com.sun.star.sdbcx.Table" + }; + + private XConnection connection; + protected String catalogName; + protected String schemaName; + protected String description; + protected String type; + + protected OContainer keys; + protected OContainer columns; + protected OContainer indexes; + protected OContainer tables; + + protected OTable(Object lock, String name, boolean isCaseSensitive, XConnection connection, OContainer tables) { + super(lock, name, isCaseSensitive); + this.tables = tables; + this.connection = connection; + registerProperties(); + } + + private void registerProperties() { + registerProperty(PropertyIds.CATALOGNAME.name, PropertyIds.CATALOGNAME.id, Type.STRING, PropertyAttribute.READONLY, + new PropertyGetter() { + @Override + public Object getValue() { + return catalogName; + + } + }, null); + registerProperty(PropertyIds.SCHEMANAME.name, PropertyIds.SCHEMANAME.id, Type.STRING, PropertyAttribute.READONLY, + new PropertyGetter() { + @Override + public Object getValue() { + return schemaName; + + } + }, null); + registerProperty(PropertyIds.DESCRIPTION.name, PropertyIds.DESCRIPTION.id, Type.STRING, PropertyAttribute.READONLY, + new PropertyGetter() { + @Override + public Object getValue() { + return description; + + } + }, null); + registerProperty(PropertyIds.TYPE.name, PropertyIds.TYPE.id, Type.STRING, PropertyAttribute.READONLY, + new PropertyGetter() { + @Override + public Object getValue() { + return type; + + } + }, null); + } + + @Override + protected void postDisposing() { + super.postDisposing(); + if (keys != null) { + keys.dispose(); + } + if (columns != null) { + columns.dispose(); + } + if (indexes != null) { + indexes.dispose(); + } + tables = null; + } + + private void checkDisposed() { + if (bInDispose || bDisposed) { + throw new DisposedException(); + } + } + + // XServiceInfo + + @Override + public String getImplementationName() { + return "com.sun.star.sdbcx.Table"; + } + + @Override + public String[] getSupportedServiceNames() { + return services.clone(); + } + + @Override + public boolean supportsService(String serviceName) { + for (String service : services) { + if (serviceName.equals(service)) { + return true; + } + } + return false; + } + + // XColumnsSupplier + + @Override + public XNameAccess getColumns() { + checkDisposed(); + synchronized (lock) { + if (columns == null) { + columns = refreshColumns(); + } + return columns; + } + } + + @Override + public XNameAccess getIndexes() { + checkDisposed(); + synchronized (lock) { + if (indexes == null) { + indexes = refreshIndexes(); + } + return indexes; + } + } + + @Override + public XIndexAccess getKeys() { + checkDisposed(); + synchronized (lock) { + if (keys == null) { + keys = refreshKeys(); + } + return keys; + } + } + + public XConnection getConnection() { + return connection; + } + + protected abstract OContainer refreshColumns(); + protected abstract OContainer refreshIndexes(); + protected abstract OContainer refreshKeys(); +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OfficeResourceBundle.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OfficeResourceBundle.java new file mode 100644 index 000000000000..c13dbce8feb5 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/OfficeResourceBundle.java @@ -0,0 +1,130 @@ +/************************************************************** + * + * 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.lang.NullPointerException; +import com.sun.star.resource.MissingResourceException; +import com.sun.star.resource.OfficeResourceLoader; +import com.sun.star.resource.XResourceBundle; +import com.sun.star.resource.XResourceBundleLoader; +import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper; +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.XComponentContext; + +public class OfficeResourceBundle implements AutoCloseable { + + private XComponentContext context; + private String baseName; + private boolean haveAttemptedCreate; + private XResourceBundle bundle; + + + /** constructs a resource bundle + @param context + the component context to operate in + @param bundleBaseName + the base name of the resource file which should be accessed (*without* the SUPD!) + @raises ::com::sun::star::lang::NullPointerException + if the given component context is <NULL/> + */ + public OfficeResourceBundle(XComponentContext context, String bundleBaseName) throws NullPointerException { + if (context == null) { + throw new NullPointerException(); + } + this.context = context; + this.baseName = bundleBaseName; + this.haveAttemptedCreate = false; + } + + @Override + public void close() { + CompHelper.disposeComponent(bundle); + } + + /** loads the string with the given resource id from the resource bundle + @param _resourceId + the id of the string to load + @return + the requested resource string. If no string with the given id exists in the resource bundle, + an empty string is returned. In a non-product version, an OSL_ENSURE will notify you of this + then. + */ + public String loadString( int _resourceId ) { + synchronized (this) { + String ret = ""; + if (loadBundle()) { + try { + Object value = bundle.getByName(getStringResourceKey(_resourceId)); + ret = AnyConverter.toString(value); + } catch (com.sun.star.uno.Exception ex) { + } + } + return ret; + } + } + + /** determines whether the resource bundle has a string with the given id + @param _resourceId + the id of the string whose existence is to be checked + @return + <TRUE/> if and only if a string with the given ID exists in the resource + bundle. + */ + public boolean hasString( int _resourceId ) { + synchronized (this) { + boolean ret = false; + if (loadBundle()) { + ret = bundle.hasByName(getStringResourceKey(_resourceId)); + } + return ret; + } + } + + private String getStringResourceKey(int resourceId) { + return "string:" + resourceId; + } + + private boolean loadBundle() { + if (haveAttemptedCreate) { + return bundle != null; + } + haveAttemptedCreate = true; + + try { + XResourceBundleLoader loader = OfficeResourceLoader.get(context); + try { + if (loader == null) { + return false; + } + try { + bundle = loader.loadBundle_Default(baseName); + } catch (MissingResourceException missingResourceException) { + } + return bundle != null; + } finally { + CompHelper.disposeComponent(loader); + } + } catch (Exception exception) { + } + return false; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/Resources.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/Resources.java new file mode 100644 index 000000000000..2b904aba1f76 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/Resources.java @@ -0,0 +1,66 @@ +/************************************************************** + * + * 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; + +public class Resources { + public static final int STR_COMMON_BASE = 1200; + + public static final int STR_STRING_LENGTH_EXCEEDED = (STR_COMMON_BASE + 1); + public static final int STR_CANNOT_CONVERT_STRING = (STR_COMMON_BASE + 2); + public static final int STR_URI_SYNTAX_ERROR = (STR_COMMON_BASE + 3); + public static final int STR_COULD_NOT_LOAD_FILE = (STR_COMMON_BASE + 4); + public static final int STR_QUERY_TOO_COMPLEX = (STR_COMMON_BASE + 5); + public static final int STR_OPERATOR_TOO_COMPLEX = (STR_COMMON_BASE + 6); + public static final int STR_QUERY_INVALID_LIKE_COLUMN = (STR_COMMON_BASE + 7); + public static final int STR_QUERY_INVALID_LIKE_STRING = (STR_COMMON_BASE + 8); + public static final int STR_QUERY_NOT_LIKE_TOO_COMPLEX = (STR_COMMON_BASE + 9); + public static final int STR_QUERY_LIKE_WILDCARD = (STR_COMMON_BASE + 10); + public static final int STR_QUERY_LIKE_WILDCARD_MANY = (STR_COMMON_BASE + 11); + public static final int STR_INVALID_COLUMNNAME = (STR_COMMON_BASE + 12); + public static final int STR_NO_CLASSNAME = (STR_COMMON_BASE + 13); + public static final int STR_NO_CLASSNAME_PATH = (STR_COMMON_BASE + 14); + public static final int STR_UNKNOWN_PARA_TYPE = (STR_COMMON_BASE + 15); + public static final int STR_INVALID_COLUMN_SELECTION = (STR_COMMON_BASE + 16); + public static final int STR_PARA_ONLY_PREPARED = (STR_COMMON_BASE + 17); + public static final int STR_COLUMN_NOT_UPDATEABLE = (STR_COMMON_BASE + 18); + public static final int STR_ROW_ALREADY_DELETED = (STR_COMMON_BASE + 19); + public static final int STR_UNKNOWN_COLUMN_TYPE = (STR_COMMON_BASE + 20); + public static final int STR_FORMULA_WRONG = (STR_COMMON_BASE + 21); + public static final int STR_NO_JAVA = (STR_COMMON_BASE + 22); + public static final int STR_NO_RESULTSET = (STR_COMMON_BASE + 23); + public static final int STR_NO_ROWCOUNT = (STR_COMMON_BASE + 24); + public static final int STR_ERRORMSG_SEQUENCE = (STR_COMMON_BASE + 25); + public static final int STR_INVALID_INDEX = (STR_COMMON_BASE + 26); + public static final int STR_UNSUPPORTED_FUNCTION = (STR_COMMON_BASE + 27); + public static final int STR_UNSUPPORTED_FEATURE = (STR_COMMON_BASE + 28); + public static final int STR_UNKNOWN_COLUMN_NAME = (STR_COMMON_BASE + 29); + public static final int STR_INVALID_PARA_COUNT = (STR_COMMON_BASE + 30); + public static final int STR_PRIVILEGE_NOT_GRANTED = (STR_COMMON_BASE + 31); + public static final int STR_PRIVILEGE_NOT_REVOKED = (STR_COMMON_BASE + 32); + public static final int STR_INVALID_BOOKMARK = (STR_COMMON_BASE + 33); + public static final int STR_NO_ELEMENT_NAME = (STR_COMMON_BASE + 34); + public static final int STR_NO_INPUTSTREAM = (STR_COMMON_BASE + 35); + public static final int STR_INPUTSTREAM_WRONG_LEN = (STR_COMMON_BASE + 36); + public static final int STR_WRONG_PARAM_INDEX = (STR_COMMON_BASE + 37); + public static final int STR_NO_CONNECTION_GIVEN = (STR_COMMON_BASE + 38); + +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/SharedResources.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/SharedResources.java new file mode 100644 index 000000000000..fa3e3660ba1c --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/SharedResources.java @@ -0,0 +1,213 @@ +/************************************************************** + * + * 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 org.apache.commons.lang3.mutable.MutableObject; +import org.apache.commons.lang3.tuple.Pair; + +import com.sun.star.lang.NullPointerException; +import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper; +import com.sun.star.uno.XComponentContext; + +/** + * helper class for accessing resources shared by different libraries + * in the connectivity module. + */ +public class SharedResources { + private static SharedResources instance; + private static int referenceCount = 0; + + private OfficeResourceBundle resourceBundle; + + // FIXME: the C++ implementation gets the XComponentContext using ::comphelper::getProcessServiceFactory(), we don't. + public synchronized static void registerClient(XComponentContext context) { + if (instance == null) { + instance = new SharedResources(context); + } + ++referenceCount; + } + + public synchronized static void revokeClient() { + if (--referenceCount == 0) { + CompHelper.disposeComponent(instance); + instance = null; + } + } + + public synchronized static SharedResources getInstance() { + return instance; + } + + private SharedResources(XComponentContext context) { + try { + resourceBundle = new OfficeResourceBundle(context, "cnr"); + } catch (NullPointerException nullPointerException) { + } + } + + private int substitute( MutableObject<String> _inout_rString, + String sPattern, String _rReplace ) { + int nOccurences = 0; + String string = _inout_rString.getValue(); + int nIndex = 0; + while ( ( nIndex = string.indexOf( sPattern ) ) > -1 ) + { + ++nOccurences; + string = string.substring(0, nIndex) + + _rReplace + string.substring(nIndex + sPattern.length()); + } + _inout_rString.setValue(string); + return nOccurences; + } + + + /** loads a string from the shared resource file + @param _nResId + the resource ID of the string + @return + the string from the resource file + */ + public String + getResourceString( + int _nResId + ) { + if (resourceBundle == null) { + return ""; + } + return resourceBundle.loadString(_nResId); + } + + /** loads a string from the shared resource file, and replaces + a given ASCII pattern with a given string + + @param _nResId + the resource ID of the string to load + @param _pAsciiPatternToReplace + the ASCII string which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute + the String which should substitute the ASCII pattern. + + @return + the string from the resource file, with applied string substitution + */ + public String + getResourceStringWithSubstitution( + int _nResId, + String _pAsciiPatternToReplace, + String _rStringToSubstitute + ) { + MutableObject<String> string = new MutableObject<>(getResourceString(_nResId)); + substitute(string, _pAsciiPatternToReplace, _rStringToSubstitute); + return string.getValue(); + } + + /** loads a string from the shared resource file, and replaces + a given ASCII pattern with a given string + + @param _nResId + the resource ID of the string to load + @param _pAsciiPatternToReplace1 + the ASCII string (1) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute1 + the String which should substitute the ASCII pattern (1) + @param _pAsciiPatternToReplace2 + the ASCII string (2) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute2 + the String which should substitute the ASCII pattern (2) + + @return + the string from the resource file, with applied string substitution + */ + public String + getResourceStringWithSubstitution( + int _nResId, + String _pAsciiPatternToReplace1, + String _rStringToSubstitute1, + String _pAsciiPatternToReplace2, + String _rStringToSubstitute2 + ) { + MutableObject<String> string = new MutableObject<>(getResourceString(_nResId)); + substitute(string, _pAsciiPatternToReplace1, _rStringToSubstitute1); + substitute(string, _pAsciiPatternToReplace2, _rStringToSubstitute2); + return string.getValue(); + } + + /** loads a string from the shared resource file, and replaces + a given ASCII pattern with a given string + + @param _nResId + the resource ID of the string to load + @param _pAsciiPatternToReplace1 + the ASCII string (1) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute1 + the String which should substitute the ASCII pattern (1) + @param _pAsciiPatternToReplace2 + the ASCII string (2) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute2 + the String which should substitute the ASCII pattern (2) + @param _pAsciiPatternToReplace3 + the ASCII string (3) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute3 + the String which should substitute the ASCII pattern (3) + + @return + the string from the resource file, with applied string substitution + */ + public String + getResourceStringWithSubstitution( + int _nResId, + String _pAsciiPatternToReplace1, + String _rStringToSubstitute1, + String _pAsciiPatternToReplace2, + String _rStringToSubstitute2, + String _pAsciiPatternToReplace3, + String _rStringToSubstitute3 + ) { + MutableObject<String> string = new MutableObject<>(getResourceString(_nResId)); + substitute(string, _pAsciiPatternToReplace1, _rStringToSubstitute1); + substitute(string, _pAsciiPatternToReplace2, _rStringToSubstitute2); + substitute(string, _pAsciiPatternToReplace3, _rStringToSubstitute3); + return string.getValue(); + } + + /** loads a string from the shared resource file, and replaces a given ASCII pattern with a given string + + @param _nResId + the resource ID of the string to load + @param _aStringToSubstitutes + A list of substitutions. + + @return + the string from the resource file, with applied string substitution + */ + public String + getResourceStringWithSubstitution( int _nResId, + List<Pair<String,String>> patternsAndSubstitutes) { + MutableObject<String> string = new MutableObject<>(getResourceString(_nResId)); + for (Pair<String,String> pair : patternsAndSubstitutes) { + substitute(string, pair.getLeft(), pair.getRight()); + } + return string.getValue(); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/SqlTableHelper.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/SqlTableHelper.java new file mode 100644 index 000000000000..ba1db755947c --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/SqlTableHelper.java @@ -0,0 +1,261 @@ +/************************************************************** + * + * 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.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XDatabaseMetaData; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XRow; +import com.sun.star.sdbcx.KeyType; +import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper; +import com.sun.star.sdbcx.comp.postgresql.util.ComposeRule; +import com.sun.star.sdbcx.comp.postgresql.util.DbTools; +import com.sun.star.sdbcx.comp.postgresql.util.Osl; +import com.sun.star.uno.Any; +import com.sun.star.uno.UnoRuntime; + +public class SqlTableHelper { + public static class ColumnDescription { + public String columnName; + public int type; + public String typeName; + public int columnSize; + public int decimalDigits; + public int nullable; + public String remarks; + public String defaultValue; + public int ordinalPosition; + } + + private static class KeyProperties { + ArrayList<String> columnNames = new ArrayList<>(); + String referencedTable; + int type; + int updateRule; + int deleteRule; + + KeyProperties(String referencedTable, int type, int updateRule, int deleteRule) { + this.referencedTable = referencedTable; + this.type = type; + this.updateRule = updateRule; + this.deleteRule = deleteRule; + } + } + + public List<ColumnDescription> readColumns(XDatabaseMetaData metadata, String catalog, String schema, String table) throws SQLException { + String catalogName = catalog; + if (catalog.isEmpty()) { + catalogName = null; + } + + XResultSet results = metadata.getColumns(catalogName, schema, table, "%"); + List<ColumnDescription> columnDescriptions = collectColumnDescriptions(results); + sanitizeColumnDescriptions(columnDescriptions); + + List<ColumnDescription> columnsByOrdinal = new ArrayList<>(columnDescriptions); + for (ColumnDescription columnDescription : columnDescriptions) { + columnsByOrdinal.set(columnDescription.ordinalPosition - 1, columnDescription); + } + return columnsByOrdinal; + } + + private List<ColumnDescription> collectColumnDescriptions(XResultSet results) throws SQLException { + List<ColumnDescription> columns = new ArrayList<>(); + XRow row = UnoRuntime.queryInterface(XRow.class, results); + while (results.next()) { + ColumnDescription columnDescription = new ColumnDescription(); + columnDescription.columnName = row.getString(4); + columnDescription.type = row.getInt(5); + columnDescription.typeName = row.getString(6); + columnDescription.columnSize = row.getInt(7); + columnDescription.decimalDigits = row.getInt(9); + columnDescription.nullable = row.getInt(11); + columnDescription.remarks = row.getString(12); + columnDescription.defaultValue = row.getString(13); + columnDescription.ordinalPosition = row.getInt(17); + columns.add(columnDescription); + } + return columns; + } + + private void sanitizeColumnDescriptions(List<ColumnDescription> columnDescriptions) { + if (columnDescriptions.isEmpty()) { + return; + } + Set<Integer> usedOrdinals = new TreeSet<>(); + int maxOrdinal = Integer.MIN_VALUE; + for (ColumnDescription columnDescription : columnDescriptions) { + usedOrdinals.add(columnDescription.ordinalPosition); + if (maxOrdinal < columnDescription.ordinalPosition) { + maxOrdinal = columnDescription.ordinalPosition; + } + } + // we need to have as many different ordinals as we have different columns + boolean hasDuplicates = usedOrdinals.size() != columnDescriptions.size(); + // and it needs to be a continuous range + boolean hasGaps = (maxOrdinal - usedOrdinals.iterator().next() + 1) != columnDescriptions.size(); + // if that's not the case, normalize it + Osl.ensure(!hasDuplicates && !hasGaps, "database provided invalid ORDINAL_POSITION values!"); + // what's left is that the range might not be from 1 to <column count>, but for instance + // 0 to <column count>-1. + int offset = usedOrdinals.iterator().next() - 1; + for (ColumnDescription columnDescription : columnDescriptions) { + columnDescription.ordinalPosition -= offset; + } + } + + public Map<String, OKey> readKeys(XDatabaseMetaData metadata, String catalogName, String schemaName, String tableName, + boolean isCaseSensitive, OTable table) throws SQLException { + Map<String, OKey> keys = new TreeMap<>(); + OKey primaryKey = readPrimaryKey(metadata, catalogName, schemaName, tableName, isCaseSensitive, table); + keys.put(primaryKey.getName(), primaryKey); + readForeignKeys(metadata, catalogName, schemaName, tableName, isCaseSensitive, keys, table); + return keys; + } + + private OKey readPrimaryKey(XDatabaseMetaData metadata, + String catalogName, String schemaName, String tableName, boolean isCaseSensitive, OTable table) throws SQLException { + Object catalog = Any.VOID; + if (!catalogName.isEmpty()) { + catalog = catalogName; + } + XResultSet results = null; + try { + ArrayList<String> columns = new ArrayList<>(); + boolean alreadyFetched = false; + String pkName = ""; + OKey key = null; + results = metadata.getPrimaryKeys(catalog, schemaName, tableName); + if (results != null) { + XRow row = UnoRuntime.queryInterface(XRow.class, results); + while (results.next()) { + String columnName = row.getString(4); + columns.add(columnName); + if (!alreadyFetched) { + alreadyFetched = true; + pkName = row.getString(6); + } + } + key = OKey.create(pkName, isCaseSensitive, "", KeyType.PRIMARY, 0, 0, columns, table); + } + return key; + } finally { + CompHelper.disposeComponent(results); + } + } + + private void readForeignKeys(XDatabaseMetaData metadata, + String catalogName, String schemaName, String tableName, boolean isCaseSensitive, Map<String, OKey> keys, OTable table) throws SQLException { + Object catalog = Any.VOID; + if (!catalogName.isEmpty()) { + catalog = catalogName; + } + XResultSet results = null; + try { + results = metadata.getImportedKeys(catalog, schemaName, tableName); + XRow row = UnoRuntime.queryInterface(XRow.class, results); + if (row != null) { + String oldFkName = ""; + KeyProperties keyProperties = null; + while (results.next()) { + String catalogReturned = row.getString(1); + if (row.wasNull()) { + catalogReturned = ""; + } + String schemaReturned = row.getString(2); + String nameReturned = row.getString(3); + + String foreignKeyColumn = row.getString(8); + int updateRule = row.getInt(10); + int deleteRule = row.getInt(11); + String fkName = row.getString(12); + + if (!row.wasNull() && !fkName.isEmpty()) { + if (!oldFkName.equals(fkName)) { + if (keyProperties != null) { + OKey key = OKey.create(oldFkName, isCaseSensitive, keyProperties.referencedTable, keyProperties.type, + keyProperties.updateRule, keyProperties.deleteRule, keyProperties.columnNames, table); + keys.put(oldFkName, key); + } + String referencedName = DbTools.composeTableName(metadata, catalogReturned, schemaReturned, nameReturned, + false, ComposeRule.InDataManipulation); + keyProperties = new KeyProperties(referencedName, KeyType.FOREIGN, updateRule, deleteRule); + keyProperties.columnNames.add(foreignKeyColumn); + oldFkName = fkName; + } else { + if (keyProperties != null) { + keyProperties.columnNames.add(foreignKeyColumn); + } + } + } + } + if (keyProperties != null) { + OKey key = OKey.create(oldFkName, isCaseSensitive, keyProperties.referencedTable, keyProperties.type, + keyProperties.updateRule, keyProperties.deleteRule, keyProperties.columnNames, table); + keys.put(oldFkName, key); + } + } + } finally { + CompHelper.disposeComponent(results); + } + } + + public ArrayList<String> readIndexes(XDatabaseMetaData metadata, String catalogName, String schemaName, String tableName, OTable table) throws SQLException { + Object catalog = Any.VOID; + if (!catalogName.isEmpty()) { + catalog = catalogName; + } + ArrayList<String> names = new ArrayList<>(); + XResultSet results = null; + try { + results = metadata.getIndexInfo(catalog, schemaName, tableName, false, false); + if (results != null) { + XRow row = UnoRuntime.queryInterface(XRow.class, results); + String catalogSep = metadata.getCatalogSeparator(); + String previousRoundName = ""; + while (results.next()) { + String name = row.getString(5); + if (!name.isEmpty()) { + name += catalogSep; + } + name += row.getString(6); + if (!name.isEmpty()) { + // don't insert the name if the last one we inserted was the same + if (!previousRoundName.equals(name)) { + names.add(name); + } + } + } + } + } finally { + CompHelper.disposeComponent(results); + } + return names; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxColumnDescriptor.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxColumnDescriptor.java new file mode 100644 index 000000000000..109940d80d9e --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxColumnDescriptor.java @@ -0,0 +1,194 @@ +/************************************************************** + * + * 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.descriptors; + +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.ODescriptor; +import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds; +import com.sun.star.uno.Type; + +public class SdbcxColumnDescriptor extends ODescriptor { + protected int type; + protected String typeName; + protected int precision; + protected int scale; + protected int isNullable; + protected boolean isAutoIncrement; + protected boolean isRowVersion; + protected String description; + protected String defaultValue; + protected boolean isCurrency; + + protected SdbcxColumnDescriptor(Object lock, boolean isCaseSensitive) { + super(lock, "", isCaseSensitive, false); + registerProperties(); + } + + public static SdbcxColumnDescriptor create(boolean isCaseSensitive) { + final Object lock = new Object(); + return new SdbcxColumnDescriptor(lock, isCaseSensitive); + } + + private void registerProperties() { + registerProperty(PropertyIds.TYPE.name, PropertyIds.TYPE.id, Type.LONG, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return type; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + type = (int) value; + } + }); + registerProperty(PropertyIds.TYPENAME.name, PropertyIds.TYPENAME.id, Type.STRING, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return typeName; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + typeName = (String) value; + } + }); + registerProperty(PropertyIds.PRECISION.name, PropertyIds.PRECISION.id, Type.LONG, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return precision; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + precision = (Integer) value; + } + }); + registerProperty(PropertyIds.SCALE.name, PropertyIds.SCALE.id, Type.LONG, (short)0, + 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, (short)0, + 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, (short)0, + 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, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return isRowVersion; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + isRowVersion = (Boolean) value; + } + }); + registerProperty(PropertyIds.DESCRIPTION.name, PropertyIds.DESCRIPTION.id, Type.STRING, (short)0, + 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, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return defaultValue; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + defaultValue = (String) value; + } + }); + registerProperty(PropertyIds.ISCURRENCY.name, PropertyIds.ISCURRENCY.id, Type.BOOLEAN, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return isCurrency; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + isCurrency = (Boolean) value; + } + }); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxColumnDescriptorContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxColumnDescriptorContainer.java new file mode 100644 index 000000000000..25ae2a597b4d --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxColumnDescriptorContainer.java @@ -0,0 +1,36 @@ +/************************************************************** + * + * 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.descriptors; + +import com.sun.star.beans.XPropertySet; + +public class SdbcxColumnDescriptorContainer extends SdbcxDescriptorContainer { + + public SdbcxColumnDescriptorContainer(Object lock, boolean isCaseSensitive) { + super(lock, isCaseSensitive); + } + + @Override + public XPropertySet createDescriptor() { + return SdbcxColumnDescriptor.create(isCaseSensitive()); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxDescriptorContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxDescriptorContainer.java new file mode 100644 index 000000000000..76d2859b715a --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxDescriptorContainer.java @@ -0,0 +1,59 @@ +/************************************************************** + * + * 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.descriptors; + +import java.util.Collections; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OContainer; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.Resources; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.SharedResources; +import com.sun.star.sdbcx.comp.postgresql.util.StandardSQLState; + +public abstract class SdbcxDescriptorContainer extends OContainer { + public SdbcxDescriptorContainer(Object lock, boolean isCaseSensitive) { + super(lock, isCaseSensitive, Collections.<String>emptyList()); + } + + @Override + public XPropertySet createObject(String name) throws SQLException { + // This should never be called. DescriptorContainer always starts off empty, + // and only grows as a result of appending. + String error = SharedResources.getInstance().getResourceString( + Resources.STR_ERRORMSG_SEQUENCE); + throw new SQLException(error, this, StandardSQLState.SQL_FUNCTION_SEQUENCE_ERROR.text(), 0, null); + } + + @Override + public void dropObject(int index, String name) throws SQLException { + } + + @Override + public void impl_refresh() { + } + + @Override + public XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException { + return cloneDescriptor(descriptor); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexColumnDescriptor.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexColumnDescriptor.java new file mode 100644 index 000000000000..101257153c49 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexColumnDescriptor.java @@ -0,0 +1,58 @@ +/************************************************************** + * + * 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.descriptors; + +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 SdbcxIndexColumnDescriptor extends SdbcxColumnDescriptor { + protected boolean isAscending; + + protected SdbcxIndexColumnDescriptor(Object lock, boolean isCaseSensitive) { + super(lock, isCaseSensitive); + registerProperties(); + } + + public static SdbcxIndexColumnDescriptor create(boolean isCaseSensitive) { + final Object lock = new Object(); + return new SdbcxIndexColumnDescriptor(lock, isCaseSensitive); + } + + private void registerProperties() { + registerProperty(PropertyIds.ISASCENDING.name, PropertyIds.ISASCENDING.id, Type.BOOLEAN, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return isAscending; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + isAscending = (boolean) value; + } + }); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexColumnDescriptorContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexColumnDescriptorContainer.java new file mode 100644 index 000000000000..f7a5e5e945a1 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexColumnDescriptorContainer.java @@ -0,0 +1,35 @@ +/************************************************************** + * + * 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.descriptors; + +import com.sun.star.beans.XPropertySet; + +public class SdbcxIndexColumnDescriptorContainer extends SdbcxDescriptorContainer { + public SdbcxIndexColumnDescriptorContainer(Object lock, boolean isCaseSensitive) { + super(lock, isCaseSensitive); + } + + @Override + public XPropertySet createDescriptor() { + return SdbcxIndexColumnDescriptor.create(isCaseSensitive()); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexDescriptor.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexDescriptor.java new file mode 100644 index 000000000000..139610fd31e9 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexDescriptor.java @@ -0,0 +1,94 @@ +/************************************************************** + * + * 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.descriptors; + +import com.sun.star.sdbcx.XColumnsSupplier; +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.ODescriptor; +import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds; +import com.sun.star.uno.Type; + +public class SdbcxIndexDescriptor extends ODescriptor implements XColumnsSupplier { + protected String catalog = ""; + protected boolean isUnique; + protected boolean isClustered; + + private SdbcxIndexColumnDescriptorContainer columns; + + protected SdbcxIndexDescriptor(Object lock, boolean isCaseSensitive) { + super(lock, "", isCaseSensitive, false); + columns = new SdbcxIndexColumnDescriptorContainer(this.lock, isCaseSensitive()); + registerProperties(); + } + + public static SdbcxIndexDescriptor create(boolean isCaseSensitive) { + final Object lock = new Object(); + return new SdbcxIndexDescriptor(lock, isCaseSensitive); + } + + private void registerProperties() { + registerProperty(PropertyIds.CATALOG.name, PropertyIds.CATALOG.id, Type.STRING, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return catalog; + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + catalog = (String) value; + } + }); + registerProperty(PropertyIds.ISUNIQUE.name, PropertyIds.ISUNIQUE.id, Type.BOOLEAN, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return isUnique; + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + isUnique = (boolean) value; + } + }); + registerProperty(PropertyIds.ISCLUSTERED.name, PropertyIds.ISCLUSTERED.id, Type.BOOLEAN, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return isClustered; + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + isClustered = (boolean) value; + } + }); + } + + public SdbcxIndexColumnDescriptorContainer getColumns() { + return columns; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexDescriptorContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexDescriptorContainer.java new file mode 100644 index 000000000000..df169dc0f50a --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxIndexDescriptorContainer.java @@ -0,0 +1,44 @@ +/************************************************************** + * + * 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.descriptors; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbcx.comp.postgresql.util.DbTools; + +public class SdbcxIndexDescriptorContainer extends SdbcxDescriptorContainer { + public SdbcxIndexDescriptorContainer(Object lock, boolean isCaseSensitive) { + super(lock, isCaseSensitive); + } + + @Override + public XPropertySet createDescriptor() { + return SdbcxIndexDescriptor.create(isCaseSensitive()); + } + + @Override + public XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException { + XPropertySet newDescriptor = cloneDescriptor(descriptor); + DbTools.cloneDescriptorColumns(descriptor, newDescriptor); + return newDescriptor; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyColumnDescriptor.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyColumnDescriptor.java new file mode 100644 index 000000000000..6ddb4d205db3 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyColumnDescriptor.java @@ -0,0 +1,58 @@ +/************************************************************** + * + * 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.descriptors; + +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 SdbcxKeyColumnDescriptor extends SdbcxColumnDescriptor { + protected String relatedColumn; + + protected SdbcxKeyColumnDescriptor(Object lock, boolean isCaseSensitive) { + super(lock, isCaseSensitive); + registerProperties(); + } + + public static SdbcxKeyColumnDescriptor create(boolean isCaseSensitive) { + final Object lock = new Object(); + return new SdbcxKeyColumnDescriptor(lock, isCaseSensitive); + } + + private void registerProperties() { + registerProperty(PropertyIds.RELATEDCOLUMN.name, PropertyIds.RELATEDCOLUMN.id, Type.STRING, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return relatedColumn; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + relatedColumn = (String) value; + } + }); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyColumnDescriptorContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyColumnDescriptorContainer.java new file mode 100644 index 000000000000..bb3aed4bbb1c --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyColumnDescriptorContainer.java @@ -0,0 +1,35 @@ +/************************************************************** + * + * 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.descriptors; + +import com.sun.star.beans.XPropertySet; + +public class SdbcxKeyColumnDescriptorContainer extends SdbcxDescriptorContainer { + public SdbcxKeyColumnDescriptorContainer(Object lock, boolean isCaseSensitive) { + super(lock, isCaseSensitive); + } + + @Override + public XPropertySet createDescriptor() { + return SdbcxKeyColumnDescriptor.create(isCaseSensitive()); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyDescriptor.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyDescriptor.java new file mode 100644 index 000000000000..262cc8724b27 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyDescriptor.java @@ -0,0 +1,113 @@ +/************************************************************** + * + * 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.descriptors; + +import com.sun.star.container.XNameAccess; +import com.sun.star.sdbcx.XColumnsSupplier; +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.ODescriptor; +import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds; +import com.sun.star.uno.Type; + +public class SdbcxKeyDescriptor extends ODescriptor implements XColumnsSupplier { + protected int type; + protected String referencedTable; + protected int updateRule; + protected int deleteRule; + + private SdbcxKeyColumnDescriptorContainer columns; + + protected SdbcxKeyDescriptor(Object lock, boolean isCaseSensitive) { + super(lock, "", isCaseSensitive, false); + registerProperties(); + columns = new SdbcxKeyColumnDescriptorContainer(this.lock, isCaseSensitive()); + } + + public static SdbcxKeyDescriptor create(boolean isCaseSensitive) { + final Object lock = new Object(); + return new SdbcxKeyDescriptor(lock, isCaseSensitive); + } + + private void registerProperties() { + registerProperty(PropertyIds.TYPE.name, PropertyIds.TYPE.id, Type.LONG, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return type; + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + type = (int) value; + } + }); + registerProperty(PropertyIds.REFERENCEDTABLE.name, PropertyIds.REFERENCEDTABLE.id, Type.STRING, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return referencedTable; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + referencedTable = (String) value; + } + }); + registerProperty(PropertyIds.UPDATERULE.name, PropertyIds.UPDATERULE.id, Type.LONG, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return updateRule; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + updateRule = (int) value; + } + }); + registerProperty(PropertyIds.DELETERULE.name, PropertyIds.DELETERULE.id, Type.LONG, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return deleteRule; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + deleteRule = (int) value; + } + }); + } + + @Override + public XNameAccess getColumns() { + return columns; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyDescriptorContainer.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyDescriptorContainer.java new file mode 100644 index 000000000000..e387ac49a3ff --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxKeyDescriptorContainer.java @@ -0,0 +1,44 @@ +/************************************************************** + * + * 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.descriptors; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbcx.comp.postgresql.util.DbTools; + +public class SdbcxKeyDescriptorContainer extends SdbcxDescriptorContainer { + public SdbcxKeyDescriptorContainer(Object lock, boolean isCaseSensitive) { + super(lock, isCaseSensitive); + } + + @Override + public XPropertySet createDescriptor() { + return SdbcxKeyDescriptor.create(isCaseSensitive()); + } + + @Override + public XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException { + XPropertySet newDescriptor = cloneDescriptor(descriptor); + DbTools.cloneDescriptorColumns(descriptor, newDescriptor); + return newDescriptor; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxTableDescriptor.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxTableDescriptor.java new file mode 100644 index 000000000000..65d08a893e83 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/sdbcx/descriptors/SdbcxTableDescriptor.java @@ -0,0 +1,109 @@ +/************************************************************** + * + * 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.descriptors; + +import com.sun.star.container.XIndexAccess; +import com.sun.star.container.XNameAccess; +import com.sun.star.sdbcx.XColumnsSupplier; +import com.sun.star.sdbcx.XKeysSupplier; +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.OContainer; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.ODescriptor; +import com.sun.star.sdbcx.comp.postgresql.util.PropertyIds; +import com.sun.star.uno.Type; + +public class SdbcxTableDescriptor extends ODescriptor implements XColumnsSupplier, XKeysSupplier { + protected String catalogName; + protected String schemaName; + protected String description; + + private OContainer columns; + private OContainer keys; + + protected SdbcxTableDescriptor(Object lock, boolean isCaseSensitive) { + super(lock, "", isCaseSensitive, false); + columns = new SdbcxColumnDescriptorContainer(this.lock, isCaseSensitive()); + keys = new SdbcxKeyDescriptorContainer(this.lock, isCaseSensitive()); + registerProperties(); + } + + public static SdbcxTableDescriptor create(boolean isCaseSensitive) { + final Object lock = new Object(); + return new SdbcxTableDescriptor(lock, isCaseSensitive); + } + + private void registerProperties() { + registerProperty(PropertyIds.CATALOGNAME.name, PropertyIds.CATALOGNAME.id, Type.STRING, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return catalogName; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + catalogName = (String) value; + } + }); + registerProperty(PropertyIds.SCHEMANAME.name, PropertyIds.SCHEMANAME.id, Type.STRING, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return schemaName; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + schemaName = (String) value; + } + }); + registerProperty(PropertyIds.DESCRIPTION.name, PropertyIds.DESCRIPTION.id, Type.STRING, (short)0, + new PropertyGetter() { + @Override + public Object getValue() { + return description; + + } + }, + new PropertySetter() { + @Override + public void setValue(Object value) { + description = (String) value; + } + }); + } + + @Override + public XNameAccess getColumns() { + return columns; + } + + @Override + public XIndexAccess getKeys() { + return keys; + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/ComposeRule.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/ComposeRule.java new file mode 100644 index 000000000000..5fee9f038e52 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/ComposeRule.java @@ -0,0 +1,31 @@ +/************************************************************** + * + * 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.util; + +public enum ComposeRule { + InTableDefinitions, + InIndexDefinitions, + InDataManipulation, + InProcedureCalls, + InPrivilegeDefinitions, + Complete +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/DBTypeConversion.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/DBTypeConversion.java new file mode 100644 index 000000000000..943c78a15747 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/DBTypeConversion.java @@ -0,0 +1,426 @@ +/************************************************************** + * + * 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.util; + +import java.util.StringTokenizer; + +import com.sun.star.util.Date; +import com.sun.star.util.DateTime; +import com.sun.star.util.Time; + +public class DBTypeConversion { + private static final int MAX_DAYS = 3636532; + private static Date standardDate = new Date((short)1, (short)1, (short)1900); + private static int aDaysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + private static final double fMilliSecondsPerDay = 86400000.0; + + public static double safeParseDouble(String value) { + try { + return Double.parseDouble(value); + } catch (NumberFormatException numberFormatException) { + return 0.0; + } + } + + public static float safeParseFloat(String value) { + try { + return Float.parseFloat(value); + } catch (NumberFormatException numberFormatException) { + return 0.0f; + } + } + + public static int safeParseInt(String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException numberFormatException) { + return 0; + } + } + + public static long safeParseLong(String value) { + try { + return Long.parseLong(value); + } catch (NumberFormatException numberFormatException) { + return 0; + } + } + + public static float unsignedLongToFloat(long value) { + float f = value & 0x7fffFFFFffffFFFFL; + if (value < 0) { + f += 0x1p63f; + } + return f; + } + + public static double unsignedLongToDouble(long value) { + double d = value & 0x7fffFFFFffffFFFFL; + if (value < 0) { + d += 0x1p63f; + } + return d; + } + + public static void addDays(int nDays, Date _rDate) { + int nTempDays = implRelativeToAbsoluteNull( _rDate ); + + nTempDays += nDays; + if ( nTempDays > MAX_DAYS ) + { + _rDate.Day = 31; + _rDate.Month = 12; + _rDate.Year = 9999; + } + else if ( nTempDays <= 0 ) + { + _rDate.Day = 1; + _rDate.Month = 1; + _rDate.Year = 00; + } + else + implBuildFromRelative( nTempDays, _rDate ); + } + + public static void subDays(int nDays, Date _rDate) { + int nTempDays = implRelativeToAbsoluteNull( _rDate ); + + nTempDays -= nDays; + if ( nTempDays > MAX_DAYS ) + { + _rDate.Day = 31; + _rDate.Month = 12; + _rDate.Year = 9999; + } + else if ( nTempDays <= 0 ) + { + _rDate.Day = 1; + _rDate.Month = 1; + _rDate.Year = 00; + } + else + implBuildFromRelative( nTempDays, _rDate ); + } + + public static int getMsFromTime(final Time rVal) { + int nHour = rVal.Hours; + int nMin = rVal.Minutes; + int nSec = rVal.Seconds; + int n100Sec = rVal.HundredthSeconds; + + return ((nHour*3600000)+(nMin*60000)+(nSec*1000)+(n100Sec*10)); + } + + public static Date getStandardDate() { + return standardDate; + } + + private static int implDaysInMonth(int _nMonth, int _nYear) { + if (_nMonth != 2) + return aDaysInMonth[_nMonth-1]; + else { + if (implIsLeapYear(_nYear)) + return aDaysInMonth[_nMonth-1] + 1; + else + return aDaysInMonth[_nMonth-1]; + } + } + + private static void implBuildFromRelative( int nDays, Date date ) { + int nTempDays; + int i = 0; + boolean bCalc; + + do { + nTempDays = nDays; + date.Year = (short)((nTempDays / 365) - i); + nTempDays -= (date.Year-1) * 365; + nTempDays -= ((date.Year-1) / 4) - ((date.Year-1) / 100) + ((date.Year-1) / 400); + bCalc = false; + if ( nTempDays < 1 ) + { + i++; + bCalc = true; + } + else + { + if ( nTempDays > 365 ) + { + if ( (nTempDays != 366) || !implIsLeapYear( date.Year ) ) + { + i--; + bCalc = true; + } + } + } + } + while ( bCalc ); + + date.Month = 1; + while ( nTempDays > implDaysInMonth( date.Month, date.Year ) ) + { + nTempDays -= implDaysInMonth( date.Month, date.Year ); + date.Month++; + } + date.Day = (short)nTempDays; + } + + private static boolean implIsLeapYear(int _nYear) { + return ( ( ((_nYear % 4) == 0) + && ((_nYear % 100) != 0) + ) + ) + || ((_nYear % 400) == 0) + ; + } + + + private static int implRelativeToAbsoluteNull(final Date _rDate) { + int nDays = 0; + + // ripped this code from the implementation of tools::Date + int nNormalizedYear = _rDate.Year - 1; + nDays = nNormalizedYear * 365; + // leap years + nDays += (nNormalizedYear / 4) - (nNormalizedYear / 100) + (nNormalizedYear / 400); + + for (int i = 1; i < _rDate.Month; ++i) + nDays += implDaysInMonth(i, _rDate.Year); + + nDays += _rDate.Day; + return nDays; + } + + public static int toDays(Date rVal) { + return toDays(rVal, getStandardDate()); + } + + public static int toDays(Date rVal, Date rNullDate) { + return implRelativeToAbsoluteNull(rVal) - implRelativeToAbsoluteNull(rNullDate); + } + + public static double toDouble(Date rVal) { + return toDouble(rVal, getStandardDate()); + } + + public static double toDouble(Date rVal, Date _rNullDate) { + return (double)toDays(rVal, _rNullDate); + } + + public static double toDouble(DateTime _rVal) { + return toDouble(_rVal, getStandardDate()); + } + + public static double toDouble(DateTime _rVal, Date _rNullDate) { + long nTime = toDays(new Date(_rVal.Day, _rVal.Month, _rVal.Year), _rNullDate); + Time aTimePart = new Time(); + + aTimePart.Hours = _rVal.Hours; + aTimePart.Minutes = _rVal.Minutes; + aTimePart.Seconds = _rVal.Seconds; + aTimePart.HundredthSeconds = _rVal.HundredthSeconds; + + return ((double)nTime) + toDouble(aTimePart); + } + + public static double toDouble(Time rVal) { + return (double)getMsFromTime(rVal) / fMilliSecondsPerDay; + } + + public static Date toDate(double dVal) { + return toDate(dVal, getStandardDate()); + } + + public static Date toDate(double dVal, Date _rNullDate) { + Date aRet = _rNullDate; + + if (dVal >= 0) + addDays((int)dVal,aRet); + else + subDays((int)(-dVal),aRet); + // x -= (sal_uInt32)(-nDays); + + return aRet; + } + + public static Date toDate(String value) { + String[] tokens = value.split("-"); + + short nYear = 0, + nMonth = 0, + nDay = 0; + if (tokens.length > 0) { + nYear = (short)safeParseInt(tokens[0]); + } + if (tokens.length > 1) { + nMonth = (short)safeParseInt(tokens[1]); + } + if (tokens.length > 2) { + nDay = (short)safeParseInt(tokens[2]); + } + + return new Date(nDay,nMonth,nYear); + } + + public static DateTime toDateTime(double dVal) { + return toDateTime(dVal, getStandardDate()); + } + + public static DateTime toDateTime(double dVal, Date _rNullDate) { + Date aDate = toDate(dVal, _rNullDate); + Time aTime = toTime(dVal); + + DateTime xRet = new DateTime(); + + xRet.Day = aDate.Day; + xRet.Month = aDate.Month; + xRet.Year = aDate.Year; + + xRet.HundredthSeconds = aTime.HundredthSeconds; + xRet.Minutes = aTime.Minutes; + xRet.Seconds = aTime.Seconds; + xRet.Hours = aTime.Hours; + + + return xRet; + } + + public static DateTime toDateTime(String _sSQLString) { + // the date part + int nSeparation = _sSQLString.indexOf( ' ' ); + String dateString; + String timeString = ""; + if (nSeparation >= 0) { + dateString = _sSQLString.substring(0, nSeparation); + timeString = _sSQLString.substring(nSeparation + 1); + } else { + dateString = _sSQLString; + } + Date aDate = toDate(dateString); + Time aTime = new Time(); + + if ( -1 != nSeparation ) + aTime = toTime( timeString ); + + return new DateTime(aTime.HundredthSeconds,aTime.Seconds,aTime.Minutes,aTime.Hours,aDate.Day,aDate.Month,aDate.Year); + } + + public static Time toTime(int _nVal) { + Time aReturn = new Time(); + aReturn.Hours = (short)(((int)(_nVal >= 0 ? _nVal : _nVal*-1)) / 1000000); + aReturn.Minutes = (short)((((int)(_nVal >= 0 ? _nVal : _nVal*-1)) / 10000) % 100); + aReturn.Seconds = (short)((((int)(_nVal >= 0 ? _nVal : _nVal*-1)) / 100) % 100); + aReturn.HundredthSeconds = (short)(((int)(_nVal >= 0 ? _nVal : _nVal*-1)) % 100); + return aReturn; + } + + public static Time toTime(double dVal) { + int nDays = (int)dVal; + int nMS = (int)((dVal - (double)nDays) * fMilliSecondsPerDay + 0.5); + + short nSign; + if ( nMS < 0 ) + { + nMS *= -1; + nSign = -1; + } + else + nSign = 1; + + Time xRet = new Time(); + // Zeit normalisieren + // we have to sal_Int32 here because otherwise we get an overflow + int nHundredthSeconds = nMS/10; + int nSeconds = nHundredthSeconds / 100; + int nMinutes = nSeconds / 60; + + xRet.HundredthSeconds = (short)(nHundredthSeconds % 100); + xRet.Seconds = (short)(nSeconds % 60); + xRet.Hours = (short)(nMinutes / 60); + xRet.Minutes = (short)(nMinutes % 60); + + // Zeit zusammenbauen + int nTime = (int)(xRet.HundredthSeconds + (xRet.Seconds*100) + (xRet.Minutes*10000) + (xRet.Hours*1000000)) * nSign; + + if(nTime < 0) + { + xRet.HundredthSeconds = 99; + xRet.Minutes = 59; + xRet.Seconds = 59; + xRet.Hours = 23; + } + return xRet; + } + + public static Time toTime(String _sSQLString) { + short nHour = 0, + nMinute = 0, + nSecond = 0, + nHundredthSeconds = 0; + StringTokenizer tokenizer = new StringTokenizer(_sSQLString, ":"); + if (tokenizer.hasMoreTokens()) { + nHour = (short)safeParseInt(tokenizer.nextToken()); + } + if (tokenizer.hasMoreTokens()) { + nMinute = (short)safeParseInt(tokenizer.nextToken()); + } + if (tokenizer.hasMoreTokens()) { + String secondAndNano = tokenizer.nextToken(); + int dot = secondAndNano.indexOf("."); + if (dot >= 0) { + nSecond = (short)safeParseInt(secondAndNano.substring(0, dot)); + String nano = secondAndNano.substring(dot + 1); + nano = nano.substring(0, 2); + nano = nano + "00".substring(0, 2 - nano.length()); + nHundredthSeconds = (short)safeParseInt(nano); + } else { + nSecond = (short)safeParseInt(secondAndNano); + } + } + return new Time(nHundredthSeconds,nSecond,nMinute,nHour); + } + + public static String toDateString(Date date) { + return String.format("%04d-%02d-%02d", + Short.toUnsignedInt(date.Year), + Short.toUnsignedInt(date.Month), + Short.toUnsignedInt(date.Day)); + } + + public static String toTimeString(Time time) { + return String.format("%02d:%02d:%02d", + Short.toUnsignedInt(time.Hours), + Short.toUnsignedInt(time.Minutes), + Short.toUnsignedInt(time.Seconds)); + } + + public static String toDateTimeString(DateTime dateTime) { + return String.format("%04d-%02d-%02d %02d:%02d:%02d.%d", + Short.toUnsignedInt(dateTime.Year), + Short.toUnsignedInt(dateTime.Month), + Short.toUnsignedInt(dateTime.Day), + Short.toUnsignedInt(dateTime.Hours), + Short.toUnsignedInt(dateTime.Minutes), + Short.toUnsignedInt(dateTime.Seconds), + Short.toUnsignedInt(dateTime.HundredthSeconds)); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/DatabaseMetaDataResultSet.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/DatabaseMetaDataResultSet.java new file mode 100644 index 000000000000..ae722c1bf2f7 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/DatabaseMetaDataResultSet.java @@ -0,0 +1,489 @@ +/************************************************************** + * + * 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.util; + +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +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.container.XNameAccess; +import com.sun.star.io.XInputStream; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lib.uno.helper.ComponentBase; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XArray; +import com.sun.star.sdbc.XBlob; +import com.sun.star.sdbc.XClob; +import com.sun.star.sdbc.XCloseable; +import com.sun.star.sdbc.XColumnLocate; +import com.sun.star.sdbc.XRef; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XResultSetMetaData; +import com.sun.star.sdbc.XResultSetMetaDataSupplier; +import com.sun.star.sdbc.XRow; +import com.sun.star.sdbcx.CompareBookmark; +import com.sun.star.sdbcx.XColumnsSupplier; +import com.sun.star.sdbcx.XRowLocate; +import com.sun.star.sdbcx.comp.postgresql.PostgresqlResultSetMetaData; +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.Date; +import com.sun.star.util.DateTime; +import com.sun.star.util.Time; + +public class DatabaseMetaDataResultSet extends ComponentBase + implements XResultSet, XCloseable, XColumnsSupplier, XRowLocate, XPropertySet, XColumnLocate, XRow, XResultSetMetaDataSupplier { + + private XCloseable implCloseable; + private XResultSetMetaDataSupplier implResultSetMetaDataSupplier; + private XColumnLocate implColumnLocate; + private XPropertySet implPropertySet; + private XColumnsSupplier implColumnSupplier; + private ArrayList<ORowSetValue[]> rows; + private AtomicBoolean isDisposed = new AtomicBoolean(false); + /// 0-based: + private int currentRow = -1; + /// 1-based: + private int currentColumn; + + public DatabaseMetaDataResultSet(XResultSet impl, ArrayList<ORowSetValue[]> rows) { + implCloseable = UnoRuntime.queryInterface(XCloseable.class, impl); + implPropertySet = UnoRuntime.queryInterface(XPropertySet.class, impl); + implColumnSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, impl); + implColumnLocate = UnoRuntime.queryInterface(XColumnLocate.class, impl); + implResultSetMetaDataSupplier = UnoRuntime.queryInterface(XResultSetMetaDataSupplier.class, impl); + this.rows = rows; + } + + // XComponent: + @Override + protected void postDisposing() { + isDisposed.set(true); + try { + implCloseable.close(); + } catch (SQLException sqlException) { + } + } + + private void checkDisposed() throws DisposedException { + if (isDisposed.get()) { + throw new DisposedException(); + } + } + + // XCloseable: + + public void close() throws SQLException { + dispose(); + } + + // XResultSet: + + private ORowSetValue getField(int columnIndex) throws SQLException { + if (isBeforeFirst() || isAfterLast()) { + throw new SQLException("Row out of range"); + } + ORowSetValue[] fields = rows.get(currentRow); + if (columnIndex < 1 || fields.length < columnIndex) { + throw new SQLException("Column out of range"); + } + currentColumn = columnIndex; + return fields[columnIndex - 1]; + } + + public synchronized boolean absolute(int position) throws SQLException { + checkDisposed(); + if (position >= 0) { + currentRow = position; + } else { + currentRow = rows.size() + position; + } + if (currentRow <= -1) { + currentRow = -1; + return false; + } + if (currentRow >= rows.size()) { + currentRow = rows.size(); + return false; + } + return true; + } + + public synchronized void afterLast() throws SQLException { + checkDisposed(); + currentRow = rows.size(); + } + + public synchronized void beforeFirst() throws SQLException { + checkDisposed(); + currentRow = -1; + } + + public synchronized boolean first() throws SQLException { + checkDisposed(); + currentRow = 0; + return true; + } + + public synchronized int getRow() throws SQLException { + checkDisposed(); + return currentRow + 1; + } + + public Object getStatement() throws SQLException { + checkDisposed(); + return null; + } + + public synchronized boolean isAfterLast() throws SQLException { + checkDisposed(); + return currentRow == rows.size(); + } + + public synchronized boolean isBeforeFirst() throws SQLException { + checkDisposed(); + return currentRow == -1; + } + + public synchronized boolean isFirst() throws SQLException { + checkDisposed(); + return currentRow == 0; + } + + public synchronized boolean isLast() throws SQLException { + checkDisposed(); + return currentRow == (rows.size() - 1); + } + + public synchronized boolean last() throws SQLException { + checkDisposed(); + currentRow = rows.size() - 1; + return true; + } + + public synchronized boolean next() throws SQLException { + checkDisposed(); + if (currentRow < rows.size()) { + ++currentRow; + } + return currentRow < rows.size(); + } + + public synchronized boolean previous() throws SQLException { + checkDisposed(); + if (currentRow > -1) { + --currentRow; + } + return currentRow > -1; + } + + public void refreshRow() throws SQLException { + checkDisposed(); + } + + public synchronized boolean relative(int offset) throws SQLException { + checkDisposed(); + currentRow += offset; + if (currentRow <= -1) { + currentRow = -1; + return false; + } + if (currentRow >= rows.size()) { + currentRow = rows.size(); + return false; + } + return true; + } + + public boolean rowDeleted() throws SQLException { + checkDisposed(); + return false; + } + + public boolean rowInserted() throws SQLException { + checkDisposed(); + return false; + } + + public boolean rowUpdated() throws SQLException { + checkDisposed(); + return false; + } + + // XResultSetMetaDataSupplier: + + public XResultSetMetaData getMetaData() throws SQLException { + checkDisposed(); + return new PostgresqlResultSetMetaData(implResultSetMetaDataSupplier.getMetaData()); + } + + // XRow: + + public XArray getArray(int columnIndex) throws SQLException { + checkDisposed(); + return null; + } + + public XInputStream getBinaryStream(int columnIndex) throws SQLException { + checkDisposed(); + return null; + } + + public XBlob getBlob(int columnIndex) throws SQLException { + checkDisposed(); + return null; + } + + public synchronized boolean getBoolean(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getBoolean(); + } + + public synchronized byte getByte(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getInt8(); + } + + public synchronized byte[] getBytes(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getSequence(); + } + + public XInputStream getCharacterStream(int columnIndex) throws SQLException { + checkDisposed(); + return null; + } + + public XClob getClob(int columnIndex) throws SQLException { + checkDisposed(); + return null; + } + + public synchronized Date getDate(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getDate(); + } + + public synchronized double getDouble(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getDouble(); + } + + public synchronized float getFloat(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getFloat(); + } + + public synchronized int getInt(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getInt32(); + } + + public synchronized long getLong(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getLong(); + } + + public synchronized Object getObject(int columnIndex, XNameAccess arg1) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.makeAny(); + } + + public XRef getRef(int columnIndex) throws SQLException { + checkDisposed(); + return null; + } + + public synchronized short getShort(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getInt16(); + } + + public synchronized String getString(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getString(); + } + + public synchronized Time getTime(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getTime(); + } + + public synchronized DateTime getTimestamp(int columnIndex) throws SQLException { + checkDisposed(); + ORowSetValue field = getField(columnIndex); + return field.getDateTime(); + } + + public synchronized boolean wasNull() throws SQLException { + checkDisposed(); + ORowSetValue field = getField(currentColumn); + return field.isNull(); + } + + // XColumnLocate: + + public int findColumn(String arg0) throws SQLException { + checkDisposed(); + return implColumnLocate.findColumn(arg0); + } + + // XPropertySet: + + public void addPropertyChangeListener(String arg0, XPropertyChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.addPropertyChangeListener(arg0, arg1); + } + + public void addVetoableChangeListener(String arg0, XVetoableChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.addVetoableChangeListener(arg0, arg1); + } + + public XPropertySetInfo getPropertySetInfo() { + checkDisposed(); + return implPropertySet.getPropertySetInfo(); + } + + public Object getPropertyValue(String arg0) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + return implPropertySet.getPropertyValue(arg0); + } + + public void removePropertyChangeListener(String arg0, XPropertyChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.removePropertyChangeListener(arg0, arg1); + } + + public void removeVetoableChangeListener(String arg0, XVetoableChangeListener arg1) throws UnknownPropertyException, WrappedTargetException { + checkDisposed(); + implPropertySet.removeVetoableChangeListener(arg0, arg1); + } + + public void setPropertyValue(String arg0, Object arg1) + throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException { + checkDisposed(); + implPropertySet.setPropertyValue(arg0, arg1); + } + + // XRowLocate: + + public int compareBookmarks(Object arg0, Object arg1) throws SQLException { + checkDisposed(); + + int bookmark1, bookmark2; + try { + bookmark1 = AnyConverter.toInt(arg0); + bookmark2 = AnyConverter.toInt(arg1); + } catch (IllegalArgumentException illegalArgumentException) { + return CompareBookmark.NOT_COMPARABLE; + } + + if (bookmark1 < bookmark2) { + return CompareBookmark.LESS; + } else if (bookmark1 > bookmark2) { + return CompareBookmark.GREATER; + } else { + return CompareBookmark.EQUAL; + } + } + + public Object getBookmark() throws SQLException { + checkDisposed(); + return currentRow; + } + + public boolean hasOrderedBookmarks() throws SQLException { + checkDisposed(); + return true; + } + + public int hashBookmark(Object arg0) throws SQLException { + checkDisposed(); + int bookmark; + try { + bookmark = AnyConverter.toInt(arg0); + } catch (IllegalArgumentException illegalArgumentException) { + throw new SQLException("Bad bookmark", this, StandardSQLState.SQL_INVALID_BOOKMARK_VALUE.text(), 0, null); + } + return bookmark; + } + + public boolean moveRelativeToBookmark(Object arg0, int arg1) throws SQLException { + checkDisposed(); + int bookmark; + boolean moved = false; + try { + bookmark = AnyConverter.toInt(arg0); + moved = absolute(bookmark); + if (moved) { + moved = relative(arg1); + } + } catch (IllegalArgumentException illegalArgumentException) { + } + if (!moved) { + afterLast(); + } + return moved; + } + + public boolean moveToBookmark(Object arg0) throws SQLException { + checkDisposed(); + int bookmark; + boolean moved = false; + try { + bookmark = AnyConverter.toInt(arg0); + moved = absolute(bookmark); + } catch (IllegalArgumentException illegalArgumentException) { + } + if (!moved) { + afterLast(); + } + return moved; + } + + // XColumnSupplier: + + public XNameAccess getColumns() { + checkDisposed(); + return implColumnSupplier.getColumns(); + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/DbTools.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/DbTools.java new file mode 100644 index 000000000000..5837c3e468ef --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/DbTools.java @@ -0,0 +1,679 @@ +/************************************************************** + * + * 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.util; + +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.lang3.mutable.MutableObject; + +import com.sun.star.beans.PropertyValue; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertySetInfo; +import com.sun.star.container.ElementExistException; +import com.sun.star.container.XIndexAccess; +import com.sun.star.container.XNameAccess; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.IndexOutOfBoundsException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.sdbc.ColumnValue; +import com.sun.star.sdbc.DataType; +import com.sun.star.sdbc.KeyRule; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbc.XDatabaseMetaData; +import com.sun.star.sdbc.XResultSet; +import com.sun.star.sdbc.XResultSetMetaData; +import com.sun.star.sdbc.XResultSetMetaDataSupplier; +import com.sun.star.sdbc.XRow; +import com.sun.star.sdbc.XStatement; +import com.sun.star.sdbcx.KeyType; +import com.sun.star.sdbcx.XAppend; +import com.sun.star.sdbcx.XColumnsSupplier; +import com.sun.star.sdbcx.XKeysSupplier; +import com.sun.star.sdbcx.comp.postgresql.comphelper.CompHelper; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.ISQLStatementHelper; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.OColumnContainer.ExtraColumnInfo; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.Resources; +import com.sun.star.sdbcx.comp.postgresql.sdbcx.SharedResources; +import com.sun.star.uno.Any; +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.UnoRuntime; + +public class DbTools { + private static class NameComponentSupport { + boolean useCatalogs; + boolean useSchemas; + + NameComponentSupport() { + useCatalogs = true; + useSchemas = true; + } + + NameComponentSupport(boolean useCatalogs, boolean useSchemas) { + this.useCatalogs = useCatalogs; + this.useSchemas = useSchemas; + } + } + + public static class NameComponents { + private String catalog = ""; + private String schema = ""; + private String table = ""; + + public NameComponents(String catalog, String schema, String table) { + this.catalog = catalog; + this.schema = schema; + this.table = table; + } + + public NameComponents() { + } + + public String getCatalog() { + return catalog; + } + + public void setCatalog(String catalog) { + this.catalog = catalog; + } + + public String getSchema() { + return schema; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public String getTable() { + return table; + } + + public void setTable(String table) { + this.table = table; + } + } + + private static NameComponentSupport getNameComponentSupport(XDatabaseMetaData metadata, ComposeRule composeRule) throws SQLException { + switch (composeRule) { + case InTableDefinitions: + return new NameComponentSupport( + metadata.supportsCatalogsInTableDefinitions(), metadata.supportsSchemasInTableDefinitions()); + case InIndexDefinitions: + return new NameComponentSupport( + metadata.supportsCatalogsInIndexDefinitions(), metadata.supportsSchemasInIndexDefinitions()); + case InDataManipulation: + return new NameComponentSupport( + metadata.supportsCatalogsInDataManipulation(), metadata.supportsSchemasInDataManipulation()); + case InProcedureCalls: + return new NameComponentSupport( + metadata.supportsCatalogsInProcedureCalls(), metadata.supportsSchemasInProcedureCalls()); + case InPrivilegeDefinitions: + return new NameComponentSupport( + metadata.supportsCatalogsInPrivilegeDefinitions(), metadata.supportsSchemasInPrivilegeDefinitions()); + case Complete: + return new NameComponentSupport( + true, true); + default: + throw new UnsupportedOperationException("Invalid/unknown enum value"); + } + } + + public static String composeTableName( + XDatabaseMetaData metadata, String catalog, String schema, String table, boolean quote, ComposeRule composeRule) throws SQLException { + if (metadata == null) { + return ""; + } + String quoteString = metadata.getIdentifierQuoteString(); + NameComponentSupport nameComponentSupport = getNameComponentSupport(metadata, composeRule); + + StringBuilder composedName = new StringBuilder(); + + String catalogSeparator = ""; + boolean catalogAtStart = true; + if (!catalog.isEmpty() && nameComponentSupport.useCatalogs) { + catalogSeparator = metadata.getCatalogSeparator(); + catalogAtStart = metadata.isCatalogAtStart(); + if (catalogAtStart && !catalogSeparator.isEmpty()) { + composedName.append(quote ? quoteName(quoteString, catalog) : catalog); + composedName.append(catalogSeparator); + } + } + if (!schema.isEmpty() && nameComponentSupport.useSchemas) { + composedName.append(quote ? quoteName(quoteString, schema) : schema); + composedName.append('.'); + } + composedName.append(quote ? quoteName(quoteString, table) : table); + if (!catalog.isEmpty() && !catalogAtStart && !catalogSeparator.isEmpty() && nameComponentSupport.useCatalogs) { + composedName.append(catalogSeparator); + composedName.append(quote ? quoteName(quoteString, catalog) : catalog); + } + return composedName.toString(); + } + + public static String composeTableName( + XDatabaseMetaData metadata, XPropertySet table, ComposeRule composeRule, + boolean suppressCatalog, boolean suppressSchema, boolean shouldQuote) throws SQLException { + MutableObject<String> catalog = new MutableObject<>(""); + MutableObject<String> schema = new MutableObject<>(""); + MutableObject<String> name = new MutableObject<>(""); + getTableNameComponents(table, catalog, schema, name); + return doComposeTableName(metadata, + suppressCatalog ? "" : catalog.getValue(), + suppressSchema ? "" : schema.getValue(), + name.getValue(), + shouldQuote, composeRule); + } + + public static boolean isDataSourcePropertyEnabled(Object object, String property, boolean defaultValue) throws SQLException { + try { + boolean enabled = defaultValue; + XPropertySet properties = UnoRuntime.queryInterface(XPropertySet.class, object); + if (properties != null) { + PropertyValue[] info = (PropertyValue[]) AnyConverter.toArray(properties.getPropertyValue("Info")); + for (PropertyValue propertyValue : info) { + if (propertyValue.Name.equals(property)) { + enabled = AnyConverter.toBoolean(propertyValue.Value); + break; + } + } + } + return enabled; + } catch (IllegalArgumentException illegalArgumentException) { + throw new SQLException("Error", object, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, illegalArgumentException); + } catch (WrappedTargetException wrappedTargetException) { + throw new SQLException("Error", object, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, wrappedTargetException); + } catch (UnknownPropertyException unknownPropertyException) { + throw new SQLException("Error", object, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, unknownPropertyException); + } + } + + public static String doComposeTableName(XDatabaseMetaData metadata, String catalog, String schema, String table, + boolean shouldQuote, ComposeRule composeRule) throws SQLException { + System.out.println(String.format("doComposeTableName(%s, %s, %s)\n", catalog, schema, table)); + Osl.ensure(!table.isEmpty(), "At least the table name should be non-empty"); + String quoteString = metadata.getIdentifierQuoteString(); + NameComponentSupport nameComponentSupport = getNameComponentSupport(metadata, composeRule); + + StringBuilder composedName = new StringBuilder(); + String catalogSeparator = ""; + boolean catalogAtStart = true; + if (!catalog.isEmpty() && nameComponentSupport.useCatalogs) { + catalogSeparator = metadata.getCatalogSeparator(); + catalogAtStart = metadata.isCatalogAtStart(); + + if (catalogAtStart && !catalogSeparator.isEmpty()) { + composedName.append(shouldQuote ? quoteName(quoteString, catalog) : catalog); + composedName.append(catalogSeparator); + } + } + + if (!schema.isEmpty() && nameComponentSupport.useSchemas) { + composedName.append(shouldQuote ? quoteName(quoteString, schema) : schema); + composedName.append("."); + } + + composedName.append(shouldQuote ? quoteName(quoteString, table) : table); + + if (!catalog.isEmpty() && !catalogAtStart && !catalogSeparator.isEmpty() && nameComponentSupport.useCatalogs) { + composedName.append(catalogSeparator); + composedName.append(shouldQuote ? quoteName(quoteString, catalog) : catalog); + } + return composedName.toString(); + } + + public static String composeTableNameForSelect(XConnection connection, String catalog, + String schema, String table) throws SQLException { + boolean useCatalogInSelect = isDataSourcePropertyEnabled(connection, "UseCatalogInSelect", true); + boolean useSchemaInSelect = isDataSourcePropertyEnabled(connection, "UseSchemaInSelect", true); + return doComposeTableName(connection.getMetaData(), useCatalogInSelect ? catalog : "", + useSchemaInSelect ? schema : "", table, true, ComposeRule.InDataManipulation); + } + + public static String composeTableNameForSelect(XConnection connection, XPropertySet table) throws SQLException { + MutableObject<String> catalog = new MutableObject<>(); + MutableObject<String> schema = new MutableObject<>(); + MutableObject<String> tableName = new MutableObject<>(); + getTableNameComponents(table, catalog, schema, tableName); + return composeTableNameForSelect(connection, catalog.getValue(), schema.getValue(), tableName.getValue()); + } + + private static void getTableNameComponents(XPropertySet table, MutableObject<String> catalog, + MutableObject<String> schema, MutableObject<String> tableName) { + try { + XPropertySetInfo propertySetInfo = table.getPropertySetInfo(); + if (propertySetInfo != null && propertySetInfo.hasPropertyByName(PropertyIds.NAME.name)) { + if (propertySetInfo.hasPropertyByName(PropertyIds.CATALOGNAME.name) + && propertySetInfo.hasPropertyByName(PropertyIds.SCHEMANAME.name)) { + catalog.setValue(AnyConverter.toString(table.getPropertyValue(PropertyIds.CATALOGNAME.name))); + schema.setValue(AnyConverter.toString(table.getPropertyValue(PropertyIds.SCHEMANAME.name))); + } + tableName.setValue(AnyConverter.toString(table.getPropertyValue(PropertyIds.NAME.name))); + } else { + Osl.ensure(false, "not a table"); + } + } catch (IllegalArgumentException illegalArgumentException) { + } catch (WrappedTargetException wrappedTargetException) { + } catch (UnknownPropertyException unknownPropertyException) { + } + } + + public static String quoteName(String quote, String name) { + if (!quote.isEmpty() && quote.codePointAt(0) != ' ') { + return quote + name + quote; + } + return name; + } + + public static String quoteTableName(XDatabaseMetaData metadata, String name, ComposeRule composeRule) throws SQLException { + NameComponents nameComponents = qualifiedNameComponents(metadata, name, composeRule); + return doComposeTableName(metadata, nameComponents.getCatalog(), nameComponents.getSchema(), nameComponents.getTable(), true, composeRule); + } + + public static NameComponents qualifiedNameComponents(XDatabaseMetaData _rxConnMetaData, String _rQualifiedName, + ComposeRule _eComposeRule) throws SQLException { + Osl.ensure(_rxConnMetaData, "QualifiedNameComponents : invalid meta data!"); + + NameComponentSupport aNameComps = getNameComponentSupport( _rxConnMetaData, _eComposeRule ); + + String sSeparator = _rxConnMetaData.getCatalogSeparator(); + NameComponents ret = new NameComponents(); + + String sName = _rQualifiedName; + // do we have catalogs ? + if ( aNameComps.useCatalogs ) { + if (_rxConnMetaData.isCatalogAtStart()) { + // search for the catalog name at the beginning + int nIndex = sName.indexOf(sSeparator); + if (-1 != nIndex) { + ret.setCatalog(sName.substring(0, nIndex)); + sName = sName.substring(nIndex + 1); + } + } else { + // Katalogname am Ende + int nIndex = sName.lastIndexOf(sSeparator); + if (-1 != nIndex) { + ret.setCatalog(sName.substring(nIndex + 1)); + sName = sName.substring(0, nIndex); + } + } + } + + if ( aNameComps.useSchemas ) { + int nIndex = sName.indexOf('.'); + Osl.ensure(-1 != nIndex, "QualifiedNameComponents : no schema separator!"); + if ( nIndex != -1 ) { + ret.setSchema(sName.substring(0, nIndex)); + } + sName = sName.substring(nIndex + 1); + } + + ret.setTable(sName); + return ret; + } + + public static String createSqlCreateTableStatement(XPropertySet descriptor, XConnection connection, + ISQLStatementHelper helper, String createPattern) throws + SQLException, WrappedTargetException, UnknownPropertyException, IllegalArgumentException, IndexOutOfBoundsException { + + String sql = createStandardCreateStatement(descriptor, connection, helper, createPattern); + final String keyStatement = createStandardKeyStatement(descriptor, connection); + if (!keyStatement.isEmpty()) { + sql += keyStatement; + } else { + sql += ')'; + } + return sql; + } + + public static String createStandardCreateStatement(XPropertySet descriptor, XConnection connection, + ISQLStatementHelper helper, String createPattern) throws + SQLException, WrappedTargetException, UnknownPropertyException, IllegalArgumentException, IndexOutOfBoundsException { + + XDatabaseMetaData metadata = connection.getMetaData(); + String catalog = AnyConverter.toString(descriptor.getPropertyValue("CatalogName")); + String schema = AnyConverter.toString(descriptor.getPropertyValue("SchemaName")); + String table = AnyConverter.toString(descriptor.getPropertyValue("Name")); + String composedName = composeTableName(metadata, catalog, schema, table, true, ComposeRule.InTableDefinitions); + if (composedName.isEmpty()) { + throw new SQLException(SharedResources.getInstance().getResourceString(Resources.STR_ERRORMSG_SEQUENCE), connection, + StandardSQLState.SQL_FUNCTION_SEQUENCE_ERROR.text(), 0, null); + } + + XIndexAccess columns = null; + XColumnsSupplier columnsSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, descriptor); + if (columnsSupplier != null) { + columns = UnoRuntime.queryInterface(XIndexAccess.class, columnsSupplier.getColumns()); + } + if (columns == null || columns.getCount() <= 0) { + throw new SQLException(SharedResources.getInstance().getResourceString(Resources.STR_ERRORMSG_SEQUENCE), connection, + StandardSQLState.SQL_FUNCTION_SEQUENCE_ERROR.text(), 0, null); + } + + int columnCount = columns.getCount(); + StringBuilder columnText = new StringBuilder(); + String separator = ""; + for (int i = 0; i < columnCount; i++) { + XPropertySet columnProperties; + columnProperties = AnyConverter.toObject(XPropertySet.class, columns.getByIndex(i)); + if (columnProperties != null) { + columnText.append(separator); + separator = ","; + columnText.append(createStandardColumnPart(columnProperties, connection, helper, createPattern)); + } + } + + return String.format("CREATE TABLE %s (%s", composedName, columnText.toString()); + } + + public static String createStandardColumnPart(XPropertySet columnProperties, XConnection connection, + ISQLStatementHelper helper, String createPattern) throws + SQLException, WrappedTargetException, UnknownPropertyException, IllegalArgumentException, IndexOutOfBoundsException { + + XDatabaseMetaData metadata = connection.getMetaData(); + + final String quoteString = metadata.getIdentifierQuoteString(); + final StringBuilder sql = new StringBuilder(); + sql.append(quoteName(quoteString, AnyConverter.toString(columnProperties.getPropertyValue("Name")))); + sql.append(' '); + + String typename = AnyConverter.toString(columnProperties.getPropertyValue("TypeName")); + int datatype = AnyConverter.toInt(columnProperties.getPropertyValue("Type")); + int precision = AnyConverter.toInt(columnProperties.getPropertyValue("Precision")); + int scale = AnyConverter.toInt(columnProperties.getPropertyValue("Scale")); + boolean isAutoIncrement = AnyConverter.toBoolean(columnProperties.getPropertyValue("IsAutoIncrement")); + + // check if the user enter a specific string to create autoincrement values + String autoIncrementValue = ""; + XPropertySetInfo columnPropertiesInfo = columnProperties.getPropertySetInfo(); + if (columnPropertiesInfo != null && columnPropertiesInfo.hasPropertyByName("AutoIncrementCreation")) { + autoIncrementValue = AnyConverter.toString(columnProperties.getPropertyValue("AutoIncrementCreation")); + } + + // look if we have to use precisions + boolean useLiteral = false; + String prefix = ""; + String postfix =""; + String createParams = ""; + XResultSet results = null; + try { + results = metadata.getTypeInfo(); + if (results != null) { + XRow row = UnoRuntime.queryInterface(XRow.class, results); + while (results.next()) { + String typeName2Cmp = row.getString(1); + int nType = row.getShort(2); + prefix = row.getString(4); + postfix = row.getString(5); + createParams = row.getString(6); + // first identical type will be used if typename is empty + if (typename.isEmpty() && nType == datatype) { + typename = typeName2Cmp; + } + if (typename.equals(typeName2Cmp) && nType == datatype && !row.wasNull() && !createParams.isEmpty()) { + useLiteral = true; + break; + } + } + } + } finally { + CompHelper.disposeComponent(results); + } + + int index = 0; + if (!autoIncrementValue.isEmpty() && (index = typename.indexOf(autoIncrementValue)) != -1) { + typename = typename.substring(0, index); + } + + if ((precision > 0 || scale > 0) && useLiteral) { + int parenPos = typename.indexOf('('); + if (parenPos == -1) { + sql.append(typename); + sql.append('('); + } else { + sql.append(typename.substring(0, ++parenPos)); + } + + if (precision > 0 && datatype != DataType.TIMESTAMP) { + sql.append(precision); + if (scale > 0 || (!createPattern.isEmpty() && createParams.indexOf(createPattern) != -1)) { + sql.append(','); + } + } + if (scale > 0 || (!createPattern.isEmpty() && createParams.indexOf(createPattern) != -1) || datatype == DataType.TIMESTAMP) { + sql.append(scale); + } + if (parenPos == -1) { + sql.append(')'); + } else { + parenPos = typename.indexOf(')', parenPos); + sql.append(typename.substring(parenPos)); + } + } else { + sql.append(typename); // simply add the type name + } + + String defaultValue = AnyConverter.toString(columnProperties.getPropertyValue("DefaultValue")); + if (defaultValue != null && !defaultValue.isEmpty()) { + sql.append(" DEFAULT "); + sql.append(prefix); + sql.append(defaultValue); + sql.append(postfix); + } + + if (AnyConverter.toInt(columnProperties.getPropertyValue("IsNullable")) == ColumnValue.NO_NULLS) { + sql.append(" NOT NULL"); + } + + if (isAutoIncrement && !autoIncrementValue.isEmpty()) { + sql.append(' '); + sql.append(autoIncrementValue); + } + + if (helper != null) { + helper.addComment(columnProperties, sql); + } + + return sql.toString(); + } + + public static String createStandardKeyStatement(XPropertySet descriptor, XConnection connection) throws + SQLException, WrappedTargetException, UnknownPropertyException, IllegalArgumentException, IndexOutOfBoundsException { + XDatabaseMetaData metadata = connection.getMetaData(); + StringBuilder sql = new StringBuilder(); + + XKeysSupplier keysSupplier = UnoRuntime.queryInterface(XKeysSupplier.class, descriptor); + XIndexAccess keys = keysSupplier.getKeys(); + if (keys != null) { + boolean hasPrimaryKey = false; + for (int i = 0; i < keys.getCount(); i++) { + XPropertySet columnProperties = AnyConverter.toObject(XPropertySet.class, keys.getByIndex(i)); + if (columnProperties != null) { + int keyType = AnyConverter.toInt(columnProperties.getPropertyValue("Type")); + XColumnsSupplier columnsSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, columnProperties); + XIndexAccess columns = UnoRuntime.queryInterface(XIndexAccess.class, columnsSupplier.getColumns()); + if (columns == null || columns.getCount() == 0) { + throw new SQLException(SharedResources.getInstance().getResourceString(Resources.STR_ERRORMSG_SEQUENCE), connection, + StandardSQLState.SQL_FUNCTION_SEQUENCE_ERROR.text(), 0, null); + } + if (keyType == KeyType.PRIMARY) { + if (hasPrimaryKey) { + throw new SQLException(SharedResources.getInstance().getResourceString(Resources.STR_ERRORMSG_SEQUENCE), connection, + StandardSQLState.SQL_FUNCTION_SEQUENCE_ERROR.text(), 0, null); + } + hasPrimaryKey = true; + sql.append(" PRIMARY KEY "); + sql.append(generateColumnNames(columns, metadata)); + } else if (keyType == KeyType.UNIQUE) { + sql.append(" UNIQUE "); + sql.append(generateColumnNames(columns, metadata)); + } else if (keyType == KeyType.FOREIGN) { + int deleteRule = AnyConverter.toInt(columnProperties.getPropertyValue("DeleteRule")); + sql.append(" FOREIGN KEY "); + sql.append(generateColumnNames(columns, metadata)); + + String referencedTable = AnyConverter.toString(columnProperties.getPropertyValue("ReferencedTable")); + NameComponents nameComponents = qualifiedNameComponents(metadata, referencedTable, ComposeRule.InDataManipulation); + String composedName = composeTableName(metadata, nameComponents.getCatalog(), nameComponents.getSchema(), nameComponents.getTable(), + true, ComposeRule.InTableDefinitions); + if (composedName.isEmpty()) { + throw new SQLException(SharedResources.getInstance().getResourceString(Resources.STR_ERRORMSG_SEQUENCE), connection, + StandardSQLState.SQL_FUNCTION_SEQUENCE_ERROR.text(), 0, null); + } + + switch (deleteRule) { + case KeyRule.CASCADE: + sql.append(" ON DELETE CASCADE "); + break; + case KeyRule.RESTRICT: + sql.append(" ON DELETE RESTRICT "); + break; + case KeyRule.SET_NULL: + sql.append(" ON DELETE SET NULL "); + break; + case KeyRule.SET_DEFAULT: + sql.append(" ON DELETE SET DEFAULT "); + break; + } + } + } + } + } + + if (sql.length() > 0) { + sql.append(')'); + } + return sql.toString(); + } + + private static String generateColumnNames(XIndexAccess columns, XDatabaseMetaData metadata) throws + SQLException, WrappedTargetException, UnknownPropertyException, IllegalArgumentException, IndexOutOfBoundsException { + String quote = metadata.getIdentifierQuoteString(); + StringBuilder sql = new StringBuilder(" ("); + int columnCount = columns.getCount(); + String separator = ""; + for (int i = 0; i < columnCount; i++) { + XPropertySet columnProperties = AnyConverter.toObject(XPropertySet.class, columns.getByIndex(i)); + if (columnProperties != null) { + sql.append(separator); + separator = ","; + String columnName = AnyConverter.toString(columnProperties.getPropertyValue("Name")); + sql.append(quoteName(quote, columnName)); + } + } + if (columnCount > 0) { + sql.append(')'); + } + return sql.toString(); + } + + public static Map<String,ExtraColumnInfo> collectColumnInformation(XConnection connection, String composedName, String columnName) throws SQLException { + String sql = String.format("SELECT %s FROM %s WHERE 0 = 1", columnName, composedName); + XStatement statement = null; + try { + statement = connection.createStatement(); + XPropertySet statementProperties = UnoRuntime.queryInterface(XPropertySet.class, statement); + statementProperties.setPropertyValue(PropertyIds.ESCAPEPROCESSING.name, false); + XResultSet results = statement.executeQuery(sql); + XResultSetMetaDataSupplier metadataSupplier = UnoRuntime.queryInterface(XResultSetMetaDataSupplier.class, results); + XResultSetMetaData metadata = metadataSupplier.getMetaData(); + + Map<String,ExtraColumnInfo> columns = new TreeMap<>(); + int count = metadata.getColumnCount(); + Osl.ensure(count > 0, "resultset has empty metadata"); + for (int i = 1; i <= count; i++) { + String newColumnName = metadata.getColumnName(i); + ExtraColumnInfo columnInfo = new ExtraColumnInfo(); + columnInfo.isAutoIncrement = metadata.isAutoIncrement(i); + columnInfo.isCurrency = metadata.isCurrency(i); + columnInfo.dataType = metadata.getColumnType(i); + columns.put(newColumnName, columnInfo); + } + return columns; + } catch (IllegalArgumentException illegalArgumentException) { + throw new SQLException(); + } catch (WrappedTargetException wrappedTargetException) { + throw new SQLException(); + } catch (UnknownPropertyException unknownPropertyException) { + throw new SQLException(); + } catch (PropertyVetoException propertyVetoException) { + throw new SQLException(); + } finally { + CompHelper.disposeComponent(statement); + } + } + + public static XNameAccess getPrimaryKeyColumns(XPropertySet table) throws SQLException { + try { + XNameAccess keyColumns = null; + XKeysSupplier keysSupplier = UnoRuntime.queryInterface(XKeysSupplier.class, table); + if (keysSupplier != null) { + XIndexAccess keys = keysSupplier.getKeys(); + if (keys != null) { + int count = keys.getCount(); + for (int i = 0; i < count; i++) { + XPropertySet propertySet = UnoRuntime.queryInterface(XPropertySet.class, keys.getByIndex(i)); + if (propertySet != null) { + int keyType = 0; + keyType = AnyConverter.toInt(propertySet.getPropertyValue(PropertyIds.TYPE.name)); + if (keyType == KeyType.PRIMARY) { + XColumnsSupplier columnsSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, propertySet); + keyColumns = columnsSupplier.getColumns(); + break; + } + } + } + } + } + return keyColumns; + } catch (IndexOutOfBoundsException indexOutOfBoundsException) { + throw new SQLException(); + } catch (IllegalArgumentException illegalArgumentException) { + throw new SQLException(); + } catch (WrappedTargetException wrappedTargetException) { + throw new SQLException(); + } catch (UnknownPropertyException unknownPropertyException) { + throw new SQLException(); + } + } + + public static void cloneDescriptorColumns(XPropertySet source, XPropertySet destination) throws SQLException { + XColumnsSupplier sourceColumnsSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, source); + XIndexAccess sourceColumns = UnoRuntime.queryInterface(XIndexAccess.class, sourceColumnsSupplier.getColumns()); + + XColumnsSupplier destinationColumnsSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, destination); + XAppend destinationAppend = UnoRuntime.queryInterface(XAppend.class, destinationColumnsSupplier.getColumns()); + + int count = sourceColumns.getCount(); + for (int i = 0; i < count; i++) { + try { + XPropertySet columnProperties = AnyConverter.toObject(XPropertySet.class, sourceColumns.getByIndex(i)); + destinationAppend.appendByDescriptor(columnProperties); + } catch (WrappedTargetException | IndexOutOfBoundsException | IllegalArgumentException | ElementExistException exception) { + throw new SQLException("Error", Any.VOID, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, exception); + } + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/MapToXNameAccessAdapter.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/MapToXNameAccessAdapter.java new file mode 100644 index 000000000000..991679ba53c5 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/MapToXNameAccessAdapter.java @@ -0,0 +1,91 @@ +/************************************************************** + * + * 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.util; + +import java.util.Map; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XNameAccess; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lib.uno.helper.WeakBase; +import com.sun.star.uno.Type; + +public class MapToXNameAccessAdapter extends WeakBase implements XNameAccess { + protected final Map<String,Object> map; + protected final Object lock; + private final Type elementType; + + public MapToXNameAccessAdapter(Map<String,Object> map, Object lock, Type elementType) { + this.map = map; + this.lock = lock; + this.elementType = elementType; + } + + // XNameAccess: + + @Override + public Object getByName(String key) + throws NoSuchElementException, WrappedTargetException { + Object object; + synchronized (lock) { + object = map.get(key); + } + if (object == null) { + throw new NoSuchElementException(); + } + return object; + } + + @Override + public String[] getElementNames() { + synchronized (lock) { + String[] names = new String[map.size()]; + int next = 0; + for (Map.Entry<String,Object> entry : map.entrySet()) { + names[next++] = entry.getKey().toString(); + } + return names; + } + } + + @Override + public boolean hasByName(String key) { + synchronized (lock) { + return map.containsKey(key); + } + } + + // XElementAccess: + + @Override + public Type getElementType() { + return elementType; + } + + + @Override + public boolean hasElements() { + synchronized (lock) { + return !map.isEmpty(); + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/MapToXNameContainerAdapter.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/MapToXNameContainerAdapter.java new file mode 100644 index 000000000000..ad5d3afed456 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/MapToXNameContainerAdapter.java @@ -0,0 +1,77 @@ +/************************************************************** + * + * 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.util; + +import java.util.Map; + +import com.sun.star.container.ElementExistException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XNameContainer; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.uno.Type; + +public class MapToXNameContainerAdapter extends MapToXNameAccessAdapter implements XNameContainer { + public MapToXNameContainerAdapter(Map<String,Object> map, Object lock, Type elementType) { + super(map, lock, elementType); + } + + // XNameContainer: + + @Override + public void insertByName(String key, Object value) + throws IllegalArgumentException, ElementExistException, + WrappedTargetException { + synchronized (lock) { + if (map.containsKey(key)) { + throw new ElementExistException(); + } + map.put(key, value); + } + } + + @Override + public void removeByName(String key) + throws NoSuchElementException, WrappedTargetException { + synchronized (lock) { + if (map.containsKey(key)) { + map.remove(key); + } else { + throw new NoSuchElementException(); + } + } + } + + // XNameReplace: + + @Override + public void replaceByName(String key, Object value) + throws IllegalArgumentException, NoSuchElementException, + WrappedTargetException { + synchronized (lock) { + if (!map.containsKey(key)) { + throw new NoSuchElementException(); + } + map.put(key, value); + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/ORowSetValue.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/ORowSetValue.java new file mode 100644 index 000000000000..f218b39b4cbd --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/ORowSetValue.java @@ -0,0 +1,1154 @@ +/************************************************************** + * + * 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.util; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; + +import com.sun.star.io.IOException; +import com.sun.star.io.XInputStream; +import com.sun.star.sdbc.DataType; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XBlob; +import com.sun.star.sdbc.XClob; +import com.sun.star.uno.Any; +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.Date; +import com.sun.star.util.DateTime; +import com.sun.star.util.Time; + +public class ORowSetValue { + private Object value; + private int typeKind; + private int flags; + private static final int FLAG_NULL = 0b1000; + private static final int FLAG_BOUND = 0b0100; + private static final int FLAG_MODIFIED = 0b0010; + private static final int FLAG_SIGNED = 0b0001; + + public ORowSetValue() { + flags = FLAG_NULL | FLAG_BOUND | FLAG_SIGNED; + typeKind = DataType.VARCHAR; + } + + public ORowSetValue(boolean value) { + this(); + setBoolean(value); + } + + public ORowSetValue(Date value) { + this(); + setDate(value); + } + + public ORowSetValue(DateTime value) { + this(); + setDateTime(value); + } + + public ORowSetValue(double value) { + this(); + setDouble(value); + } + + public ORowSetValue(float value) { + this(); + setFloat(value); + } + + public ORowSetValue(byte value) { + this(); + setInt8(value); + } + + public ORowSetValue(short value) { + this(); + setInt16(value); + } + + public ORowSetValue(int value) { + this(); + setInt32(value); + } + + public ORowSetValue(long value) { + this(); + setLong(value); + } + + public ORowSetValue(byte[] value) { + this(); + setSequence(value); + } + + public ORowSetValue(String value) { + this(); + setString(value); + } + + public ORowSetValue(Time value) { + this(); + setTime(value); + } + + public boolean isNull() { + return (flags & FLAG_NULL) != 0; + } + + public void setNull() { + free(); + flags |= FLAG_NULL; + } + + public boolean isBound() { + return (flags & FLAG_BOUND) != 0; + } + + public void setBound(boolean isBound) { + if (isBound) { + flags |= FLAG_BOUND; + } else { + flags &= ~FLAG_BOUND; + } + } + + public boolean isModified() { + return (flags & FLAG_MODIFIED) != 0; + } + + public void setModified(boolean isModified) { + flags |= FLAG_MODIFIED; + } + + public boolean isSigned() { + return (flags & FLAG_SIGNED) != 0; + } + + public void setSigned() throws IOException, SQLException { + setSigned(true); + } + + public void setSigned(boolean isSigned) { + if (isSigned) { + flags |= FLAG_SIGNED; + } else { + flags &= ~FLAG_SIGNED; + } + } + + private boolean isStorageCompatible(int _eType1, int _eType2) { + boolean bIsCompatible = true; + + if (_eType1 != _eType2) { + switch (_eType1) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + bIsCompatible = (DataType.CHAR == _eType2) + || (DataType.VARCHAR == _eType2) + || (DataType.DECIMAL == _eType2) + || (DataType.NUMERIC == _eType2) + || (DataType.LONGVARCHAR == _eType2); + break; + + case DataType.DOUBLE: + case DataType.REAL: + bIsCompatible = (DataType.DOUBLE == _eType2) + || (DataType.REAL == _eType2); + break; + + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + bIsCompatible = (DataType.BINARY == _eType2) + || (DataType.VARBINARY == _eType2) + || (DataType.LONGVARBINARY == _eType2); + break; + + case DataType.INTEGER: + bIsCompatible = (DataType.SMALLINT == _eType2) + || (DataType.TINYINT == _eType2) + || (DataType.BIT == _eType2) + || (DataType.BOOLEAN == _eType2); + break; + case DataType.SMALLINT: + bIsCompatible = (DataType.TINYINT == _eType2) + || (DataType.BIT == _eType2) + || (DataType.BOOLEAN == _eType2); + break; + case DataType.TINYINT: + bIsCompatible = (DataType.BIT == _eType2) + || (DataType.BOOLEAN == _eType2); + break; + + case DataType.BLOB: + case DataType.CLOB: + case DataType.OBJECT: + bIsCompatible = (DataType.BLOB == _eType2) + || (DataType.CLOB == _eType2) + || (DataType.OBJECT == _eType2); + break; + + default: + bIsCompatible = false; + } + } + return bIsCompatible; + } + + public int getTypeKind() { + return typeKind; + } + + public void setTypeKind(int type) throws SQLException { + if (!isNull() && !isStorageCompatible(type, typeKind)) { + switch (type) { + case DataType.VARCHAR: + case DataType.CHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + setString(getString()); + break; + case DataType.BIGINT: + setLong(getLong()); + break; + + case DataType.FLOAT: + setFloat(getFloat()); + break; + case DataType.DOUBLE: + case DataType.REAL: + setDouble(getDouble()); + break; + case DataType.TINYINT: + setInt8(getInt8()); + break; + case DataType.SMALLINT: + setInt16(getInt16()); + break; + case DataType.INTEGER: + setInt32(getInt32()); + break; + case DataType.BIT: + case DataType.BOOLEAN: + setBoolean(getBoolean()); + break; + case DataType.DATE: + setDate(getDate()); + break; + case DataType.TIME: + setTime(getTime()); + break; + case DataType.TIMESTAMP: + setDateTime(getDateTime()); + break; + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + setSequence(getSequence()); + break; + case DataType.BLOB: + case DataType.CLOB: + case DataType.OBJECT: + case DataType.OTHER: + setAny(getAny()); + break; + default: + setAny(getAny()); + //OSL_ENSURE(0,"ORowSetValue:operator==(): UNSPUPPORTED TYPE!"); + } + } + typeKind = type; + } + + private void free() { + if (!isNull()) { + value = null; + flags |= FLAG_NULL; + } + } + + public Any getAny() { + Any any = (Any)value; + return new Any(any.getType(), any.getObject()); + } + + public boolean getBoolean() { + boolean bRet = false; + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.LONGVARCHAR: + if (((String)value).equals("true")) { + bRet = true; + } else if (((String)value).equals("false")) { + bRet = false; + } + // fall through + case DataType.DECIMAL: + case DataType.NUMERIC: + bRet = DBTypeConversion.safeParseInt((String)value) != 0; + break; + case DataType.BIGINT: + bRet = (long)value != 0; + break; + case DataType.FLOAT: + bRet = (float)value != 0.0; + break; + case DataType.DOUBLE: + case DataType.REAL: + bRet = (double)value != 0.0; + break; + case DataType.DATE: + case DataType.TIME: + case DataType.TIMESTAMP: + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + break; + case DataType.BIT: + case DataType.BOOLEAN: + bRet = (boolean)value; + break; + case DataType.TINYINT: + bRet = (byte)value != 0; + break; + case DataType.SMALLINT: + bRet = (short)value != 0; + break; + case DataType.INTEGER: + bRet = (int)value != 0; + break; + default: + try { + bRet = AnyConverter.toBoolean(value); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } + break; + } + } + return bRet; + } + + public Date getDate() throws SQLException { + Date aValue = new Date(); + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.LONGVARCHAR: + aValue = DBTypeConversion.toDate(getString()); + break; + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.FLOAT: + case DataType.DOUBLE: + case DataType.REAL: + aValue = DBTypeConversion.toDate(getDouble()); + break; + case DataType.DATE: + Date date = (Date)value; + aValue.Day = date.Day; + aValue.Month = date.Month; + aValue.Year = date.Year; + break; + case DataType.TIMESTAMP: + DateTime dateTime = (DateTime)value; + aValue.Day = dateTime.Day; + aValue.Month = dateTime.Month; + aValue.Year = dateTime.Year; + break; + case DataType.BIT: + case DataType.BOOLEAN: + case DataType.TINYINT: + case DataType.SMALLINT: + case DataType.INTEGER: + case DataType.BIGINT: + aValue = DBTypeConversion.toDate((double)getLong()); + break; + + case DataType.BLOB: + case DataType.CLOB: + case DataType.OBJECT: + default: + //OSL_ENSURE( false, "ORowSetValue::getDate: cannot retrieve the data!" ); + // NO break! + + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + case DataType.TIME: + aValue = DBTypeConversion.toDate(0.0); + break; + } + } + return aValue; + + } + + public DateTime getDateTime() throws SQLException { + DateTime aValue = new DateTime(); + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.LONGVARCHAR: + aValue = DBTypeConversion.toDateTime(getString()); + break; + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.FLOAT: + case DataType.DOUBLE: + case DataType.REAL: + aValue = DBTypeConversion.toDateTime(getDouble()); + break; + case DataType.DATE: + Date date = (Date)value; + aValue.Day = date.Day; + aValue.Month = date.Month; + aValue.Year = date.Year; + break; + case DataType.TIME: + Time time = (Time)value; + aValue.HundredthSeconds = time.HundredthSeconds; + aValue.Seconds = time.Seconds; + aValue.Minutes = time.Minutes; + aValue.Hours = time.Hours; + break; + case DataType.TIMESTAMP: + DateTime dateTime = (DateTime)value; + aValue.Year = dateTime.Year; + aValue.Month = dateTime.Month; + aValue.Day = dateTime.Day; + aValue.Hours = dateTime.Hours; + aValue.Minutes = dateTime.Minutes; + aValue.Seconds = dateTime.Seconds; + aValue.HundredthSeconds = dateTime.HundredthSeconds; + break; + default: + try { + DateTime any = AnyConverter.toObject(DateTime.class, value); + aValue.Year = any.Year; + aValue.Month = any.Month; + aValue.Day = any.Day; + aValue.Hours = any.Hours; + aValue.Minutes = any.Minutes; + aValue.Seconds = any.Seconds; + aValue.HundredthSeconds = any.HundredthSeconds; + } catch (com.sun.star.lang.IllegalArgumentException e) { + } catch (ClassCastException classCastException) { + } + break; + } + } + return aValue; + } + + public double getDouble() { + double nRet = 0.0; + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + nRet = DBTypeConversion.safeParseDouble((String)value); + break; + case DataType.BIGINT: + nRet = isSigned() ? (long)value : DBTypeConversion.unsignedLongToDouble((long)value); + break; + case DataType.FLOAT: + nRet = (float)value; + break; + case DataType.DOUBLE: + case DataType.REAL: + nRet = (double)value; + break; + case DataType.DATE: + nRet = DBTypeConversion.toDouble((Date)value); + break; + case DataType.TIME: + nRet = DBTypeConversion.toDouble((Time)value); + break; + case DataType.TIMESTAMP: + nRet = DBTypeConversion.toDouble((DateTime)value); + break; + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + case DataType.BLOB: + case DataType.CLOB: + //OSL_ASSERT(!"getDouble() for this type is not allowed!"); + break; + case DataType.BIT: + case DataType.BOOLEAN: + nRet = (boolean)value ? 1 : 0; + break; + case DataType.TINYINT: + nRet = isSigned() ? (byte)value : 0xff & (byte)value; + break; + case DataType.SMALLINT: + nRet = isSigned() ? (short)value : 0xffff & (short)value; + break; + case DataType.INTEGER: + nRet = isSigned() ? (int)value : 0xffffFFFFL & (int)value; + break; + default: + try { + nRet = AnyConverter.toDouble(value); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } + break; + } + } + return nRet; + } + + public float getFloat() { + float nRet = 0.0f; + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + nRet = DBTypeConversion.safeParseFloat((String)value); + break; + case DataType.BIGINT: + nRet = isSigned() ? (long)value : DBTypeConversion.unsignedLongToFloat((long)value); + break; + case DataType.FLOAT: + nRet = (float)value; + break; + case DataType.DOUBLE: + case DataType.REAL: + nRet = (float)(double)value; + break; + case DataType.DATE: + nRet = (float)DBTypeConversion.toDouble((Date)value); + break; + case DataType.TIME: + nRet = (float)DBTypeConversion.toDouble((Time)value); + break; + case DataType.TIMESTAMP: + nRet = (float)DBTypeConversion.toDouble((DateTime)value); + break; + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + case DataType.BLOB: + case DataType.CLOB: + //OSL_ASSERT(!"getDouble() for this type is not allowed!"); + break; + case DataType.BIT: + case DataType.BOOLEAN: + nRet = (boolean)value ? 1 : 0; + break; + case DataType.TINYINT: + nRet = isSigned() ? (byte)value : 0xff & (byte)value; + break; + case DataType.SMALLINT: + nRet = isSigned() ? (short)value : 0xffff & (short)value; + break; + case DataType.INTEGER: + nRet = isSigned() ? (int)value : 0xffffFFFFL & (int)value; + break; + default: + try { + nRet = AnyConverter.toFloat(value); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } + break; + } + } + return nRet; + } + + public byte getInt8() { + byte nRet = 0; + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + nRet = (byte)DBTypeConversion.safeParseInt((String)value); + break; + case DataType.BIGINT: + nRet = (byte)(long)value; + break; + case DataType.FLOAT: + nRet = (byte)(float)value; + break; + case DataType.DOUBLE: + case DataType.REAL: + nRet = (byte)(double)value; + break; + case DataType.DATE: + case DataType.TIME: + case DataType.TIMESTAMP: + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + case DataType.BLOB: + case DataType.CLOB: + break; + case DataType.BIT: + case DataType.BOOLEAN: + nRet = (byte)((boolean)value ? 1 : 0); + break; + case DataType.TINYINT: + nRet = (byte)value; + break; + case DataType.SMALLINT: + nRet = (byte)(short)value; + break; + case DataType.INTEGER: + nRet = (byte)(int)value; + break; + default: + try { + nRet = AnyConverter.toByte(value); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } + break; + } + } + return nRet; + } + + public short getInt16() { + short nRet = 0; + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + nRet = (short)DBTypeConversion.safeParseInt((String)value); + break; + case DataType.BIGINT: + nRet = (short)(long)value; + break; + case DataType.FLOAT: + nRet = (short)(float)value; + break; + case DataType.DOUBLE: + case DataType.REAL: + nRet = (short)(double)value; + break; + case DataType.DATE: + case DataType.TIME: + case DataType.TIMESTAMP: + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + case DataType.BLOB: + case DataType.CLOB: + break; + case DataType.BIT: + case DataType.BOOLEAN: + nRet = (short)((boolean)value ? 1 : 0); + break; + case DataType.TINYINT: + nRet = (short)(isSigned() ? (byte)value : 0xff & (byte)value); + break; + case DataType.SMALLINT: + nRet = (short)value; + break; + case DataType.INTEGER: + nRet = (short)(int)value; + break; + default: + try { + nRet = AnyConverter.toShort(value); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } + break; + } + } + return nRet; + } + + public int getInt32() { + int nRet = 0; + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + nRet = DBTypeConversion.safeParseInt((String)value); + break; + case DataType.BIGINT: + nRet = (int)(long)value; + break; + case DataType.FLOAT: + nRet = (int)(float)value; + break; + case DataType.DOUBLE: + case DataType.REAL: + nRet = (int)(double)value; + break; + case DataType.DATE: + nRet = DBTypeConversion.toDays((Date)value); + break; + case DataType.TIME: + case DataType.TIMESTAMP: + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + case DataType.BLOB: + case DataType.CLOB: + break; + case DataType.BIT: + case DataType.BOOLEAN: + nRet = (boolean)value ? 1 : 0; + break; + case DataType.TINYINT: + nRet = isSigned() ? (byte)value : 0xff & (byte)value; + break; + case DataType.SMALLINT: + nRet = isSigned() ? (short)value : 0xffff & (short)value; + break; + case DataType.INTEGER: + nRet = (int)value; + break; + default: + try { + nRet = AnyConverter.toInt(value); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } + break; + } + } + return nRet; + } + + public long getLong() { + long nRet = 0; + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + nRet = DBTypeConversion.safeParseLong((String)value); + break; + case DataType.BIGINT: + nRet = (long)value; + break; + case DataType.FLOAT: + nRet = (long)(float)value; + break; + case DataType.DOUBLE: + case DataType.REAL: + nRet = (long)(double)value; + break; + case DataType.DATE: + nRet = DBTypeConversion.toDays((Date)value); + break; + case DataType.TIME: + case DataType.TIMESTAMP: + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + case DataType.BLOB: + case DataType.CLOB: + break; + case DataType.BIT: + case DataType.BOOLEAN: + nRet = (boolean)value ? 1 : 0; + break; + case DataType.TINYINT: + nRet = isSigned() ? (byte)value : 0xff & (byte)value; + break; + case DataType.SMALLINT: + nRet = isSigned() ? (short)value : 0xffff & (short)value; + break; + case DataType.INTEGER: + nRet = isSigned() ? (int)value : 0xffffFFFFL & (int)value; + break; + default: + try { + nRet = AnyConverter.toInt(value); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } + break; + } + } + return nRet; + } + + public byte[] getSequence() throws SQLException { + byte[] aSeq = new byte[0]; + if (!isNull()) { + switch (getTypeKind()) { + case DataType.OBJECT: + case DataType.CLOB: + case DataType.BLOB: + XInputStream xStream = null; + if (value != null) { + XBlob blob = UnoRuntime.queryInterface(XBlob.class, value); + if (blob != null) { + xStream = blob.getBinaryStream(); + } else { + XClob clob = UnoRuntime.queryInterface(XClob.class, value); + if (clob != null) { + xStream = clob.getCharacterStream(); + } + } + if (xStream != null) { + try { + try { + final int bytesToRead = 65535; + byte[][] aReadSeq = new byte[1][]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int read; + do { + read = xStream.readBytes(aReadSeq, bytesToRead); + baos.write(aReadSeq[0], 0, read); + } while (read == bytesToRead); + aSeq = baos.toByteArray(); + } finally { + xStream.closeInput(); + } + } catch (IOException ioException) { + throw new SQLException(ioException.getMessage()); + } + } + } + break; + case DataType.VARCHAR: + case DataType.LONGVARCHAR: + try { + aSeq = ((String)value).getBytes("UTF-16"); + } catch (UnsupportedEncodingException unsupportedEncodingException) { + } + break; + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + aSeq = ((byte[])value).clone(); + break; + default: + try { + aSeq = ((byte[])AnyConverter.toArray(value)).clone(); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } catch (ClassCastException classCastException) { + } + break; + } + } + return aSeq; + } + + public String getString() throws SQLException { + String aRet = ""; + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + aRet = (String)value; + break; + case DataType.BIGINT: + aRet = isSigned() ? Long.toString((long)value) : Long.toUnsignedString((long)value); + break; + case DataType.FLOAT: + aRet = ((Float)value).toString(); + break; + case DataType.DOUBLE: + case DataType.REAL: + aRet = ((Double)value).toString(); + break; + case DataType.DATE: + aRet = DBTypeConversion.toDateString((Date)value); + break; + case DataType.TIME: + aRet = DBTypeConversion.toTimeString((Time)value); + break; + case DataType.TIMESTAMP: + aRet = DBTypeConversion.toDateTimeString((DateTime)value); + break; + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + { + StringBuilder sVal = new StringBuilder("0x"); + byte[] sSeq = getSequence(); + for (byte b : sSeq) { + sVal.append(String.format("%02x", Byte.toUnsignedInt(b))); + } + aRet = sVal.toString(); + } + break; + case DataType.BIT: + case DataType.BOOLEAN: + aRet = ((Boolean)value).toString(); + break; + case DataType.TINYINT: + aRet = isSigned() ? Integer.toString((byte)value) : Integer.toUnsignedString(0xff & (byte)value); + break; + case DataType.SMALLINT: + aRet = isSigned() ? Integer.toString((short)value) : Integer.toUnsignedString(0xffff & (short)value); + break; + case DataType.INTEGER: + aRet = isSigned() ? Integer.toString((int)value) : Integer.toUnsignedString((int)value); + break; + case DataType.CLOB: + if (AnyConverter.isObject(value)) { + try { + XClob clob = AnyConverter.toObject(XClob.class, value); + if (clob != null) { + aRet = clob.getSubString(1, (int)clob.length()); + } + } catch (ClassCastException classCastException) { + } catch (com.sun.star.lang.IllegalArgumentException e) { + } + } + break; + default: + try { + aRet = AnyConverter.toString(value); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } + break; + } + } + return aRet; + } + + public Time getTime() throws SQLException { + Time aValue = new Time(); + if (!isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.LONGVARCHAR: + aValue = DBTypeConversion.toTime(getString()); + break; + case DataType.DECIMAL: + case DataType.NUMERIC: + aValue = DBTypeConversion.toTime(getDouble()); + break; + case DataType.FLOAT: + case DataType.DOUBLE: + case DataType.REAL: + aValue = DBTypeConversion.toTime(getDouble()); + break; + case DataType.TIMESTAMP: + DateTime pDateTime = (DateTime)value; + aValue.HundredthSeconds = pDateTime.HundredthSeconds; + aValue.Seconds = pDateTime.Seconds; + aValue.Minutes = pDateTime.Minutes; + aValue.Hours = pDateTime.Hours; + break; + case DataType.TIME: + Time time = (Time)value; + aValue.Hours = time.Hours; + aValue.Minutes = time.Minutes; + aValue.Seconds = time.Seconds; + aValue.HundredthSeconds = time.HundredthSeconds; + break; + default: + try { + aValue = AnyConverter.toObject(Time.class, value); + } catch (com.sun.star.lang.IllegalArgumentException e) { + } catch (ClassCastException classCastException) { + } + break; + } + } + return aValue; + } + + public void setAny(Any value) { + flags &= ~FLAG_NULL; + this.value = new Any(value.getType(), value.getObject()); + typeKind = DataType.OBJECT; + } + + public void setBoolean(boolean value) { + flags &= ~FLAG_NULL; + this.value = value; + typeKind = DataType.BIT; + } + + public void setDate(Date date) { + flags &= ~FLAG_NULL; + this.value = new Date(date.Day, date.Month, date.Year); + typeKind = DataType.DATE; + } + + public void setDateTime(DateTime value) { + flags &= ~FLAG_NULL; + this.value = new DateTime(value.HundredthSeconds, value.Seconds, value.Minutes, value.Hours, + value.Day, value.Minutes, value.Year); + typeKind = DataType.TIMESTAMP; + } + + public void setDouble(double value) { + flags &= ~FLAG_NULL; + this.value = value; + typeKind = DataType.DOUBLE; + } + + public void setFloat(float value) { + flags &= ~FLAG_NULL; + this.value = value; + typeKind = DataType.FLOAT; + } + + public void setInt8(byte value) { + flags &= ~FLAG_NULL; + this.value = value; + typeKind = DataType.TINYINT; + } + + public void setInt16(short value) { + flags &= ~FLAG_NULL; + this.value = value; + typeKind = DataType.SMALLINT; + } + + public void setInt32(int value) { + flags &= ~FLAG_NULL; + this.value = value; + typeKind = DataType.INTEGER; + } + + public void setLong(long value) { + flags &= ~FLAG_NULL; + this.value = value; + typeKind = DataType.BIGINT; + } + + public void setSequence(byte[] value) { + flags &= ~FLAG_NULL; + this.value = value.clone(); + typeKind = DataType.LONGVARBINARY; + } + + public void setString(String value) { + flags &= ~FLAG_NULL; + this.value = value; + typeKind = DataType.VARCHAR; + } + + public void setTime(Time value) { + flags &= ~FLAG_NULL; + this.value = new Time(value.Hours, value.Minutes, value.Seconds, value.HundredthSeconds); + typeKind = DataType.TIME; + } + + public Object makeAny() { + Object rValue = new Any(Type.VOID, null); + if(isBound() && !isNull()) { + switch (getTypeKind()) { + case DataType.CHAR: + case DataType.VARCHAR: + case DataType.DECIMAL: + case DataType.NUMERIC: + case DataType.LONGVARCHAR: + rValue = value; + break; + case DataType.BIGINT: + rValue = value; + break; + case DataType.FLOAT: + rValue = value; + break; + case DataType.DOUBLE: + case DataType.REAL: + rValue = value; + break; + case DataType.DATE: + Date date = (Date)value; + Date dateOut = new Date(); + dateOut.Day = date.Day; + dateOut.Month = date.Month; + dateOut.Year = date.Year; + rValue = dateOut; + break; + case DataType.TIME: + Time time = (Time)value; + Time timeOut = new Time(); + timeOut.Hours = time.Hours; + timeOut.Minutes = time.Minutes; + timeOut.Seconds = time.Seconds; + timeOut.HundredthSeconds = time.HundredthSeconds; + rValue = timeOut; + break; + case DataType.TIMESTAMP: + DateTime dateTime = (DateTime)value; + DateTime dateTimeOut = new DateTime(dateTime.HundredthSeconds, dateTime.Seconds, dateTime.Minutes, dateTime.Hours, + dateTime.Day, dateTime.Minutes, dateTime.Year); + rValue = dateTimeOut; + break; + case DataType.BINARY: + case DataType.VARBINARY: + case DataType.LONGVARBINARY: + rValue = ((byte[])value).clone(); + break; + case DataType.BLOB: + case DataType.CLOB: + case DataType.OBJECT: + case DataType.OTHER: + rValue = getAny(); + break; + case DataType.BIT: + case DataType.BOOLEAN: + rValue = (boolean)value; + break; + case DataType.TINYINT: + rValue = (byte)value; + break; + case DataType.SMALLINT: + rValue = (short)value; + break; + case DataType.INTEGER: + rValue = (int)value; + break; + default: + rValue = getAny(); + break; + } + } + return rValue; + } +} + diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/Osl.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/Osl.java new file mode 100644 index 000000000000..8ace907d77e0 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/Osl.java @@ -0,0 +1,36 @@ +/************************************************************** + * + * 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.util; + +public class Osl { + public static void ensure(boolean condition, String message) { + if (!condition) { + throw new com.sun.star.uno.RuntimeException(message); + } + } + + public static void ensure(Object reference, String message) { + if (reference == null) { + throw new com.sun.star.uno.RuntimeException(message); + } + } +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/PropertyIds.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/PropertyIds.java new file mode 100644 index 000000000000..0e59e0d9b8d4 --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/PropertyIds.java @@ -0,0 +1,95 @@ +/************************************************************** + * + * 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.util; + +public enum PropertyIds { + QUERYTIMEOUT(1, "QueryTimeOut"), + MAXFIELDSIZE(2, "MaxFieldSize"), + MAXROWS(3, "MaxRows"), + CURSORNAME(4, "CursorName"), + RESULTSETCONCURRENCY(5, "ResultSetConcurrency"), + RESULTSETTYPE(6, "ResultSetType"), + FETCHDIRECTION(7, "FetchDirection"), + FETCHSIZE(8, "FetchSize"), + ESCAPEPROCESSING(9, "EscapeProcessing"), + USEBOOKMARKS (10, "UseBookmarks"), + // Column + NAME (11, "Name"), + TYPE (12, "Type"), + TYPENAME (13, "TypeName"), + PRECISION (14, "Precision"), + SCALE (15, "Scale"), + ISNULLABLE (16, "IsNullable"), + ISAUTOINCREMENT (17, "IsAutoIncrement"), + ISROWVERSION (18, "IsRowVersion"), + DESCRIPTION (19, "Description"), + DEFAULTVALUE (20, "DefaultValue"), + REFERENCEDTABLE (21, "ReferencedTable"), + UPDATERULE (22, "UpdateRule"), + DELETERULE (23, "DeleteRule"), + CATALOG (24, "Catalog"), + ISUNIQUE (25, "IsUnique"), + ISPRIMARYKEYINDEX (26, "IsPrimaryKeyIndex"), + ISCLUSTERED (27, "IsClustered"), + ISASCENDING (28, "IsAscending"), + SCHEMANAME (29, "SchemaName"), + CATALOGNAME (30, "CatalogName"), + COMMAND (31, "CheckOption"), + CHECKOPTION (32, "Password"), + PASSWORD (33, "RelatedColumn"), + RELATEDCOLUMN (34, ""), + FUNCTION (35, "Function"), + TABLENAME (36, "TableName"), + REALNAME (37, "RealName"), + DBASEPRECISIONCHANGED (38, "DbasePrecisionChanged"), + ISCURRENCY (39, "IsCurrency"), + ISBOOKMARKABLE (40, "IsBookmarkable"), + INVALID_INDEX (41, ""), + HY010 (43, "HY010"), + LABEL (44, "Label"), + DELIMITER (45, "/"), + FORMATKEY (46, "FormatKey"), + LOCALE (47, "Locale"), + IM001 (48, ""), + AUTOINCREMENTCREATION (49, "AutoIncrementCreation"), + PRIVILEGES (50, "Privileges"), + HAVINGCLAUSE (51, "HavingClause"), + ISSIGNED (52, "IsSigned"), + AGGREGATEFUNCTION (53, "AggregateFunction"), + ISSEARCHABLE (54, "IsSearchable"), + APPLYFILTER (55, "ApplyFilter"), + FILTER (56, "Filter"), + MASTERFIELDS (57, "MasterFields"), + DETAILFIELDS (58, "DetailFields"), + FIELDTYPE (59, "FieldType"), + VALUE (60, "Value"), + ACTIVE_CONNECTION (61, "ActiveConnection"); + + + PropertyIds(int id, String name) { + this.id = id; + this.name = name; + } + + public final int id; + public final String name; +} diff --git a/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/StandardSQLState.java b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/StandardSQLState.java new file mode 100644 index 000000000000..3d6990f4ad6a --- /dev/null +++ b/connectivity/java/sdbc_postgresql/src/com/sun/star/sdbcx/comp/postgresql/util/StandardSQLState.java @@ -0,0 +1,58 @@ +/************************************************************** + * + * 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.util; + +public enum StandardSQLState { + SQL_WRONG_PARAMETER_NUMBER("07001"), + SQL_INVALID_DESCRIPTOR_INDEX("07009"), + SQL_UNABLE_TO_CONNECT("08001"), + SQL_NUMERIC_OUT_OF_RANGE("22003"), + SQL_INVALID_DATE_TIME("22007"), + SQL_INVALID_CURSOR_STATE("24000"), + SQL_TABLE_OR_VIEW_EXISTS("42S01"), + SQL_TABLE_OR_VIEW_NOT_FOUND("42S02"), + SQL_INDEX_EXISTS("42S11"), + SQL_INDEX_NOT_FOUND("42S12"), + SQL_COLUMN_EXISTS("42S21"), + SQL_COLUMN_NOT_FOUND("42S22"), + SQL_GENERAL_ERROR("HY000"), + SQL_INVALID_SQL_DATA_TYPE("HY004"), + SQL_OPERATION_CANCELED("HY008"), + SQL_FUNCTION_SEQUENCE_ERROR("HY010"), + SQL_INVALID_CURSOR_POSITION("HY109"), + SQL_INVALID_BOOKMARK_VALUE("HY111"), + SQL_FEATURE_NOT_IMPLEMENTED("HYC00"), + SQL_FUNCTION_NOT_SUPPORTED("IM001"), + SQL_CONNECTION_DOES_NOT_EXIST("08003"), + SQL_ERROR_UNSPECIFIED(""); + + + private String text; + + private StandardSQLState(String text) { + this.text = text; + } + + public String text() { + return text; + } +} diff --git a/connectivity/prj/build.lst b/connectivity/prj/build.lst index a16d486d3358..249cf339c84a 100644 --- a/connectivity/prj/build.lst +++ b/connectivity/prj/build.lst @@ -1,7 +1,8 @@ -cn connectivity : shell L10N:l10n comphelper SO:moz_prebuilt svl UNIXODBC:unixODBC unoil javaunohelper HSQLDB:hsqldb qadevOOo officecfg LIBXSLT:libxslt NULL +cn connectivity : shell L10N:l10n comphelper SO:moz_prebuilt svl UNIXODBC:unixODBC unoil javaunohelper HSQLDB:hsqldb qadevOOo officecfg LIBXSLT:libxslt apache-commons NULL cn connectivity usr1 - all cn_mkout NULL cn connectivity\inc nmake - all cn_inc NULL cn connectivity\java\sdbc_hsqldb nmake - all cn_jhsqldbdb cn_hsqldb cn_inc NULL +cn connectivity\java\sdbc_postgresql nmake - all cn_postgresqldb cn_dbtools cn_inc NULL cn connectivity\source\commontools nmake - all cn_cmtools cn_parse cn_inc NULL cn connectivity\source\manager nmake - all cn_manager cn_dbtools cn_inc NULL cn connectivity\source\cpool nmake - all cn_cpool cn_dbtools cn_inc NULL diff --git a/connectivity/prj/d.lst b/connectivity/prj/d.lst index 394bba416eba..5fa4e80ab4a6 100644 --- a/connectivity/prj/d.lst +++ b/connectivity/prj/d.lst @@ -21,6 +21,7 @@ ..\source\drivers\mysql\*.xml %_DEST%\xml%_EXT%\*.xml ..\%__SRC%\class\*.jar %_DEST%\bin%_EXT%\*.jar ..\%__SRC%\class\sdbc_hsqldb\*.jar %_DEST%\bin%_EXT%\*.jar +..\%__SRC%\class\sdbc_postgresql\*.jar %_DEST%\bin%_EXT%\*.jar mkdir: %_DEST%\inc%_EXT%\connectivity mkdir: %_DEST%\inc%_EXT%\connectivity\sdbcx @@ -46,4 +47,5 @@ mkdir: %_DEST%\xml%_EXT%\registry\spool\DataAccess ..\%__SRC%\misc\macab1.component %_DEST%\xml%_EXT%\macab1.component ..\%__SRC%\misc\mysql.component %_DEST%\xml%_EXT%\mysql.component ..\%__SRC%\misc\odbc.component %_DEST%\xml%_EXT%\odbc.component +..\%__SRC%\misc\postgresql.component %_DEST%\xml%_EXT%\postgresql.component ..\%__SRC%\misc\sdbc2.component %_DEST%\xml%_EXT%\sdbc2.component diff --git a/connectivity/target.pmk b/connectivity/target.pmk index 9bb63cc914a9..50e5b639d273 100644 --- a/connectivity/target.pmk +++ b/connectivity/target.pmk @@ -21,7 +21,8 @@ -.INCLUDE : target.mk +#.INCLUDE : target.mk +.INCLUDE : ant.mk COMPONENT_CONFIG_SCHEMA*=$(TARGET).xcs |