Line data Source code
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 <rtl/ustrbuf.hxx>
38 :
39 : #include "pq_resultsetmetadata.hxx"
40 : #include "pq_resultset.hxx"
41 : #include "pq_tools.hxx"
42 : #include "pq_statics.hxx"
43 :
44 : #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
45 : #include <com/sun/star/sdbc/ColumnValue.hpp>
46 : #include <com/sun/star/sdbc/XRow.hpp>
47 :
48 : #include <string.h>
49 :
50 : using osl::Mutex;
51 : using osl::MutexGuard;
52 :
53 :
54 : using com::sun::star::uno::Any;
55 : using com::sun::star::uno::RuntimeException;
56 : using com::sun::star::uno::Exception;
57 : using com::sun::star::uno::Reference;
58 : using com::sun::star::uno::XInterface;
59 : using com::sun::star::uno::UNO_QUERY;
60 :
61 : using com::sun::star::lang::IllegalArgumentException;
62 :
63 : using com::sun::star::sdbc::SQLException;
64 : using com::sun::star::sdbc::XStatement;
65 : using com::sun::star::sdbc::XRow;
66 : using com::sun::star::sdbc::XResultSet;
67 : using com::sun::star::sdbcx::XColumnsSupplier;
68 : using com::sun::star::sdbcx::XTablesSupplier;
69 :
70 : using com::sun::star::beans::XPropertySet;
71 : using com::sun::star::container::XNameAccess;
72 :
73 :
74 : namespace pq_sdbc_driver
75 : {
76 :
77 : // struct ColumnMetaData
78 : // {
79 : // OUString tableName;
80 : // OUString schemaTableName;
81 : // OUString typeName;
82 : // com::sun::star::sdbc::DataType type;
83 : // sal_Int32 precision;
84 : // sal_Int32 scale;
85 : // sal_Bool isCurrency;
86 : // sal_Bool isNullable;
87 : // sal_Bool isAutoIncrement;
88 : // sal_Bool isReadOnly;
89 : // sal_Bool isSigned;
90 : // };
91 :
92 : // is not exported by the postgres header
93 : const static int PQ_VARHDRSZ = sizeof( sal_Int32 );
94 :
95 0 : static void extractPrecisionAndScale( sal_Int32 atttypmod, sal_Int32 *precision, sal_Int32 *scale )
96 : {
97 0 : if( atttypmod < PQ_VARHDRSZ )
98 : {
99 0 : *precision = 0;
100 0 : *scale = 0;
101 : }
102 : else
103 : {
104 0 : if( atttypmod & 0xffff0000 )
105 : {
106 0 : *precision = ( ( atttypmod - PQ_VARHDRSZ ) >> 16 ) & 0xffff;
107 0 : *scale = (atttypmod - PQ_VARHDRSZ ) & 0xffff;
108 : }
109 : else
110 : {
111 0 : *precision = atttypmod - PQ_VARHDRSZ;
112 0 : *scale = 0;
113 : }
114 : }
115 0 : }
116 :
117 0 : ResultSetMetaData::ResultSetMetaData(
118 : const ::rtl::Reference< RefCountedMutex > & refMutex,
119 : const ::com::sun::star::uno::Reference< com::sun::star::sdbc::XResultSet > & origin,
120 : ResultSet * pResultSet,
121 : ConnectionSettings **ppSettings,
122 : PGresult *pResult,
123 : const OUString &schemaName,
124 : const OUString &tableName ) :
125 : m_refMutex( refMutex ),
126 : m_ppSettings( ppSettings ),
127 : m_origin( origin ),
128 : m_tableName( tableName ),
129 : m_schemaName( schemaName ),
130 0 : m_colDesc( PQnfields( pResult ) ),
131 : m_pResultSet( pResultSet ),
132 : m_checkedForTable( false ),
133 : m_checkedForTypes( false ),
134 0 : m_colCount( PQnfields( pResult ) )
135 : {
136 :
137 : // extract all needed information from the result object, so that we don't
138 : // need it anymore after this call !
139 0 : for( int col = 0; col < m_colCount ; col ++ )
140 : {
141 0 : sal_Int32 size = PQfsize( pResult, col );
142 0 : size = -1 == size ? 25 : size;
143 0 : m_colDesc[col].displaySize = size;
144 :
145 : extractPrecisionAndScale(
146 0 : PQfmod( pResult, col ),
147 0 : & ( m_colDesc[col].precision ),
148 0 : & ( m_colDesc[col].scale ) );
149 0 : char *name = PQfname( pResult, col );
150 0 : m_colDesc[col].name = OUString( name, strlen(name) , (*m_ppSettings)->encoding );
151 0 : m_colDesc[col].typeOid = PQftype( pResult, col );
152 0 : m_colDesc[col].type = com::sun::star::sdbc::DataType::LONGVARCHAR;
153 : }
154 0 : }
155 :
156 0 : void ResultSetMetaData::checkForTypes()
157 : {
158 0 : if( ! m_checkedForTypes )
159 : {
160 : Reference< XStatement > stmt =
161 0 : extractConnectionFromStatement( m_origin->getStatement() )->createStatement();
162 0 : DisposeGuard guard( stmt );
163 0 : OUStringBuffer buf(128);
164 0 : buf.appendAscii( "SELECT oid, typname, typtype FROM pg_type WHERE ");
165 0 : for( int i = 0 ; i < m_colCount ; i ++ )
166 : {
167 0 : if( i > 0 )
168 0 : buf.appendAscii( " OR " );
169 0 : int oid = m_colDesc[i].typeOid;
170 0 : buf.appendAscii( "oid=" );
171 0 : buf.append( (sal_Int32) oid, 10 );
172 : }
173 0 : Reference< XResultSet > rs = stmt->executeQuery( buf.makeStringAndClear() );
174 0 : Reference< XRow > xRow( rs, UNO_QUERY );
175 0 : while( rs->next() )
176 : {
177 0 : Oid oid = xRow->getInt( 1 );
178 0 : OUString typeName = xRow->getString( 2 );
179 0 : OUString typType = xRow->getString( 3 );
180 :
181 0 : sal_Int32 type = typeNameToDataType( typeName, typType );
182 :
183 0 : for( sal_Int32 j = 0; j < m_colCount ; j ++ )
184 : {
185 0 : if( m_colDesc[j].typeOid == oid )
186 : {
187 0 : m_colDesc[j].typeName = typeName;
188 0 : m_colDesc[j].type = type;
189 : }
190 : }
191 0 : }
192 0 : m_checkedForTypes = true;
193 : }
194 0 : }
195 :
196 0 : void ResultSetMetaData::checkTable()
197 : {
198 0 : if( ! m_checkedForTable )
199 : {
200 0 : m_checkedForTable = true;
201 0 : if( m_tableName.getLength() )
202 : {
203 :
204 0 : Reference< com::sun::star::container::XNameAccess > tables = (*m_ppSettings)->tables;
205 0 : if( ! tables.is() )
206 : {
207 :
208 : Reference< XTablesSupplier > supplier =
209 : Reference< XTablesSupplier > (
210 0 : extractConnectionFromStatement( m_origin->getStatement() ), UNO_QUERY);
211 0 : if( supplier.is() )
212 0 : tables = supplier->getTables();
213 : }
214 0 : if( tables.is() )
215 : {
216 0 : const OUString name (getTableName ( 1 ));
217 0 : const OUString schema (getSchemaName( 1 ));
218 0 : const OUString composedName( schema.isEmpty() ? name : (schema + "." + name) );
219 0 : tables->getByName( composedName ) >>= m_table;
220 0 : }
221 : }
222 : }
223 0 : }
224 :
225 0 : sal_Int32 ResultSetMetaData::getIntColumnProperty( const OUString & name, int index, int def )
226 : {
227 0 : sal_Int32 ret = def; // give defensive answers, when data is not available
228 : try
229 : {
230 0 : MutexGuard guard( m_refMutex->mutex );
231 0 : checkColumnIndex( index );
232 0 : Reference< XPropertySet > set = getColumnByIndex( index );
233 :
234 0 : if( set.is() )
235 : {
236 0 : set->getPropertyValue( name ) >>= ret;
237 0 : }
238 : }
239 0 : catch( com::sun::star::uno::Exception & )
240 : {
241 : }
242 0 : return ret;
243 : }
244 :
245 0 : sal_Bool ResultSetMetaData::getBoolColumnProperty( const OUString & name, int index, sal_Bool def )
246 : {
247 0 : sal_Bool ret = def;
248 : try
249 : {
250 0 : MutexGuard guard( m_refMutex->mutex );
251 0 : checkColumnIndex( index );
252 0 : Reference< XPropertySet > set = getColumnByIndex( index );
253 0 : if( set.is() )
254 : {
255 0 : set->getPropertyValue( name ) >>= ret;
256 0 : }
257 : }
258 0 : catch( com::sun::star::uno::Exception & )
259 : {
260 : }
261 :
262 0 : return ret;
263 : }
264 :
265 0 : Reference< com::sun::star::beans::XPropertySet > ResultSetMetaData::getColumnByIndex( int index )
266 : {
267 0 : Reference< XPropertySet > ret;
268 0 : checkTable();
269 0 : if( m_table.is() )
270 : {
271 0 : OUString columnName = getColumnName( index );
272 0 : Reference< XColumnsSupplier > supplier( m_table, UNO_QUERY );
273 0 : if( supplier.is() )
274 : {
275 0 : Reference< XNameAccess > columns = supplier->getColumns();
276 0 : if( columns.is() && columns->hasByName( columnName ) )
277 : {
278 0 : columns->getByName( columnName ) >>= ret;
279 0 : }
280 0 : }
281 : }
282 0 : return ret;
283 : }
284 :
285 : // Methods
286 0 : sal_Int32 ResultSetMetaData::getColumnCount( )
287 : throw (SQLException, RuntimeException, std::exception)
288 : {
289 0 : return m_colCount;
290 : }
291 :
292 0 : sal_Bool ResultSetMetaData::isAutoIncrement( sal_Int32 column )
293 : throw (SQLException, RuntimeException, std::exception)
294 : {
295 :
296 0 : sal_Bool ret = getBoolColumnProperty( getStatics().IS_AUTO_INCREMENT, column, sal_False );
297 0 : return ret;
298 : }
299 :
300 0 : sal_Bool ResultSetMetaData::isCaseSensitive( sal_Int32 column )
301 : throw (SQLException, RuntimeException, std::exception)
302 : {
303 : (void) column;
304 0 : return sal_True; // ??? hmm, numeric types or
305 : }
306 :
307 0 : sal_Bool ResultSetMetaData::isSearchable( sal_Int32 column ) throw (SQLException, RuntimeException, std::exception)
308 : {
309 : (void) column;
310 0 : return sal_True; // mmm, what types are not searchable ?
311 : }
312 :
313 0 : sal_Bool ResultSetMetaData::isCurrency( sal_Int32 column ) throw (SQLException, RuntimeException, std::exception)
314 : {
315 0 : return getBoolColumnProperty( getStatics().IS_CURRENCY, column, sal_False );
316 : }
317 :
318 0 : sal_Int32 ResultSetMetaData::isNullable( sal_Int32 column )
319 : throw (SQLException, RuntimeException, std::exception)
320 : {
321 : return getIntColumnProperty(
322 0 : getStatics().IS_NULLABLE, column, com::sun::star::sdbc::ColumnValue::NULLABLE_UNKNOWN );
323 : }
324 :
325 0 : sal_Bool ResultSetMetaData::isSigned( sal_Int32 column )
326 : throw (SQLException, RuntimeException, std::exception)
327 : {
328 : (void) column;
329 0 : return sal_True;
330 : }
331 :
332 0 : sal_Int32 ResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
333 : throw (SQLException, RuntimeException, std::exception)
334 : {
335 0 : MutexGuard guard( m_refMutex->mutex );
336 0 : checkClosed();
337 0 : checkColumnIndex( column );
338 0 : return m_colDesc[column-1].displaySize;
339 : }
340 :
341 0 : OUString ResultSetMetaData::getColumnLabel( sal_Int32 column )
342 : throw (SQLException, RuntimeException, std::exception)
343 : {
344 0 : return getColumnName( column);
345 : }
346 :
347 0 : OUString ResultSetMetaData::getColumnName( sal_Int32 column ) throw (SQLException, RuntimeException, std::exception)
348 : {
349 0 : MutexGuard guard( m_refMutex->mutex );
350 0 : checkClosed();
351 0 : checkColumnIndex( column );
352 :
353 0 : return m_colDesc[column-1].name;
354 : }
355 :
356 0 : OUString ResultSetMetaData::getSchemaName( sal_Int32 column ) throw (SQLException, RuntimeException, std::exception)
357 : {
358 : (void) column;
359 0 : return m_schemaName;
360 : }
361 :
362 0 : sal_Int32 ResultSetMetaData::getPrecision( sal_Int32 column )
363 : throw (SQLException, RuntimeException, std::exception)
364 : {
365 0 : MutexGuard guard( m_refMutex->mutex );
366 0 : checkClosed();
367 0 : checkColumnIndex( column );
368 0 : return m_colDesc[column-1].precision;
369 : }
370 :
371 0 : sal_Int32 ResultSetMetaData::getScale( sal_Int32 column )
372 : throw (SQLException, RuntimeException, std::exception)
373 : {
374 0 : MutexGuard guard( m_refMutex->mutex );
375 0 : checkClosed();
376 0 : checkColumnIndex( column );
377 0 : return m_colDesc[column-1].scale;
378 : }
379 :
380 0 : OUString ResultSetMetaData::getTableName( sal_Int32 column )
381 : throw (SQLException, RuntimeException, std::exception)
382 : {
383 : (void) column;
384 : // LEM TODO This is very fishy.. Should probably return the table to which that column belongs!
385 0 : return m_tableName;
386 : }
387 :
388 0 : OUString ResultSetMetaData::getCatalogName( sal_Int32 column )
389 : throw (SQLException, RuntimeException, std::exception)
390 : {
391 : (void) column;
392 : // can do this through XConnection.getCatalog() !
393 0 : return OUString();
394 : }
395 0 : sal_Int32 ResultSetMetaData::getColumnType( sal_Int32 column )
396 : throw (SQLException, RuntimeException, std::exception)
397 : {
398 0 : int ret = getIntColumnProperty( getStatics().TYPE, column, -100 );
399 0 : if( -100 == ret )
400 : {
401 0 : checkForTypes();
402 0 : if( com::sun::star::sdbc::DataType::LONGVARCHAR == m_colDesc[column-1].type && m_pResultSet )
403 0 : m_colDesc[column-1].type = m_pResultSet->guessDataType( column );
404 0 : ret = m_colDesc[column-1].type;
405 : }
406 0 : return ret;
407 : }
408 :
409 0 : OUString ResultSetMetaData::getColumnTypeName( sal_Int32 column )
410 : throw (SQLException, RuntimeException, std::exception)
411 : {
412 0 : OUString ret; // give defensive answers, when data is not available
413 : try
414 : {
415 0 : MutexGuard guard( m_refMutex->mutex );
416 0 : checkColumnIndex( column );
417 0 : Reference< XPropertySet > set = getColumnByIndex( column );
418 :
419 0 : if( set.is() )
420 : {
421 0 : set->getPropertyValue( getStatics().TYPE_NAME ) >>= ret;
422 : }
423 : else
424 : {
425 0 : checkForTypes();
426 0 : ret = m_colDesc[column-1].typeName;
427 0 : }
428 : }
429 0 : catch( com::sun::star::uno::Exception & )
430 : {
431 : }
432 0 : return ret;
433 : }
434 :
435 :
436 0 : sal_Bool ResultSetMetaData::isReadOnly( sal_Int32 column )
437 : throw (SQLException, RuntimeException, std::exception)
438 : {
439 : (void) column;
440 0 : return sal_False;
441 : }
442 :
443 0 : sal_Bool ResultSetMetaData::isWritable( sal_Int32 column )
444 : throw (SQLException, RuntimeException, std::exception)
445 : {
446 0 : return ! isReadOnly( column ); // what's the sense if this method ?
447 : }
448 :
449 0 : sal_Bool ResultSetMetaData::isDefinitelyWritable( sal_Int32 column )
450 : throw (SQLException, RuntimeException, std::exception)
451 : {
452 0 : return isWritable(column); // uhh, now it becomes really esoteric ....
453 : }
454 0 : OUString ResultSetMetaData::getColumnServiceName( sal_Int32 column )
455 : throw (SQLException, RuntimeException, std::exception)
456 : {
457 : (void) column;
458 0 : return OUString();
459 : }
460 :
461 0 : void ResultSetMetaData::checkClosed()
462 : throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
463 : {
464 : // we never close
465 0 : }
466 :
467 0 : void ResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex)
468 : throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
469 : {
470 0 : if( columnIndex < 1 || columnIndex > m_colCount )
471 : {
472 0 : OUStringBuffer buf(128);
473 :
474 0 : buf.appendAscii( "pq_resultsetmetadata: index out of range (expected 1 to " );
475 0 : buf.append( m_colCount );
476 0 : buf.appendAscii( ", got " );
477 0 : buf.append( columnIndex );
478 : throw SQLException(
479 0 : buf.makeStringAndClear(), *this, OUString(), 1, Any() );
480 : }
481 0 : }
482 :
483 : }
484 :
485 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|