execute.c 20.6 KB
Newer Older
1 2

/* Module:          execute.c
3
 *
4 5
 * Description:     This module contains routines related to 
 *                  preparing and executing an SQL statement.
6
 *
7
 * Classes:         n/a
8
 *
9 10
 * API functions:   SQLPrepare, SQLExecute, SQLExecDirect, SQLTransact,
 *                  SQLCancel, SQLNativeSql, SQLParamData, SQLPutData
11
 *
12
 * Comments:        See "notice.txt" for copyright and license information.
13 14
 *
 */
15

Byron Nikolaidis's avatar
Byron Nikolaidis committed
16
#ifdef HAVE_CONFIG_H
17
#include "config.h"
Byron Nikolaidis's avatar
Byron Nikolaidis committed
18 19
#endif

20 21 22
#include "psqlodbc.h"
#include <stdio.h>
#include <string.h>
Byron Nikolaidis's avatar
Byron Nikolaidis committed
23

24
#ifndef WIN32
Byron Nikolaidis's avatar
Byron Nikolaidis committed
25 26 27
#include "iodbc.h"
#include "isqlext.h"
#else
28 29
#include <windows.h>
#include <sqlext.h>
Byron Nikolaidis's avatar
Byron Nikolaidis committed
30
#endif
31 32 33 34 35 36

#include "connection.h"
#include "statement.h"
#include "qresult.h"
#include "convert.h"
#include "bind.h"
37
#include "lobj.h"
38

39 40
extern GLOBAL_VALUES globals;

41

42 43 44 45
/*      Perform a Prepare on the SQL statement */
RETCODE SQL_API SQLPrepare(HSTMT     hstmt,
                           UCHAR FAR *szSqlStr,
                           SDWORD    cbSqlStr)
46
{
47 48
static char *func = "SQLPrepare";
StatementClass *self = (StatementClass *) hstmt;
49

50
	mylog( "%s: entering...\n", func);
51

52
	if ( ! self) {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
53
		SC_log_error(func, "", NULL);
54
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
55
	}
56 57 58 59
    
	/*	According to the ODBC specs it is valid to call SQLPrepare mulitple times.
		In that case, the bound SQL statement is replaced by the new one 
	*/
60

61 62 63 64 65
	switch(self->status) {
	case STMT_PREMATURE:
		mylog("**** SQLPrepare: STMT_PREMATURE, recycle\n");
		SC_recycle_statement(self); /* recycle the statement, but do not remove parameter bindings */
		break;
66

67 68 69 70
	case STMT_FINISHED:
		mylog("**** SQLPrepare: STMT_FINISHED, recycle\n");
		SC_recycle_statement(self); /* recycle the statement, but do not remove parameter bindings */
		break;
71

72 73 74 75
	case STMT_ALLOCATED:
		mylog("**** SQLPrepare: STMT_ALLOCATED, copy\n");
		self->status = STMT_READY;
		break;
76

77 78 79
	case STMT_READY:
		mylog("**** SQLPrepare: STMT_READY, change SQL\n");
		break;
80

81 82
	case STMT_EXECUTING:
		mylog("**** SQLPrepare: STMT_EXECUTING, error!\n");
83

84 85 86
		self->errornumber = STMT_SEQUENCE_ERROR;
		self->errormsg = "SQLPrepare(): The handle does not point to a statement that is ready to be executed";
		SC_log_error(func, "", self);
87

88
		return SQL_ERROR;
89

90 91 92 93 94
	default:
		self->errornumber = STMT_INTERNAL_ERROR;
		self->errormsg = "An Internal Error has occured -- Unknown statement status.";
		SC_log_error(func, "", self);
		return SQL_ERROR;
95
	}
96 97 98 99 100

	if (self->statement)
		free(self->statement);

	self->statement = make_string(szSqlStr, cbSqlStr, NULL);
101
	if ( ! self->statement) {
102 103
		self->errornumber = STMT_NO_MEMORY_ERROR;
		self->errormsg = "No memory available to store statement";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
104
		SC_log_error(func, "", self);
105 106 107 108 109 110
		return SQL_ERROR;
	}

	self->prepare = TRUE;
	self->statement_type = statement_type(self->statement);

111 112
	/*	Check if connection is onlyread (only selects are allowed) */
	if ( CC_is_onlyread(self->hdbc) && STMT_UPDATE(self)) {
113 114
		self->errornumber = STMT_EXEC_ERROR;
		self->errormsg = "Connection is readonly, only select statements are allowed.";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
115
		SC_log_error(func, "", self);
116 117 118 119 120 121
		return SQL_ERROR;
	}

	return SQL_SUCCESS;


122 123
}

