Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*************************************************************************
3 : *
4 : * Effective License of whole file:
5 : *
6 : * This library is free software; you can redistribute it and/or
7 : * modify it under the terms of the GNU Lesser General Public
8 : * License version 2.1, as published by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18 : * MA 02111-1307 USA
19 : *
20 : * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
21 : *
22 : * The Contents of this file are made available subject to the terms of
23 : * the GNU Lesser General Public License Version 2.1
24 : *
25 : * Copyright: 2000 by Sun Microsystems, Inc.
26 : *
27 : * Contributor(s): Joerg Budischewski
28 : *
29 : * All parts contributed on or after August 2011:
30 : *
31 : * This Source Code Form is subject to the terms of the Mozilla Public
32 : * License, v. 2.0. If a copy of the MPL was not distributed with this
33 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
34 : *
35 : ************************************************************************/
36 :
37 : #include <rtl/strbuf.hxx>
38 : #include <rtl/ustrbuf.hxx>
39 :
40 : #include <com/sun/star/beans/XPropertySet.hpp>
41 : #include <com/sun/star/lang/XComponent.hpp>
42 :
43 : #include <com/sun/star/sdbc/XRow.hpp>
44 : #include <com/sun/star/sdbc/XParameters.hpp>
45 : #include <com/sun/star/sdbc/DataType.hpp>
46 : #include <com/sun/star/sdbc/KeyRule.hpp>
47 : #include <com/sun/star/sdbcx/KeyType.hpp>
48 : #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
49 :
50 : #include "pq_xcontainer.hxx"
51 : #include "pq_tools.hxx"
52 : #include "pq_statics.hxx"
53 :
54 : #include <libpq-fe.h>
55 : #include <string.h>
56 :
57 : using com::sun::star::beans::XPropertySet;
58 :
59 : using com::sun::star::lang::XComponent;
60 :
61 : using com::sun::star::sdbc::SQLException;
62 : using com::sun::star::sdbc::XStatement;
63 : using com::sun::star::sdbc::XConnection;
64 : using com::sun::star::sdbc::XPreparedStatement;
65 : using com::sun::star::sdbc::XParameters;
66 : using com::sun::star::sdbc::XResultSet;
67 : using com::sun::star::sdbc::XRow;
68 :
69 : using com::sun::star::sdbcx::XColumnsSupplier;
70 :
71 : using com::sun::star::uno::RuntimeException;
72 : using com::sun::star::uno::UNO_QUERY;
73 : using com::sun::star::uno::UNO_QUERY_THROW;
74 : using com::sun::star::uno::Reference;
75 : using com::sun::star::uno::Sequence;
76 : using com::sun::star::uno::XInterface;
77 : using com::sun::star::uno::Any;
78 : using com::sun::star::uno::makeAny;
79 :
80 : using com::sun::star::container::XEnumeration;
81 : using com::sun::star::container::XEnumerationAccess;
82 :
83 : namespace pq_sdbc_driver
84 : {
85 :
86 0 : OUString concatQualified( const OUString & a, const OUString &b)
87 : {
88 0 : OUStringBuffer buf( a.getLength() + 2 + b.getLength() );
89 0 : buf.append( a );
90 0 : buf.append( "." );
91 0 : buf.append( b );
92 0 : return buf.makeStringAndClear();
93 : }
94 :
95 0 : static inline OString iOUStringToOString( const OUString& str, ConnectionSettings *settings) {
96 : OSL_ENSURE(settings, "pgsql-sdbc: OUStringToOString got NULL settings");
97 0 : return OUStringToOString( str, settings->encoding );
98 : }
99 :
100 0 : OString OUStringToOString( const OUString& str, ConnectionSettings *settings) {
101 0 : return iOUStringToOString( str, settings );
102 : }
103 :
104 0 : void bufferEscapeConstant( OUStringBuffer & buf, const OUString & value, ConnectionSettings *settings )
105 : {
106 :
107 0 : OString y = iOUStringToOString( value, settings );
108 0 : OStringBuffer strbuf( y.getLength() * 2 + 2 );
109 : int error;
110 0 : int len = PQescapeStringConn(settings->pConnection, ((char*)strbuf.getStr()), y.getStr() , y.getLength(), &error );
111 0 : if ( error )
112 : {
113 0 : char *errstr = PQerrorMessage(settings->pConnection);
114 : // As of PostgreSQL 9.1, the only possible errors "involve invalid multibyte encoding"
115 : // According to https://www2.opengroup.org/ogsys/jsp/publications/PublicationDetails.jsp?publicationid=11216
116 : // (X/Open SQL CLI, March 1995, ISBN: 1-85912-081-4, X/Open Document Number: C451)
117 : // 22018 is for "Invalid character value" and seems to be the best match.
118 : // We have no good XInterface Reference to pass here, so just give NULL
119 0 : throw SQLException(OUString(errstr, strlen(errstr), settings->encoding),
120 : NULL,
121 : OUString("22018"),
122 : -1,
123 0 : Any());
124 : }
125 0 : strbuf.setLength( len );
126 : // Previously here RTL_TEXTENCODING_ASCII_US; as we set the PostgreSQL client_encoding to UTF8,
127 : // we get UTF8 here, too. I'm not sure why it worked well before...
128 0 : buf.append( OStringToOUString( strbuf.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ) );
129 0 : }
130 :
131 0 : static inline void ibufferQuoteConstant( OUStringBuffer & buf, const OUString & value, ConnectionSettings *settings )
132 : {
133 0 : buf.append( "'" );
134 0 : bufferEscapeConstant( buf, value, settings );
135 0 : buf.append( "'" );
136 0 : }
137 :
138 0 : void bufferQuoteConstant( OUStringBuffer & buf, const OUString & value, ConnectionSettings *settings )
139 : {
140 0 : return ibufferQuoteConstant( buf, value, settings );
141 : }
142 :
143 0 : void bufferQuoteAnyConstant( OUStringBuffer & buf, const Any &val, ConnectionSettings *settings )
144 : {
145 0 : if( val.hasValue() )
146 : {
147 0 : OUString str;
148 0 : val >>= str;
149 0 : bufferQuoteConstant( buf, str, settings );
150 : }
151 : else
152 0 : buf.append( "NULL" );
153 0 : }
154 :
155 0 : static inline void ibufferQuoteIdentifier( OUStringBuffer & buf, const OUString &toQuote, ConnectionSettings *settings )
156 : {
157 : OSL_ENSURE(settings, "pgsql-sdbc: bufferQuoteIdentifier got NULL settings");
158 :
159 0 : OString y = iOUStringToOString( toQuote, settings );
160 0 : char *cstr = PQescapeIdentifier(settings->pConnection, y.getStr(), y.getLength());
161 0 : if ( cstr == NULL )
162 : {
163 0 : char *errstr = PQerrorMessage(settings->pConnection);
164 : // Implementation-defined SQLACCESS error
165 0 : throw SQLException(OUString(errstr, strlen(errstr), settings->encoding),
166 : NULL,
167 : OUString("22018"),
168 : -1,
169 0 : Any());
170 : }
171 0 : buf.append( OStringToOUString( cstr, RTL_TEXTENCODING_UTF8 ) );
172 0 : PQfreemem( cstr );
173 0 : }
174 :
175 0 : void bufferQuoteIdentifier( OUStringBuffer & buf, const OUString &toQuote, ConnectionSettings *settings )
176 : {
177 0 : return ibufferQuoteIdentifier(buf, toQuote, settings);
178 : }
179 :
180 :
181 0 : void bufferQuoteQualifiedIdentifier(
182 : OUStringBuffer & buf, const OUString &schema, const OUString &table, ConnectionSettings *settings )
183 : {
184 0 : ibufferQuoteIdentifier(buf, schema, settings);
185 0 : buf.append( "." );
186 0 : ibufferQuoteIdentifier(buf, table, settings);
187 0 : }
188 :
189 0 : void bufferQuoteQualifiedIdentifier(
190 : OUStringBuffer & buf,
191 : const OUString &schema,
192 : const OUString &table,
193 : const OUString &col,
194 : ConnectionSettings *settings)
195 : {
196 0 : ibufferQuoteIdentifier(buf, schema, settings);
197 0 : buf.append( "." );
198 0 : ibufferQuoteIdentifier(buf, table, settings);
199 0 : buf.append( "." );
200 0 : ibufferQuoteIdentifier(buf, col, settings);
201 0 : }
202 :
203 :
204 0 : OUString extractStringProperty(
205 : const Reference< XPropertySet > & descriptor, const OUString &name )
206 : {
207 0 : OUString value;
208 0 : descriptor->getPropertyValue( name ) >>= value;
209 0 : return value;
210 : }
211 :
212 0 : sal_Bool extractBoolProperty(
213 : const Reference< XPropertySet > & descriptor, const OUString &name )
214 : {
215 0 : sal_Bool value = sal_False;
216 0 : descriptor->getPropertyValue( name ) >>= value;
217 0 : return value;
218 : }
219 :
220 0 : sal_Int32 extractIntProperty(
221 : const Reference< XPropertySet > & descriptor, const OUString &name )
222 : {
223 0 : sal_Int32 ret = 0;
224 0 : descriptor->getPropertyValue( name ) >>= ret;
225 0 : return ret;
226 : }
227 :
228 0 : void disposeObject( const com::sun::star::uno::Reference< com::sun::star::uno::XInterface > & r )
229 : {
230 0 : Reference< XComponent > comp( r, UNO_QUERY );
231 0 : if( comp.is() )
232 0 : comp->dispose();
233 0 : }
234 :
235 0 : void disposeNoThrow( const com::sun::star::uno::Reference< com::sun::star::uno::XInterface > & r )
236 : {
237 : try
238 : {
239 0 : disposeObject( r );
240 : }
241 0 : catch( SQLException & )
242 : {
243 : // ignore this
244 : }
245 :
246 0 : }
247 :
248 0 : Reference< XConnection > extractConnectionFromStatement( const Reference< XInterface > & stmt )
249 : {
250 0 : Reference< XConnection > ret;
251 :
252 0 : Reference< com::sun::star::sdbc::XStatement > owner( stmt, UNO_QUERY );
253 0 : if( owner.is() )
254 0 : ret = owner->getConnection();
255 : else
256 : {
257 0 : Reference< com::sun::star::sdbc::XPreparedStatement > myowner( stmt, UNO_QUERY );
258 0 : if( myowner.is() )
259 0 : ret = myowner->getConnection();
260 0 : if( ! ret.is() )
261 : throw SQLException(
262 : "PQSDBC: Couldn't retrieve connection from statement",
263 0 : Reference< XInterface > () , OUString(), 0 , com::sun::star::uno::Any() );
264 : }
265 :
266 0 : return ret;
267 :
268 : }
269 :
270 0 : DisposeGuard::DisposeGuard( const Reference< XInterface > & r )
271 0 : : d( r )
272 0 : {}
273 :
274 0 : DisposeGuard::~DisposeGuard()
275 : {
276 0 : disposeNoThrow( d );
277 0 : }
278 :
279 0 : TransactionGuard::TransactionGuard( const Reference< XStatement > &stmt )
280 : : m_stmt( stmt ),
281 0 : m_commited( sal_False )
282 : {
283 0 : m_stmt->executeUpdate( getStatics().BEGIN );
284 0 : }
285 :
286 0 : void TransactionGuard::commit()
287 : {
288 0 : m_stmt->executeUpdate( getStatics().COMMIT );
289 0 : m_commited = sal_True;
290 0 : }
291 :
292 0 : void TransactionGuard::executeUpdate( const OUString & sql )
293 : {
294 0 : m_stmt->executeUpdate( sql );
295 0 : }
296 :
297 0 : TransactionGuard::~TransactionGuard()
298 : {
299 : try
300 : {
301 0 : if( ! m_commited )
302 0 : m_stmt->executeUpdate( getStatics().ROLLBACK );
303 : }
304 0 : catch( com::sun::star::uno::Exception & )
305 : {
306 : // ignore, we are within a dtor
307 : }
308 :
309 0 : disposeNoThrow( m_stmt );
310 0 : }
311 :
312 :
313 0 : bool isWhitespace( sal_Unicode c )
314 : {
315 0 : return ' ' == c || 9 == c || 10 == c || 13 == c;
316 : }
317 :
318 0 : OUString extractTableFromInsert( const OUString & sql )
319 : {
320 0 : OUString ret;
321 0 : int i = 0;
322 0 : while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
323 :
324 0 : if( sql.matchIgnoreAsciiCase("insert", i) )
325 : {
326 0 : i += 6;
327 0 : while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
328 0 : if( sql.matchIgnoreAsciiCase("into", i) )
329 : {
330 0 : i +=4;
331 0 : while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
332 0 : int start = i;
333 0 : bool quote = (sql[i] == '"');
334 0 : for( i++ ; i < sql.getLength() ; i ++ )
335 : {
336 0 : if( quote && sql[i] == '"' )
337 : {
338 0 : while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
339 0 : if( '.' == sql[i] )
340 : {
341 0 : while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
342 0 : if( '"' == sql[i] )
343 : {
344 : // the second part of the table name does not use quotes
345 : // parse on
346 0 : quote = false;
347 : }
348 : }
349 : else
350 : {
351 : // end quoted name, ok
352 0 : break;
353 : }
354 : }
355 : else
356 : {
357 0 : if( isWhitespace( sql[i] ) )
358 : {
359 : // found the end of an unquoted name
360 0 : break;
361 : }
362 : }
363 : }
364 0 : ret = sql.copy(start, i - start ).trim();
365 : // printf( "pq_statement: parsed table name %s from insert\n" ,
366 : // OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US).getStr() );
367 : }
368 : }
369 0 : return ret;
370 : }
371 :
372 :
373 0 : static bool isOperator( char c )
374 : {
375 : bool ret;
376 0 : switch(c)
377 : {
378 : case '+':
379 : case '-':
380 : case '*':
381 : case '/':
382 : case '<':
383 : case '>':
384 : case '=':
385 : case '~':
386 : case '!':
387 : case '@':
388 : case '#':
389 : case '%':
390 : case '^':
391 : case '&':
392 : case '|':
393 : case '`':
394 : case '?':
395 : case '$':
396 0 : ret = true;
397 0 : break;
398 : default:
399 0 : ret = false;
400 : }
401 0 : return ret;
402 : }
403 :
404 0 : void splitSQL( const OString & sql, OStringVector &vec )
405 : {
406 0 : int length = sql.getLength();
407 :
408 0 : int i = 0;
409 0 : bool singleQuote = false;
410 0 : bool doubleQuote = false;
411 0 : int start = 0;
412 0 : for( ; i < length ; i ++ )
413 : {
414 0 : char c = sql[i];
415 0 : if( doubleQuote )
416 : {
417 0 : if( '"' == c )
418 : {
419 0 : vec.push_back( OString( &sql.getStr()[start], i-start+1 ) );
420 0 : start = i + 1;
421 0 : doubleQuote = false;
422 : }
423 : }
424 0 : else if( singleQuote )
425 : {
426 0 : if( '\'' == c && '\'' == sql[i+1] )
427 : {
428 : // two subsequent single quotes within a quoted string
429 : // mean a single quote within the string
430 0 : i ++;
431 : }
432 0 : else if( '\'' == c )
433 : {
434 0 : vec.push_back( OString( &sql.getStr()[start], i - start +1 ) );
435 0 : start = i + 1; // leave single quotes !
436 0 : singleQuote = false;
437 : }
438 : }
439 : else
440 : {
441 0 : if( '"' == c )
442 : {
443 0 : vec.push_back( OString( &sql.getStr()[start], i - start ) );
444 0 : doubleQuote = true;
445 0 : start = i;
446 : }
447 0 : else if( '\'' == c )
448 : {
449 0 : vec.push_back( OString( &sql.getStr()[start], i - start ) );
450 0 : singleQuote = true;
451 0 : start = i;
452 : }
453 : }
454 : }
455 0 : if( start < i )
456 0 : vec.push_back( OString( &sql.getStr()[start] , i - start ) );
457 :
458 : // for( i = 0 ; i < vec.size() ; i ++ )
459 : // printf( "%s!" , vec[i].getStr() );
460 : // printf( "\n" );
461 :
462 0 : }
463 :
464 0 : void tokenizeSQL( const OString & sql, OStringVector &vec )
465 : {
466 0 : int length = sql.getLength();
467 :
468 0 : int i = 0;
469 0 : bool singleQuote = false;
470 0 : bool doubleQuote = false;
471 0 : int start = 0;
472 0 : for( ; i < length ; i ++ )
473 : {
474 0 : char c = sql[i];
475 0 : if( doubleQuote )
476 : {
477 0 : if( '"' == c )
478 : {
479 0 : vec.push_back( OString( &sql.getStr()[start], i-start ) );
480 0 : start = i + 1;
481 0 : doubleQuote = false;
482 : }
483 : }
484 0 : else if( singleQuote )
485 : {
486 0 : if( '\'' == c )
487 : {
488 0 : vec.push_back( OString( &sql.getStr()[start], i - start +1 ) );
489 0 : start = i + 1; // leave single quotes !
490 0 : singleQuote = false;
491 : }
492 : }
493 : else
494 : {
495 0 : if( '"' == c )
496 : {
497 0 : doubleQuote = true;
498 0 : start = i +1; // skip double quotes !
499 : }
500 0 : else if( '\'' == c )
501 : {
502 0 : singleQuote = true;
503 0 : start = i; // leave single quotes
504 : }
505 0 : else if( isWhitespace( c ) )
506 : {
507 0 : if( i == start )
508 0 : start ++; // skip additional whitespace
509 : else
510 : {
511 0 : vec.push_back( OString( &sql.getStr()[start], i - start ) );
512 0 : start = i +1;
513 : }
514 : }
515 0 : else if( ',' == c || isOperator( c ) || '(' == c || ')' == c )
516 : {
517 0 : if( i - start )
518 0 : vec.push_back( OString( &sql.getStr()[start], i - start ) );
519 0 : vec.push_back( OString( &sql.getStr()[i], 1 ) );
520 0 : start = i + 1;
521 : }
522 0 : else if( '.' == c )
523 : {
524 0 : if( ( i > start && sql[start] >= '0' && sql[start] <= '9' ) ||
525 0 : ( i == start && i > 1 && isWhitespace( sql[i-1] ) ) )
526 : {
527 : // ignore, is a literal
528 : }
529 : else
530 : {
531 0 : if( i - start )
532 0 : vec.push_back( OString( &sql.getStr()[start], i - start ) );
533 0 : vec.push_back( OString( "." ) );
534 0 : start = i + 1;
535 : }
536 : }
537 : }
538 : }
539 0 : if( start < i )
540 0 : vec.push_back( OString( &sql.getStr()[start] , i - start ) );
541 :
542 : // for( i = 0 ; i < vec.size() ; i ++ )
543 : // printf( "%s!" , vec[i].getStr() );
544 : // printf( "\n" );
545 0 : }
546 :
547 :
548 0 : void splitConcatenatedIdentifier( const OUString & source, OUString *first, OUString *second)
549 : {
550 0 : OStringVector vec;
551 0 : tokenizeSQL( OUStringToOString( source, RTL_TEXTENCODING_UTF8 ), vec );
552 0 : switch (vec.size())
553 : {
554 : case 1:
555 0 : *first = OUString();
556 0 : *second = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 );
557 0 : break;
558 : case 3:
559 0 : *first = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 );
560 0 : *second = OStringToOUString( vec[2], RTL_TEXTENCODING_UTF8 );
561 0 : break;
562 : default:
563 : SAL_WARN("connectivity.postgresql",
564 : "pq_tools::splitConcatenatedIdentifier unexpected number of tokens in identifier: "
565 : << vec.size());
566 0 : }
567 0 : }
568 :
569 : typedef std::vector< sal_Int32 , Allocator< sal_Int32 > > IntVector;
570 :
571 :
572 0 : OUString array2String( const com::sun::star::uno::Sequence< Any > &seq )
573 : {
574 0 : OUStringBuffer buf(128);
575 0 : int len = seq.getLength();
576 0 : buf.append( "{" );
577 0 : for( int i = 0 ; i < len ; i ++ )
578 : {
579 0 : OUString element;
580 0 : seq[i] >>= element;
581 :
582 0 : if( i > 0 )
583 0 : buf.append( "," );
584 0 : int strLength = element.getLength();
585 0 : buf.append( "\"" );
586 0 : for( int j = 0 ; j < strLength ; j ++ )
587 : {
588 0 : sal_Unicode c = element[j];
589 0 : if( c == '\\' || c == '"' || c == '{' || c == '}' )
590 : {
591 0 : buf.append( "\\" );
592 : }
593 0 : buf.append( c );
594 : }
595 0 : buf.append( "\"" );
596 0 : }
597 0 : buf.append( "}" );
598 0 : return buf.makeStringAndClear();
599 : }
600 :
601 : typedef
602 : std::vector
603 : <
604 : com::sun::star::uno::Any,
605 : Allocator< com::sun::star::uno::Any >
606 : > AnyVector;
607 :
608 0 : com::sun::star::uno::Sequence< Any > parseArray( const OUString & str ) throw( SQLException )
609 : {
610 0 : int len = str.getLength();
611 0 : bool doubleQuote = false;
612 0 : int brackets = 0;
613 0 : int i = 0;
614 :
615 0 : OUStringBuffer current;
616 0 : AnyVector elements;
617 0 : bool doubleQuotedValue = false;
618 0 : while( i < len )
619 : {
620 0 : sal_Unicode c = str[i];
621 0 : sal_Unicode cnext = str[i+1];
622 0 : if( doubleQuote )
623 : {
624 0 : if( '\\' == c )
625 : {
626 0 : i ++;
627 0 : current.append( cnext );
628 : }
629 0 : else if( '"' == c )
630 : {
631 0 : doubleQuote = false;
632 0 : doubleQuotedValue = true; // signal, that there was an empty element
633 : }
634 : else
635 : {
636 0 : current.append( c );
637 : }
638 : }
639 0 : else if ( '{' == c )
640 : {
641 0 : brackets ++;
642 : }
643 0 : else if( '}' == c )
644 : {
645 0 : brackets --;
646 0 : if( brackets < 0 )
647 : {
648 :
649 0 : OUStringBuffer buf;
650 0 : buf.appendAscii( "error during array parsing, didn't expect a } at position " );
651 0 : buf.append( (sal_Int32) i );
652 0 : buf.appendAscii( " ('" );
653 0 : buf.append( str );
654 0 : buf.appendAscii( "')" );
655 : throw SQLException(
656 : buf.makeStringAndClear(),
657 0 : Reference< XInterface > (), OUString(), 1, Any() );
658 : }
659 0 : if( brackets == 0 )
660 : {
661 0 : if( !current.isEmpty() || doubleQuotedValue )
662 0 : elements.push_back( makeAny( current.makeStringAndClear() ) );
663 : }
664 : else
665 : {
666 0 : current.append( c );
667 : }
668 : }
669 0 : else if( '"' == c )
670 : {
671 : // if( current.getLength() != 0 )
672 : // {
673 : // OUStringBuffer buf;
674 : // buf.appendAscii( "error during array parsing, didn't expect a \" at position " );
675 : // buf.append( i );
676 : // buf.append( " ('" );
677 : // buf.append( str );
678 : // buf.append( "')" );
679 : // throw SDBCException(
680 : // buf.makeStringAndClear(),
681 : // Reference< XInterface > (), 1, Any() );
682 : // }
683 : // else
684 : // {
685 0 : doubleQuote = true;
686 : // }
687 : }
688 0 : else if( ',' == c && brackets == 1)
689 : {
690 0 : doubleQuotedValue = false;
691 0 : elements.push_back( makeAny( current.makeStringAndClear() ) );
692 : }
693 0 : else if( isWhitespace( c ) )
694 : {
695 : // ignore whitespace without quotes
696 : }
697 : else
698 : {
699 0 : current.append( c );
700 : }
701 0 : i++;
702 : }
703 0 : return sequence_of_vector(elements);
704 : }
705 :
706 0 : com::sun::star::uno::Sequence< sal_Int32 > parseIntArray( const OUString & str )
707 : {
708 0 : sal_Int32 start = 0;
709 0 : IntVector vec;
710 : // printf( ">%s<\n" , OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
711 0 : for( sal_Int32 i = str.indexOf( ' ' ) ; i != -1 ; i = str.indexOf( ' ', start) )
712 : {
713 0 : vec.push_back( (sal_Int32)rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
714 : // printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
715 0 : start = i + 1;
716 : }
717 0 : vec.push_back( (sal_Int32)rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
718 : // printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
719 0 : return sequence_of_vector(vec);
720 : }
721 :
722 0 : void fillAttnum2attnameMap(
723 : Int2StringMap &map,
724 : const Reference< com::sun::star::sdbc::XConnection > &conn,
725 : const OUString &schema,
726 : const OUString &table )
727 : {
728 0 : Reference< XPreparedStatement > prep = conn->prepareStatement(
729 : "SELECT attname,attnum "
730 : "FROM pg_attribute "
731 : "INNER JOIN pg_class ON attrelid = pg_class.oid "
732 : "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
733 0 : "WHERE relname=? AND nspname=?" );
734 :
735 0 : Reference< XParameters > paras( prep, UNO_QUERY_THROW );
736 0 : paras->setString( 1 , table );
737 0 : paras->setString( 2 , schema );
738 0 : Reference< XResultSet > rs = prep->executeQuery();
739 :
740 0 : Reference< XRow > xRow( rs , UNO_QUERY_THROW );
741 0 : while( rs->next() )
742 : {
743 0 : map[ xRow->getInt(2) ] = xRow->getString(1);
744 0 : }
745 0 : }
746 :
747 0 : OString extractSingleTableFromSelect( const OStringVector &vec )
748 : {
749 0 : OString ret;
750 :
751 0 : if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
752 0 : vec[0].pData->buffer, vec[0].pData->length, "select" , 6 , 6 ) )
753 : {
754 0 : size_t token = 0;
755 :
756 0 : for( token = 1; token < vec.size() ; token ++ )
757 : {
758 0 : if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
759 0 : vec[token].getStr(), vec[token].getLength(), "from" , 4 , 4 ) )
760 : {
761 : // found from
762 0 : break;
763 : }
764 : }
765 0 : token ++;
766 :
767 0 : if( token < vec.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
768 0 : vec[token].pData->buffer, vec[token].pData->length, "only " , 4 , 4 ) )
769 : {
770 0 : token ++;
771 : }
772 :
773 0 : if( token < vec.size() && rtl_str_compare_WithLength(
774 0 : vec[token].getStr(), vec[token].getLength(),
775 0 : RTL_CONSTASCII_STRINGPARAM("(") ) )
776 : {
777 : // it is a table or a function name
778 0 : OStringBuffer buf(128);
779 0 : if( '"' == vec[token][0] )
780 0 : buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
781 : else
782 0 : buf.append( vec[token] );
783 0 : token ++;
784 :
785 0 : if( token < vec.size() )
786 : {
787 0 : if( rtl_str_compare_WithLength(
788 0 : vec[token].getStr(), vec[token].getLength(),
789 0 : RTL_CONSTASCII_STRINGPARAM( "." ) ) == 0 )
790 : {
791 0 : buf.append( vec[token] );
792 0 : token ++;
793 0 : if( token < vec.size() )
794 : {
795 0 : if( '"' == vec[token][0] )
796 0 : buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
797 : else
798 0 : buf.append( vec[token] );
799 0 : token ++;
800 : }
801 : }
802 : }
803 :
804 0 : ret = buf.makeStringAndClear();
805 : // now got my table candidate
806 :
807 0 : if( token < vec.size() && rtl_str_compare_WithLength(
808 0 : vec[token].getStr(), vec[token].getLength(),
809 0 : RTL_CONSTASCII_STRINGPARAM( "(" ) ) == 0 )
810 : {
811 : // whoops, it is a function
812 0 : ret = OString();
813 : }
814 : else
815 : {
816 0 : if( token < vec.size() )
817 : {
818 0 : if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
819 0 : vec[token].pData->buffer, vec[token].pData->length, "as" , 2, 2 ) )
820 : {
821 0 : token += 2; // skip alias
822 : }
823 : }
824 :
825 0 : if( token < vec.size() )
826 : {
827 0 : if( rtl_str_compare_WithLength(
828 0 : vec[token].getStr(), vec[token].getLength(),
829 0 : RTL_CONSTASCII_STRINGPARAM( "," ) ) == 0 )
830 : {
831 : // whoops, multiple tables are used
832 0 : ret = OString();
833 : }
834 : else
835 : {
836 : static const char * forbiddenKeywords[] =
837 : { "join", "natural", "outer", "inner", "left", "right", "full" , 0 };
838 0 : for( int i = 0 ; forbiddenKeywords[i] ; i ++ )
839 : {
840 0 : if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
841 0 : vec[token].pData->buffer, vec[token].pData->length,
842 0 : forbiddenKeywords[i], strlen(forbiddenKeywords[i]),
843 0 : strlen(forbiddenKeywords[i]) ) )
844 : {
845 : // whoops, it is a join
846 0 : ret = OString();
847 : }
848 : }
849 : }
850 : }
851 0 : }
852 : }
853 : }
854 0 : return ret;
855 :
856 : }
857 :
858 0 : com::sun::star::uno::Sequence< sal_Int32 > string2intarray( const OUString & str )
859 : {
860 0 : com::sun::star::uno::Sequence< sal_Int32 > ret;
861 0 : const sal_Int32 strlen = str.getLength();
862 0 : if( str.getLength() > 1 )
863 : {
864 0 : sal_Int32 start = 0;
865 0 : while ( iswspace( str.iterateCodePoints(&start) ) )
866 0 : if ( start == strlen)
867 0 : return ret;
868 0 : if ( str.iterateCodePoints(&start) != L'{' )
869 0 : return ret;
870 0 : while ( iswspace( str.iterateCodePoints(&start) ) )
871 0 : if ( start == strlen)
872 0 : return ret;
873 0 : if ( str.iterateCodePoints(&start, 0) == L'}' )
874 0 : return ret;
875 :
876 0 : std::vector< sal_Int32, Allocator< sal_Int32 > > vec;
877 : do
878 : {
879 0 : OUString digits;
880 : sal_Int32 c;
881 0 : while ( isdigit( c = str.iterateCodePoints(&start) ) )
882 : {
883 0 : if ( start == strlen)
884 0 : return ret;
885 0 : digits += OUString(c);
886 : }
887 0 : vec.push_back( digits.toInt32() );
888 0 : while ( iswspace( str.iterateCodePoints(&start) ) )
889 0 : if ( start == strlen)
890 0 : return ret;
891 0 : if ( str.iterateCodePoints(&start, 0) == L'}' )
892 0 : break;
893 0 : if ( str.iterateCodePoints(&start) != L',' )
894 0 : return ret;
895 0 : if ( start == strlen)
896 0 : return ret;
897 : } while( true );
898 : // vec is guaranteed non-empty
899 0 : ret = com::sun::star::uno::Sequence< sal_Int32 > ( &vec[0] , vec.size() );
900 : }
901 0 : return ret;
902 : }
903 :
904 :
905 0 : Sequence< OUString > convertMappedIntArray2StringArray(
906 : const Int2StringMap &map, const Sequence< sal_Int32 > &intArray )
907 : {
908 0 : Sequence< OUString > ret( intArray.getLength() );
909 0 : for( int i = 0; i < intArray.getLength() ; i ++ )
910 : {
911 0 : Int2StringMap::const_iterator ii = map.find( intArray[i] );
912 0 : if( ii != map.end() )
913 0 : ret[i] = ii->second;
914 : }
915 0 : return ret;
916 : }
917 :
918 :
919 0 : OUString sqltype2string( const Reference< XPropertySet > & desc )
920 : {
921 0 : OUStringBuffer typeName;
922 0 : typeName.append( extractStringProperty( desc, getStatics().TYPE_NAME ) );
923 0 : sal_Int32 precision = extractIntProperty( desc, getStatics().PRECISION );
924 :
925 0 : if( precision )
926 : {
927 0 : switch( extractIntProperty( desc, getStatics().TYPE ) )
928 : {
929 : case com::sun::star::sdbc::DataType::VARBINARY:
930 : case com::sun::star::sdbc::DataType::VARCHAR:
931 : case com::sun::star::sdbc::DataType::CHAR:
932 : {
933 0 : typeName.append( "(" );
934 0 : typeName.append( precision );
935 0 : typeName.append( ")" );
936 0 : break;
937 : }
938 : case com::sun::star::sdbc::DataType::DECIMAL:
939 : case com::sun::star::sdbc::DataType::NUMERIC:
940 : {
941 0 : typeName.append( "(" );
942 0 : typeName.append( precision );
943 0 : typeName.append( "," );
944 0 : typeName.append( extractIntProperty( desc, getStatics().SCALE ) );
945 0 : typeName.append( ")" );
946 0 : break;
947 : }
948 : default:
949 : ((void)0);
950 : }
951 : }
952 0 : return typeName.makeStringAndClear();
953 : }
954 :
955 :
956 :
957 :
958 0 : static void keyType2String( OUStringBuffer & buf, sal_Int32 keyType )
959 : {
960 0 : if( com::sun::star::sdbc::KeyRule::CASCADE == keyType )
961 : {
962 0 : buf.append( "CASCADE " );
963 : }
964 0 : else if( com::sun::star::sdbc::KeyRule::RESTRICT == keyType )
965 : {
966 0 : buf.append( "RESTRICT " );
967 : }
968 0 : else if( com::sun::star::sdbc::KeyRule::SET_DEFAULT == keyType )
969 : {
970 0 : buf.append( "SET DEFAULT " );
971 : }
972 0 : else if( com::sun::star::sdbc::KeyRule::SET_NULL == keyType )
973 : {
974 0 : buf.append( "SET NULL " );
975 : }
976 : else //if( com::sun::star::sdbc::KeyRule::NO_ACTION == keyType )
977 : {
978 0 : buf.append( "NO ACTION " );
979 : }
980 0 : }
981 :
982 0 : void bufferKey2TableConstraint(
983 : OUStringBuffer &buf, const Reference< XPropertySet > &key, ConnectionSettings *settings )
984 : {
985 0 : Statics &st = getStatics();
986 0 : sal_Int32 type = extractIntProperty( key, st.TYPE );
987 0 : OUString referencedTable = extractStringProperty( key, st.REFERENCED_TABLE );
988 0 : sal_Int32 updateRule = extractIntProperty( key, st.UPDATE_RULE );
989 0 : sal_Int32 deleteRule = extractIntProperty( key, st.DELETE_RULE );
990 0 : bool foreign = false;
991 0 : if( type == com::sun::star::sdbcx::KeyType::UNIQUE )
992 : {
993 0 : buf.append( "UNIQUE( " );
994 : }
995 0 : else if( type == com::sun::star::sdbcx::KeyType::PRIMARY )
996 : {
997 0 : buf.append( "PRIMARY KEY( " );
998 : }
999 0 : else if( type == com::sun::star::sdbcx::KeyType::FOREIGN )
1000 : {
1001 0 : foreign = true;
1002 0 : buf.append( "FOREIGN KEY( " );
1003 : }
1004 :
1005 0 : Reference< XColumnsSupplier > columns( key, UNO_QUERY );
1006 0 : if( columns.is() )
1007 : {
1008 0 : Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY );
1009 0 : if( colEnumAccess.is() )
1010 : {
1011 0 : Reference< XEnumeration > colEnum = colEnumAccess->createEnumeration();
1012 0 : bool first = true;
1013 0 : while(colEnum.is() && colEnum->hasMoreElements() )
1014 : {
1015 0 : if( first )
1016 : {
1017 0 : first = false;
1018 : }
1019 : else
1020 : {
1021 0 : buf.append( ", " );
1022 : }
1023 0 : Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW );
1024 0 : bufferQuoteIdentifier(buf, extractStringProperty( keyColumn, st.NAME ), settings );
1025 0 : }
1026 0 : }
1027 : }
1028 0 : buf.append( ") " );
1029 :
1030 0 : if( foreign )
1031 : {
1032 0 : buf.append( "REFERENCES " );
1033 0 : OUString schema;
1034 0 : OUString tableName;
1035 0 : splitConcatenatedIdentifier( referencedTable, &schema, &tableName );
1036 0 : bufferQuoteQualifiedIdentifier(buf , schema, tableName, settings );
1037 0 : if(columns.is() )
1038 : {
1039 0 : Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY);
1040 0 : if( colEnumAccess.is() )
1041 : {
1042 0 : buf.append( " (" );
1043 0 : Reference< XEnumeration > colEnum(colEnumAccess->createEnumeration());
1044 0 : bool first = true;
1045 0 : while(colEnum.is() && colEnum->hasMoreElements() )
1046 : {
1047 0 : if( first )
1048 : {
1049 0 : first = false;
1050 : }
1051 : else
1052 : {
1053 0 : buf.append( ", " );
1054 : }
1055 0 : Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW );
1056 : bufferQuoteIdentifier(
1057 0 : buf, extractStringProperty( keyColumn, st.RELATED_COLUMN ), settings );
1058 0 : }
1059 0 : buf.append( ") " );
1060 0 : }
1061 : }
1062 :
1063 0 : buf.append( "ON DELETE " );
1064 0 : keyType2String( buf, deleteRule );
1065 0 : buf.append( " ON UPDATE " );
1066 0 : keyType2String( buf, updateRule );
1067 0 : }
1068 :
1069 0 : }
1070 :
1071 0 : void extractNameValuePairsFromInsert( String2StringMap & map, const OString & lastQuery )
1072 : {
1073 0 : OStringVector vec;
1074 0 : tokenizeSQL( lastQuery, vec );
1075 :
1076 0 : int nSize = vec.size();
1077 : // printf( "1 %d\n", nSize );
1078 0 : if( nSize > 6 &&
1079 0 : vec[0].equalsIgnoreAsciiCase( "insert" ) &&
1080 0 : vec[1].equalsIgnoreAsciiCase( "into" ) )
1081 : {
1082 0 : int n = 2;
1083 :
1084 : // printf( "1a\n" );
1085 : // extract table name
1086 0 : OString tableName;
1087 0 : if( vec[n+1].equalsIgnoreAsciiCase( "." ) )
1088 : {
1089 0 : tableName = vec[n];
1090 0 : tableName += vec[n+1];
1091 0 : tableName += vec[n+2];
1092 0 : n +=2;
1093 : }
1094 : else
1095 : {
1096 0 : tableName = vec[n];
1097 : }
1098 :
1099 0 : OStringVector names;
1100 0 : n ++;
1101 0 : if( vec[n].equalsIgnoreAsciiCase( "(" ) )
1102 : {
1103 : // printf( "2\n" );
1104 : // extract names
1105 0 : n++;
1106 0 : while( nSize > n && ! vec[n].equalsIgnoreAsciiCase( ")" ) )
1107 : {
1108 0 : names.push_back( vec[n] );
1109 0 : if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase( "," ) )
1110 : {
1111 0 : n ++;
1112 : }
1113 0 : n++;
1114 : }
1115 0 : n++;
1116 :
1117 : // now read the values
1118 0 : if( nSize > n +1 && vec[n].equalsIgnoreAsciiCase("VALUES") &&
1119 0 : vec[n+1].equalsIgnoreAsciiCase( "(" ) )
1120 : {
1121 0 : n +=2;
1122 : // printf( "3\n" );
1123 0 : for ( OStringVector::size_type i = 0 ; i < names.size() && nSize > n ; i ++ )
1124 : {
1125 0 : map[names[i]] = vec[n];
1126 0 : if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase(",") )
1127 : {
1128 0 : n ++;
1129 : }
1130 0 : n++;
1131 : }
1132 : }
1133 0 : }
1134 0 : }
1135 0 : }
1136 :
1137 0 : OUString querySingleValue(
1138 : const com::sun::star::uno::Reference< com::sun::star::sdbc::XConnection > &connection,
1139 : const OUString &query )
1140 : {
1141 0 : OUString ret;
1142 0 : Reference< XStatement > stmt = connection->createStatement();
1143 0 : DisposeGuard guard( stmt );
1144 0 : Reference< XResultSet > rs = stmt->executeQuery( query );
1145 0 : Reference< XRow > xRow( rs, UNO_QUERY );
1146 0 : if( rs->next() )
1147 0 : ret = xRow->getString( 1 );
1148 0 : return ret;
1149 : }
1150 :
1151 :
1152 : // copied from connectivity/source/dbtools, can't use the function directly
1153 0 : bool implSetObject( const Reference< XParameters >& _rxParameters,
1154 : const sal_Int32 _nColumnIndex, const Any& _rValue)
1155 : {
1156 0 : sal_Bool bSuccessfullyReRouted = sal_True;
1157 0 : switch (_rValue.getValueTypeClass())
1158 : {
1159 : case typelib_TypeClass_HYPER:
1160 : {
1161 0 : sal_Int64 nValue = 0;
1162 0 : _rxParameters->setLong( _nColumnIndex, nValue );
1163 : }
1164 0 : break;
1165 :
1166 : case typelib_TypeClass_VOID:
1167 0 : _rxParameters->setNull(_nColumnIndex,com::sun::star::sdbc::DataType::VARCHAR);
1168 0 : break;
1169 :
1170 : case typelib_TypeClass_STRING:
1171 0 : _rxParameters->setString(_nColumnIndex, *(OUString*)_rValue.getValue());
1172 0 : break;
1173 :
1174 : case typelib_TypeClass_BOOLEAN:
1175 0 : _rxParameters->setBoolean(_nColumnIndex, *(sal_Bool *)_rValue.getValue());
1176 0 : break;
1177 :
1178 : case typelib_TypeClass_BYTE:
1179 0 : _rxParameters->setByte(_nColumnIndex, *(sal_Int8 *)_rValue.getValue());
1180 0 : break;
1181 :
1182 : case typelib_TypeClass_UNSIGNED_SHORT:
1183 : case typelib_TypeClass_SHORT:
1184 0 : _rxParameters->setShort(_nColumnIndex, *(sal_Int16*)_rValue.getValue());
1185 0 : break;
1186 :
1187 : case typelib_TypeClass_CHAR:
1188 0 : _rxParameters->setString(_nColumnIndex, OUString((sal_Unicode *)_rValue.getValue(),1));
1189 0 : break;
1190 :
1191 : case typelib_TypeClass_UNSIGNED_LONG:
1192 : case typelib_TypeClass_LONG:
1193 0 : _rxParameters->setInt(_nColumnIndex, *(sal_Int32*)_rValue.getValue());
1194 0 : break;
1195 :
1196 : case typelib_TypeClass_FLOAT:
1197 0 : _rxParameters->setFloat(_nColumnIndex, *(float*)_rValue.getValue());
1198 0 : break;
1199 :
1200 : case typelib_TypeClass_DOUBLE:
1201 0 : _rxParameters->setDouble(_nColumnIndex, *(double*)_rValue.getValue());
1202 0 : break;
1203 :
1204 : case typelib_TypeClass_SEQUENCE:
1205 0 : if (_rValue.getValueType() == ::getCppuType((const Sequence< sal_Int8 > *)0))
1206 : {
1207 0 : _rxParameters->setBytes(_nColumnIndex, *(Sequence<sal_Int8>*)_rValue.getValue());
1208 : }
1209 : else
1210 0 : bSuccessfullyReRouted = sal_False;
1211 0 : break;
1212 : case typelib_TypeClass_STRUCT:
1213 0 : if (_rValue.getValueType() == ::getCppuType((const com::sun::star::util::DateTime*)0))
1214 0 : _rxParameters->setTimestamp(_nColumnIndex, *(com::sun::star::util::DateTime*)_rValue.getValue());
1215 0 : else if (_rValue.getValueType() == ::getCppuType((const com::sun::star::util::Date*)0))
1216 0 : _rxParameters->setDate(_nColumnIndex, *(com::sun::star::util::Date*)_rValue.getValue());
1217 0 : else if (_rValue.getValueType() == ::getCppuType((const com::sun::star::util::Time*)0))
1218 0 : _rxParameters->setTime(_nColumnIndex, *(com::sun::star::util::Time*)_rValue.getValue());
1219 : else
1220 0 : bSuccessfullyReRouted = sal_False;
1221 0 : break;
1222 :
1223 : case typelib_TypeClass_INTERFACE:
1224 : {
1225 0 : Reference< com::sun::star::io::XInputStream > xStream;
1226 0 : if (_rValue >>= xStream)
1227 : {
1228 0 : _rValue >>= xStream;
1229 0 : _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
1230 0 : break;
1231 0 : }
1232 : }
1233 : // run through
1234 : default:
1235 0 : bSuccessfullyReRouted = sal_False;
1236 :
1237 : }
1238 :
1239 0 : return bSuccessfullyReRouted;
1240 : }
1241 :
1242 : }
1243 :
1244 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|