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