124
/*      -       -       -       -       -       -       -       -       - */
125

126
/*      Performs the equivalent of SQLPrepare, followed by SQLExecute. */
127

128 129 130 131
RETCODE SQL_API SQLExecDirect(
        HSTMT     hstmt,
        UCHAR FAR *szSqlStr,
        SDWORD    cbSqlStr)
132
{
133 134 135
StatementClass *stmt = (StatementClass *) hstmt;
RETCODE result;
static char *func = "SQLExecDirect";
136

137 138 139
	mylog( "%s: entering...\n", func);
    
	if ( ! stmt) {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
140
		SC_log_error(func, "", NULL);
141
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
142
	}
143 144 145 146

	if (stmt->statement)
		free(stmt->statement);

147 148
	/* keep a copy of the un-parametrized statement, in case */
	/* they try to execute this statement again */
149
	stmt->statement = make_string(szSqlStr, cbSqlStr, NULL);
150
	if ( ! stmt->statement) {
151 152
		stmt->errornumber = STMT_NO_MEMORY_ERROR;
		stmt->errormsg = "No memory available to store statement";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
153
		SC_log_error(func, "", stmt);
154 155 156
		return SQL_ERROR;
	}

157
	mylog("**** %s: hstmt=%u, statement='%s'\n", func, hstmt, stmt->statement);
158 159

	stmt->prepare = FALSE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
160

161 162 163
	/* If an SQLPrepare was performed prior to this, but was left in  */
	/* the premature state because an error occurred prior to SQLExecute */
	/* then set the statement to finished so it can be recycled. */
164
	if ( stmt->status == STMT_PREMATURE )
Byron Nikolaidis's avatar
Byron Nikolaidis committed
165 166
		stmt->status = STMT_FINISHED;

167 168
	stmt->statement_type = statement_type(stmt->statement);

169 170
	/*	Check if connection is onlyread (only selects are allowed) */
	if ( CC_is_onlyread(stmt->hdbc) && STMT_UPDATE(stmt)) {
171 172
		stmt->errornumber = STMT_EXEC_ERROR;
		stmt->errormsg = "Connection is readonly, only select statements are allowed.";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
173
		SC_log_error(func, "", stmt);
174 175
		return SQL_ERROR;
	}
176
	
177 178 179
	mylog("%s: calling SQLExecute...\n", func);

	result = SQLExecute(hstmt);
180

181 182
	mylog("%s: returned %hd from SQLExecute\n", func, result);
	return result;
183 184
}

185 186 187
/*      Execute a prepared SQL statement */
RETCODE SQL_API SQLExecute(
        HSTMT   hstmt)
