1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3  *
4  *  Effective License of whole file:
5  *
6  *    This library is free software; you can redistribute it and/or
7  *    modify it under the terms of the GNU Lesser General Public
8  *    License version 2.1, as published by the Free Software Foundation.
9  *
10  *    This library is distributed in the hope that it will be useful,
11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *    Lesser General Public License for more details.
14  *
15  *    You should have received a copy of the GNU Lesser General Public
16  *    License along with this library; if not, write to the Free Software
17  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18  *    MA  02111-1307  USA
19  *
20  *  Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
21  *
22  *    The Contents of this file are made available subject to the terms of
23  *    the GNU Lesser General Public License Version 2.1
24  *
25  *    Copyright: 2000 by Sun Microsystems, Inc.
26  *
27  *    Contributor(s): Joerg Budischewski
28  *
29  *  All parts contributed on or after August 2011:
30  *
31  *    This Source Code Form is subject to the terms of the Mozilla Public
32  *    License, v. 2.0. If a copy of the MPL was not distributed with this
33  *    file, You can obtain one at http://mozilla.org/MPL/2.0/.
34  *
35  ************************************************************************/
36 
37 #include <sal/log.hxx>
38 #include <rtl/ref.hxx>
39 #include <rtl/ustrbuf.hxx>
40 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
41 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
42 #include <com/sun/star/sdbc/SQLException.hpp>
43 #include <com/sun/star/sdbc/XRow.hpp>
44 #include <com/sun/star/sdbc/XParameters.hpp>
45 #include <cppuhelper/exc_hlp.hxx>
46 
47 #include "pq_xindexes.hxx"
48 #include "pq_xindex.hxx"
49 #include "pq_statics.hxx"
50 #include "pq_tools.hxx"
51 
52 using osl::MutexGuard;
53 
54 
55 using com::sun::star::beans::XPropertySet;
56 
57 using com::sun::star::uno::Any;
58 using com::sun::star::uno::makeAny;
59 using com::sun::star::uno::UNO_QUERY;
60 using com::sun::star::uno::Reference;
61 using com::sun::star::uno::Sequence;
62 
63 using com::sun::star::container::XEnumerationAccess;
64 using com::sun::star::container::XEnumeration;
65 
66 
67 using com::sun::star::sdbcx::XColumnsSupplier;
68 
69 using com::sun::star::sdbc::XRow;
70 using com::sun::star::sdbc::XResultSet;
71 using com::sun::star::sdbc::XParameters;
72 using com::sun::star::sdbc::XPreparedStatement;
73 
74 namespace pq_sdbc_driver
75 {
76 
Indexes(const::rtl::Reference<comphelper::RefCountedMutex> & refMutex,const css::uno::Reference<css::sdbc::XConnection> & origin,ConnectionSettings * pSettings,const OUString & schemaName,const OUString & tableName)77 Indexes::Indexes(
78         const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
79         const css::uno::Reference< css::sdbc::XConnection >  & origin,
80         ConnectionSettings *pSettings,
81         const OUString &schemaName,
82         const OUString &tableName)
83     : Container( refMutex, origin, pSettings,  getStatics().KEY ),
84       m_schemaName( schemaName ),
85       m_tableName( tableName )
86 {
87 }
88 
~Indexes()89 Indexes::~Indexes()
90 {}
91 
refresh()92 void Indexes::refresh()
93 {
94     try
95     {
96         SAL_INFO("connectivity.postgresql", "sdbcx.Indexes get refreshed for table " << m_schemaName << "." << m_tableName);
97 
98         osl::MutexGuard guard( m_xMutex->GetMutex() );
99         Statics & st = getStatics();
100 
101         Int2StringMap column2NameMap;
102         fillAttnum2attnameMap( column2NameMap, m_origin, m_schemaName, m_tableName );
103 
104         // see XDatabaseMetaData::getIndexInfo()
105         Reference< XPreparedStatement > stmt = m_origin->prepareStatement(
106                 "SELECT nspname, "      // 1
107                    "pg_class.relname, " // 2
108                    "class2.relname, "   // 3
109                    "indisclustered, "   // 4
110                    "indisunique, "      // 5
111                    "indisprimary, "     // 6
112                    "indkey "            // 7
113                 "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid "
114                     "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
115                     "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid "
116                 "WHERE nspname = ? AND pg_class.relname = ?" );
117 
118         Reference< XParameters > params( stmt, UNO_QUERY);
119         params->setString( 1, m_schemaName );
120         params->setString( 2, m_tableName );
121         Reference< XResultSet > rs = stmt->executeQuery();
122 
123         Reference< XRow > row( rs, UNO_QUERY );
124         String2IntMap map;
125         m_values.clear();
126         sal_Int32 index = 0;
127         while( rs->next() )
128         {
129             // C_SCHEMA = 1
130             // C_TABLENAME = 2
131             static const sal_Int32 C_INDEXNAME = 3;
132             static const sal_Int32 C_IS_CLUSTERED = 4;
133             static const sal_Int32 C_IS_UNIQUE = 5;
134             static const sal_Int32 C_IS_PRIMARY = 6;
135             static const sal_Int32 C_COLUMNS = 7;
136             OUString currentIndexName = row->getString( C_INDEXNAME );
137             rtl::Reference<Index> pIndex =
138                 new Index( m_xMutex, m_origin, m_pSettings,
139                            m_schemaName, m_tableName );
140 
141             bool isUnique = row->getBoolean( C_IS_UNIQUE );
142             bool isPrimary = row->getBoolean( C_IS_PRIMARY );
143             bool isClusterd = row->getBoolean( C_IS_CLUSTERED );
144             Reference< css::beans::XPropertySet > prop = pIndex;
145             pIndex->setPropertyValue_NoBroadcast_public(
146                 st.IS_UNIQUE, Any( isUnique ) );
147             pIndex->setPropertyValue_NoBroadcast_public(
148                 st.IS_PRIMARY_KEY_INDEX, Any( isPrimary ) );
149             pIndex->setPropertyValue_NoBroadcast_public(
150                 st.IS_CLUSTERED, Any( isClusterd ) );
151             pIndex->setPropertyValue_NoBroadcast_public(
152                 st.NAME, makeAny( currentIndexName ) );
153 
154             std::vector< sal_Int32 > seq = parseIntArray( row->getString( C_COLUMNS ) );
155             Sequence< OUString > columnNames(seq.size());
156             for( size_t columns = 0 ; columns < seq.size() ; columns ++ )
157             {
158                 columnNames[columns] = column2NameMap[ seq[columns] ];
159             }
160 
161             pIndex->setPropertyValue_NoBroadcast_public(
162                 st.PRIVATE_COLUMN_INDEXES, makeAny( columnNames ));
163 
164             {
165                 m_values.push_back( makeAny( prop ) );
166                 map[ currentIndexName ] = index;
167                 ++index;
168             }
169         }
170         m_name2index.swap( map );
171     }
172     catch ( css::sdbc::SQLException & e )
173     {
174         css::uno::Any anyEx = cppu::getCaughtException();
175         throw css::lang::WrappedTargetRuntimeException( e.Message,
176                         e.Context, anyEx );
177     }
178 
179     fire( RefreshedBroadcaster( *this ) );
180 }
181 
182 
appendByDescriptor(const css::uno::Reference<css::beans::XPropertySet> & descriptor)183 void Indexes::appendByDescriptor(
184     const css::uno::Reference< css::beans::XPropertySet >& descriptor )
185 {
186     Statics & st = getStatics();
187     OUString name = extractStringProperty( descriptor, st.NAME );
188 
189     bool isUnique = extractBoolProperty( descriptor, st.IS_UNIQUE );
190 
191     OUStringBuffer buf( 128 );
192 
193     buf.append( "CREATE " );
194     if( isUnique )
195         buf.append( "UNIQUE " );
196     buf.append( "INDEX " );
197     bufferQuoteIdentifier( buf, name, m_pSettings );
198     buf.append( " ON " );
199     bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings );
200 
201     buf.append( " ( " );
202 
203     Reference< XColumnsSupplier > columns( descriptor, UNO_QUERY );
204     if( columns.is() )
205     {
206         Reference< XEnumerationAccess > access( columns->getColumns(), UNO_QUERY );
207         if( access.is() )
208         {
209             Reference< XEnumeration > xEnum( access->createEnumeration() );
210             bool first = true;
211             while( xEnum.is() && xEnum->hasMoreElements() )
212             {
213                 Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY );
214                 if( first )
215                 {
216                     first = false;
217                 }
218                 else
219                 {
220                     buf.append( ", " );
221                 }
222                 buf.append( extractStringProperty( column, st.NAME ) );
223             }
224         }
225     }
226     buf.append( " ) " );
227 
228     m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() );
229     refresh();
230 }
231 
dropByIndex(sal_Int32 index)232 void Indexes::dropByIndex( sal_Int32 index )
233 {
234 
235 
236     osl::MutexGuard guard( m_xMutex->GetMutex() );
237     if( index < 0 ||  index >= static_cast<sal_Int32>(m_values.size()) )
238     {
239         throw css::lang::IndexOutOfBoundsException(
240             "Indexes: Index out of range (allowed 0 to "
241             + OUString::number( m_values.size() -1 )
242             + ", got " + OUString::number( index )
243             + ")",
244             *this );
245     }
246 
247     Reference< XPropertySet > set;
248     m_values[index] >>= set;
249     Statics &st = getStatics();
250 
251     OUStringBuffer buf( 128 );
252     buf.append( "DROP INDEX " );
253     bufferQuoteIdentifier( buf, extractStringProperty( set, st.NAME ), m_pSettings );
254     m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() );
255 
256     Container::dropByIndex( index );
257 }
258 
259 
createDataDescriptor()260 css::uno::Reference< css::beans::XPropertySet > Indexes::createDataDescriptor()
261 {
262     return new IndexDescriptor( m_xMutex, m_origin, m_pSettings );
263 }
264 
create(const::rtl::Reference<comphelper::RefCountedMutex> & refMutex,const css::uno::Reference<css::sdbc::XConnection> & origin,ConnectionSettings * pSettings,const OUString & schemaName,const OUString & tableName)265 Reference< css::container::XNameAccess > Indexes::create(
266     const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
267     const css::uno::Reference< css::sdbc::XConnection >  & origin,
268     ConnectionSettings *pSettings,
269     const OUString & schemaName,
270     const OUString & tableName)
271 {
272     rtl::Reference<Indexes> pIndexes
273         = new Indexes( refMutex, origin, pSettings, schemaName, tableName );
274     pIndexes->refresh();
275     return pIndexes;
276 }
277 
278 
IndexDescriptors(const::rtl::Reference<comphelper::RefCountedMutex> & refMutex,const css::uno::Reference<css::sdbc::XConnection> & origin,ConnectionSettings * pSettings)279 IndexDescriptors::IndexDescriptors(
280         const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
281         const css::uno::Reference< css::sdbc::XConnection >  & origin,
282         ConnectionSettings *pSettings)
283     : Container( refMutex, origin, pSettings,  getStatics().INDEX )
284 {}
285 
create(const::rtl::Reference<comphelper::RefCountedMutex> & refMutex,const css::uno::Reference<css::sdbc::XConnection> & origin,ConnectionSettings * pSettings)286 Reference< css::container::XNameAccess > IndexDescriptors::create(
287     const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
288     const css::uno::Reference< css::sdbc::XConnection >  & origin,
289     ConnectionSettings *pSettings)
290 {
291     return new IndexDescriptors( refMutex, origin, pSettings );
292 }
293 
createDataDescriptor()294 css::uno::Reference< css::beans::XPropertySet > IndexDescriptors::createDataDescriptor()
295 {
296     return new IndexDescriptor( m_xMutex, m_origin, m_pSettings );
297 }
298 
299 };
300 
301 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
302