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