188
{
189 190 191 192
static char *func="SQLExecute";
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
int i, retval;
193

194

195 196
	mylog("%s: entering...\n", func);

197
	if ( ! stmt) {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
198
		SC_log_error(func, "", NULL);
199
		mylog("%s: NULL statement so return SQL_INVALID_HANDLE\n", func);
200
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
201
	}
202

203 204 205 206 207 208 209
	/*  If the statement is premature, it means we already executed
		it from an SQLPrepare/SQLDescribeCol type of scenario.  So
		just return success.
	*/
	if ( stmt->prepare && stmt->status == STMT_PREMATURE) {
		stmt->status = STMT_FINISHED;       
		if (stmt->errormsg == NULL) {
210
			mylog("%s: premature statement but return SQL_SUCCESS\n", func);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
211
			return SQL_SUCCESS;
212
		}
213
		else {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
214
			SC_log_error(func, "", stmt);
215
			mylog("%s: premature statement so return SQL_ERROR\n", func);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
216 217
			return SQL_ERROR;
		}
218
	}  
219

220 221
	mylog("%s: clear errors...\n", func);

222 223 224
	SC_clear_error(stmt);

	conn = SC_get_conn(stmt);
225
	if (conn->status == CONN_EXECUTING) {
226 227
		stmt->errormsg = "Connection is already in use.";
		stmt->errornumber = STMT_SEQUENCE_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
228
		SC_log_error(func, "", stmt);
229
		mylog("%s: problem with connection\n", func);
230 231 232
		return SQL_ERROR;
	}

233
	if ( ! stmt->statement) {
234 235
		stmt->errornumber = STMT_NO_STMTSTRING;
		stmt->errormsg = "This handle does not have a SQL statement stored in it";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
236
		SC_log_error(func, "", stmt);
237
		mylog("%s: problem with handle\n", func);
238 239 240
		return SQL_ERROR;
	}

241 242 243 244 245
	/*	If SQLExecute is being called again, recycle the statement.
		Note this should have been done by the application in a call
		to SQLFreeStmt(SQL_CLOSE) or SQLCancel.
	*/
	if (stmt->status == STMT_FINISHED) {
246
		mylog("%s: recycling statement (should have been done by app)...\n", func);
247 248 249
		SC_recycle_statement(stmt);
	}

250 251 252 253
	/*	Check if the statement is in the correct state */
	if ((stmt->prepare && stmt->status != STMT_READY) || 
		(stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) {
		
254 255
		stmt->errornumber = STMT_STATUS_ERROR;
		stmt->errormsg = "The handle does not point to a statement that is ready to be executed";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
256
		SC_log_error(func, "", stmt);
257
		mylog("%s: problem with statement\n", func);
258
		return SQL_ERROR;
259 260 261
	}


262 263 264
	/*	The bound parameters could have possibly changed since the last execute
		of this statement?  Therefore check for params and re-copy.
	*/
265
	stmt->data_at_exec = -1;
266 267 268
	for (i = 0; i < stmt->parameters_allocated; i++) {
		/*	Check for data at execution parameters */
		if ( stmt->parameters[i].data_at_exec == TRUE) {
269 270 271 272 273 274
			if (stmt->data_at_exec < 0)
				stmt->data_at_exec = 1;
			else
				stmt->data_at_exec++;
		}
	}
275 276
	/*	If there are some data at execution parameters, return need data */
	/*	SQLParamData and SQLPutData will be used to send params and execute the statement. */
277 278 279 280
	if (stmt->data_at_exec > 0)
		return SQL_NEED_DATA;


281
	mylog("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement);
282

283
	/*	Create the statement with parameters substituted. */
284
	retval = copy_statement_with_parameters(stmt);
285
	if( retval != SQL_SUCCESS)
286 287 288 289 290 291 292
		/* error msg passed from above */
		return retval;

	mylog("   stmt_with_params = '%s'\n", stmt->stmt_with_params);


	return SC_execute(stmt);
293

294
}
295 296 297



298

299 300 301 302 303
/*      -       -       -       -       -       -       -       -       - */
RETCODE SQL_API SQLTransact(
        HENV    henv,
        HDBC    hdbc,
        UWORD   fType)
304
{
305 306 307 308 309 310
static char *func = "SQLTransact";
extern ConnectionClass *conns[];
ConnectionClass *conn;
QResultClass *res;
char ok, *stmt_string;
int lf;
311

312
	mylog("entering %s: hdbc=%u, henv=%u\n", func, hdbc, henv);
313

314
	if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV) {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
315
		CC_log_error(func, "", NULL);
316
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
317
	}
318

319 320 321 322 323
	/* If hdbc is null and henv is valid,
	it means transact all connections on that henv.  
	*/
	if (hdbc == SQL_NULL_HDBC && henv != SQL_NULL_HENV) {
		for (lf=0; lf <MAX_CONNECTIONS; lf++) {
324 325 326
			conn = conns[lf];

			if (conn && conn->henv == henv)
327
				if ( SQLTransact(henv, (HDBC) conn, fType) != SQL_SUCCESS)
328
					return SQL_ERROR;
329

330
		}
331
		return SQL_SUCCESS;       
332 333 334 335
	}

	conn = (ConnectionClass *) hdbc;

336
	if (fType == SQL_COMMIT) {
337
		stmt_string = "COMMIT";
338 339

	} else if (fType == SQL_ROLLBACK) {
340
		stmt_string = "ROLLBACK";
341 342

	} else {
343
		conn->errornumber = CONN_INVALID_ARGUMENT_NO;
344
		conn->errormsg ="SQLTransact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
345
		CC_log_error(func, "", conn);
346
		return SQL_ERROR;
347 348 349 350
	}    

	/*	If manual commit and in transaction, then proceed. */
	if ( ! CC_is_in_autocommit(conn) &&  CC_is_in_trans(conn)) {
351 352 353

		mylog("SQLTransact: sending on conn %d '%s'\n", conn, stmt_string);

354
		res = CC_send_query(conn, stmt_string, NULL);
355 356
		CC_set_no_trans(conn);

357 358
		if ( ! res) {
			/*	error msg will be in the connection */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
359
			CC_log_error(func, "", conn);
360
			return SQL_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
361
		}
362

363
		ok = QR_command_successful(res);   
364 365
		QR_Destructor(res);

366
		if (!ok) {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
367
			CC_log_error(func, "", conn);
368
			return SQL_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
369
		}
370
	}    
371 372 373
	return SQL_SUCCESS;
}

374
/*      -       -       -       -       -       -       -       -       - */
375

376 377
RETCODE SQL_API SQLCancel(
        HSTMT   hstmt)  /* Statement to cancel. */
378
{
379 380 381
static char *func="SQLCancel";
StatementClass *stmt = (StatementClass *) hstmt;
RETCODE result;
382
#ifdef WIN32
383 384
HMODULE hmodule;
FARPROC addr;
385
#endif
386

387
	mylog( "%s: entering...\n", func);
388

389 390
	/*	Check if this can handle canceling in the middle of a SQLPutData? */
	if ( ! stmt) {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
391
		SC_log_error(func, "", NULL);
392
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
393
	}
394

395 396 397 398 399 400 401 402 403 404 405
	/*	Not in the middle of SQLParamData/SQLPutData so cancel like a close. */
	if (stmt->data_at_exec < 0) {


		/*	MAJOR HACK for Windows to reset the driver manager's cursor state:
			Because of what seems like a bug in the Odbc driver manager,
			SQLCancel does not act like a SQLFreeStmt(CLOSE), as many
			applications depend on this behavior.  So, this 
			brute force method calls the driver manager's function on
			behalf of the application.  
		*/
406 407

#ifdef WIN32
408
		if (globals.cancel_as_freestmt) {
409 410
			hmodule = GetModuleHandle("ODBC32");
			addr = GetProcAddress(hmodule, "SQLFreeStmt");
411 412 413 414
			result = addr( (char *) (stmt->phstmt) - 96, SQL_CLOSE);
		}
		else {
			result = SQLFreeStmt( hstmt, SQL_CLOSE);
415 416
		}
#else
417
		result = SQLFreeStmt( hstmt, SQL_CLOSE);
418 419 420 421 422 423 424
#endif

		mylog("SQLCancel:  SQLFreeStmt returned %d\n", result);

		SC_clear_error(hstmt);
		return SQL_SUCCESS;
	}
425

426 427 428
	/*	In the middle of SQLParamData/SQLPutData, so cancel that. */
	/*	Note, any previous data-at-exec buffers will be freed in the recycle */
	/*	if they call SQLExecDirect or SQLExecute again. */
429 430 431 432 433

	stmt->data_at_exec = -1;
	stmt->current_exec_param = -1;
	stmt->put_data = FALSE;

Byron Nikolaidis's avatar
Byron Nikolaidis committed
434
	return SQL_SUCCESS;
435

436 437
}

438
/*      -       -       -       -       -       -       -       -       - */
439

440
/*      Returns the SQL string as modified by the driver. */
441 442
/*		Currently, just copy the input string without modification */
/*		observing buffer limits and truncation. */
443 444 445 446 447 448 449
RETCODE SQL_API SQLNativeSql(
        HDBC      hdbc,
        UCHAR FAR *szSqlStrIn,
        SDWORD     cbSqlStrIn,
        UCHAR FAR *szSqlStr,
        SDWORD     cbSqlStrMax,
        SDWORD FAR *pcbSqlStr)
450
{
451 452 453 454 455
static char *func="SQLNativeSql";
int len = 0;
char *ptr;
ConnectionClass *conn = (ConnectionClass *) hdbc;
RETCODE result;
456

457
	mylog( "%s: entering...cbSqlStrIn=%d\n", func, cbSqlStrIn);
458 459

	ptr = (cbSqlStrIn == 0) ? "" : make_string(szSqlStrIn, cbSqlStrIn, NULL);
460
	if ( ! ptr) {
461 462 463 464 465 466 467 468 469
		conn->errornumber = CONN_NO_MEMORY_ERROR;
		conn->errormsg = "No memory available to store native sql string";
		CC_log_error(func, "", conn);
		return SQL_ERROR;
	}

	result = SQL_SUCCESS;
	len = strlen(ptr);

470
	if (szSqlStr) {
471 472
		strncpy_null(szSqlStr, ptr, cbSqlStrMax);

473
		if (len >= cbSqlStrMax)  {
474 475 476 477 478 479 480 481
			result = SQL_SUCCESS_WITH_INFO;
			conn->errornumber = STMT_TRUNCATED;
			conn->errormsg = "The buffer was too small for the result.";
		}
	}

	if (pcbSqlStr)
		*pcbSqlStr = len;
482

483
	free(ptr);
484

485
    return result;
486 487
}

488
/*      -       -       -       -       -       -       -       -       - */
489

490 491
/*      Supplies parameter data at execution time.      Used in conjuction with */
/*      SQLPutData. */
492

493 494 495
RETCODE SQL_API SQLParamData(
        HSTMT   hstmt,
        PTR FAR *prgbValue)
496
{
497 498 499
static char *func = "SQLParamData";
StatementClass *stmt = (StatementClass *) hstmt;
int i, retval;
500

501
	mylog( "%s: entering...\n", func);
502

503
	if ( ! stmt) {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
504
		SC_log_error(func, "", NULL);
505
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
506
	}
507

508
	mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, stmt->parameters_allocated);
509

510
	if (stmt->data_at_exec < 0) {
511 512
		stmt->errornumber = STMT_SEQUENCE_ERROR;
		stmt->errormsg = "No execution-time parameters for this statement";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
513
		SC_log_error(func, "", stmt);
514 515 516
		return SQL_ERROR;
	}

517
	if (stmt->data_at_exec > stmt->parameters_allocated) {
518 519
		stmt->errornumber = STMT_SEQUENCE_ERROR;
		stmt->errormsg = "Too many execution-time parameters were present";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
520
		SC_log_error(func, "", stmt);
521 522 523 524
		return SQL_ERROR;
	}

	/* close the large object */
525
	if ( stmt->lobj_fd >= 0) {
526
		lo_close(stmt->hdbc, stmt->lobj_fd);
527 528

		/* commit transaction if needed */
529
		if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) {
530
			QResultClass *res;
531
			char ok;
532 533

			res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
534
			if (!res) {
535 536 537 538 539 540 541
				stmt->errormsg = "Could not commit (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				SC_log_error(func, "", stmt);
				return SQL_ERROR;
			}
			ok = QR_command_successful(res);
			QR_Destructor(res);
542
			if (!ok) {
543 544 545 546 547 548 549 550 551
				stmt->errormsg = "Could not commit (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				SC_log_error(func, "", stmt);
				return SQL_ERROR;
			}

			CC_set_no_trans(stmt->hdbc);
		}

552 553 554 555
		stmt->lobj_fd = -1;
	}


