1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * Effective License of whole file:
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.
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.
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,
20 * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
22 * The Contents of this file are made available subject to the terms of
23 * the GNU Lesser General Public License Version 2.1
25 * Copyright: 2000 by Sun Microsystems, Inc.
27 * Contributor(s): Joerg Budischewski
29 * All parts contributed on or after August 2011:
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/.
35 ************************************************************************/
37 #include <rtl/ustrbuf.hxx>
39 #include "pq_resultsetmetadata.hxx"
40 #include "pq_resultset.hxx"
41 #include "pq_tools.hxx"
42 #include "pq_statics.hxx"
44 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
45 #include <com/sun/star/sdbc/ColumnValue.hpp>
46 #include <com/sun/star/sdbc/XRow.hpp>
51 using osl::MutexGuard
;
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
;
61 using com::sun::star::lang::IllegalArgumentException
;
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
;
70 using com::sun::star::beans::XPropertySet
;
71 using com::sun::star::container::XNameAccess
;
74 namespace pq_sdbc_driver
77 // struct ColumnMetaData
79 // OUString tableName;
80 // OUString schemaTableName;
82 // com::sun::star::sdbc::DataType type;
83 // sal_Int32 precision;
85 // sal_Bool isCurrency;
86 // sal_Bool isNullable;
87 // sal_Bool isAutoIncrement;
88 // sal_Bool isReadOnly;
92 // is not exported by the postgres header
93 const static int PQ_VARHDRSZ
= sizeof( sal_Int32
);
95 static void extractPrecisionAndScale( sal_Int32 atttypmod
, sal_Int32
*precision
, sal_Int32
*scale
)
97 if( atttypmod
< PQ_VARHDRSZ
)
104 if( atttypmod
& 0xffff0000 )
106 *precision
= ( ( atttypmod
- PQ_VARHDRSZ
) >> 16 ) & 0xffff;
107 *scale
= (atttypmod
- PQ_VARHDRSZ
) & 0xffff;
111 *precision
= atttypmod
- PQ_VARHDRSZ
;
117 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
,
123 const OUString
&schemaName
,
124 const OUString
&tableName
) :
125 m_refMutex( refMutex
),
126 m_ppSettings( ppSettings
),
128 m_tableName( tableName
),
129 m_schemaName( schemaName
),
130 m_colDesc( PQnfields( pResult
) ),
131 m_pResultSet( pResultSet
),
132 m_checkedForTable( false ),
133 m_checkedForTypes( false ),
134 m_colCount( PQnfields( pResult
) )
137 // extract all needed information from the result object, so that we don't
138 // need it anymore after this call !
139 for( int col
= 0; col
< m_colCount
; col
++ )
141 sal_Int32 size
= PQfsize( pResult
, col
);
142 size
= -1 == size
? 25 : size
;
143 m_colDesc
[col
].displaySize
= size
;
145 extractPrecisionAndScale(
146 PQfmod( pResult
, col
),
147 & ( m_colDesc
[col
].precision
),
148 & ( m_colDesc
[col
].scale
) );
149 char *name
= PQfname( pResult
, col
);
150 m_colDesc
[col
].name
= OUString( name
, strlen(name
) , (*m_ppSettings
)->encoding
);
151 m_colDesc
[col
].typeOid
= PQftype( pResult
, col
);
152 m_colDesc
[col
].type
= com::sun::star::sdbc::DataType::LONGVARCHAR
;
156 void ResultSetMetaData::checkForTypes()
158 if( ! m_checkedForTypes
)
160 Reference
< XStatement
> stmt
=
161 extractConnectionFromStatement( m_origin
->getStatement() )->createStatement();
162 DisposeGuard
guard( stmt
);
163 OUStringBuffer
buf(128);
164 buf
.appendAscii( "SELECT oid, typname, typtype FROM pg_type WHERE ");
165 for( int i
= 0 ; i
< m_colCount
; i
++ )
168 buf
.appendAscii( " OR " );
169 int oid
= m_colDesc
[i
].typeOid
;
170 buf
.appendAscii( "oid=" );
171 buf
.append( (sal_Int32
) oid
, 10 );
173 Reference
< XResultSet
> rs
= stmt
->executeQuery( buf
.makeStringAndClear() );
174 Reference
< XRow
> xRow( rs
, UNO_QUERY
);
177 Oid oid
= xRow
->getInt( 1 );
178 OUString typeName
= xRow
->getString( 2 );
179 OUString typType
= xRow
->getString( 3 );
181 sal_Int32 type
= typeNameToDataType( typeName
, typType
);
183 for( sal_Int32 j
= 0; j
< m_colCount
; j
++ )
185 if( m_colDesc
[j
].typeOid
== oid
)
187 m_colDesc
[j
].typeName
= typeName
;
188 m_colDesc
[j
].type
= type
;
192 m_checkedForTypes
= true;
196 void ResultSetMetaData::checkTable()
198 if( ! m_checkedForTable
)
200 m_checkedForTable
= true;
201 if( m_tableName
.getLength() )
204 Reference
< com::sun::star::container::XNameAccess
> tables
= (*m_ppSettings
)->tables
;
208 Reference
< XTablesSupplier
> supplier
=
209 Reference
< XTablesSupplier
> (
210 extractConnectionFromStatement( m_origin
->getStatement() ), UNO_QUERY
);
212 tables
= supplier
->getTables();
216 const OUString
name (getTableName ( 1 ));
217 const OUString
schema (getSchemaName( 1 ));
218 const OUString
composedName( schema
.isEmpty() ? name
: (schema
+ "." + name
) );
219 tables
->getByName( composedName
) >>= m_table
;
225 sal_Int32
ResultSetMetaData::getIntColumnProperty( const OUString
& name
, int index
, int def
)
227 sal_Int32 ret
= def
; // give defensive answers, when data is not available
230 MutexGuard
guard( m_refMutex
->mutex
);
231 checkColumnIndex( index
);
232 Reference
< XPropertySet
> set
= getColumnByIndex( index
);
236 set
->getPropertyValue( name
) >>= ret
;
239 catch( com::sun::star::uno::Exception
& )
245 bool ResultSetMetaData::getBoolColumnProperty( const OUString
& name
, int index
, bool def
)
250 MutexGuard
guard( m_refMutex
->mutex
);
251 checkColumnIndex( index
);
252 Reference
< XPropertySet
> set
= getColumnByIndex( index
);
255 set
->getPropertyValue( name
) >>= ret
;
258 catch( com::sun::star::uno::Exception
& )
265 Reference
< com::sun::star::beans::XPropertySet
> ResultSetMetaData::getColumnByIndex( int index
)
267 Reference
< XPropertySet
> ret
;
271 OUString columnName
= getColumnName( index
);
272 Reference
< XColumnsSupplier
> supplier( m_table
, UNO_QUERY
);
275 Reference
< XNameAccess
> columns
= supplier
->getColumns();
276 if( columns
.is() && columns
->hasByName( columnName
) )
278 columns
->getByName( columnName
) >>= ret
;
286 sal_Int32
ResultSetMetaData::getColumnCount( )
287 throw (SQLException
, RuntimeException
, std::exception
)
292 sal_Bool
ResultSetMetaData::isAutoIncrement( sal_Int32 column
)
293 throw (SQLException
, RuntimeException
, std::exception
)
296 bool ret
= getBoolColumnProperty( getStatics().IS_AUTO_INCREMENT
, column
, false );
300 sal_Bool
ResultSetMetaData::isCaseSensitive( sal_Int32 column
)
301 throw (SQLException
, RuntimeException
, std::exception
)
304 return sal_True
; // ??? hmm, numeric types or
307 sal_Bool
ResultSetMetaData::isSearchable( sal_Int32 column
) throw (SQLException
, RuntimeException
, std::exception
)
310 return sal_True
; // mmm, what types are not searchable ?
313 sal_Bool
ResultSetMetaData::isCurrency( sal_Int32 column
) throw (SQLException
, RuntimeException
, std::exception
)
315 return getBoolColumnProperty( getStatics().IS_CURRENCY
, column
, false );
318 sal_Int32
ResultSetMetaData::isNullable( sal_Int32 column
)
319 throw (SQLException
, RuntimeException
, std::exception
)
321 return getIntColumnProperty(
322 getStatics().IS_NULLABLE
, column
, com::sun::star::sdbc::ColumnValue::NULLABLE_UNKNOWN
);
325 sal_Bool
ResultSetMetaData::isSigned( sal_Int32 column
)
326 throw (SQLException
, RuntimeException
, std::exception
)
332 sal_Int32
ResultSetMetaData::getColumnDisplaySize( sal_Int32 column
)
333 throw (SQLException
, RuntimeException
, std::exception
)
335 MutexGuard
guard( m_refMutex
->mutex
);
337 checkColumnIndex( column
);
338 return m_colDesc
[column
-1].displaySize
;
341 OUString
ResultSetMetaData::getColumnLabel( sal_Int32 column
)
342 throw (SQLException
, RuntimeException
, std::exception
)
344 return getColumnName( column
);
347 OUString
ResultSetMetaData::getColumnName( sal_Int32 column
) throw (SQLException
, RuntimeException
, std::exception
)
349 MutexGuard
guard( m_refMutex
->mutex
);
351 checkColumnIndex( column
);
353 return m_colDesc
[column
-1].name
;
356 OUString
ResultSetMetaData::getSchemaName( sal_Int32 column
) throw (SQLException
, RuntimeException
, std::exception
)
362 sal_Int32
ResultSetMetaData::getPrecision( sal_Int32 column
)
363 throw (SQLException
, RuntimeException
, std::exception
)
365 MutexGuard
guard( m_refMutex
->mutex
);
367 checkColumnIndex( column
);
368 return m_colDesc
[column
-1].precision
;
371 sal_Int32
ResultSetMetaData::getScale( sal_Int32 column
)
372 throw (SQLException
, RuntimeException
, std::exception
)
374 MutexGuard
guard( m_refMutex
->mutex
);
376 checkColumnIndex( column
);
377 return m_colDesc
[column
-1].scale
;
380 OUString
ResultSetMetaData::getTableName( sal_Int32 column
)
381 throw (SQLException
, RuntimeException
, std::exception
)
384 // LEM TODO This is very fishy.. Should probably return the table to which that column belongs!
388 OUString
ResultSetMetaData::getCatalogName( sal_Int32 column
)
389 throw (SQLException
, RuntimeException
, std::exception
)
392 // can do this through XConnection.getCatalog() !
395 sal_Int32
ResultSetMetaData::getColumnType( sal_Int32 column
)
396 throw (SQLException
, RuntimeException
, std::exception
)
398 int ret
= getIntColumnProperty( getStatics().TYPE
, column
, -100 );
402 if( com::sun::star::sdbc::DataType::LONGVARCHAR
== m_colDesc
[column
-1].type
&& m_pResultSet
)
403 m_colDesc
[column
-1].type
= m_pResultSet
->guessDataType( column
);
404 ret
= m_colDesc
[column
-1].type
;
409 OUString
ResultSetMetaData::getColumnTypeName( sal_Int32 column
)
410 throw (SQLException
, RuntimeException
, std::exception
)
412 OUString ret
; // give defensive answers, when data is not available
415 MutexGuard
guard( m_refMutex
->mutex
);
416 checkColumnIndex( column
);
417 Reference
< XPropertySet
> set
= getColumnByIndex( column
);
421 set
->getPropertyValue( getStatics().TYPE_NAME
) >>= ret
;
426 ret
= m_colDesc
[column
-1].typeName
;
429 catch( com::sun::star::uno::Exception
& )
436 sal_Bool
ResultSetMetaData::isReadOnly( sal_Int32 column
)
437 throw (SQLException
, RuntimeException
, std::exception
)
443 sal_Bool
ResultSetMetaData::isWritable( sal_Int32 column
)
444 throw (SQLException
, RuntimeException
, std::exception
)
446 return ! isReadOnly( column
); // what's the sense if this method ?
449 sal_Bool
ResultSetMetaData::isDefinitelyWritable( sal_Int32 column
)
450 throw (SQLException
, RuntimeException
, std::exception
)
452 return isWritable(column
); // uhh, now it becomes really esoteric ....
454 OUString
ResultSetMetaData::getColumnServiceName( sal_Int32 column
)
455 throw (SQLException
, RuntimeException
, std::exception
)
461 void ResultSetMetaData::checkClosed()
462 throw (::com::sun::star::sdbc::SQLException
, ::com::sun::star::uno::RuntimeException
)
467 void ResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex
)
468 throw (::com::sun::star::sdbc::SQLException
, ::com::sun::star::uno::RuntimeException
)
470 if( columnIndex
< 1 || columnIndex
> m_colCount
)
472 OUStringBuffer
buf(128);
474 buf
.appendAscii( "pq_resultsetmetadata: index out of range (expected 1 to " );
475 buf
.append( m_colCount
);
476 buf
.appendAscii( ", got " );
477 buf
.append( columnIndex
);
479 buf
.makeStringAndClear(), *this, OUString(), 1, Any() );
485 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */