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