556 557
	/*	Done, now copy the params and then execute the statement */
	if (stmt->data_at_exec == 0) {
558 559 560 561 562 563 564 565 566
		retval = copy_statement_with_parameters(stmt);
		if (retval != SQL_SUCCESS)
			return retval;

		stmt->current_exec_param = -1;

		return SC_execute(stmt);
	}

567 568 569 570 571 572 573 574
	/*	Set beginning param;  if first time SQLParamData is called , start at 0.
		Otherwise, start at the last parameter + 1.
	*/
	i = stmt->current_exec_param >= 0 ? stmt->current_exec_param+1 : 0;

	/*	At least 1 data at execution parameter, so Fill in the token value */
	for ( ; i < stmt->parameters_allocated; i++) {
		if (stmt->parameters[i].data_at_exec == TRUE) {
575 576 577 578 579 580 581 582 583
			stmt->data_at_exec--;
			stmt->current_exec_param = i;
			stmt->put_data = FALSE;
			*prgbValue = stmt->parameters[i].buffer;	/* token */
			break;
		}
	}

	return SQL_NEED_DATA;
584 585
}

586
/*      -       -       -       -       -       -       -       -       - */
587

588 589
/*      Supplies parameter data at execution time.      Used in conjunction with */
/*      SQLParamData. */
590

