LibreOffice Module connectivity (master) 1
pq_resultset.cxx
Go to the documentation of this file.
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 "pq_resultset.hxx"
39
41
42#include <com/sun/star/sdbc/FetchDirection.hpp>
43#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
44#include <com/sun/star/sdbc/ResultSetType.hpp>
45#include <com/sun/star/sdbc/DataType.hpp>
46#include <com/sun/star/sdbc/SQLException.hpp>
47#include <utility>
48
49
50using osl::MutexGuard;
51
52using com::sun::star::uno::Any;
54using com::sun::star::uno::XInterface;
55
56using com::sun::star::sdbc::SQLException;
57using com::sun::star::sdbc::XResultSetMetaData;
58
59
60namespace pq_sdbc_driver
61{
62
64{
65 if( ! m_result )
66 {
67 throw SQLException( "pq_resultset: already closed",
68 *this, OUString(), 1, Any() );
69 }
70
71 if( ! m_ppSettings || ! *m_ppSettings || ! (*m_ppSettings)->pConnection )
72 {
73 throw SQLException( "pq_resultset: statement has been closed already",
74 *this, OUString(), 1, Any() );
75 }
76
77}
78
79ResultSet::ResultSet( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
80 const Reference< XInterface > & owner,
81 ConnectionSettings **ppSettings,
82 PGresult * result,
83 OUString schema,
84 OUString table)
86 refMutex, owner, PQntuples( result ),
87 PQnfields( result ),(*ppSettings)->tc ),
88 m_result( result ),
89 m_schema(std::move( schema )),
90 m_table(std::move( table )),
91 m_ppSettings( ppSettings )
92{
93 // LEM TODO: shouldn't these things be inherited from the statement or something like that?
94 // Positioned update/delete not supported, so no cursor name
95 // Fetch direction and size are cursor-specific things, so not used now.
96 // Fetch size not set
97 m_props[ BASERESULTSET_FETCH_DIRECTION ] <<= css::sdbc::FetchDirection::UNKNOWN;
98 // No escape processing for now
100 // Bookmarks not implemented for now
102 m_props[ BASERESULTSET_RESULT_SET_CONCURRENCY ] <<= css::sdbc::ResultSetConcurrency::READ_ONLY;
103 m_props[ BASERESULTSET_RESULT_SET_TYPE ] <<= css::sdbc::ResultSetType::SCROLL_INSENSITIVE;
104}
105
106
107Any ResultSet::getValue( sal_Int32 columnIndex )
108{
109 Any ret;
110 if( PQgetisnull( m_result, m_row, columnIndex -1 ) )
111 {
112 m_wasNull = true;
113 }
114 else
115 {
116 m_wasNull = false;
117 ret <<= OUString(
118 PQgetvalue( m_result, m_row , columnIndex -1 ) ,
119 PQgetlength( m_result, m_row , columnIndex -1 ) ,
121
122 }
123 return ret;
124}
125
127{}
128
130{
132 {
133 MutexGuard guard( m_xMutex->GetMutex() );
134 if( m_result )
135 {
136 PQclear(m_result );
137 m_result = nullptr;
138 m_row = -1;
139 }
140 owner = m_owner;
141 m_owner.clear();
142 }
143}
144
146{
147 MutexGuard guard( m_xMutex->GetMutex() );
148 checkClosed();
149 return new ResultSetMetaData(
151}
152
153sal_Int32 ResultSet::findColumn( const OUString& columnName )
154{
155 MutexGuard guard( m_xMutex->GetMutex() );
156 checkClosed();
157 sal_Int32 res = PQfnumber( m_result,
159 /* PQfnumber return -1 for not found, which is what we want
160 * other than that we use col number as 1-based not 0-based */
161 if(res >= 0)
162 {
163 res += 1;
164 }
165 else
166 {
168 assert(false);
169 }
170 return res;
171}
172
173static bool isNumber( const char * data, sal_Int32 len )
174{
175 bool ret = false;
176 if( len )
177 {
178 ret = true;
179 for( int i = 0 ; i < len ; i ++ )
180 {
181 if( ( data[i] >= '0' && data[i] <= '9' ) ||
182 data[i] == '-' || data[i] == '+' || data[i] == '.' || data[i] == ',' )
183 {
184 if( data[i] == '-' && i != 0 && i != len-1 )
185 {
186 // no number, maybe a date
187 ret = false;
188 break;
189 }
190 }
191 else
192 {
193 ret = false;
194 break;
195 }
196 }
197 }
198 return ret;
199}
200
201static bool isInteger( const char * data, sal_Int32 len )
202{
203 bool ret = false;
204 if( len )
205 {
206 ret = true;
207 for( int i = 0 ; i < len ; i ++ )
208 {
209 if( ( data[i] >= '0' && data[i] <= '9' ) ||
210 data[i] == '-' || data[i] == '+' )
211 {
212 if( data[i] == '-' && i != 0 && i != len-1 )
213 {
214 // no number, maybe a date
215 ret = false;
216 break;
217 }
218 }
219 else
220 {
221 ret = false;
222 break;
223 }
224 }
225 }
226 return ret;
227}
228
229static bool isDate( const char * data, sal_Int32 len )
230{
231 return 10 == len &&
232 '-' == data[4] &&
233 '-' == data[7] &&
234 isInteger( &(data[0]),4 ) &&
235 isInteger( &(data[5]),2) &&
236 isInteger( &(data[8]),2 );
237}
238
239static bool isTime( const char * data, sal_Int32 len )
240{
241 return 8 == len &&
242 ':' == data[2] &&
243 ':' == data[5] &&
244 isInteger( &(data[0]),2 ) &&
245 isInteger( &(data[3]),2) &&
246 isInteger( &(data[6]),2 );
247
248}
249
250static bool isTimestamp( const char * data, sal_Int32 len )
251{
252 return len == 19 && isDate( data, 10) && isTime( &(data[11]),8 );
253}
254
255sal_Int32 ResultSet::guessDataType( sal_Int32 column )
256{
257 // we don't look into more than 100 rows ...
258 sal_Int32 ret = css::sdbc::DataType::INTEGER;
259
260 int maxRows = std::min<sal_Int32>( m_rowCount, 100 );
261 for( int i = 0 ; i < maxRows ; i ++ )
262 {
263 if( ! PQgetisnull( m_result, i , column-1 ) )
264 {
265 const char * p = PQgetvalue( m_result, i , column -1 );
266 int len = PQgetlength( m_result, i , column -1 );
267
268 if( css::sdbc::DataType::INTEGER == ret )
269 {
270 if( ! isInteger( p,len ) )
271 ret = css::sdbc::DataType::NUMERIC;
272 }
273 if( css::sdbc::DataType::NUMERIC == ret )
274 {
275 if( ! isNumber( p,len ) )
276 {
277 ret = css::sdbc::DataType::DATE;
278 }
279 }
280 if( css::sdbc::DataType::DATE == ret )
281 {
282 if( ! isDate( p,len ) )
283 {
284 ret = css::sdbc::DataType::TIME;
285 }
286 }
287 if( css::sdbc::DataType::TIME == ret )
288 {
289 if( ! isTime( p,len ) )
290 {
291 ret = css::sdbc::DataType::TIMESTAMP;
292 }
293 }
294 if( css::sdbc::DataType::TIMESTAMP == ret )
295 {
296 if( ! isTimestamp( p,len ) )
297 {
298 ret = css::sdbc::DataType::LONGVARCHAR;
299 break;
300 }
301 }
302 }
303 }
304 return ret;
305}
306
307}
308
309/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::uno::XInterface > m_owner
::rtl::Reference< comphelper::RefCountedMutex > m_xMutex
css::uno::Any m_props[BASERESULTSET_SIZE]
virtual css::uno::Any getValue(sal_Int32 columnIndex) override
unchecked, acquire mutex before calling
ResultSet(const ::rtl::Reference< comphelper::RefCountedMutex > &mutex, const css::uno::Reference< css::uno::XInterface > &owner, ConnectionSettings **pSettings, PGresult *result, OUString schema, OUString table)
virtual ~ResultSet() override
virtual void SAL_CALL close() override
virtual sal_Int32 SAL_CALL findColumn(const OUString &columnName) override
ConnectionSettings ** m_ppSettings
virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData() override
sal_Int32 guessDataType(sal_Int32 column)
virtual void checkClosed() override
mutex should be locked before called
void * p
@ table
void throwInvalidColumnException(const OUString &_rColumnName, const Reference< XInterface > &_rxContext)
int i
const sal_Int32 BASERESULTSET_RESULT_SET_CONCURRENCY
const sal_Int32 BASERESULTSET_FETCH_DIRECTION
static bool isTimestamp(const char *data, sal_Int32 len)
const sal_Int32 BASERESULTSET_IS_BOOKMARKABLE
static bool isDate(const char *data, sal_Int32 len)
const sal_Int32 BASERESULTSET_RESULT_SET_TYPE
static bool isInteger(const char *data, sal_Int32 len)
static bool isNumber(const char *data, sal_Int32 len)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Definition: pq_tools.cxx:100
const sal_Int32 BASERESULTSET_ESCAPE_PROCESSING
static bool isTime(const char *data, sal_Int32 len)
const char * columnName
Definition: pq_statics.cxx:56
static const rtl_TextEncoding encoding
Any result