Branch data 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 : : }
|