1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * Effective License of whole file:
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
22 * The Contents of this file are made available subject to the terms of
23 * the GNU Lesser General Public License Version 2.1
25 * Copyright: 2000 by Sun Microsystems, Inc.
27 * Contributor(s): Joerg Budischewski
29 * All parts contributed on or after August 2011:
31 * This Source Code Form is subject to the terms of the Mozilla Public
32 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
35 ************************************************************************/
37 #include <sal/config.h>
39 #include <o3tl/any.hxx>
40 #include <rtl/strbuf.hxx>
41 #include <rtl/ustrbuf.hxx>
42 #include <sal/log.hxx>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/lang/XComponent.hpp>
46 #include <com/sun/star/sdbc/SQLException.hpp>
47 #include <com/sun/star/sdbc/XRow.hpp>
48 #include <com/sun/star/sdbc/XParameters.hpp>
49 #include <com/sun/star/sdbc/DataType.hpp>
50 #include <com/sun/star/sdbc/KeyRule.hpp>
51 #include <com/sun/star/sdbcx/KeyType.hpp>
52 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
54 #include "pq_xcontainer.hxx"
55 #include "pq_tools.hxx"
56 #include "pq_statics.hxx"
61 using com::sun::star::beans::XPropertySet
;
63 using com::sun::star::lang::XComponent
;
65 using com::sun::star::sdbc::SQLException
;
66 using com::sun::star::sdbc::XStatement
;
67 using com::sun::star::sdbc::XConnection
;
68 using com::sun::star::sdbc::XPreparedStatement
;
69 using com::sun::star::sdbc::XParameters
;
70 using com::sun::star::sdbc::XResultSet
;
71 using com::sun::star::sdbc::XRow
;
73 using com::sun::star::sdbcx::XColumnsSupplier
;
75 using com::sun::star::uno::UNO_QUERY
;
76 using com::sun::star::uno::UNO_QUERY_THROW
;
77 using com::sun::star::uno::Reference
;
78 using com::sun::star::uno::Sequence
;
79 using com::sun::star::uno::XInterface
;
80 using com::sun::star::uno::Any
;
81 using com::sun::star::uno::makeAny
;
83 using com::sun::star::container::XEnumeration
;
84 using com::sun::star::container::XEnumerationAccess
;
86 namespace pq_sdbc_driver
89 OUString
concatQualified( const OUString
& a
, const OUString
&b
)
91 OUStringBuffer
buf( a
.getLength() + 2 + b
.getLength() );
95 return buf
.makeStringAndClear();
98 static OString
iOUStringToOString( const OUString
& str
, ConnectionSettings
const *settings
) {
99 OSL_ENSURE(settings
, "pgsql-sdbc: OUStringToOString got NULL settings");
100 return OUStringToOString( str
, ConnectionSettings::encoding
);
103 OString
OUStringToOString( const OUString
& str
, ConnectionSettings
const *settings
) {
104 return iOUStringToOString( str
, settings
);
107 void bufferEscapeConstant( OUStringBuffer
& buf
, const OUString
& value
, ConnectionSettings
*settings
)
110 OString y
= iOUStringToOString( value
, settings
);
111 OStringBuffer
strbuf( y
.getLength() * 2 + 2 );
113 int len
= PQescapeStringConn(settings
->pConnection
, const_cast<char*>(strbuf
.getStr()), y
.getStr() , y
.getLength(), &error
);
116 char *errstr
= PQerrorMessage(settings
->pConnection
);
117 // As of PostgreSQL 9.1, the only possible errors "involve invalid multibyte encoding"
118 // According to https://www2.opengroup.org/ogsys/jsp/publications/PublicationDetails.jsp?publicationid=11216
119 // (X/Open SQL CLI, March 1995, ISBN: 1-85912-081-4, X/Open Document Number: C451)
120 // 22018 is for "Invalid character value" and seems to be the best match.
121 // We have no good XInterface Reference to pass here, so just give NULL
122 throw SQLException(OUString(errstr
, strlen(errstr
), ConnectionSettings::encoding
),
128 strbuf
.setLength( len
);
129 // Previously here RTL_TEXTENCODING_ASCII_US; as we set the PostgreSQL client_encoding to UTF8,
130 // we get UTF8 here, too. I'm not sure why it worked well before...
131 buf
.append( OStringToOUString( strbuf
.makeStringAndClear(), RTL_TEXTENCODING_UTF8
) );
134 static void ibufferQuoteConstant( OUStringBuffer
& buf
, const OUString
& value
, ConnectionSettings
*settings
)
137 bufferEscapeConstant( buf
, value
, settings
);
141 void bufferQuoteConstant( OUStringBuffer
& buf
, const OUString
& value
, ConnectionSettings
*settings
)
143 return ibufferQuoteConstant( buf
, value
, settings
);
146 void bufferQuoteAnyConstant( OUStringBuffer
& buf
, const Any
&val
, ConnectionSettings
*settings
)
152 bufferQuoteConstant( buf
, str
, settings
);
155 buf
.append( "NULL" );
158 static void ibufferQuoteIdentifier( OUStringBuffer
& buf
, const OUString
&toQuote
, ConnectionSettings
*settings
)
160 OSL_ENSURE(settings
, "pgsql-sdbc: bufferQuoteIdentifier got NULL settings");
162 OString y
= iOUStringToOString( toQuote
, settings
);
163 char *cstr
= PQescapeIdentifier(settings
->pConnection
, y
.getStr(), y
.getLength());
164 if ( cstr
== nullptr )
166 char *errstr
= PQerrorMessage(settings
->pConnection
);
167 // Implementation-defined SQLACCESS error
168 throw SQLException(OUString(errstr
, strlen(errstr
), ConnectionSettings::encoding
),
174 buf
.append( OStringToOUString( cstr
, RTL_TEXTENCODING_UTF8
) );
178 void bufferQuoteIdentifier( OUStringBuffer
& buf
, const OUString
&toQuote
, ConnectionSettings
*settings
)
180 return ibufferQuoteIdentifier(buf
, toQuote
, settings
);
184 void bufferQuoteQualifiedIdentifier(
185 OUStringBuffer
& buf
, const OUString
&schema
, const OUString
&table
, ConnectionSettings
*settings
)
187 ibufferQuoteIdentifier(buf
, schema
, settings
);
189 ibufferQuoteIdentifier(buf
, table
, settings
);
192 void bufferQuoteQualifiedIdentifier(
193 OUStringBuffer
& buf
,
194 const OUString
&schema
,
195 const OUString
&table
,
197 ConnectionSettings
*settings
)
199 ibufferQuoteIdentifier(buf
, schema
, settings
);
201 ibufferQuoteIdentifier(buf
, table
, settings
);
203 ibufferQuoteIdentifier(buf
, col
, settings
);
207 OUString
extractStringProperty(
208 const Reference
< XPropertySet
> & descriptor
, const OUString
&name
)
211 descriptor
->getPropertyValue( name
) >>= value
;
215 bool extractBoolProperty(
216 const Reference
< XPropertySet
> & descriptor
, const OUString
&name
)
219 descriptor
->getPropertyValue( name
) >>= value
;
223 sal_Int32
extractIntProperty(
224 const Reference
< XPropertySet
> & descriptor
, const OUString
&name
)
227 descriptor
->getPropertyValue( name
) >>= ret
;
231 void disposeObject( const css::uno::Reference
< css::uno::XInterface
> & r
)
233 Reference
< XComponent
> comp( r
, UNO_QUERY
);
238 void disposeNoThrow( const css::uno::Reference
< css::uno::XInterface
> & r
)
244 catch( SQLException
& )
251 Reference
< XConnection
> extractConnectionFromStatement( const Reference
< XInterface
> & stmt
)
253 Reference
< XConnection
> ret
;
255 Reference
< css::sdbc::XStatement
> owner( stmt
, UNO_QUERY
);
257 ret
= owner
->getConnection();
260 Reference
< css::sdbc::XPreparedStatement
> myowner( stmt
, UNO_QUERY
);
262 ret
= myowner
->getConnection();
265 "PQSDBC: Couldn't retrieve connection from statement",
266 Reference
< XInterface
> () , OUString(), 0 , css::uno::Any() );
273 DisposeGuard::DisposeGuard( const Reference
< XInterface
> & r
)
277 DisposeGuard::~DisposeGuard()
282 TransactionGuard::TransactionGuard( const Reference
< XStatement
> &stmt
)
286 m_stmt
->executeUpdate( getStatics().BEGIN
);
289 void TransactionGuard::commit()
291 m_stmt
->executeUpdate( getStatics().COMMIT
);
295 void TransactionGuard::executeUpdate( const OUString
& sql
)
297 m_stmt
->executeUpdate( sql
);
300 TransactionGuard::~TransactionGuard()
305 m_stmt
->executeUpdate( getStatics().ROLLBACK
);
307 catch( css::uno::Exception
& )
309 // ignore, we are within a dtor
312 disposeNoThrow( m_stmt
);
316 bool isWhitespace( sal_Unicode c
)
318 return ' ' == c
|| 9 == c
|| 10 == c
|| 13 == c
;
321 OUString
extractTableFromInsert( const OUString
& sql
)
325 while (i
< sql
.getLength() && isWhitespace(sql
[i
])) { i
++; }
327 if( sql
.matchIgnoreAsciiCase("insert", i
) )
330 while (i
< sql
.getLength() && isWhitespace(sql
[i
])) { i
++; }
331 if( sql
.matchIgnoreAsciiCase("into", i
) )
334 while (i
< sql
.getLength() && isWhitespace(sql
[i
])) { i
++; }
336 bool quote
= (sql
[i
] == '"');
337 for( i
++ ; i
< sql
.getLength() ; i
++ )
339 if( quote
&& sql
[i
] == '"' )
341 while (i
< sql
.getLength() && isWhitespace(sql
[i
])) { i
++; }
344 while (i
< sql
.getLength() && isWhitespace(sql
[i
])) { i
++; }
347 // the second part of the table name does not use quotes
354 // end quoted name, ok
360 if( isWhitespace( sql
[i
] ) )
362 // found the end of an unquoted name
367 ret
= sql
.copy(start
, i
- start
).trim();
368 // printf( "pq_statement: parsed table name %s from insert\n" ,
369 // OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US).getStr() );
376 static bool isOperator( char c
)
407 void splitSQL( const OString
& sql
, std::vector
< OString
> &vec
)
409 int length
= sql
.getLength();
412 bool singleQuote
= false;
413 bool doubleQuote
= false;
415 for( ; i
< length
; i
++ )
422 vec
.push_back( OString( &sql
.getStr()[start
], i
-start
+1 ) );
427 else if( singleQuote
)
429 if( '\'' == c
&& (i
+1) < length
&& '\'' == sql
[i
+1] )
431 // two subsequent single quotes within a quoted string
432 // mean a single quote within the string
437 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
+1 ) );
438 start
= i
+ 1; // leave single quotes !
446 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
452 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
459 vec
.push_back( OString( &sql
.getStr()[start
] , i
- start
) );
461 // for( i = 0 ; i < vec.size() ; i ++ )
462 // printf( "%s!" , vec[i].getStr() );
467 void tokenizeSQL( const OString
& sql
, std::vector
< OString
> &vec
)
469 int length
= sql
.getLength();
472 bool singleQuote
= false;
473 bool doubleQuote
= false;
475 for( ; i
< length
; i
++ )
482 vec
.push_back( OString( &sql
.getStr()[start
], i
-start
) );
487 else if( singleQuote
)
491 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
+1 ) );
492 start
= i
+ 1; // leave single quotes !
501 start
= i
+1; // skip double quotes !
506 start
= i
; // leave single quotes
508 else if( isWhitespace( c
) )
511 start
++; // skip additional whitespace
514 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
518 else if( ',' == c
|| isOperator( c
) || '(' == c
|| ')' == c
)
521 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
522 vec
.push_back( OString( &sql
.getStr()[i
], 1 ) );
527 if( ( i
> start
&& sql
[start
] >= '0' && sql
[start
] <= '9' ) ||
528 ( i
== start
&& i
> 1 && isWhitespace( sql
[i
-1] ) ) )
530 // ignore, is a literal
535 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
536 vec
.push_back( OString( "." ) );
543 vec
.push_back( OString( &sql
.getStr()[start
] , i
- start
) );
545 // for( i = 0 ; i < vec.size() ; i ++ )
546 // printf( "%s!" , vec[i].getStr() );
551 void splitConcatenatedIdentifier( const OUString
& source
, OUString
*first
, OUString
*second
)
553 std::vector
< OString
> vec
;
554 tokenizeSQL( OUStringToOString( source
, RTL_TEXTENCODING_UTF8
), vec
);
559 *second
= OStringToOUString( vec
[0], RTL_TEXTENCODING_UTF8
);
562 *first
= OStringToOUString( vec
[0], RTL_TEXTENCODING_UTF8
);
563 *second
= OStringToOUString( vec
[2], RTL_TEXTENCODING_UTF8
);
566 SAL_WARN("connectivity.postgresql",
567 "pq_tools::splitConcatenatedIdentifier unexpected number of tokens in identifier: "
572 OUString
array2String( const css::uno::Sequence
< Any
> &seq
)
574 OUStringBuffer
buf(128);
575 int len
= seq
.getLength();
577 for( int i
= 0 ; i
< len
; i
++ )
584 int strLength
= element
.getLength();
586 for( int j
= 0 ; j
< strLength
; j
++ )
588 sal_Unicode c
= element
[j
];
589 if( c
== '\\' || c
== '"' || c
== '{' || c
== '}' )
598 return buf
.makeStringAndClear();
602 std::vector
< Any
> parseArray( const OUString
& str
)
604 int len
= str
.getLength();
605 bool doubleQuote
= false;
609 OUStringBuffer current
;
610 std::vector
<Any
> elements
;
611 bool doubleQuotedValue
= false;
614 sal_Unicode c
= str
[i
];
615 sal_Unicode cnext
= str
[i
+1];
621 current
.append( cnext
);
626 doubleQuotedValue
= true; // signal, that there was an empty element
643 "error during array parsing, didn't expect a } at position "
644 + OUString::number(i
) + " ('" + str
+ "')",
645 Reference
< XInterface
> (), OUString(), 1, Any() );
649 if( !current
.isEmpty() || doubleQuotedValue
)
650 elements
.push_back( makeAny( current
.makeStringAndClear() ) );
659 // if( current.getLength() != 0 )
661 // OUStringBuffer buf;
662 // buf.appendAscii( "error during array parsing, didn't expect a \" at position " );
664 // buf.append( " ('" );
665 // buf.append( str );
666 // buf.append( "')" );
667 // throw SDBCException(
668 // buf.makeStringAndClear(),
669 // Reference< XInterface > (), 1, Any() );
676 else if( ',' == c
&& brackets
== 1)
678 doubleQuotedValue
= false;
679 elements
.push_back( makeAny( current
.makeStringAndClear() ) );
681 else if( isWhitespace( c
) )
683 // ignore whitespace without quotes
694 std::vector
< sal_Int32
> parseIntArray( const OUString
& str
)
697 std::vector
<sal_Int32
> vec
;
698 // printf( ">%s<\n" , OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
699 for( sal_Int32 i
= str
.indexOf( ' ' ) ; i
!= -1 ; i
= str
.indexOf( ' ', start
) )
701 vec
.push_back( rtl_ustr_toInt32( &str
.pData
->buffer
[start
], 10 ) );
702 // printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
705 vec
.push_back( rtl_ustr_toInt32( &str
.pData
->buffer
[start
], 10 ) );
706 // printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
710 void fillAttnum2attnameMap(
712 const Reference
< css::sdbc::XConnection
> &conn
,
713 const OUString
&schema
,
714 const OUString
&table
)
716 Reference
< XPreparedStatement
> prep
= conn
->prepareStatement(
717 "SELECT attname,attnum "
719 "INNER JOIN pg_class ON attrelid = pg_class.oid "
720 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
721 "WHERE relname=? AND nspname=?" );
723 Reference
< XParameters
> paras( prep
, UNO_QUERY_THROW
);
724 paras
->setString( 1 , table
);
725 paras
->setString( 2 , schema
);
726 Reference
< XResultSet
> rs
= prep
->executeQuery();
728 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
731 map
[ xRow
->getInt(2) ] = xRow
->getString(1);
735 OString
extractSingleTableFromSelect( const std::vector
< OString
> &vec
)
739 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
740 vec
[0].pData
->buffer
, vec
[0].pData
->length
, "select" , 6 , 6 ) )
744 for( token
= 1; token
< vec
.size() ; token
++ )
746 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
747 vec
[token
].getStr(), vec
[token
].getLength(), "from" , 4 , 4 ) )
755 if( token
< vec
.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
756 vec
[token
].pData
->buffer
, vec
[token
].pData
->length
, "only " , 4 , 4 ) )
761 if( token
< vec
.size() && vec
[token
] != "(" )
763 // it is a table or a function name
764 OStringBuffer
buf(128);
765 if( '"' == vec
[token
][0] )
766 buf
.append( &(vec
[token
].getStr()[1]) , vec
[token
].getLength() -2 );
768 buf
.append( vec
[token
] );
771 if( token
< vec
.size() )
773 if( vec
[token
] == "." )
775 buf
.append( vec
[token
] );
777 if( token
< vec
.size() )
779 if( '"' == vec
[token
][0] )
780 buf
.append( &(vec
[token
].getStr()[1]) , vec
[token
].getLength() -2 );
782 buf
.append( vec
[token
] );
788 ret
= buf
.makeStringAndClear();
789 // now got my table candidate
791 if( token
< vec
.size() && vec
[token
] == "(" )
793 // whoops, it is a function
798 if( token
< vec
.size() )
800 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
801 vec
[token
].pData
->buffer
, vec
[token
].pData
->length
, "as" , 2, 2 ) )
803 token
+= 2; // skip alias
807 if( token
< vec
.size() )
809 if( vec
[token
] == "," )
811 // whoops, multiple tables are used
816 static const char * forbiddenKeywords
[] =
817 { "join", "natural", "outer", "inner", "left", "right", "full" , nullptr };
818 for( int i
= 0 ; forbiddenKeywords
[i
] ; i
++ )
820 size_t nKeywordLen
= strlen(forbiddenKeywords
[i
]);
821 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
822 vec
[token
].pData
->buffer
, vec
[token
].pData
->length
,
823 forbiddenKeywords
[i
], nKeywordLen
,
826 // whoops, it is a join
839 css::uno::Sequence
< sal_Int32
> string2intarray( const OUString
& str
)
841 css::uno::Sequence
< sal_Int32
> ret
;
842 const sal_Int32 strlen
= str
.getLength();
843 if( str
.getLength() > 1 )
847 while ( iswspace( (c
=str
.iterateCodePoints(&start
)) ) )
848 if ( start
== strlen
)
852 while ( iswspace( c
=str
.iterateCodePoints(&start
) ) )
853 if ( start
== strlen
)
858 std::vector
< sal_Int32
> vec
;
861 OUStringBuffer digits
;
866 if ( start
== strlen
)
868 c
=str
.iterateCodePoints(&start
);
874 if ( start
== strlen
)
876 digits
.append(OUString(&c
, 1));
877 c
= str
.iterateCodePoints(&start
);
879 vec
.push_back( digits
.makeStringAndClear().toInt32() );
884 if ( start
== strlen
)
886 c
= str
.iterateCodePoints(&start
);
890 if ( str
.iterateCodePoints(&start
) != L
',' )
892 if ( start
== strlen
)
895 // vec is guaranteed non-empty
896 assert(vec
.size() > 0);
897 ret
= css::uno::Sequence
< sal_Int32
> ( vec
.data() , vec
.size() );
903 Sequence
< OUString
> convertMappedIntArray2StringArray(
904 const Int2StringMap
&map
, const Sequence
< sal_Int32
> &intArray
)
906 Sequence
< OUString
> ret( intArray
.getLength() );
907 for( int i
= 0; i
< intArray
.getLength() ; i
++ )
909 Int2StringMap::const_iterator ii
= map
.find( intArray
[i
] );
910 if( ii
!= map
.end() )
917 OUString
sqltype2string( const Reference
< XPropertySet
> & desc
)
919 OUStringBuffer typeName
;
920 typeName
.append( extractStringProperty( desc
, getStatics().TYPE_NAME
) );
921 sal_Int32 precision
= extractIntProperty( desc
, getStatics().PRECISION
);
925 switch( extractIntProperty( desc
, getStatics().TYPE
) )
927 case css::sdbc::DataType::VARBINARY
:
928 case css::sdbc::DataType::VARCHAR
:
929 case css::sdbc::DataType::CHAR
:
931 typeName
.append( "(" );
932 typeName
.append( precision
);
933 typeName
.append( ")" );
936 case css::sdbc::DataType::DECIMAL
:
937 case css::sdbc::DataType::NUMERIC
:
939 typeName
.append( "(" );
940 typeName
.append( precision
);
941 typeName
.append( "," );
942 typeName
.append( extractIntProperty( desc
, getStatics().SCALE
) );
943 typeName
.append( ")" );
950 return typeName
.makeStringAndClear();
954 static void keyType2String( OUStringBuffer
& buf
, sal_Int32 keyType
)
956 if( css::sdbc::KeyRule::CASCADE
== keyType
)
958 buf
.append( "CASCADE " );
960 else if( css::sdbc::KeyRule::RESTRICT
== keyType
)
962 buf
.append( "RESTRICT " );
964 else if( css::sdbc::KeyRule::SET_DEFAULT
== keyType
)
966 buf
.append( "SET DEFAULT " );
968 else if( css::sdbc::KeyRule::SET_NULL
== keyType
)
970 buf
.append( "SET NULL " );
972 else //if( css::sdbc::KeyRule::NO_ACTION == keyType )
974 buf
.append( "NO ACTION " );
978 void bufferKey2TableConstraint(
979 OUStringBuffer
&buf
, const Reference
< XPropertySet
> &key
, ConnectionSettings
*settings
)
981 Statics
&st
= getStatics();
982 sal_Int32 type
= extractIntProperty( key
, st
.TYPE
);
983 OUString referencedTable
= extractStringProperty( key
, st
.REFERENCED_TABLE
);
984 sal_Int32 updateRule
= extractIntProperty( key
, st
.UPDATE_RULE
);
985 sal_Int32 deleteRule
= extractIntProperty( key
, st
.DELETE_RULE
);
986 bool foreign
= false;
987 if( type
== css::sdbcx::KeyType::UNIQUE
)
989 buf
.append( "UNIQUE( " );
991 else if( type
== css::sdbcx::KeyType::PRIMARY
)
993 buf
.append( "PRIMARY KEY( " );
995 else if( type
== css::sdbcx::KeyType::FOREIGN
)
998 buf
.append( "FOREIGN KEY( " );
1001 Reference
< XColumnsSupplier
> columns( key
, UNO_QUERY
);
1004 Reference
< XEnumerationAccess
> colEnumAccess( columns
->getColumns(), UNO_QUERY
);
1005 if( colEnumAccess
.is() )
1007 Reference
< XEnumeration
> colEnum
= colEnumAccess
->createEnumeration();
1009 while(colEnum
.is() && colEnum
->hasMoreElements() )
1019 Reference
< XPropertySet
> keyColumn( colEnum
->nextElement(), UNO_QUERY_THROW
);
1020 bufferQuoteIdentifier(buf
, extractStringProperty( keyColumn
, st
.NAME
), settings
);
1028 buf
.append( "REFERENCES " );
1031 splitConcatenatedIdentifier( referencedTable
, &schema
, &tableName
);
1032 bufferQuoteQualifiedIdentifier(buf
, schema
, tableName
, settings
);
1035 Reference
< XEnumerationAccess
> colEnumAccess( columns
->getColumns(), UNO_QUERY
);
1036 if( colEnumAccess
.is() )
1039 Reference
< XEnumeration
> colEnum(colEnumAccess
->createEnumeration());
1041 while(colEnum
.is() && colEnum
->hasMoreElements() )
1051 Reference
< XPropertySet
> keyColumn( colEnum
->nextElement(), UNO_QUERY_THROW
);
1052 bufferQuoteIdentifier(
1053 buf
, extractStringProperty( keyColumn
, st
.RELATED_COLUMN
), settings
);
1059 buf
.append( "ON DELETE " );
1060 keyType2String( buf
, deleteRule
);
1061 buf
.append( " ON UPDATE " );
1062 keyType2String( buf
, updateRule
);
1067 void extractNameValuePairsFromInsert( String2StringMap
& map
, const OString
& lastQuery
)
1069 std::vector
< OString
> vec
;
1070 tokenizeSQL( lastQuery
, vec
);
1072 int nSize
= vec
.size();
1073 // printf( "1 %d\n", nSize );
1075 vec
[0].equalsIgnoreAsciiCase( "insert" ) &&
1076 vec
[1].equalsIgnoreAsciiCase( "into" ) )
1080 // printf( "1a\n" );
1082 if( vec
[n
+1].equalsIgnoreAsciiCase( "." ) )
1088 if( vec
[n
].equalsIgnoreAsciiCase( "(" ) )
1090 std::vector
< OString
> names
;
1094 while( nSize
> n
&& ! vec
[n
].equalsIgnoreAsciiCase( ")" ) )
1096 names
.push_back( vec
[n
] );
1097 if( nSize
> n
+1 && vec
[n
+1].equalsIgnoreAsciiCase( "," ) )
1105 // now read the values
1106 if( nSize
> n
+1 && vec
[n
].equalsIgnoreAsciiCase("VALUES") &&
1107 vec
[n
+1].equalsIgnoreAsciiCase( "(" ) )
1111 for (auto& name
: names
)
1117 if( nSize
> n
+1 && vec
[n
+1].equalsIgnoreAsciiCase(",") )
1128 OUString
querySingleValue(
1129 const css::uno::Reference
< css::sdbc::XConnection
> &connection
,
1130 const OUString
&query
)
1133 Reference
< XStatement
> stmt
= connection
->createStatement();
1134 DisposeGuard
guard( stmt
);
1135 Reference
< XResultSet
> rs
= stmt
->executeQuery( query
);
1136 Reference
< XRow
> xRow( rs
, UNO_QUERY
);
1138 ret
= xRow
->getString( 1 );
1143 // copied from connectivity/source/dbtools, can't use the function directly
1144 bool implSetObject( const Reference
< XParameters
>& _rxParameters
,
1145 const sal_Int32 _nColumnIndex
, const Any
& _rValue
)
1147 bool bSuccessfullyReRouted
= true;
1148 switch (_rValue
.getValueTypeClass())
1150 case css::uno::TypeClass_HYPER
:
1152 _rxParameters
->setLong( _nColumnIndex
, sal_Int64(0) );
1156 case css::uno::TypeClass_VOID
:
1157 _rxParameters
->setNull(_nColumnIndex
,css::sdbc::DataType::VARCHAR
);
1160 case css::uno::TypeClass_STRING
:
1161 _rxParameters
->setString(_nColumnIndex
, *o3tl::forceAccess
<OUString
>(_rValue
));
1164 case css::uno::TypeClass_BOOLEAN
:
1165 _rxParameters
->setBoolean(_nColumnIndex
, *o3tl::forceAccess
<bool>(_rValue
));
1168 case css::uno::TypeClass_BYTE
:
1169 _rxParameters
->setByte(_nColumnIndex
, *o3tl::forceAccess
<sal_Int8
>(_rValue
));
1172 case css::uno::TypeClass_UNSIGNED_SHORT
:
1173 case css::uno::TypeClass_SHORT
:
1174 _rxParameters
->setShort(_nColumnIndex
, *o3tl::forceAccess
<sal_Int16
>(_rValue
));
1177 case css::uno::TypeClass_CHAR
:
1178 _rxParameters
->setString(_nColumnIndex
, OUString(*o3tl::forceAccess
<sal_Unicode
>(_rValue
)));
1181 case css::uno::TypeClass_UNSIGNED_LONG
:
1182 case css::uno::TypeClass_LONG
:
1183 _rxParameters
->setInt(_nColumnIndex
, *o3tl::forceAccess
<sal_Int32
>(_rValue
));
1186 case css::uno::TypeClass_FLOAT
:
1187 _rxParameters
->setFloat(_nColumnIndex
, *o3tl::forceAccess
<float>(_rValue
));
1190 case css::uno::TypeClass_DOUBLE
:
1191 _rxParameters
->setDouble(_nColumnIndex
, *o3tl::forceAccess
<double>(_rValue
));
1194 case css::uno::TypeClass_SEQUENCE
:
1195 if (auto s
= o3tl::tryAccess
<Sequence
< sal_Int8
>>(_rValue
))
1197 _rxParameters
->setBytes(_nColumnIndex
, *s
);
1200 bSuccessfullyReRouted
= false;
1202 case css::uno::TypeClass_STRUCT
:
1203 if (auto s1
= o3tl::tryAccess
<css::util::DateTime
>(_rValue
))
1204 _rxParameters
->setTimestamp(_nColumnIndex
, *s1
);
1205 else if (auto s2
= o3tl::tryAccess
<css::util::Date
>(_rValue
))
1206 _rxParameters
->setDate(_nColumnIndex
, *s2
);
1207 else if (auto s3
= o3tl::tryAccess
<css::util::Time
>(_rValue
))
1208 _rxParameters
->setTime(_nColumnIndex
, *s3
);
1210 bSuccessfullyReRouted
= false;
1213 case css::uno::TypeClass_INTERFACE
:
1215 Reference
< css::io::XInputStream
> xStream
;
1216 if (_rValue
>>= xStream
)
1218 _rValue
>>= xStream
;
1219 _rxParameters
->setBinaryStream(_nColumnIndex
, xStream
, xStream
->available());
1225 bSuccessfullyReRouted
= false;
1229 return bSuccessfullyReRouted
;
1234 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */