1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_connectivity.hxx"
30 #include "connectivity/dbtools.hxx"
31 #include "connectivity/dbconversion.hxx"
32 #include "connectivity/dbcharset.hxx"
33 #include "connectivity/SQLStatementHelper.hxx"
34 #include <unotools/confignode.hxx>
35 #include "resource/sharedresources.hxx"
36 #include "resource/common_res.hrc"
37 #include <com/sun/star/sdbc/XConnection.hpp>
38 #include <com/sun/star/sdbc/ColumnValue.hpp>
39 #include <com/sun/star/sdbc/DataType.hpp>
40 #include <com/sun/star/sdbc/XRow.hpp>
41 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
42 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
43 #include <com/sun/star/sdbc/XDriverAccess.hpp>
44 #include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
45 #include <com/sun/star/sdbcx/Privilege.hpp>
46 #include <com/sun/star/container/XIndexAccess.hpp>
47 #include <com/sun/star/container/XEnumerationAccess.hpp>
48 #include <com/sun/star/sdbc/KeyRule.hpp>
49 #include <com/sun/star/sdbcx/KeyType.hpp>
50 #include "TConnection.hxx"
51 #include "connectivity/sdbcx/VColumn.hxx"
52 #include <com/sun/star/frame/XModel.hpp>
53 #include <com/sun/star/container/XChild.hpp>
54 
55 #include <tools/diagnose_ex.h>
56 #include <unotools/sharedunocomponent.hxx>
57 #include <comphelper/configurationhelper.hxx>
58 
59 //.........................................................................
60 namespace dbtools
61 {
62 //.........................................................................
63 	using namespace ::com::sun::star::uno;
64 	using namespace ::com::sun::star::beans;
65 	using namespace ::com::sun::star::sdbc;
66 	using namespace ::com::sun::star::sdbcx;
67 	using namespace ::com::sun::star::lang;
68 	using namespace ::com::sun::star::container;
69 	using namespace ::com::sun::star::frame;
70 	using namespace connectivity;
71 	using namespace comphelper;
72 
73 ::rtl::OUString createStandardColumnPart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,const ::rtl::OUString& _sCreatePattern)
74 {
75 
76 	Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
77 
78 	::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
79 
80 	::rtl::OUString sTypeName;
81 	sal_Int32		nDataType	= 0;
82 	sal_Int32		nPrecision	= 0;
83 	sal_Int32		nScale		= 0;
84 
85 	const ::rtl::OUString sQuoteString = xMetaData->getIdentifierQuoteString();
86 	::rtl::OUStringBuffer aSql = ::dbtools::quoteName(sQuoteString,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))));
87 
88 	aSql.appendAscii(" ");
89 
90 	nDataType = nPrecision = nScale = 0;
91 	sal_Bool bIsAutoIncrement = sal_False;
92 	xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPENAME))			>>= sTypeName;
93 	xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE))				>>= nDataType;
94 	xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_PRECISION))			>>= nPrecision;
95 	xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCALE))				>>= nScale;
96 	xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))	>>= bIsAutoIncrement;
97 
98 	// check if the user enter a specific string to create autoincrement values
99 	::rtl::OUString sAutoIncrementValue;
100 	Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
101 	if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
102 		xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
103 	// look if we have to use precisions
104 	sal_Bool bUseLiteral = sal_False;
105 	::rtl::OUString sPreFix,sPostFix,sCreateParams;
106 	{
107 		Reference<XResultSet> xRes = xMetaData->getTypeInfo();
108 		if(xRes.is())
109 		{
110 			Reference<XRow> xRow(xRes,UNO_QUERY);
111 			while(xRes->next())
112 			{
113 				::rtl::OUString sTypeName2Cmp = xRow->getString(1);
114 				sal_Int32 nType = xRow->getShort(2);
115 				sPreFix = xRow->getString (4);
116 				sPostFix = xRow->getString (5);
117 				sCreateParams = xRow->getString(6);
118 				// first identical type will be used if typename is empty
119 				if ( !sTypeName.getLength() && nType == nDataType )
120 					sTypeName = sTypeName2Cmp;
121 
122 				if( sTypeName.equalsIgnoreAsciiCase(sTypeName2Cmp) && nType == nDataType && sCreateParams.getLength() && !xRow->wasNull())
123 				{
124 					bUseLiteral = sal_True;
125 					break;
126 				}
127 			}
128 		}
129 	}
130 
131 	sal_Int32 nIndex = 0;
132 	if ( sAutoIncrementValue.getLength() && (nIndex = sTypeName.indexOf(sAutoIncrementValue)) != -1 )
133 	{
134 		sTypeName = sTypeName.replaceAt(nIndex,sTypeName.getLength() - nIndex,::rtl::OUString());
135 	}
136 
137 	if ( (nPrecision > 0 || nScale > 0) && bUseLiteral )
138 	{
139 		sal_Int32 nParenPos = sTypeName.indexOf('(');
140 		if ( nParenPos == -1 )
141 		{
142 			aSql.append(sTypeName);
143 			aSql.appendAscii("(");
144 		}
145 		else
146 		{
147 			aSql.append(sTypeName.copy(0,++nParenPos));
148 		}
149 
150         if ( nPrecision > 0 && nDataType != DataType::TIMESTAMP )
151         {
152 		    aSql.append(nPrecision);
153             if ( (nScale > 0) || (_sCreatePattern.getLength() && sCreateParams.indexOf(_sCreatePattern) != -1) )
154                 aSql.appendAscii(",");
155         }
156 		if ( (nScale > 0) || (_sCreatePattern.getLength() && sCreateParams.indexOf(_sCreatePattern) != -1 ) || nDataType == DataType::TIMESTAMP )
157 			aSql.append(nScale);
158 
159         if ( nParenPos == -1 )
160 			aSql.appendAscii(")");
161 		else
162 		{
163 			nParenPos = sTypeName.indexOf(')',nParenPos);
164 			aSql.append(sTypeName.copy(nParenPos));
165 		}
166 	}
167 	else
168 		aSql.append(sTypeName); // simply add the type name
169 
170 	::rtl::OUString aDefault = ::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)));
171 	if ( aDefault.getLength() )
172     {
173 		aSql.append(::rtl::OUString::createFromAscii(" DEFAULT "));
174         aSql.append(sPreFix);
175         aSql.append(aDefault);
176         aSql.append(sPostFix);
177     } // if ( aDefault.getLength() )
178 
179 	if(::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISNULLABLE))) == ColumnValue::NO_NULLS)
180 		aSql.append(::rtl::OUString::createFromAscii(" NOT NULL"));
181 
182 	if ( bIsAutoIncrement && sAutoIncrementValue.getLength())
183 	{
184 		aSql.appendAscii(" ");
185 		aSql.append(sAutoIncrementValue);
186 	}
187 
188     if ( _pHelper )
189         _pHelper->addComment(xColProp,aSql);
190 
191 	return aSql.makeStringAndClear();
192 }
193 // -----------------------------------------------------------------------------
194 
195 ::rtl::OUString createStandardCreateStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,const ::rtl::OUString& _sCreatePattern)
196 {
197 	::rtl::OUStringBuffer aSql	= ::rtl::OUString::createFromAscii("CREATE TABLE ");
198 	::rtl::OUString sCatalog,sSchema,sTable,sComposedName;
199 
200 	Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
201 	::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
202 
203 	descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))	>>= sCatalog;
204 	descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME))	>>= sSchema;
205 	descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))			>>= sTable;
206 
207 	sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, sal_True, ::dbtools::eInTableDefinitions );
208 	if ( !sComposedName.getLength() )
209 		::dbtools::throwFunctionSequenceException(_xConnection);
210 
211 	aSql.append(sComposedName);
212     aSql.append(::rtl::OUString::createFromAscii(" ("));
213 
214 	// columns
215 	Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
216 	Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
217 	// check if there are columns
218 	if(!xColumns.is() || !xColumns->getCount())
219 		::dbtools::throwFunctionSequenceException(_xConnection);
220 
221 	Reference< XPropertySet > xColProp;
222 
223 	sal_Int32 nCount = xColumns->getCount();
224 	for(sal_Int32 i=0;i<nCount;++i)
225 	{
226 		if ( (xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
227 		{
228 			aSql.append(createStandardColumnPart(xColProp,_xConnection,_pHelper,_sCreatePattern));
229 			aSql.appendAscii(",");
230 		}
231 	}
232 	return aSql.makeStringAndClear();
233 }
234 namespace
235 {
236 	::rtl::OUString generateColumnNames(const Reference<XIndexAccess>& _xColumns,const Reference<XDatabaseMetaData>& _xMetaData)
237 	{
238 		::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
239 		static const ::rtl::OUString sComma(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(",")));
240 
241 		const ::rtl::OUString sQuote(_xMetaData->getIdentifierQuoteString());
242 		::rtl::OUString sSql = ::rtl::OUString::createFromAscii(" (");
243 		Reference< XPropertySet > xColProp;
244 
245 		sal_Int32 nColCount  = _xColumns->getCount();
246 		for(sal_Int32 i=0;i<nColCount;++i)
247 		{
248 			if ( (_xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
249 				sSql += ::dbtools::quoteName(sQuote,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))))
250 						+ sComma;
251 		}
252 
253 		if ( nColCount )
254 			sSql = sSql.replaceAt(sSql.getLength()-1,1,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(")")));
255 		return sSql;
256 	}
257 }
258 // -----------------------------------------------------------------------------
259 ::rtl::OUString createStandardKeyStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection)
260 {
261 	Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
262 	::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
263 
264 	::rtl::OUStringBuffer aSql;
265 	// keys
266 	Reference<XKeysSupplier> xKeySup(descriptor,UNO_QUERY);
267 	Reference<XIndexAccess> xKeys = xKeySup->getKeys();
268 	if ( xKeys.is() )
269 	{
270 		Reference< XPropertySet > xColProp;
271 		Reference<XIndexAccess> xColumns;
272 		Reference<XColumnsSupplier> xColumnSup;
273 		::rtl::OUString sCatalog,sSchema,sTable,sComposedName;
274 		sal_Bool bPKey = sal_False;
275 		for(sal_Int32 i=0;i<xKeys->getCount();++i)
276 		{
277 			if ( (xKeys->getByIndex(i) >>= xColProp) && xColProp.is() )
278 			{
279 
280 				sal_Int32 nKeyType		= ::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)));
281 
282 				if ( nKeyType == KeyType::PRIMARY )
283 				{
284 					if(bPKey)
285 						::dbtools::throwFunctionSequenceException(_xConnection);
286 
287 					bPKey = sal_True;
288 					xColumnSup = Reference<XColumnsSupplier>(xColProp,UNO_QUERY);
289 					xColumns = Reference<XIndexAccess>(xColumnSup->getColumns(),UNO_QUERY);
290 					if(!xColumns.is() || !xColumns->getCount())
291 						::dbtools::throwFunctionSequenceException(_xConnection);
292 
293 					const ::rtl::OUString sQuote	 = xMetaData->getIdentifierQuoteString();
294 					aSql.append(::rtl::OUString::createFromAscii(" PRIMARY KEY "));
295 					aSql.append(generateColumnNames(xColumns,xMetaData));
296 				}
297 				else if(nKeyType == KeyType::UNIQUE)
298 				{
299 					xColumnSup = Reference<XColumnsSupplier>(xColProp,UNO_QUERY);
300 					xColumns = Reference<XIndexAccess>(xColumnSup->getColumns(),UNO_QUERY);
301 					if(!xColumns.is() || !xColumns->getCount())
302 						::dbtools::throwFunctionSequenceException(_xConnection);
303 
304 					const ::rtl::OUString sQuote	 = xMetaData->getIdentifierQuoteString();
305 					aSql.append(::rtl::OUString::createFromAscii(" UNIQUE "));
306 					aSql.append(generateColumnNames(xColumns,xMetaData));
307 				}
308 				else if(nKeyType == KeyType::FOREIGN)
309 				{
310 					sal_Int32 nDeleteRule	= getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)));
311 
312 					xColumnSup = Reference<XColumnsSupplier>(xColProp,UNO_QUERY);
313 					xColumns = Reference<XIndexAccess>(xColumnSup->getColumns(),UNO_QUERY);
314 					if(!xColumns.is() || !xColumns->getCount())
315 						::dbtools::throwFunctionSequenceException(_xConnection);
316 
317 					aSql.append(::rtl::OUString::createFromAscii(" FOREIGN KEY "));
318 					::rtl::OUString sRefTable = getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)));
319 					::dbtools::qualifiedNameComponents(xMetaData,
320 														sRefTable,
321 														sCatalog,
322 														sSchema,
323 														sTable,
324 														::dbtools::eInDataManipulation);
325 					sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, sal_True, ::dbtools::eInTableDefinitions );
326 
327 
328 					if ( !sComposedName.getLength() )
329 						::dbtools::throwFunctionSequenceException(_xConnection);
330 
331 					aSql.append(generateColumnNames(xColumns,xMetaData));
332 
333 					switch(nDeleteRule)
334 					{
335 						case KeyRule::CASCADE:
336 							aSql.append(::rtl::OUString::createFromAscii(" ON DELETE CASCADE "));
337 							break;
338 						case KeyRule::RESTRICT:
339 							aSql.append(::rtl::OUString::createFromAscii(" ON DELETE RESTRICT "));
340 							break;
341 						case KeyRule::SET_NULL:
342 							aSql.append(::rtl::OUString::createFromAscii(" ON DELETE SET NULL "));
343 							break;
344 						case KeyRule::SET_DEFAULT:
345 							aSql.append(::rtl::OUString::createFromAscii(" ON DELETE SET DEFAULT "));
346 							break;
347 						default:
348 							;
349 					}
350 				}
351 			}
352 		}
353 	}
354 
355 	if ( aSql.getLength() )
356 	{
357 		if ( aSql.charAt(aSql.getLength()-1) == ',' )
358 			aSql.setCharAt(aSql.getLength()-1,')');
359 		else
360 			aSql.appendAscii(")");
361 	}
362 
363 	return aSql.makeStringAndClear();
364 
365 }
366 // -----------------------------------------------------------------------------
367 ::rtl::OUString createSqlCreateTableStatement(	const Reference< XPropertySet >& descriptor,
368 												const Reference< XConnection>& _xConnection,
369                                                 ISQLStatementHelper* _pHelper,
370                                                 const ::rtl::OUString& _sCreatePattern)
371 {
372 	::rtl::OUString aSql = ::dbtools::createStandardCreateStatement(descriptor,_xConnection,_pHelper,_sCreatePattern);
373 	const ::rtl::OUString sKeyStmt = ::dbtools::createStandardKeyStatement(descriptor,_xConnection);
374 	if ( sKeyStmt.getLength() )
375 		aSql += sKeyStmt;
376 	else
377 	{
378 		if ( aSql.lastIndexOf(',') == (aSql.getLength()-1) )
379 			aSql = aSql.replaceAt(aSql.getLength()-1,1,::rtl::OUString::createFromAscii(")"));
380 		else
381 			aSql += ::rtl::OUString::createFromAscii(")");
382 	}
383 	return aSql;
384 }
385 namespace
386 {
387 	Reference<XPropertySet> lcl_createSDBCXColumn(const Reference<XNameAccess>& _xPrimaryKeyColumns,
388 										  const Reference<XConnection>& _xConnection,
389 										  const Any& _aCatalog,
390 										  const ::rtl::OUString& _aSchema,
391 										  const ::rtl::OUString& _aTable,
392 										  const ::rtl::OUString& _rQueryName,
393 										  const ::rtl::OUString& _rName,
394 										  sal_Bool _bCase,
395 										  sal_Bool _bQueryForInfo,
396 										  sal_Bool _bIsAutoIncrement,
397 										  sal_Bool _bIsCurrency,
398 										  sal_Int32 _nDataType)
399 	{
400 		Reference<XPropertySet> xProp;
401 		Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
402 		Reference< XResultSet > xResult = xMetaData->getColumns(_aCatalog, _aSchema, _aTable, _rQueryName);
403 
404 		if ( xResult.is() )
405 		{
406 			UStringMixEqual aMixCompare(_bCase);
407 			Reference< XRow > xRow(xResult,UNO_QUERY);
408 			while( xResult->next() )
409 			{
410 				if ( aMixCompare(xRow->getString(4),_rName) )
411 				{
412 					sal_Int32		nField5	= xRow->getInt(5);
413 					::rtl::OUString aField6 = xRow->getString(6);
414 					sal_Int32		nField7 = xRow->getInt(7)
415 								,	nField9 = xRow->getInt(9)
416 								,	nField11= xRow->getInt(11);
417 					::rtl::OUString sField12 = xRow->getString(12),
418                                     sField13 = xRow->getString(13);
419 					::comphelper::disposeComponent(xRow);
420 
421 					sal_Bool bAutoIncrement = _bIsAutoIncrement
422 							,bIsCurrency	= _bIsCurrency;
423 					if ( _bQueryForInfo )
424 					{
425 						const ::rtl::OUString sQuote = xMetaData->getIdentifierQuoteString();
426 						::rtl::OUString sQuotedName  = ::dbtools::quoteName(sQuote,_rName);
427 						::rtl::OUString sComposedName;
428 						sComposedName = composeTableNameForSelect(_xConnection, getString( _aCatalog ), _aSchema, _aTable );
429 
430 						ColumnInformationMap aInfo(_bCase);
431 						collectColumnInformation(_xConnection,sComposedName,sQuotedName,aInfo);
432 						ColumnInformationMap::iterator aIter = aInfo.begin();
433 						if ( aIter != aInfo.end() )
434 						{
435 							bAutoIncrement	= aIter->second.first.first;
436 							bIsCurrency		= aIter->second.first.second;
437 							if ( DataType::OTHER == nField5 )
438 								nField5		= aIter->second.second;
439 						}
440 					}
441 					else if ( DataType::OTHER == nField5 )
442 						nField5 = _nDataType;
443 
444 					if ( nField11 != ColumnValue::NO_NULLS )
445 					{
446 						try
447 						{
448                             if ( _xPrimaryKeyColumns.is() )
449                             {
450                                 if ( _xPrimaryKeyColumns->hasByName(_rName) )
451                                     nField11 = ColumnValue::NO_NULLS;
452 
453                             }
454                             else
455                             {
456 							    Reference< XResultSet > xPKeys = xMetaData->getPrimaryKeys( _aCatalog, _aSchema, _aTable );
457                                 Reference< XRow > xPKeyRow( xPKeys, UNO_QUERY_THROW );
458                                 while( xPKeys->next() ) // there can be only one primary key
459 							    {
460                                     ::rtl::OUString sKeyColumn = xPKeyRow->getString(4);
461 								    if ( aMixCompare(_rName,sKeyColumn) )
462 								    {
463 									    nField11 = ColumnValue::NO_NULLS;
464 									    break;
465 								    }
466 							    }
467 							}
468                         }
469 						catch(SQLException&)
470 						{
471                             OSL_ENSURE( false, "lcl_createSDBCXColumn: caught an exception!" );
472 						}
473 					}
474 
475 					connectivity::sdbcx::OColumn* pRet = new connectivity::sdbcx::OColumn(_rName,
476 												aField6,
477 												sField13,
478                                                 sField12,
479 												nField11,
480 												nField7,
481 												nField9,
482 												nField5,
483 												bAutoIncrement,
484 												sal_False,
485 												bIsCurrency,
486 												_bCase);
487 
488 					xProp = pRet;
489 					break;
490 				}
491 			}
492 		}
493 
494 		return xProp;
495 	}
496 	//------------------------------------------------------------------
497 	Reference< XModel> lcl_getXModel(const Reference< XInterface>& _xIface)
498 	{
499 		Reference< XInterface > xParent = _xIface;
500 		Reference< XModel > xModel(xParent,UNO_QUERY);;
501 		while( xParent.is() && !xModel.is() )
502 		{
503 			Reference<XChild> xChild(xParent,UNO_QUERY);
504 			xParent.set(xChild.is() ? xChild->getParent() : Reference< XInterface >(),UNO_QUERY);
505 			xModel.set(xParent,UNO_QUERY);
506 		}
507 		return xModel;
508 	}
509 }
510 // -----------------------------------------------------------------------------
511 Reference<XPropertySet> createSDBCXColumn(const Reference<XPropertySet>& _xTable,
512 										  const Reference<XConnection>& _xConnection,
513 										  const ::rtl::OUString& _rName,
514 										  sal_Bool _bCase,
515 										  sal_Bool _bQueryForInfo,
516 										  sal_Bool _bIsAutoIncrement,
517 										  sal_Bool _bIsCurrency,
518 										  sal_Int32 _nDataType)
519 {
520 	Reference<XPropertySet> xProp;
521 	OSL_ENSURE(_xTable.is(),"Table is NULL!");
522 	if ( !_xTable.is() )
523 		return xProp;
524 
525 	::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
526 	Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
527 	Any aCatalog;
528 	aCatalog = _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME));
529 
530 	::rtl::OUString aSchema, aTable;
531 	_xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME))	>>= aSchema;
532 	_xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))		>>= aTable;
533 
534     Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(_xTable);
535 
536 	xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, _rName,_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
537 	if ( !xProp.is() )
538 	{
539 		xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("%")),_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
540 		if ( !xProp.is() )
541 			xProp = new connectivity::sdbcx::OColumn(_rName,
542 												::rtl::OUString(),::rtl::OUString(),::rtl::OUString(),
543 												ColumnValue::NULLABLE_UNKNOWN,
544 												0,
545 												0,
546 												DataType::VARCHAR,
547 												_bIsAutoIncrement,
548 												sal_False,
549 												_bIsCurrency,
550 												_bCase);
551 
552 	}
553 
554 	return xProp;
555 }
556 
557 // -----------------------------------------------------------------------------
558 bool getBooleanDataSourceSetting( const Reference< XConnection >& _rxConnection, const sal_Char* _pAsciiSettingName )
559 {
560     bool bValue( false );
561     try
562     {
563 		Reference< XPropertySet> xDataSourceProperties( findDataSource( _rxConnection ), UNO_QUERY );
564         OSL_ENSURE( xDataSourceProperties.is(), "::dbtools::getBooleanDataSourceSetting: somebody is using this with a non-SDB-level connection!" );
565 		if ( xDataSourceProperties.is() )
566 		{
567 			Reference< XPropertySet > xSettings(
568 			    xDataSourceProperties->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Settings") ) ),
569                 UNO_QUERY_THROW
570             );
571             OSL_VERIFY( xSettings->getPropertyValue( ::rtl::OUString::createFromAscii( _pAsciiSettingName ) ) >>= bValue );
572 		}
573     }
574     catch( const Exception& )
575     {
576     	DBG_UNHANDLED_EXCEPTION();
577     }
578     return bValue;
579 }
580 // -------------------------------------------------------------------------
581 bool getDataSourceSetting( const Reference< XInterface >& _xChild, const ::rtl::OUString& _sAsciiSettingsName,
582     Any& /* [out] */ _rSettingsValue )
583 {
584     bool bIsPresent = false;
585     try
586     {
587         const Reference< XPropertySet> xDataSourceProperties( findDataSource( _xChild ), UNO_QUERY );
588         if ( !xDataSourceProperties.is() )
589             return false;
590 
591         const Reference< XPropertySet > xSettings(
592 			    xDataSourceProperties->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Settings") ) ),
593                 UNO_QUERY_THROW
594             );
595 
596         _rSettingsValue = xSettings->getPropertyValue( _sAsciiSettingsName );
597         bIsPresent = true;
598     }
599     catch( const Exception& )
600     {
601 	    bIsPresent = false;
602     }
603     return bIsPresent;
604 }
605 // -------------------------------------------------------------------------
606 bool getDataSourceSetting( const Reference< XInterface >& _rxDataSource, const sal_Char* _pAsciiSettingsName,
607     Any& /* [out] */ _rSettingsValue )
608 {
609     ::rtl::OUString sAsciiSettingsName = ::rtl::OUString::createFromAscii(_pAsciiSettingsName);
610     return getDataSourceSetting( _rxDataSource, sAsciiSettingsName,_rSettingsValue );
611 }
612 // -----------------------------------------------------------------------------
613 sal_Bool isDataSourcePropertyEnabled(const Reference<XInterface>& _xProp,const ::rtl::OUString& _sProperty,sal_Bool _bDefault)
614 {
615 	sal_Bool bEnabled = _bDefault;
616 	try
617 	{
618 		Reference< XPropertySet> xProp(findDataSource(_xProp),UNO_QUERY);
619 		if ( xProp.is() )
620 		{
621 			Sequence< PropertyValue > aInfo;
622 			xProp->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Info"))) >>= aInfo;
623 			const PropertyValue* pValue =::std::find_if(aInfo.getConstArray(),
624 												aInfo.getConstArray() + aInfo.getLength(),
625 												::std::bind2nd(TPropertyValueEqualFunctor(),_sProperty));
626 			if ( pValue && pValue != (aInfo.getConstArray() + aInfo.getLength()) )
627 				pValue->Value >>= bEnabled;
628 		}
629 	}
630 	catch(SQLException&)
631 	{
632         DBG_UNHANDLED_EXCEPTION();
633 	}
634 	return bEnabled;
635 }
636 // -----------------------------------------------------------------------------
637 Reference< XTablesSupplier> getDataDefinitionByURLAndConnection(
638 			const ::rtl::OUString& _rsUrl,
639 			const Reference< XConnection>& _xConnection,
640 			const Reference< XMultiServiceFactory>& _rxFactory)
641 {
642 	Reference< XTablesSupplier> xTablesSup;
643     try
644     {
645 	    Reference< XDriverAccess> xManager(
646             _rxFactory->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.sdbc.DriverManager") ),
647             UNO_QUERY_THROW );
648 	    Reference< XDataDefinitionSupplier > xSupp( xManager->getDriverByURL( _rsUrl ), UNO_QUERY );
649 
650 	    if ( xSupp.is() )
651         {
652 		    xTablesSup = xSupp->getDataDefinitionByConnection( _xConnection );
653             OSL_ENSURE(xTablesSup.is(),"No table supplier!");
654         }
655     }
656     catch( const Exception& )
657     {
658     	DBG_UNHANDLED_EXCEPTION();
659     }
660 	return xTablesSup;
661 }
662 
663 // -----------------------------------------------------------------------------
664 sal_Int32 getTablePrivileges(const Reference< XDatabaseMetaData>& _xMetaData,
665 							 const ::rtl::OUString& _sCatalog,
666 							 const ::rtl::OUString& _sSchema,
667 							 const ::rtl::OUString& _sTable)
668 {
669 	OSL_ENSURE(_xMetaData.is(),"Invalid metadata!");
670 	sal_Int32 nPrivileges = 0;
671 	try
672 	{
673 		Any aVal;
674 		if(_sCatalog.getLength())
675 			aVal <<= _sCatalog;
676 		Reference< XResultSet > xPrivileges = _xMetaData->getTablePrivileges(aVal, _sSchema, _sTable);
677 		Reference< XRow > xCurrentRow(xPrivileges, UNO_QUERY);
678 
679 		if ( xCurrentRow.is() )
680 		{
681 			::rtl::OUString sUserWorkingFor = _xMetaData->getUserName();
682 			static const ::rtl::OUString sSELECT	= ::rtl::OUString::createFromAscii("SELECT");
683 			static const ::rtl::OUString sINSERT	= ::rtl::OUString::createFromAscii("INSERT");
684 			static const ::rtl::OUString sUPDATE	= ::rtl::OUString::createFromAscii("UPDATE");
685 			static const ::rtl::OUString sDELETE	= ::rtl::OUString::createFromAscii("DELETE");
686 			static const ::rtl::OUString sREAD		= ::rtl::OUString::createFromAscii("READ");
687 			static const ::rtl::OUString sCREATE	= ::rtl::OUString::createFromAscii("CREATE");
688 			static const ::rtl::OUString sALTER		= ::rtl::OUString::createFromAscii("ALTER");
689 			static const ::rtl::OUString sREFERENCE = ::rtl::OUString::createFromAscii("REFERENCE");
690 			static const ::rtl::OUString sDROP		= ::rtl::OUString::createFromAscii("DROP");
691 			// after creation the set is positioned before the first record, per definitionem
692 #ifdef DBG_UTIL
693 			Reference< XResultSetMetaDataSupplier > xSup(xPrivileges,UNO_QUERY);
694 			if ( xSup.is() )
695 			{
696 				Reference< XResultSetMetaData > xRsMetaData = xSup->getMetaData();
697 				if ( xRsMetaData.is() )
698 				{
699 					sal_Int32 nCount = xRsMetaData->getColumnCount();
700 					for (sal_Int32 i=1; i<=nCount; ++i)
701 					{
702 						::rtl::OUString sColumnName = xRsMetaData->getColumnName(i);
703 					}
704 				}
705 			}
706 #endif
707 
708 			::rtl::OUString sPrivilege, sGrantee;
709 			while ( xPrivileges->next() )
710 			{
711 #ifdef DBG_UTIL
712 				::rtl::OUString sCat, sSchema, sName, sGrantor, sGrantable;
713 				sCat		= xCurrentRow->getString(1);
714 				sSchema		= xCurrentRow->getString(2);
715 				sName		= xCurrentRow->getString(3);
716 				sGrantor	= xCurrentRow->getString(4);
717 #endif
718 				sGrantee	= xCurrentRow->getString(5);
719 				sPrivilege	= xCurrentRow->getString(6);
720 #ifdef DBG_UTIL
721 				sGrantable	= xCurrentRow->getString(7);
722 #endif
723 
724 				if (!sUserWorkingFor.equalsIgnoreAsciiCase(sGrantee))
725 					continue;
726 
727 				if (sPrivilege.equalsIgnoreAsciiCase(sSELECT))
728 					nPrivileges |= Privilege::SELECT;
729 				else if (sPrivilege.equalsIgnoreAsciiCase(sINSERT))
730 					nPrivileges |= Privilege::INSERT;
731 				else if (sPrivilege.equalsIgnoreAsciiCase(sUPDATE))
732 					nPrivileges |= Privilege::UPDATE;
733 				else if (sPrivilege.equalsIgnoreAsciiCase(sDELETE))
734 					nPrivileges |= Privilege::DELETE;
735 				else if (sPrivilege.equalsIgnoreAsciiCase(sREAD))
736 					nPrivileges |= Privilege::READ;
737 				else if (sPrivilege.equalsIgnoreAsciiCase(sCREATE))
738 					nPrivileges |= Privilege::CREATE;
739 				else if (sPrivilege.equalsIgnoreAsciiCase(sALTER))
740 					nPrivileges |= Privilege::ALTER;
741 				else if (sPrivilege.equalsIgnoreAsciiCase(sREFERENCE))
742 					nPrivileges |= Privilege::REFERENCE;
743 				else if (sPrivilege.equalsIgnoreAsciiCase(sDROP))
744 					nPrivileges |= Privilege::DROP;
745 			}
746 		}
747 		disposeComponent(xPrivileges);
748 	}
749 	catch(const SQLException& e)
750 	{
751 		static ::rtl::OUString sNotSupportedState = ::rtl::OUString::createFromAscii("IM001");
752 		// some drivers don't support any privileges so we assume that we are allowed to do all we want :-)
753 		if(e.SQLState == sNotSupportedState)
754 			nPrivileges |=	Privilege::DROP			|
755 							Privilege::REFERENCE	|
756 							Privilege::ALTER		|
757 							Privilege::CREATE		|
758 							Privilege::READ			|
759 							Privilege::DELETE		|
760 							Privilege::UPDATE		|
761 							Privilege::INSERT		|
762 							Privilege::SELECT;
763 		else
764 			OSL_ENSURE(0,"Could not collect the privileges !");
765 	}
766 	return nPrivileges;
767 }
768 // -----------------------------------------------------------------------------
769 // we need some more information about the column
770 void collectColumnInformation(const Reference< XConnection>& _xConnection,
771 							  const ::rtl::OUString& _sComposedName,
772 							  const ::rtl::OUString& _rName,
773 							  ColumnInformationMap& _rInfo)
774 {
775 	static ::rtl::OUString STR_WHERE = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" WHERE "));
776 
777 	::rtl::OUString sSelect = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SELECT "));
778 	sSelect += _rName;
779 	sSelect += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" FROM "));
780 	sSelect += _sComposedName;
781 	sSelect += STR_WHERE;
782 	sSelect += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("0 = 1"));
783 
784 	try
785 	{
786         ::utl::SharedUNOComponent< XStatement > xStmt( _xConnection->createStatement() );
787         Reference< XPropertySet > xStatementProps( xStmt, UNO_QUERY_THROW );
788         xStatementProps->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ), makeAny( (sal_Bool)sal_False ) );
789 		Reference< XResultSet > xResult( xStmt->executeQuery( sSelect ), UNO_QUERY_THROW );
790         Reference< XResultSetMetaDataSupplier > xSuppMeta( xResult, UNO_QUERY_THROW );
791 		Reference< XResultSetMetaData > xMeta( xSuppMeta->getMetaData(), UNO_QUERY_THROW );
792 
793         sal_Int32 nCount = xMeta->getColumnCount();
794         OSL_ENSURE( nCount != 0, "::dbtools::collectColumnInformation: result set has empty (column-less) meta data!" );
795 		for (sal_Int32 i=1; i <= nCount ; ++i)
796 		{
797 			_rInfo.insert(ColumnInformationMap::value_type(xMeta->getColumnName(i),
798 				ColumnInformation(TBoolPair(xMeta->isAutoIncrement(i),xMeta->isCurrency(i)),xMeta->getColumnType(i))));
799 		}
800 	}
801     catch( const Exception& )
802     {
803     	DBG_UNHANDLED_EXCEPTION();
804     }
805 }
806 
807 // -----------------------------------------------------------------------------
808 bool isEmbeddedInDatabase( const Reference< XInterface >& _rxComponent, Reference< XConnection >& _rxActualConnection )
809 {
810     bool bIsEmbedded = false;
811 	try
812 	{
813 		Reference< XModel > xModel = lcl_getXModel( _rxComponent );
814 
815 		if ( xModel.is() )
816 		{
817 			Sequence< PropertyValue > aArgs = xModel->getArgs();
818 			const PropertyValue* pIter = aArgs.getConstArray();
819 			const PropertyValue* pEnd  = pIter + aArgs.getLength();
820 			for(;pIter != pEnd;++pIter)
821 			{
822 				if ( pIter->Name.equalsAscii("ComponentData") )
823 				{
824 					Sequence<PropertyValue> aDocumentContext;
825 					pIter->Value >>= aDocumentContext;
826 					const PropertyValue* pContextIter = aDocumentContext.getConstArray();
827 					const PropertyValue* pContextEnd  = pContextIter + aDocumentContext.getLength();
828 					for(;pContextIter != pContextEnd;++pContextIter)
829 					{
830 						if (  pContextIter->Name.equalsAscii( "ActiveConnection" )
831                         && ( pContextIter->Value >>= _rxActualConnection )
832                         )
833 						{
834                             bIsEmbedded = true;
835 							break;
836 						}
837 					}
838 					break;
839 				}
840 			}
841 		}
842 	}
843 	catch(Exception&)
844 	{
845 		// not intereseted in
846 	}
847     return bIsEmbedded;
848 }
849 // -----------------------------------------------------------------------------
850 namespace
851 {
852     ::rtl::OUString lcl_getEncodingName( rtl_TextEncoding _eEncoding )
853     {
854         ::rtl::OUString sEncodingName;
855 
856         OCharsetMap aCharsets;
857         OCharsetMap::CharsetIterator aEncodingPos = aCharsets.find( _eEncoding );
858         OSL_ENSURE( aEncodingPos != aCharsets.end(), "lcl_getEncodingName: *which* encoding?" );
859         if ( aEncodingPos != aCharsets.end() )
860             sEncodingName = (*aEncodingPos).getIanaName();
861 
862         return sEncodingName;
863     }
864 }
865 
866 // -----------------------------------------------------------------------------
867 sal_Int32 DBTypeConversion::convertUnicodeString( const ::rtl::OUString& _rSource, ::rtl::OString& _rDest, rtl_TextEncoding _eEncoding ) SAL_THROW((com::sun::star::sdbc::SQLException))
868 {
869     if ( !rtl_convertUStringToString( &_rDest.pData, _rSource.getStr(), _rSource.getLength(),
870             _eEncoding,
871             RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
872             RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
873             RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 |
874             RTL_UNICODETOTEXT_FLAGS_NOCOMPOSITE )
875         )
876     {
877         SharedResources aResources;
878         ::rtl::OUString sMessage = aResources.getResourceStringWithSubstitution( STR_CANNOT_CONVERT_STRING,
879             "$string$", _rSource,
880             "$charset$",  lcl_getEncodingName( _eEncoding )
881         );
882 
883         throw SQLException(
884             sMessage,
885             NULL,
886             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "22018" ) ),
887             22018,
888             Any()
889         );
890     }
891 
892     return _rDest.getLength();
893 }
894 
895 // -----------------------------------------------------------------------------
896 sal_Int32 DBTypeConversion::convertUnicodeStringToLength( const ::rtl::OUString& _rSource, ::rtl::OString&  _rDest,
897    sal_Int32 _nMaxLen, rtl_TextEncoding _eEncoding ) SAL_THROW((SQLException))
898 {
899     sal_Int32 nLen = convertUnicodeString( _rSource, _rDest, _eEncoding );
900     if ( nLen > _nMaxLen )
901     {
902         SharedResources aResources;
903         ::rtl::OUString sMessage = aResources.getResourceStringWithSubstitution( STR_STRING_LENGTH_EXCEEDED,
904             "$string$", _rSource,
905             "$maxlen$", ::rtl::OUString::valueOf( _nMaxLen ),
906             "$charset$", lcl_getEncodingName( _eEncoding )
907         );
908 
909         throw SQLException(
910             sMessage,
911             NULL,
912             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "22001" ) ),
913             22001,
914             Any()
915         );
916     }
917 
918    return nLen;
919 }
920 ::rtl::OUString lcl_getReportEngines()
921 {
922 	static ::rtl::OUString s_sNodeName(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.Office.DataAccess/ReportEngines"));
923 	return s_sNodeName;
924 }
925 // -----------------------------------------------------------------------------
926 ::rtl::OUString lcl_getDefaultReportEngine()
927 {
928 	static ::rtl::OUString s_sNodeName(RTL_CONSTASCII_USTRINGPARAM("DefaultReportEngine"));
929 	return s_sNodeName;
930 }
931 // -----------------------------------------------------------------------------
932 ::rtl::OUString lcl_getReportEngineNames()
933 {
934 	static ::rtl::OUString s_sNodeName(RTL_CONSTASCII_USTRINGPARAM("ReportEngineNames"));
935 	return s_sNodeName;
936 }
937 // -----------------------------------------------------------------------------
938 ::rtl::OUString getDefaultReportEngineServiceName(const Reference< XMultiServiceFactory >& _rxORB)
939 {
940 	::utl::OConfigurationTreeRoot aReportEngines = ::utl::OConfigurationTreeRoot::createWithServiceFactory(
941 		_rxORB, lcl_getReportEngines(), -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
942 
943 	if ( aReportEngines.isValid() )
944 	{
945 		::rtl::OUString sDefaultReportEngineName;
946 		aReportEngines.getNodeValue(lcl_getDefaultReportEngine()) >>= sDefaultReportEngineName;
947         if ( sDefaultReportEngineName.getLength() )
948         {
949 		    ::utl::OConfigurationNode aReportEngineNames = aReportEngines.openNode(lcl_getReportEngineNames());
950 		    if ( aReportEngineNames.isValid() )
951 		    {
952 			    ::utl::OConfigurationNode aReportEngine = aReportEngineNames.openNode(sDefaultReportEngineName);
953 			    if ( aReportEngine.isValid() )
954 			    {
955                     ::rtl::OUString sRet;
956 		            const static ::rtl::OUString s_sService(RTL_CONSTASCII_USTRINGPARAM("ServiceName"));
957 		            aReportEngine.getNodeValue(s_sService) >>= sRet;
958 				    return sRet;
959 			    }
960 		    }
961         }
962     	else
963         	return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.report.pentaho.SOReportJobFactory"));
964 	}
965     else
966         return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.report.pentaho.SOReportJobFactory"));
967 	return ::rtl::OUString();
968 }
969 // -----------------------------------------------------------------------------
970 //.........................................................................
971 }	// namespace dbtools
972 //.........................................................................
973 
974