1 /*
2  * Copyright (C) 2002 - 2003 Rodrigo Moya <rodrigo@gnome-db.org>
3  * Copyright (C) 2002 Tim Coleman <tim@timcoleman.com>
4  * Copyright (C) 2003 Akira TAGOH <tagoh@gnome-db.org>
5  * Copyright (C) 2003 Gonzalo Paniagua Javier <gonzalo@src.gnome.org>
6  * Copyright (C) 2003 Laurent Sansonetti <lrz@gnome.org>
7  * Copyright (C) 2003 Steve Fosdick <fozzy@src.gnome.org>
8  * Copyright (C) 2005 - 2011 Vivien Malerba <malerba@gnome-db.org>
9  * Copyright (C) 2005 Álvaro Peña <alvaropg@telefonica.net>
10  * Copyright (C) 2007 Murray Cumming <murrayc@murrayc-desktop>
11  * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the
25  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26  * Boston, MA  02110-1301, USA.
27  */
28 
29 #include <stdarg.h>
30 #include <string.h>
31 #include <glib/gi18n-lib.h>
32 #include <libgda/gda-util.h>
33 #include <libgda/gda-connection-private.h>
34 #include "gda-oracle.h"
35 #include "gda-oracle-recordset.h"
36 #include "gda-oracle-provider.h"
37 #include "gda-oracle-util.h"
38 
39 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
40 #define BUFFER_SIZE 4095 /* size of the buffer to fecth data from the server using the callback API (OCIDefineDynamic) */
41 
42 static void gda_oracle_recordset_class_init (GdaOracleRecordsetClass *klass);
43 static void gda_oracle_recordset_init       (GdaOracleRecordset *recset,
44 					     GdaOracleRecordsetClass *klass);
45 static void gda_oracle_recordset_dispose   (GObject *object);
46 
47 /* virtual methods */
48 static gint     gda_oracle_recordset_fetch_nb_rows (GdaDataSelect *model);
49 static gboolean gda_oracle_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
50 static gboolean gda_oracle_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
51 
52 static GdaRow  *new_row (GdaDataSelect *imodel, GdaConnection *cnc, GdaOraclePStmt *ps);
53 
54 struct _GdaOracleRecordsetPrivate {
55 	gint     next_row_num;
56 };
57 static GObjectClass *parent_class = NULL;
58 
59 #ifdef GDA_DEBUG
60 #define TS_DIFF(a,b) (((b).tv_sec * 1000000 + (b).tv_usec) - ((a).tv_sec * 1000000 + (a).tv_usec))
61 #include <sys/time.h>
62 #endif
63 
64 /*
65  * Object init and finalize
66  */
67 static void
gda_oracle_recordset_init(GdaOracleRecordset * recset,GdaOracleRecordsetClass * klass)68 gda_oracle_recordset_init (GdaOracleRecordset *recset,
69 			   GdaOracleRecordsetClass *klass)
70 {
71 	g_return_if_fail (GDA_IS_ORACLE_RECORDSET (recset));
72 	recset->priv = g_new0 (GdaOracleRecordsetPrivate, 1);
73 	recset->priv->next_row_num = 0;
74 }
75 
76 static void
gda_oracle_recordset_class_init(GdaOracleRecordsetClass * klass)77 gda_oracle_recordset_class_init (GdaOracleRecordsetClass *klass)
78 {
79 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
80 	GdaDataSelectClass *pmodel_class = GDA_DATA_SELECT_CLASS (klass);
81 
82 	parent_class = g_type_class_peek_parent (klass);
83 
84 	object_class->dispose = gda_oracle_recordset_dispose;
85 	pmodel_class->fetch_nb_rows = gda_oracle_recordset_fetch_nb_rows;
86 	pmodel_class->fetch_random = gda_oracle_recordset_fetch_random;
87 
88 	pmodel_class->fetch_next = gda_oracle_recordset_fetch_next;
89 	pmodel_class->fetch_prev = NULL;
90 	pmodel_class->fetch_at = NULL;
91 }
92 
93 static void
gda_oracle_recordset_dispose(GObject * object)94 gda_oracle_recordset_dispose (GObject *object)
95 {
96 	GdaOracleRecordset *recset = (GdaOracleRecordset *) object;
97 
98 	g_return_if_fail (GDA_IS_ORACLE_RECORDSET (recset));
99 
100 	if (recset->priv) {
101 		/* free specific information */
102 		g_free (recset->priv);
103 		recset->priv = NULL;
104 	}
105 
106 	parent_class->dispose (object);
107 }
108 
109 /*
110  * Public functions
111  */
112 
113 GType
gda_oracle_recordset_get_type(void)114 gda_oracle_recordset_get_type (void)
115 {
116 	static GType type = 0;
117 
118 	if (G_UNLIKELY (type == 0)) {
119 		static GMutex registering;
120 		static const GTypeInfo info = {
121 			sizeof (GdaOracleRecordsetClass),
122 			(GBaseInitFunc) NULL,
123 			(GBaseFinalizeFunc) NULL,
124 			(GClassInitFunc) gda_oracle_recordset_class_init,
125 			NULL,
126 			NULL,
127 			sizeof (GdaOracleRecordset),
128 			0,
129 			(GInstanceInitFunc) gda_oracle_recordset_init,
130 			NULL
131 		};
132 		g_mutex_lock (&registering);
133 		if (type == 0)
134 			type = g_type_register_static (GDA_TYPE_DATA_SELECT, "GdaOracleRecordset", &info, 0);
135 		g_mutex_unlock (&registering);
136 	}
137 
138 	return type;
139 }
140 
141 static sb4
ora_def_callback(GdaOracleValue * ora_value,OCIDefine * def,ub4 iter,dvoid ** bufpp,ub4 ** alenpp,ub1 * piecep,dvoid ** indpp,ub2 ** rcodep)142 ora_def_callback (GdaOracleValue *ora_value,
143 		  OCIDefine *def,
144 		  ub4 iter,
145 		  dvoid **bufpp,
146 		  ub4 **alenpp,
147 		  ub1 *piecep,
148 		  dvoid **indpp,
149 		  ub2 **rcodep)
150 {
151 	*piecep = OCI_ONE_PIECE;
152 
153 	if (!ora_value->value) {
154 		/* 1st chunk */
155 		ora_value->defined_size = 0;
156 		ora_value->value = g_new0 (guchar, BUFFER_SIZE + 1);
157 		*bufpp = ora_value->value;
158 	}
159 	else {
160 		/* other chunks */
161 		ora_value->defined_size += ora_value->xlen; /* previous's chunk's real size */
162 #ifdef GDA_DEBUG_NO
163 		gint i;
164 		g_print ("XLEN= %d\n", ora_value->xlen);
165 		for (i = 0 ; i < ora_value->defined_size; i++)
166 			g_print ("SO FAR[%d]=[%d]%c\n", i, ((gchar*) ora_value->value)[i],
167 				 g_unichar_isgraph (((gchar*) ora_value->value)[i]) ? ((gchar*) ora_value->value)[i] : '-');
168 #endif
169 		ora_value->value = g_renew (guchar, ora_value->value, ora_value->defined_size + BUFFER_SIZE);
170 		*bufpp = ora_value->value + ora_value->defined_size;
171 	}
172 
173 	ora_value->xlen = BUFFER_SIZE;
174 	*alenpp = &(ora_value->xlen);
175 	*indpp = (dvoid *) &(ora_value->indicator);
176 	*rcodep = (ub2 *) &(ora_value->rcode);
177 
178 	return OCI_CONTINUE;
179 }
180 
181 /*
182  * the @ps struct is modified and transferred to the new data model created in
183  * this function
184  */
185 GdaDataModel *
gda_oracle_recordset_new(GdaConnection * cnc,GdaOraclePStmt * ps,GdaSet * exec_params,GdaDataModelAccessFlags flags,GType * col_types)186 gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_params,
187 			  GdaDataModelAccessFlags flags, GType *col_types)
188 {
189 	GdaOracleRecordset *model;
190         OracleConnectionData *cdata;
191         gint i;
192 	GdaDataModelAccessFlags rflags;
193 
194 	gint nb_rows = -1;
195 
196         g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
197         g_return_val_if_fail (ps != NULL, NULL);
198 
199 	cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
200 	if (!cdata)
201 		return NULL;
202 
203 	/* make sure @ps reports the correct number of columns using the API */
204         if (_GDA_PSTMT (ps)->ncols < 0) {
205 		ub4 ncolumns;
206 		int result;
207 
208                 /* get the number of columns in the result set */
209                 result = OCIAttrGet ((dvoid *) ps->hstmt,
210                                      (ub4) OCI_HTYPE_STMT,
211                                      (dvoid *) &ncolumns,
212                                      (ub4 *) 0,
213                                      (ub4) OCI_ATTR_PARAM_COUNT,
214                                      cdata->herr);
215                 if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
216                                              _("Could not get the number of columns in the result set")))
217                         return NULL;
218 
219                 _GDA_PSTMT (ps)->ncols = ncolumns;
220 	}
221 
222         /* completing @ps if not yet done */
223         if (!_GDA_PSTMT (ps)->types && (_GDA_PSTMT (ps)->ncols > 0)) {
224 		/* create prepared statement's columns */
225 		GSList *list;
226 		GList *ora_values = NULL;
227 
228 		for (i = 0; i < _GDA_PSTMT (ps)->ncols; i++)
229 			_GDA_PSTMT (ps)->tmpl_columns = g_slist_prepend (_GDA_PSTMT (ps)->tmpl_columns,
230 									 gda_column_new ());
231 		_GDA_PSTMT (ps)->tmpl_columns = g_slist_reverse (_GDA_PSTMT (ps)->tmpl_columns);
232 
233 		/* create prepared statement's types, all types are initialized to GDA_TYPE_NULL */
234 		_GDA_PSTMT (ps)->types = g_new (GType, _GDA_PSTMT (ps)->ncols);
235 		for (i = 0; i < _GDA_PSTMT (ps)->ncols; i++)
236 			_GDA_PSTMT (ps)->types [i] = GDA_TYPE_NULL;
237 
238 		if (col_types) {
239 			for (i = 0; ; i++) {
240 				if (col_types [i] > 0) {
241 					if (col_types [i] == G_TYPE_NONE)
242 						break;
243 					if (i >= _GDA_PSTMT (ps)->ncols) {
244 						g_warning (_("Column %d out of range (0-%d), ignoring its specified type"), i,
245 							   _GDA_PSTMT (ps)->ncols - 1);
246 						break;
247 					}
248 					else
249 						_GDA_PSTMT (ps)->types [i] = col_types [i];
250 				}
251 			}
252 		}
253 
254 		/* fill GdaColumn's data and define the GdaOracleValue structures */
255 		for (i=0, list = _GDA_PSTMT (ps)->tmpl_columns;
256 		     i < GDA_PSTMT (ps)->ncols;
257 		     i++, list = list->next) {
258 			GdaColumn *column;
259 			int result;
260 			GdaOracleValue *ora_value;
261 			gboolean use_callback = FALSE;
262 
263 			ora_value = g_new0 (GdaOracleValue, 1);
264 			ora_values = g_list_prepend (ora_values, ora_value);
265 
266 			/* parameter to get attributes */
267 			result = OCIParamGet (ps->hstmt,
268 					      OCI_HTYPE_STMT,
269 					      cdata->herr,
270 					      (dvoid **) &(ora_value->pard),
271 					      (ub4) i+1);
272 			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
273 						     _("Could not get the Oracle parameter descripter in the result set"))) {
274 				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
275 				return NULL;
276 			}
277 
278 			/* data size */
279 			result = OCIAttrGet ((dvoid *) (ora_value->pard),
280 					     OCI_DTYPE_PARAM,
281 					     &(ora_value->defined_size),
282 					     0,
283 					     (ub4) OCI_ATTR_DATA_SIZE,
284 					     cdata->herr);
285 			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
286 						     _("Could not get the parameter defined size"))) {
287 				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
288 				return NULL;
289 			}
290 			ora_value->defined_size++;
291 
292 			/* data type */
293 			result = OCIAttrGet ((dvoid *) (ora_value->pard),
294 					     OCI_DTYPE_PARAM,
295 					     &(ora_value->sql_type),
296 					     0,
297 					     OCI_ATTR_DATA_TYPE,
298 					     cdata->herr);
299 			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
300 						     _("Could not get the parameter data type"))) {
301 				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
302 				return NULL;
303 			}
304 
305 			result = OCIAttrGet ((dvoid *) (ora_value->pard),
306 					     OCI_DTYPE_PARAM,
307 					     &(ora_value->precision),
308 					     0,
309 					     OCI_ATTR_PRECISION,
310 					     cdata->herr);
311 			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
312 						     _("Could not get the type's precision"))) {
313 				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
314 				return NULL;
315 			}
316 
317 			result = OCIAttrGet ((dvoid *) (ora_value->pard),
318 					     OCI_DTYPE_PARAM,
319 					     &(ora_value->scale),
320 					     0,
321 					     OCI_ATTR_SCALE,
322 					     cdata->herr);
323 			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
324 						     _("Could not get the type's scale"))) {
325 				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
326 				return NULL;
327 			}
328 
329 			/* column's name */
330 			text *name;
331 			ub4 name_len;
332 
333 			column = GDA_COLUMN (list->data);
334 			result = OCIAttrGet ((dvoid *) (ora_value->pard),
335                                              (ub4) OCI_DTYPE_PARAM,
336                                              (dvoid **) &name,
337                                              (ub4 *) &name_len,
338                                              (ub4) OCI_ATTR_NAME,
339                                              (OCIError *) cdata->herr);
340 			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
341                                                      _("Could not get column name in the result set"))) {
342 				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
343                                 return NULL;
344 			}
345 
346 			gchar *name_buffer;
347 			name_buffer = g_new (gchar, name_len + 1);
348 			memcpy (name_buffer, name, name_len);
349                         name_buffer [name_len] = '\0';
350 			gda_column_set_name (column, name_buffer);
351 			gda_column_set_description (column, name_buffer);
352 			g_free (name_buffer);
353 
354 			/* for data fetching  */
355 			if (_GDA_PSTMT (ps)->types [i] != GDA_TYPE_NULL)
356 				ora_value->sql_type = _g_type_to_oracle_sqltype (_GDA_PSTMT (ps)->types [i]);
357 
358 			switch (ora_value->sql_type) {
359 			case SQLT_CHR: /* for G_TYPE_STRING => request SQLT_CHR */
360 			case SQLT_STR:
361 			case SQLT_VCS:
362 			case SQLT_RID:
363 			case SQLT_AVC:
364 			case SQLT_AFC:
365 				ora_value->sql_type = SQLT_CHR;
366 				if (ora_value->defined_size == 1)
367 					use_callback = TRUE;
368 				break;
369 
370 			case SQLT_INT:
371 				ora_value->defined_size = sizeof (gint);
372 				break;
373 
374 			case SQLT_FLT:
375 			case SQLT_BFLOAT:
376 				ora_value->defined_size = sizeof (gfloat);
377 				break;
378 
379 			case SQLT_BDOUBLE:
380 				ora_value->defined_size = sizeof (gdouble);
381 				break;
382 
383 			case SQLT_DAT: /* request OCIDate */
384 				ora_value->sql_type = SQLT_ODT;
385 				break;
386 
387 			case SQLT_NUM: /* for GDA_TYPE_NUMERIC => request SQLT_CHR */
388 			case SQLT_VNU:
389 				ora_value->sql_type = SQLT_CHR;
390 				break;
391 
392 			case SQLT_LBI:
393 			case SQLT_LVB:
394 			case SQLT_LVC:
395 			case SQLT_LNG:
396 			case SQLT_VBI:
397 			case SQLT_BIN:
398 				use_callback = TRUE;
399 				break;
400 			default:
401 				use_callback = TRUE;
402 				break;
403 			}
404 
405 			if (_GDA_PSTMT (ps)->types [i] != GDA_TYPE_NULL)
406 				ora_value->g_type = _GDA_PSTMT (ps)->types [i];
407 			else
408 				ora_value->g_type = _oracle_sqltype_to_g_type (ora_value->sql_type, ora_value->precision,
409 									       ora_value->scale);
410 
411 			if (ora_value->g_type == GDA_TYPE_BLOB) {
412 				/* allocate a Lob locator */
413 				OCILobLocator *lob;
414 
415 				result = OCIDescriptorAlloc ((dvoid *) cdata->henv, (dvoid **) &lob,
416 							     (ub4) gda_oracle_blob_type (ora_value->sql_type),
417 							     (size_t) 0, (dvoid **) 0);
418 				if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
419 							     _("Could not allocate Lob locator"))) {
420 					g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
421 					return NULL;
422 				}
423 				ora_value->value = lob;
424 				ora_value->defined_size = 0;
425 			}
426 			else if (use_callback) {
427 				ora_value->value = NULL;
428 				ora_value->defined_size = 33554432; /* 32M */
429 			}
430 			else
431 				ora_value->value = g_malloc0 (ora_value->defined_size);
432 
433 			ora_value->s_type = gda_g_type_to_static_type (ora_value->g_type);
434 			if (_GDA_PSTMT (ps)->types [i] == GDA_TYPE_NULL)
435 				_GDA_PSTMT (ps)->types [i] = ora_value->g_type;
436 			gda_column_set_g_type (column, ora_value->g_type);
437 
438 #ifdef GDA_DEBUG_NO
439 			g_print ("**COL type is %d, GType is %s, ORA defined size is %d%s\n",
440 				 ora_value->sql_type,
441 				 g_type_name (ora_value->g_type),
442 				 ora_value->defined_size - 1,
443 				 use_callback ? " using callback": "");
444 #endif
445 
446 			ora_value->hdef = (OCIDefine *) 0;
447 			ora_value->indicator = 0;
448 			result = OCIDefineByPos ((OCIStmt *) ps->hstmt,
449 						 (OCIDefine **) &(ora_value->hdef),
450 						 (OCIError *) cdata->herr,
451 						 (ub4) i + 1,
452 						 ora_value->value,
453 						 ora_value->defined_size,
454 						 ora_value->sql_type,
455 						 (dvoid *) &(ora_value->indicator),
456 						 &(ora_value->rlen),
457 						 &(ora_value->rcode),
458 						 (ub4) (use_callback ? OCI_DYNAMIC_FETCH : OCI_DEFAULT));
459 			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
460 						     _("Could not define by position"))) {
461 				OCIDescriptorFree ((dvoid *) ora_value->pard, OCI_DTYPE_PARAM);
462 				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
463 				return NULL;
464 			}
465 
466 			if (use_callback) {
467 				result = OCIDefineDynamic ((OCIDefine *) (ora_value->hdef),
468 							   (OCIError *) (cdata->herr),
469 							   (dvoid*) (ora_value),
470 							   (OCICallbackDefine) ora_def_callback);
471 				if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
472 							     _("Could not define by position"))) {
473 					OCIDescriptorFree ((dvoid *) ora_value->pard, OCI_DTYPE_PARAM);
474 					g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
475 					return NULL;
476 				}
477 			}
478 
479 			ora_value->use_callback = use_callback;
480 		}
481 
482 		ps->ora_values = g_list_reverse (ora_values);
483         }
484 
485 	/* determine access mode: RANDOM or CURSOR FORWARD are the only supported; if CURSOR BACKWARD
486          * is requested, then we need RANDOM mode */
487         if (flags & GDA_DATA_MODEL_ACCESS_RANDOM)
488                 rflags = GDA_DATA_MODEL_ACCESS_RANDOM;
489         else if (flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD)
490                 rflags = GDA_DATA_MODEL_ACCESS_RANDOM;
491         else
492                 rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
493 
494 	ub4 prefetch;
495 	prefetch = (ub4) (100);
496 	OCIAttrSet (ps->hstmt, OCI_HTYPE_STMT,
497 		    &prefetch, 0,
498 		    OCI_ATTR_PREFETCH_ROWS, cdata->herr);
499 
500 	/* create data model */
501         model = g_object_new (GDA_TYPE_ORACLE_RECORDSET,
502 			      "connection", cnc,
503 			      "prepared-stmt", ps,
504 			      "model-usage", rflags,
505 			      "exec-params", exec_params, NULL);
506 	GDA_DATA_SELECT (model)->advertized_nrows = nb_rows;
507 
508         return GDA_DATA_MODEL (model);
509 }
510 
511 static GdaRow *
fetch_next_oracle_row(GdaOracleRecordset * model,G_GNUC_UNUSED gboolean do_store,GError ** error)512 fetch_next_oracle_row (GdaOracleRecordset *model, G_GNUC_UNUSED gboolean do_store, GError **error)
513 {
514 	int result;
515 	GdaRow *prow = NULL;
516 	GdaOraclePStmt *ps = GDA_ORACLE_PSTMT (((GdaDataSelect*)model)->prep_stmt);
517 	OracleConnectionData *cdata;
518 	GdaConnection *cnc;
519 
520 	cnc = gda_data_select_get_connection ((GdaDataSelect*) model);
521 	cdata = (OracleConnectionData*)	gda_connection_internal_get_provider_data_error (cnc, error);
522 	if (!cdata)
523 		return NULL;
524 
525 	/* fetch row */
526 	if (cdata->major_version > 9)
527 		result = OCIStmtFetch2 (ps->hstmt,
528 					cdata->herr,
529 					(ub4) 1,
530 					(ub2) OCI_FETCH_NEXT,
531 					(sb4) 1,
532 					(ub4) OCI_DEFAULT);
533 	else
534 		result = OCIStmtFetch (ps->hstmt,
535 				       cdata->herr,
536 				       (ub4) 1,
537 				       (ub2) OCI_FETCH_NEXT,
538 				       (ub4) OCI_DEFAULT);
539 	if (result == OCI_NO_DATA) {
540 		GDA_DATA_SELECT (model)->advertized_nrows = model->priv->next_row_num;
541 		return NULL;
542 	}
543 	else {
544 		GdaConnectionEvent *event;
545 		if ((event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
546 						      _("Could not fetch next row")))) {
547 			/* set @error */
548 			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
549 				     "%s", gda_connection_event_get_description (event));
550 
551 			return NULL;
552 		}
553 	}
554 
555 	prow = new_row ((GdaDataSelect*) model, cnc, ps);
556 	gda_data_select_take_row ((GdaDataSelect*) model, prow, model->priv->next_row_num);
557 	model->priv->next_row_num ++;
558 
559 	return prow;
560 }
561 
562 
563 /*
564  * Get the number of rows in @model, if possible
565  */
566 static gint
gda_oracle_recordset_fetch_nb_rows(GdaDataSelect * model)567 gda_oracle_recordset_fetch_nb_rows (GdaDataSelect *model)
568 {
569 	GdaOracleRecordset *imodel;
570         GdaRow *prow = NULL;
571 
572         imodel = GDA_ORACLE_RECORDSET (model);
573         if (model->advertized_nrows >= 0)
574                 return model->advertized_nrows;
575 
576 	struct timeval stm1, stm2;
577 
578 	gettimeofday (&stm1, NULL);
579 
580         for (prow = fetch_next_oracle_row (imodel, TRUE, NULL);
581              prow;
582              prow = fetch_next_oracle_row (imodel, TRUE, NULL));
583 
584 	gettimeofday (&stm2, NULL);
585 	/*g_print ("TOTAL time to get nb rows: %0.2f ms\n", (float) (TS_DIFF(stm1,stm2) / 1000.));*/
586 
587         return model->advertized_nrows;
588 }
589 
590 /*
591  * Create a new filled #GdaRow object for the row at position @rownum, and put it into *prow.
592  *
593  * Each new #GdaRow created needs to be "given" to the #GdaDataSelect implementation using
594  * gda_data_select_take_row() because backward iterating is not supported.
595  */
596 static gboolean
gda_oracle_recordset_fetch_random(GdaDataSelect * model,GdaRow ** prow,gint rownum,GError ** error)597 gda_oracle_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
598 {
599 	GdaOracleRecordset *imodel;
600 	OracleConnectionData *cdata;
601 	GdaConnection *cnc;
602 
603 	imodel = GDA_ORACLE_RECORDSET (model);
604 	cnc = gda_data_select_get_connection (model);
605 	cdata = (OracleConnectionData*)	gda_connection_internal_get_provider_data_error (cnc, error);
606 	if (!cdata)
607 		return TRUE;
608 
609 	if (imodel->priv->next_row_num >= rownum) {
610 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
611 			     GDA_SERVER_PROVIDER_INTERNAL_ERROR,
612 			     "%s", _("Requested row could not be found"));
613 		return TRUE;
614 	}
615 	for (*prow = fetch_next_oracle_row (imodel, TRUE, error);
616 	     *prow && (imodel->priv->next_row_num < rownum);
617 	     *prow = fetch_next_oracle_row (imodel, TRUE, error));
618 
619 	return TRUE;
620 }
621 
622 /*
623  * Create a new filled #GdaRow object for the next cursor row, and put it into *prow.
624  *
625  * Each new #GdaRow created needs to be "given" to the #GdaDataSelect implementation using
626  * gda_data_select_take_row() because backward iterating is not supported.
627  */
628 static gboolean
gda_oracle_recordset_fetch_next(GdaDataSelect * model,GdaRow ** prow,gint rownum,GError ** error)629 gda_oracle_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
630 {
631 	GdaOracleRecordset *imodel = (GdaOracleRecordset*) model;
632 
633 	if (imodel->priv->next_row_num != rownum) {
634 		GError *lerror = NULL;
635 		*prow = NULL;
636 		g_set_error (&lerror, GDA_DATA_MODEL_ERROR,
637 			     GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR,
638 			     "%s", _("Can't set iterator on requested row"));
639 		gda_data_select_add_exception (GDA_DATA_SELECT (model), lerror);
640 		if (error)
641 			g_propagate_error (error, g_error_copy (lerror));
642 		return TRUE;
643 	}
644 	*prow = fetch_next_oracle_row ((GdaOracleRecordset*) model, TRUE, error);
645 	return TRUE;
646 }
647 
648 
649 /* create a new GdaRow from the last read row */
650 static GdaRow *
new_row(GdaDataSelect * imodel,GdaConnection * cnc,GdaOraclePStmt * ps)651 new_row (GdaDataSelect *imodel, GdaConnection *cnc, GdaOraclePStmt *ps)
652 {
653 	GdaRow *prow;
654 	GList *nodes;
655 	gint i;
656 
657 	prow = gda_row_new (((GdaDataSelect*) imodel)->prep_stmt->ncols);
658 	for (i = 0, nodes = ps->ora_values;
659 	     nodes;
660 	     i++, nodes = nodes->next) {
661 		GdaOracleValue *ora_value = (GdaOracleValue *) nodes->data;
662                 GValue *value = gda_row_get_value (prow, i);
663                 _gda_oracle_set_value (value, ora_value, cnc);
664 	}
665 
666 	return prow;
667 }
668