591 592 593 594
RETCODE SQL_API SQLPutData(
        HSTMT   hstmt,
        PTR     rgbValue,
        SDWORD  cbValue)
595
{
596 597 598 599 600
static char *func = "SQLPutData";
StatementClass *stmt = (StatementClass *) hstmt;
int old_pos, retval;
ParameterInfoClass *current_param;
char *buffer;
601

602
	mylog( "%s: entering...\n", func);
603

604
	if ( ! stmt) {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
605
		SC_log_error(func, "", NULL);
606
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
607
	}
608

609 610
	
	if (stmt->current_exec_param < 0) {
611 612
		stmt->errornumber = STMT_SEQUENCE_ERROR;
		stmt->errormsg = "Previous call was not SQLPutData or SQLParamData";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
613
		SC_log_error(func, "", stmt);
614 615 616 617 618
		return SQL_ERROR;
	}

	current_param = &(stmt->parameters[stmt->current_exec_param]);

619
	if ( ! stmt->put_data) {	/* first call */
620 621 622 623 624 625

		mylog("SQLPutData: (1) cbValue = %d\n", cbValue);

		stmt->put_data = TRUE;

		current_param->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD));
626
		if ( ! current_param->EXEC_used) {
627 628
			stmt->errornumber = STMT_NO_MEMORY_ERROR;
			stmt->errormsg = "Out of memory in SQLPutData (1)";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
629
			SC_log_error(func, "", stmt);
630 631 632 633 634 635 636 637 638
			return SQL_ERROR;
		}

		*current_param->EXEC_used = cbValue;

		if (cbValue == SQL_NULL_DATA)
			return SQL_SUCCESS;


