1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_ucbhelper.hxx"
26 
27 /**************************************************************************
28 								TODO
29  **************************************************************************
30 
31  *************************************************************************/
32 
33 #include "osl/diagnose.h"
34 #include <com/sun/star/beans/Property.hpp>
35 #include <com/sun/star/beans/XPropertySetInfo.hpp>
36 #include <com/sun/star/io/XInputStream.hpp>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/sdbc/DataType.hpp>
39 #include <com/sun/star/sdbc/XArray.hpp>
40 #include <com/sun/star/sdbc/XBlob.hpp>
41 #include <com/sun/star/sdbc/XClob.hpp>
42 #include <com/sun/star/sdbc/XRef.hpp>
43 #include <com/sun/star/util/Date.hpp>
44 #include <com/sun/star/util/Time.hpp>
45 #include <com/sun/star/util/DateTime.hpp>
46 #include <ucbhelper/resultsetmetadata.hxx>
47 
48 using namespace com::sun::star::beans;
49 using namespace com::sun::star::io;
50 using namespace com::sun::star::lang;
51 using namespace com::sun::star::sdbc;
52 using namespace com::sun::star::uno;
53 using namespace com::sun::star::util;
54 using namespace rtl;
55 
56 namespace ucbhelper_impl {
57 
58 struct ResultSetMetaData_Impl
59 {
60 	osl::Mutex						   	            m_aMutex;
61 	std::vector< ::ucbhelper::ResultSetColumnData > m_aColumnData;
62 	sal_Bool 						   	            m_bObtainedTypes;
63 	sal_Bool							            m_bGlobalReadOnlyValue;
64 
ResultSetMetaData_Implucbhelper_impl::ResultSetMetaData_Impl65 	ResultSetMetaData_Impl( sal_Int32 nSize )
66 	: m_aColumnData( nSize ), m_bObtainedTypes( sal_False ),
67 	  m_bGlobalReadOnlyValue( sal_True ) {}
68 
ResultSetMetaData_Implucbhelper_impl::ResultSetMetaData_Impl69 	ResultSetMetaData_Impl(
70 		const std::vector< ::ucbhelper::ResultSetColumnData >& rColumnData )
71 	: m_aColumnData( rColumnData ), m_bObtainedTypes( sal_False ),
72 	  m_bGlobalReadOnlyValue( sal_False ) {}
73 };
74 
75 }
76 
77 using namespace ucbhelper_impl;
78 
79 namespace ucbhelper {
80 
81 //=========================================================================
82 //=========================================================================
83 //
84 // ResultSetMetaData Implementation.
85 //
86 //=========================================================================
87 //=========================================================================
88 
ResultSetMetaData(const Reference<XMultiServiceFactory> & rxSMgr,const Sequence<Property> & rProps,sal_Bool bReadOnly)89 ResultSetMetaData::ResultSetMetaData(
90 						const Reference< XMultiServiceFactory >& rxSMgr,
91 						const Sequence< Property >& rProps,
92 						sal_Bool bReadOnly )
93 : m_pImpl( new ResultSetMetaData_Impl( rProps.getLength() ) ),
94   m_xSMgr( rxSMgr ),
95   m_aProps( rProps ),
96   m_bReadOnly( bReadOnly )
97 {
98 }
99 
100 //=========================================================================
ResultSetMetaData(const Reference<XMultiServiceFactory> & rxSMgr,const Sequence<Property> & rProps,const std::vector<ResultSetColumnData> & rColumnData)101 ResultSetMetaData::ResultSetMetaData(
102 						const Reference< XMultiServiceFactory >& rxSMgr,
103 						const Sequence< Property >& rProps,
104 						const std::vector< ResultSetColumnData >& rColumnData )
105 : m_pImpl( new ResultSetMetaData_Impl( rColumnData ) ),
106   m_xSMgr( rxSMgr ),
107   m_aProps( rProps ),
108   m_bReadOnly( sal_True )
109 {
110 	OSL_ENSURE( rColumnData.size() == sal_uInt32( rProps.getLength() ),
111 				"ResultSetMetaData ctor - different array sizes!" );
112 }
113 
114 //=========================================================================
115 // virtual
~ResultSetMetaData()116 ResultSetMetaData::~ResultSetMetaData()
117 {
118 	delete m_pImpl;
119 }
120 
121 //=========================================================================
122 //
123 // XInterface methods.
124 //
125 //=========================================================================
126 
127 XINTERFACE_IMPL_2( ResultSetMetaData,
128 				   XTypeProvider,
129 				   XResultSetMetaData );
130 
131 //=========================================================================
132 //
133 // XTypeProvider methods.
134 //
135 //=========================================================================
136 
137 XTYPEPROVIDER_IMPL_2( ResultSetMetaData,
138 					  XTypeProvider,
139 					  XResultSetMetaData );
140 
141 //=========================================================================
142 //
143 // XResultSetMetaData methods.
144 //
145 //=========================================================================
146 
147 // virtual
getColumnCount()148 sal_Int32 SAL_CALL ResultSetMetaData::getColumnCount()
149 	throw( SQLException, RuntimeException )
150 {
151 	return m_aProps.getLength();
152 }
153 
154 //=========================================================================
155 // virtual
isAutoIncrement(sal_Int32 column)156 sal_Bool SAL_CALL ResultSetMetaData::isAutoIncrement( sal_Int32 column )
157 	throw( SQLException, RuntimeException )
158 {
159 	/*
160 		Checks whether column is automatically numbered, which makes it
161 		read-only.
162 	 */
163 
164 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
165 		return sal_False;
166 
167 	return m_pImpl->m_aColumnData[ column - 1 ].isAutoIncrement;
168 }
169 
170 //=========================================================================
171 // virtual
isCaseSensitive(sal_Int32 column)172 sal_Bool SAL_CALL ResultSetMetaData::isCaseSensitive( sal_Int32 column )
173 	throw( SQLException, RuntimeException )
174 {
175 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
176 		return sal_False;
177 
178 	return m_pImpl->m_aColumnData[ column - 1 ].isCaseSensitive;
179 }
180 
181 //=========================================================================
182 // virtual
isSearchable(sal_Int32 column)183 sal_Bool SAL_CALL ResultSetMetaData::isSearchable( sal_Int32 column )
184 	throw( SQLException, RuntimeException )
185 {
186 	/*
187 		Checks whether the value stored in column can be used in a
188 		WHERE clause.
189 	 */
190 
191 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
192 		return sal_False;
193 
194 	return m_pImpl->m_aColumnData[ column - 1 ].isSearchable;
195 }
196 
197 //=========================================================================
198 // virtual
isCurrency(sal_Int32 column)199 sal_Bool SAL_CALL ResultSetMetaData::isCurrency( sal_Int32 column )
200 	throw( SQLException, RuntimeException )
201 {
202 	/*
203 		Checks whether column is a cash value.
204 	 */
205 
206 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
207 		return sal_False;
208 
209 	return m_pImpl->m_aColumnData[ column - 1 ].isCurrency;
210 }
211 
212 //=========================================================================
213 // virtual
isNullable(sal_Int32 column)214 sal_Int32 SAL_CALL ResultSetMetaData::isNullable( sal_Int32 column )
215 	throw( SQLException, RuntimeException )
216 {
217 	/*
218 		Checks whether a NULL can be stored in column.
219 		Possible values: see com/sun/star/sdbc/ColumnValue.idl
220 	 */
221 
222 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
223 		return ColumnValue::NULLABLE;
224 
225 	return m_pImpl->m_aColumnData[ column - 1 ].isNullable;
226 }
227 
228 //=========================================================================
229 // virtual
isSigned(sal_Int32 column)230 sal_Bool SAL_CALL ResultSetMetaData::isSigned( sal_Int32 column )
231 	throw( SQLException, RuntimeException )
232 {
233 	/*
234 		Checks whether the value stored in column is a signed number.
235 	 */
236 
237 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
238 		return sal_False;
239 
240 	return m_pImpl->m_aColumnData[ column - 1 ].isSigned;
241 }
242 
243 //=========================================================================
244 // virtual
getColumnDisplaySize(sal_Int32 column)245 sal_Int32 SAL_CALL ResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
246 	throw( SQLException, RuntimeException )
247 {
248 	/*
249 		Gets the normal maximum width in characters for column.
250 	 */
251 
252 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
253 		return 16;
254 
255 	return m_pImpl->m_aColumnData[ column - 1 ].columnDisplaySize;
256 }
257 
258 //=========================================================================
259 // virtual
getColumnLabel(sal_Int32 column)260 OUString SAL_CALL ResultSetMetaData::getColumnLabel( sal_Int32 column )
261 	throw( SQLException, RuntimeException )
262 {
263 	/*
264 		Gets the suggested column title for column, to be used in print-
265 		outs and displays.
266 	 */
267 
268 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
269 		return OUString();
270 
271 	OUString aLabel = m_pImpl->m_aColumnData[ column - 1 ].columnLabel;
272 	if ( aLabel.getLength() )
273 		return aLabel;
274 
275 	return m_aProps.getConstArray()[ column - 1 ].Name;
276 }
277 
278 //=========================================================================
279 // virtual
getColumnName(sal_Int32 column)280 OUString SAL_CALL ResultSetMetaData::getColumnName( sal_Int32 column )
281 	throw( SQLException, RuntimeException )
282 {
283 	/*
284 		Gets the name of column.
285 	 */
286 
287 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
288 		return OUString();
289 
290 	return m_aProps.getConstArray()[ column - 1 ].Name;
291 }
292 
293 //=========================================================================
294 // virtual
getSchemaName(sal_Int32 column)295 OUString SAL_CALL ResultSetMetaData::getSchemaName( sal_Int32 column )
296 	throw( SQLException, RuntimeException )
297 {
298 	/*
299 		Gets the schema name for the table from which column of this
300 		result set was derived.
301 		Because this feature is not widely supported, the return value
302 		for many DBMSs will be an empty string.
303 	 */
304 
305 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
306 		return OUString();
307 
308 	return m_pImpl->m_aColumnData[ column - 1 ].schemaName;
309 }
310 
311 //=========================================================================
312 // virtual
getPrecision(sal_Int32 column)313 sal_Int32 SAL_CALL ResultSetMetaData::getPrecision( sal_Int32 column )
314 	throw( SQLException, RuntimeException )
315 {
316 	/*
317 		For number types, getprecision gets the number of decimal digits
318 		in column.
319 		For character types, it gets the maximum length in characters for
320 		column.
321 		For binary types, it gets the maximum length in bytes for column.
322 	 */
323 
324 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
325 		return -1;
326 
327 	return m_pImpl->m_aColumnData[ column - 1 ].precision;
328 }
329 
330 //=========================================================================
331 // virtual
getScale(sal_Int32 column)332 sal_Int32 SAL_CALL ResultSetMetaData::getScale( sal_Int32 column )
333 	throw( SQLException, RuntimeException )
334 {
335 	/*
336 		Gets the number of digits to the right of the decimal point for
337 		values in column.
338 	 */
339 
340 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
341 		return 0;
342 
343 	return m_pImpl->m_aColumnData[ column - 1 ].scale;
344 }
345 
346 //=========================================================================
347 // virtual
getTableName(sal_Int32 column)348 OUString SAL_CALL ResultSetMetaData::getTableName( sal_Int32 column )
349 	throw( SQLException, RuntimeException )
350 {
351 	/*
352 		Gets the name of the table from which column of this result set
353 		was derived or "" if there is none (for example, for a join).
354 		Because this feature is not widely supported, the return value
355 		for many DBMSs will be an empty string.
356 	 */
357 
358 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
359 		return OUString();
360 
361 	return m_pImpl->m_aColumnData[ column - 1 ].tableName;
362 }
363 
364 //=========================================================================
365 // virtual
getCatalogName(sal_Int32 column)366 OUString SAL_CALL ResultSetMetaData::getCatalogName( sal_Int32 column )
367 	throw( SQLException, RuntimeException )
368 {
369 	/*
370 		Gets the catalog name for the table from which column of this
371 		result set was derived.
372 		Because this feature is not widely supported, the return value
373 		for many DBMSs will be an empty string.
374 	 */
375 
376 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
377 		return OUString();
378 
379 	return m_pImpl->m_aColumnData[ column - 1 ].catalogName;
380 }
381 
382 //=========================================================================
383 // virtual
getColumnType(sal_Int32 column)384 sal_Int32 SAL_CALL ResultSetMetaData::getColumnType( sal_Int32 column )
385 	throw( SQLException, RuntimeException )
386 {
387 	/*
388 		Gets the JDBC type for the value stored in column. ... The STRUCT
389 		and DISTINCT type codes are always returned for structured and
390 		distinct types, regardless of whether the value will be mapped
391 		according to the standard mapping or be a custom mapping.
392 	 */
393 
394 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
395 		return DataType::SQLNULL;
396 
397 	if ( m_aProps.getConstArray()[ column - 1 ].Type
398 			== getCppuVoidType() )
399 	{
400 		// No type given. Try UCB's Properties Manager...
401 
402 		osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
403 
404 		if ( !m_pImpl->m_bObtainedTypes )
405 		{
406 			try
407 			{
408 				Reference< XPropertySetInfo > xInfo(
409 							m_xSMgr->createInstance(
410 								OUString::createFromAscii(
411 									"com.sun.star.ucb.PropertiesManager" ) ),
412 							UNO_QUERY );
413 				if ( xInfo.is() )
414 				{
415 #if 0
416 	// Convenient...
417 
418 					sal_Int32 nCount = m_pImpl->m_aProps.getLength();
419 					Property* pProps = m_pImpl->m_aProps.getArray();
420 					for ( sal_Int32 n = 0; n < nCount; ++n )
421 					{
422 						Property& rProp = pProps[ n ];
423 
424 						try
425 						{
426 							Property aProp
427 								= xInfo->getPropertyByName( rProp.Name );
428 							rProp.Type = aProp.Type;
429 						}
430 						catch ( UnknownPropertyException& )
431 						{
432 							// getPropertyByName
433 						}
434 					}
435 #else
436 	// Less (remote) calls...
437 
438 					Sequence< Property > aProps = xInfo->getProperties();
439 					const Property* pProps1 = aProps.getConstArray();
440 					sal_Int32 nCount1 = aProps.getLength();
441 
442 					sal_Int32 nCount = m_aProps.getLength();
443 					Property* pProps = m_aProps.getArray();
444 					for ( sal_Int32 n = 0; n < nCount; ++n )
445 					{
446 						Property& rProp = pProps[ n ];
447 
448 						for ( sal_Int32 m = 0; m < nCount1; ++m )
449 						{
450 							const Property& rProp1 = pProps1[ m ];
451 							if ( rProp.Name == rProp1.Name )
452 							{
453 								// Found...
454 								rProp.Type = rProp1.Type;
455 								break;
456 							}
457 						}
458 					}
459 #endif
460 				}
461 			}
462 			catch ( RuntimeException& )
463 			{
464 				throw;
465 			}
466 			catch ( Exception& )
467 			{
468 				// createInstance
469 			}
470 
471 			m_pImpl->m_bObtainedTypes = sal_True;
472 		}
473 	}
474 
475 	const Type& rType = m_aProps.getConstArray()[ column - 1 ].Type;
476 	sal_Int32 nType = DataType::OTHER;
477 
478 	if ( rType == getCppuType( static_cast< const rtl::OUString * >( 0 ) ) )
479 		nType = DataType::VARCHAR;  // XRow::getString
480 	else if ( rType == getCppuBooleanType() )
481 		nType = DataType::BIT;		// XRow::getBoolean
482 	else if ( rType == getCppuType( static_cast< const sal_Int32 * >( 0 ) ) )
483 		nType = DataType::INTEGER;	// XRow::getInt
484 	else if ( rType == getCppuType( static_cast< const sal_Int64 * >( 0 ) ) )
485 		nType = DataType::BIGINT;	// XRow::getLong
486 	else if ( rType == getCppuType( static_cast< const sal_Int16 * >( 0 ) ) )
487 		nType = DataType::SMALLINT;	// XRow::getShort
488 	else if ( rType == getCppuType( static_cast< const sal_Int8 * >( 0 ) ) )
489 		nType = DataType::TINYINT;	// XRow::getByte
490 	else if ( rType == getCppuType( static_cast< const float * >( 0 ) ) )
491 		nType = DataType::REAL;  	// XRow::getFloat
492 	else if ( rType == getCppuType( static_cast< const double * >( 0 ) ) )
493 		nType = DataType::DOUBLE;  	// XRow::getDouble
494 	else if ( rType == getCppuType( static_cast< const Sequence< sal_Int8 > * >( 0 ) ) )
495 		nType = DataType::VARBINARY;// XRow::getBytes
496 	else if ( rType == getCppuType( static_cast< const Date * >( 0 ) ) )
497 		nType = DataType::DATE;		// XRow::getDate
498 	else if ( rType == getCppuType( static_cast< const Time * >( 0 ) ) )
499 		nType = DataType::TIME;		// XRow::getTime
500 	else if ( rType == getCppuType( static_cast< const DateTime * >( 0 ) ) )
501 		nType = DataType::TIMESTAMP;// XRow::getTimestamp
502 	else if ( rType == getCppuType( static_cast< Reference< XInputStream > * >( 0 ) ) )
503 		nType = DataType::LONGVARBINARY;	// XRow::getBinaryStream
504 //		nType = DataType::LONGVARCHAR;		// XRow::getCharacterStream
505 	else if ( rType == getCppuType( static_cast< Reference< XClob > * >( 0 ) ) )
506 		nType = DataType::CLOB;	// XRow::getClob
507 	else if ( rType == getCppuType( static_cast< Reference< XBlob > * >( 0 ) ) )
508 		nType = DataType::BLOB;	// XRow::getBlob
509 	else if ( rType == getCppuType( static_cast< Reference< XArray > * >( 0 ) ) )
510 		nType = DataType::ARRAY;// XRow::getArray
511 	else if ( rType == getCppuType( static_cast< Reference< XRef > * >( 0 ) ) )
512 		nType = DataType::REF;// XRow::getRef
513 	else
514 		nType = DataType::OBJECT;// XRow::getObject
515 
516 	return nType;
517 }
518 
519 //=========================================================================
520 // virtual
getColumnTypeName(sal_Int32 column)521 OUString SAL_CALL ResultSetMetaData::getColumnTypeName( sal_Int32 column )
522 	throw( SQLException, RuntimeException )
523 {
524 	/*
525 		Gets the type name used by this particular data source for the
526 		values stored in column. If the type code for the type of value
527 		stored in column is STRUCT, DISTINCT or JAVA_OBJECT, this method
528 		returns a fully-qualified SQL type name.
529 	 */
530 
531 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
532 		return OUString();
533 
534 	return m_pImpl->m_aColumnData[ column - 1 ].columnTypeName;
535 }
536 
537 //=========================================================================
538 // virtual
isReadOnly(sal_Int32 column)539 sal_Bool SAL_CALL ResultSetMetaData::isReadOnly( sal_Int32 column )
540 	throw( SQLException, RuntimeException )
541 {
542 	if ( m_pImpl->m_bGlobalReadOnlyValue )
543 		return m_bReadOnly;
544 
545 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
546 		return sal_True;
547 
548 	// autoincrement==true => readonly
549 	return m_pImpl->m_aColumnData[ column - 1 ].isAutoIncrement ||
550 	       m_pImpl->m_aColumnData[ column - 1 ].isReadOnly;
551 }
552 
553 //=========================================================================
554 // virtual
isWritable(sal_Int32 column)555 sal_Bool SAL_CALL ResultSetMetaData::isWritable( sal_Int32 column )
556 	throw( SQLException, RuntimeException )
557 {
558 	if ( m_pImpl->m_bGlobalReadOnlyValue )
559 		return !m_bReadOnly;
560 
561 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
562 		return sal_False;
563 
564 	return m_pImpl->m_aColumnData[ column - 1 ].isWritable;
565 }
566 
567 //=========================================================================
568 // virtual
isDefinitelyWritable(sal_Int32 column)569 sal_Bool SAL_CALL ResultSetMetaData::isDefinitelyWritable( sal_Int32 column )
570 	throw( SQLException, RuntimeException )
571 {
572 	if ( m_pImpl->m_bGlobalReadOnlyValue )
573 		return !m_bReadOnly;
574 
575 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
576 		return sal_False;
577 
578 	return m_pImpl->m_aColumnData[ column - 1 ].isDefinitelyWritable;
579 }
580 
581 //=========================================================================
582 // virtual
getColumnServiceName(sal_Int32 column)583 OUString SAL_CALL ResultSetMetaData::getColumnServiceName( sal_Int32 column )
584 	throw( SQLException, RuntimeException )
585 {
586     /*
587 	  	Returns the fully-qualified name of the service whose instances
588      	are manufactured if XResultSet::getObject is called to retrieve
589 		a value from the column.
590 	 */
591 
592 	if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
593 		return OUString();
594 
595 	return m_pImpl->m_aColumnData[ column - 1 ].columnServiceName;
596 }
597 
598 } // namespace ucbhelper
599