639 640 641
		/*	Handle Long Var Binary with Large Objects */
		if ( current_param->SQLType == SQL_LONGVARBINARY) {

642
			/* begin transaction if needed */
643
			if(!CC_is_in_trans(stmt->hdbc)) {
644
				QResultClass *res;
645
				char ok;
646 647

				res = CC_send_query(stmt->hdbc, "BEGIN", NULL);
648
				if (!res) {
649 650 651 652 653 654 655
					stmt->errormsg = "Could not begin (in-line) a transaction";
					stmt->errornumber = STMT_EXEC_ERROR;
					SC_log_error(func, "", stmt);
					return SQL_ERROR;
				}
				ok = QR_command_successful(res);
				QR_Destructor(res);
656
				if (!ok) {
657 658 659 660 661 662 663 664 665
					stmt->errormsg = "Could not begin (in-line) a transaction";
					stmt->errornumber = STMT_EXEC_ERROR;
					SC_log_error(func, "", stmt);
					return SQL_ERROR;
				}

				CC_set_in_trans(stmt->hdbc);
			}

666
			/*	store the oid */
667
			current_param->lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE);
668
			if (current_param->lobj_oid == 0) {
669 670
				stmt->errornumber = STMT_EXEC_ERROR;
				stmt->errormsg = "Couldnt create large object.";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
671
				SC_log_error(func, "", stmt);
672 673 674
				return SQL_ERROR;
			}

675 676
			/*	major hack -- to allow convert to see somethings there */
			/*					have to modify convert to handle this better */
677 678
			current_param->EXEC_buffer = (char *) &current_param->lobj_oid;

679
			/*	store the fd */
680
			stmt->lobj_fd = lo_open(stmt->hdbc, current_param->lobj_oid, INV_WRITE);
681
			if ( stmt->lobj_fd < 0) {
682 683
				stmt->errornumber = STMT_EXEC_ERROR;
				stmt->errormsg = "Couldnt open large object for writing.";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
684
				SC_log_error(func, "", stmt);
685 686 687 688 689
				return SQL_ERROR;
			}

			retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue);
			mylog("lo_write: cbValue=%d, wrote %d bytes\n", cbValue, retval);
690

691
		}
692
		else {	/* for handling text fields and small binaries */
693

694
			if (cbValue == SQL_NTS) {
695
				current_param->EXEC_buffer = strdup(rgbValue);
696
				if ( ! current_param->EXEC_buffer) {
697 698
					stmt->errornumber = STMT_NO_MEMORY_ERROR;
					stmt->errormsg = "Out of memory in SQLPutData (2)";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
699
					SC_log_error(func, "", stmt);
700 701 702
					return SQL_ERROR;
				}
			}
703
			else {
704
				current_param->EXEC_buffer = malloc(cbValue + 1);
705
				if ( ! current_param->EXEC_buffer) {
706 707
					stmt->errornumber = STMT_NO_MEMORY_ERROR;
					stmt->errormsg = "Out of memory in SQLPutData (2)";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
708
					SC_log_error(func, "", stmt);
709 710 711 712 713 714 715 716
					return SQL_ERROR;
				}
				memcpy(current_param->EXEC_buffer, rgbValue, cbValue);
				current_param->EXEC_buffer[cbValue] = '\0';
			}
		}
	}

717
	else {	/* calling SQLPutData more than once */
718 719 720

		mylog("SQLPutData: (>1) cbValue = %d\n", cbValue);

721 722
		if (current_param->SQLType == SQL_LONGVARBINARY) {

723 724 725 726 727
			/* the large object fd is in EXEC_buffer */
			retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue);
			mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", cbValue, retval);

			*current_param->EXEC_used += cbValue;
728 729 730

		} else {

731 732
			buffer = current_param->EXEC_buffer;

733
			if (cbValue == SQL_NTS) {
734
				buffer = realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1);
735
				if ( ! buffer) {
736 737
					stmt->errornumber = STMT_NO_MEMORY_ERROR;
					stmt->errormsg = "Out of memory in SQLPutData (3)";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
738
					SC_log_error(func, "", stmt);
739 740 741 742 743 744 745 746
					return SQL_ERROR;
				}
				strcat(buffer, rgbValue);

				mylog("       cbValue = SQL_NTS: strlen(buffer) = %d\n", strlen(buffer));

				*current_param->EXEC_used = cbValue;

747
				/*	reassign buffer incase realloc moved it */
748
				current_param->EXEC_buffer = buffer;
749

750
			}
751 752
			else if (cbValue > 0) {

753 754 755 756 757 758 759 760
				old_pos = *current_param->EXEC_used;

				*current_param->EXEC_used += cbValue;

				mylog("        cbValue = %d, old_pos = %d, *used = %d\n", cbValue, old_pos, *current_param->EXEC_used);

				/* dont lose the old pointer in case out of memory */
				buffer = realloc(current_param->EXEC_buffer, *current_param->EXEC_used + 1);
761
				if ( ! buffer) {
762 763
					stmt->errornumber = STMT_NO_MEMORY_ERROR;
					stmt->errormsg = "Out of memory in SQLPutData (3)";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
764
					SC_log_error(func, "", stmt);
765 766 767 768 769 770
					return SQL_ERROR;
				}

				memcpy(&buffer[old_pos], rgbValue, cbValue);
				buffer[*current_param->EXEC_used] = '\0';

771
				/*	reassign buffer incase realloc moved it */
772
				current_param->EXEC_buffer = buffer;
773
				
774
			}
775
			else {
Byron Nikolaidis's avatar
Byron Nikolaidis committed
776
				SC_log_error(func, "bad cbValue", stmt);
777
				return SQL_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
778
			}
779

780 781 782 783 784
		}
	}


	return SQL_SUCCESS;
785
}