1
/* (C) Copyright MySQL AB
3
** CURSOR.C - This is the MyODBC sample driver code for implementing
6
** With a non-keyset client-side cursor, the server sends the entire
7
** result set across the network to the client machine. The client
8
** machine provides and manages the temporary resources needed by
9
** the cursor and result set. The client-side application can browse
10
** through the entire result set to determine which rows it requires.
12
** Static and keyset-driven client-side cursors may place a significant
13
** load on your workstation if they include too many rows. While all of
14
** the cursor libraries are capable of building cursors with thousands
15
** of rows, applications designed to fetch such large rowsets may perform
16
** poorly. There are exceptions, of course. For some applications, a large
17
** client-side cursor may be perfectly appropriate and performance may not
20
** One obvious benefit of the client-side cursor is quick response. After
21
** the result set has been downloaded to the client machine, browsing
22
** through the rows is very fast. Your application is generally more
23
** scalable with client-side cursors because the cursor's resource
24
** requirements are placed on each separate client and not on the server.
27
** @date : 2001-June-01
32
static const char *find_used_table(STMT *stmt);
34
void my_param_bind(STMT FAR *srcStmt, STMT FAR *dstStmt,
35
SQLUSMALLINT nSrcCol,SQLUSMALLINT nDstCol);
37
SQLRETURN my_if_pk_exits(STMT FAR *stmt);
38
SQLRETURN my_pk_param_bind(STMT FAR *stmtNew,STMT FAR *stmt,
39
SQLUSMALLINT irow,SQLUSMALLINT nColParam);
40
my_bool my_build_where_clause(STMT FAR *stmt,
41
DYNAMIC_STRING *dynQuery);
42
void my_set_cursor_data(STMT FAR *stmt);
43
SQLRETURN my_pos_add(STMT FAR *stmt, SQLUSMALLINT irow,
44
DYNAMIC_STRING dynQuery);
46
SQLSetCursorName associates a cursor name with an active statement.
49
SQLRETURN SQL_API SQLSetCursorName(SQLHSTMT hstmt,
50
SQLCHAR FAR *szCursor,
53
STMT FAR *stmt=(STMT FAR*) hstmt;
55
DBUG_ENTER("SQLSetCursorName");
57
/* if null string passed as the cursor name */
59
DBUG_RETURN(set_stmt_error(stmt,"S1009",
60
"Invalid use of null pointer",0));
62
if (cbCursor == SQL_NTS)
63
cbCursor = (SQLSMALLINT) strlen(szCursor);
66
This will be handled by the DM, but when the application is linked
67
with the client lib(myodbc.lib), then driver need to through the error
70
DBUG_RETURN(set_stmt_error(stmt,"S1090",
71
"Invalid string or buffer length",0));
73
Through an error, when trying to set the cursor in the middle of
76
if (stmt->cursor_state == MYSQL_CURSOR_IN_EXECUTION ||
77
stmt->cursor_state == MYSQL_CURSOR_NEED_DATA)
78
DBUG_RETURN(set_stmt_error(stmt,"24000","Invalid cursor state",0));
80
/* validate for cursor names */
81
if ( (cbCursor == 0) ||
82
(my_casecmp(szCursor, "SQLCUR", 6) == 0) ||
83
(my_casecmp(szCursor, "SQL_CUR", 7) == 0))
84
DBUG_RETURN(set_stmt_error(stmt,"34000","Invalid cursor name",0));
86
stmt->cursor_state = MYSQL_CURSOR_DEFINED;
88
if length is larger than the supported, then truncate and
91
if (cbCursor > MYSQL_MAX_CURSOR_LEN)
93
/* set the warning ...by truncating the cursor name to max length */
94
strmake( stmt->cursor_name, szCursor, MYSQL_MAX_CURSOR_LEN);
95
set_stmt_error(stmt,"01004","String data, right truncated",01004);
96
DBUG_RETURN(SQL_SUCCESS_WITH_INFO);
98
strmake( stmt->cursor_name, szCursor, cbCursor);
99
DBUG_RETURN(SQL_SUCCESS);
104
SQLGetCursorName returns the cursor name associated with a specified
108
SQLRETURN SQL_API SQLGetCursorName(SQLHSTMT hstmt,
109
SQLCHAR FAR *szCursor,
110
SQLSMALLINT cbCursorMax,
111
SQLSMALLINT FAR *pcbCursor)
113
STMT FAR *stmt=(STMT FAR*) hstmt;
115
SQLINTEGER nDummyLength;
116
DBUG_ENTER("SQLGetCursorName");
119
LINT_INIT(nDummyLength);
122
If no prior cursor set by the application, as 2.x driver doesn't
123
handle any default cursors, give an error
125
if (stmt->cursor_state == MYSQL_CURSOR_UNDEFINED)
126
DBUG_RETURN(set_stmt_error(stmt,"S1015","No cursor name available",0));
128
/* if invalid buffer length */
130
DBUG_RETURN(set_stmt_error(stmt,"S1090",
131
"Invalid string or buffer length",0));
133
/* if the stmt is in the middle of execution... */
134
if (stmt->cursor_state == MYSQL_CURSOR_NEED_DATA )
135
DBUG_RETURN(set_stmt_error(stmt,"S1010","Function sequence error",0));
137
if (pcbCursor == NULL)
138
pcbCursor = (SQLSMALLINT *) &nDummyLength;
140
*pcbCursor = strlen(stmt->cursor_name);
142
cbCursorMax -= sizeof(char); /* NULL termination */
144
if ( szCursor && cbCursorMax > 0)
145
strmake( szCursor, stmt->cursor_name, cbCursorMax);
147
nLength = min( *pcbCursor , cbCursorMax );
148
if ( nLength != *pcbCursor )
150
set_stmt_error(stmt,"01004","String data, right truncated",01004);
151
DBUG_RETURN(SQL_SUCCESS_WITH_INFO);
153
DBUG_RETURN(SQL_SUCCESS);
158
SQLSetPos sets the cursor position in a rowset and allows an application
159
to refresh data in the rowset or to update or delete data in the result
162
As the server doesn't give the BEST_ROWID always..better to manage
163
all the rows in the where clause to avoid duplicate data delete/update
166
SQLRETURN SQL_API SQLSetPos(SQLHSTMT hstmt,
168
SQLUSMALLINT fOption,
171
STMT FAR *stmt=(STMT FAR*) hstmt;
173
DYNAMIC_STRING dynQuery;
174
MYSQL_RES *result = stmt->result;
176
DBUG_ENTER("SQLSetPos");
177
DBUG_PRINT("enter",("irow, refresh: %d Lock: %d",irow,fOption,fLock));
180
if no result set, no meaning for SQLSetPos call, so just
184
DBUG_RETURN(set_stmt_error(stmt,"S1010",
185
"Function sequence error, no result set",0));
187
/* if irow > maximum rows in the resultset */
188
if ( fOption != SQL_ADD && irow > mysql_num_rows(result))
189
DBUG_RETURN(set_stmt_error(stmt,"S1107","Row value out of range",0));
191
if ( fLock > SQL_LOCK_UNLOCK)
192
DBUG_RETURN(set_stmt_error(stmt,"S1009","Invalid argument value",0));
197
/* The RowNumber argument was 0, and the Operation argument was SQL_POSITION
198
through an error as per the spec
201
DBUG_RETURN(set_stmt_error(stmt,"S1109","Invalid cursor position",0));
203
irow--; sqlRet = SQL_SUCCESS;
204
stmt->position_in_set=irow;
205
stmt->current_row = irow;
206
mysql_data_seek(result,irow);
208
}/* END OF SQL_POSITION */
212
const char *table_name=find_used_table(stmt);
215
DBUG_RETURN(SQL_ERROR);
217
if(irow && (stmt->current_row != (uint)irow-1))
218
DBUG_RETURN(set_stmt_error(stmt,"S1109","Invalid cursor position",0));
221
dynamic string, to build and store the SQL Query for
224
if (init_dynamic_string(&dynQuery, "DELETE FROM ", 1024, 1024))
225
DBUG_RETURN(set_stmt_error(stmt,"S1001","Not enough memory",4001));
227
dynstr_append(&dynQuery,table_name);
228
sqlRet = my_pos_delete(stmt,irow,dynQuery);
229
dynstr_free(&dynQuery);
231
} /* END of CASE SQL_DELETE */
235
MYSQL_FIELD *field, *end;
236
const char *table_name=find_used_table(stmt);
239
DBUG_RETURN(SQL_ERROR);
241
if(irow && stmt->current_row != (uint)irow-1)
242
DBUG_RETURN(set_stmt_error(stmt,"S1109","Invalid cursor position",0));
245
dynamic string, to build and store the SQL Query for
248
if (init_dynamic_string(&dynQuery, "UPDATE ", 1024,1024))
249
DBUG_RETURN(set_stmt_error(stmt,"S1001","Not enough memory",4001));
251
dynstr_append(&dynQuery,table_name);
252
dynstr_append_mem(&dynQuery," SET ",5);
255
SET clause manipulation
257
TODO: as per spec: driver should retrieve the lengths of the data from
258
the number-of-bytes buffers (the pcbValue argument in SQLBindCol).
259
If the length of any column is SQL_IGNORE, the column is not
262
for (field=result->fields, end=field+ result->field_count;
268
dynstr_append(&dynQuery,field->name);
269
dynstr_append(&dynQuery,"=?,");
272
/* Remove last ',' */
273
dynQuery.str[--dynQuery.length]=0;
274
sqlRet = my_pos_update(stmt,irow,dynQuery,1);
275
dynstr_free(&dynQuery);
277
} /* END of CASE SQL_UPDATE */
281
/* The driver positions the cursor on the row specified by irow and
282
refreshes data in the rowset buffers for that row.
284
Note that, data in the buffers is refreshed but not refetched,
285
the membership in the rowset is fixed.
287
so it needs to refresh the specified row buffers, as this does't
288
need refetches the data
290
sqlRet = SQLExtendedFetch(hstmt,SQL_FETCH_ABSOLUTE,irow,
291
NULL,stmt->rgfRowStatus);
296
MYSQL_FIELD *field, *end;
297
const char *table_name=find_used_table(stmt);
301
DBUG_RETURN(SQL_ERROR);
303
if (init_dynamic_string(&dynQuery, "INSERT INTO ", 1024,1024))
304
DBUG_RETURN(set_stmt_error(stmt,"S1001","Not enough memory",4001));
306
dynstr_append(&dynQuery,table_name);
307
dynstr_append_mem(&dynQuery,"(",1);
312
for (field=result->fields, end=field+ result->field_count;
316
dynstr_append(&dynQuery,field->name);
317
dynstr_append(&dynQuery,",");
319
/* Remove last ',' */
320
dynQuery.length--;dynstr_append(&dynQuery,") VALUES (");
321
for (index=0; index < result->field_count; index++)
322
dynstr_append(&dynQuery,"?,");
324
dynQuery.length--;dynstr_append(&dynQuery,")");
325
sqlRet = my_pos_add(stmt,irow,dynQuery);
326
dynstr_free(&dynQuery);
331
DBUG_RETURN(set_stmt_error(stmt,"S1009","Invalid argument value",0));
339
my_pos_delete deletes the positioned row
342
SQLRETURN my_pos_delete(STMT FAR *stmt, SQLUSMALLINT irow,
343
DYNAMIC_STRING dynQuery)
347
MYSQL_RES *result = stmt->result;
352
/* if irow = 0, then DELETE all rows, else delete the current row */
354
pk_exists = my_build_where_clause(stmt,&dynQuery);
357
allocate new stmt handle, and execute the DELETE query in
358
that stmt, without disturbing the original stmt
361
/* Make sure the cursor is still in the same position..
362
Fix to MS Access making wrong calls
364
my_set_cursor_data(stmt);
366
sqlRet = my_SQLAllocStmt(stmt->dbc, &hstmtNew);
367
if(sqlRet != SQL_SUCCESS)
370
stmtNew = (STMT FAR *)hstmtNew;
372
sqlRet = my_SQLPrepare(stmtNew,dynQuery.str,SQL_NTS);
373
if(sqlRet != SQL_SUCCESS)
374
goto my_time_to_return_error;
376
/* if only the current row to be deleted, then supply param data */
379
/* check if PK column exists in the result set, else
380
use the temporary result set to get the PK column data
383
my_pk_param_bind(stmtNew,stmt,irow,0);
386
for (ncol = 0; ncol < result->field_count; ncol++)
388
if (result->fields[ncol].table)
389
my_param_bind(stmtNew,stmt,ncol,ncol);
391
stmtNew->query = insert_params(stmtNew);
395
/* now execute the real DELETE query... */
396
DBUG_PRINT("SQL_DELETE:",("%s",stmtNew->query));
397
sqlRet = do_query(stmtNew,stmtNew->query);
398
if( sqlRet == SQL_SUCCESS || sqlRet == SQL_SUCCESS_WITH_INFO )
400
/* if irow=0, server returns affected rows as 0, this is a bug, so
401
manually do this from driver side, but change this when server
406
stmt->affected_rows=result->row_count;
407
stmt->dbc->mysql.affected_rows = result->row_count;
410
stmt->affected_rows=mysql_affected_rows(&stmtNew->dbc->mysql);
412
/* no rows updated/deleted, return warning */
413
if( stmt->affected_rows == 0)
415
sqlRet = SQL_SUCCESS_WITH_INFO;
416
set_stmt_error(stmt,"01S03","No rows updated/deleted",0);
418
/* if irow !=0 and stmt->affected_rows > 1, then return warning */
419
else if( irow != 0 && stmt->affected_rows > 1)
421
sqlRet = SQL_SUCCESS_WITH_INFO;
422
set_stmt_error(stmt,"01S04","More than one row updated/deleted",0);
424
else if( stmt->rgfRowStatus) /* update the status */
426
for(ncol = 0; ncol < stmt->affected_rows; ncol++)
427
stmt->rgfRowStatus[ncol+stmt->current_row] = SQL_ROW_DELETED;
432
DBUG_PRINT("error",("%s:%s",stmtNew->sqlstate,stmtNew->last_error));
433
set_stmt_error(stmt,stmtNew->sqlstate,stmtNew->last_error,
436
my_time_to_return_error:
437
my_SQLFreeStmt(hstmtNew,SQL_DROP);
443
my_pos_update updates the positioned row
446
SQLRETURN my_pos_update(STMT FAR *stmt,
448
DYNAMIC_STRING dynQuery,
449
SQLUSMALLINT set_param_exists)
453
MYSQL_RES *result = stmt->result;
458
/* if irow = 0, then UPDATE all rows, else update the current row */
460
pk_exists = my_build_where_clause(stmt,&dynQuery);
462
/* Make sure the cursor is still in the same position..
463
Fix to MS Access making wrong calls
465
my_set_cursor_data(stmt);
467
/* now...prepare to execute */
468
sqlRet = my_SQLAllocStmt(stmt->dbc, &hstmtNew);
469
if(sqlRet != SQL_SUCCESS)
472
stmtNew = (STMT FAR *)hstmtNew;
473
sqlRet = my_SQLPrepare(stmtNew,dynQuery.str,SQL_NTS);
474
if(sqlRet != SQL_SUCCESS)
475
goto my_time_to_return_error;
477
if (set_param_exists)
480
copy row buffers to param buffers to set the update data i.e.
484
/* The argument fOption was SQL_ADD or SQL_UPDATE and no columns were
485
bound with SQLBindCol.
488
set_stmt_error(stmt,"21S02",
489
"Degree of derived table does not match column list",0);
490
goto my_time_to_return_error;
492
for (ncol = 0; ncol < stmt->result->field_count; ncol++)
494
PARAM_BIND *param = dynamic_element(&stmtNew->params,ncol,PARAM_BIND*);
495
ulong transfer_length,precision,display_size;
496
MYSQL_FIELD *field = mysql_fetch_field_direct(result,ncol);
497
BIND *bind = stmt->bind+ncol;
500
param->SqlType = unireg_to_sql_datatype(stmt,field,0,
501
&transfer_length,&precision,
503
param->CType = bind->fCType;
504
param->buffer = (SQLCHAR *)bind->rgbValue;
505
param->ValueMax = bind->cbValueMax;
506
param->actual_len= bind->pcbValue;
507
param->real_param_done = TRUE;
509
set_dynamic(&stmtNew->params,(gptr)param,ncol);
513
/* if only the current row to be updated, then supply param data */
516
if (set_param_exists)
521
dstCol = result->field_count;
522
my_pk_param_bind(stmtNew,stmt,irow,dstCol);
526
for (ncol = 0; ncol < result->field_count; ncol++)
528
dstCol = ncol+result->field_count;
529
my_param_bind(stmtNew,stmt,ncol,dstCol);
531
stmtNew->query = insert_params(stmtNew);
537
my_pk_param_bind(stmtNew,stmt,irow,0);
540
for (ncol = 0; ncol < result->field_count; ncol++)
541
my_param_bind(stmtNew,stmt,ncol,ncol);
542
stmtNew->query = insert_params(stmtNew);
545
}/* END of if (iRow) */
547
/* now execute the real UPDATE query... */
548
DBUG_PRINT("SQL_UPDATE:",("%s",stmtNew->query));
549
sqlRet = do_query(stmtNew,stmtNew->query);
550
if( sqlRet == SQL_SUCCESS || sqlRet == SQL_SUCCESS_WITH_INFO )
552
stmt->affected_rows=mysql_affected_rows(&stmtNew->dbc->mysql);
554
/* no rows updated/deleted, return warning */
555
if( stmt->affected_rows == 0)
557
sqlRet = SQL_SUCCESS_WITH_INFO;
558
set_stmt_error(stmt,"01S03","No rows updated/deleted",0);
560
/* if irow !=0 and stmt->affected_rows > 1, then return warning */
561
else if( irow != 0 && stmt->affected_rows > 1)
563
sqlRet = SQL_SUCCESS_WITH_INFO;
564
set_stmt_error(stmt,"01S04","More than one row updated/deleted",0);
566
else if( stmt->rgfRowStatus) /* update the status */
568
for(ncol = 0; ncol < stmt->affected_rows; ncol++)
569
stmt->rgfRowStatus[ncol+stmt->current_row] = SQL_ROW_UPDATED;
574
DBUG_PRINT("error",("%s:%s",stmtNew->sqlstate,stmtNew->last_error));
575
set_stmt_error(stmt,stmtNew->sqlstate,stmtNew->last_error,
579
my_time_to_return_error:
580
my_SQLFreeStmt(hstmtNew,SQL_DROP);
585
my_pos_add inserts a positioned row of data
588
SQLRETURN my_pos_add(STMT FAR *stmt,
590
DYNAMIC_STRING dynQuery)
594
MYSQL_RES *result = stmt->result;
598
/* now...prepare to execute */
599
sqlRet = my_SQLAllocStmt(stmt->dbc, &hstmtNew);
600
if(sqlRet != SQL_SUCCESS)
603
stmtNew = (STMT FAR *)hstmtNew;
604
sqlRet = my_SQLPrepare(stmtNew,dynQuery.str,SQL_NTS);
605
if(sqlRet != SQL_SUCCESS)
606
goto my_time_to_return_error;
609
copy row buffers to param buffers to set the update data i.e.
613
/* The argument fOption was SQL_ADD or SQL_UPDATE and no columns were
614
bound with SQLBindCol.
617
set_stmt_error(stmt,"21S02",
618
"Degree of derived table does not match column list",0);
619
goto my_time_to_return_error;
621
for (ncol = 0; ncol < stmt->result->field_count; ncol++)
623
PARAM_BIND *param = dynamic_element(&stmtNew->params,ncol,PARAM_BIND*);
624
ulong transfer_length,precision,display_size;
625
MYSQL_FIELD *field = mysql_fetch_field_direct(result,ncol);
626
BIND *bind = stmt->bind+ncol;
630
param->SqlType = unireg_to_sql_datatype(stmt,field,0,
631
&transfer_length,&precision,
633
param->CType = bind->fCType;
634
param->buffer = (SQLCHAR *)bind->rgbValue;
635
param->ValueMax = bind->cbValueMax;
636
param->actual_len= bind->pcbValue;
637
param->real_param_done = TRUE;
639
set_dynamic(&stmtNew->params,(gptr)param,ncol);
641
/* This is a buggy code..it doesn't handle DATA_LEN_AT_EXEC...
642
better to use my_SQLExecute, so that it will take care of it, but
643
it reduces the performance
645
stmtNew->query = insert_params(stmtNew);/* INSERT param DATA */
646
/* now execute the real INSERT query... */
647
DBUG_PRINT("SQL_ADD:",("%s",stmtNew->query));
648
sqlRet = do_query(stmtNew,stmtNew->query);
649
if( sqlRet == SQL_SUCCESS || sqlRet == SQL_SUCCESS_WITH_INFO )
651
stmt->affected_rows=mysql_affected_rows(&stmtNew->dbc->mysql);
652
if( stmt->rgfRowStatus) /* update the INSERT status */
653
stmt->rgfRowStatus[stmt->current_row] = SQL_ROW_ADDED;
657
DBUG_PRINT("error",("%s:%s",stmtNew->sqlstate,stmtNew->last_error));
658
set_stmt_error(stmt,stmtNew->sqlstate,stmtNew->last_error,
662
my_time_to_return_error:
663
my_SQLFreeStmt(hstmtNew,SQL_DROP);
668
my_param_bind, does the param binding for the specific stmt by taking the
669
data from the current row of the result set
672
void my_param_bind(STMT FAR *dstStmt, STMT FAR *srcStmt,
673
SQLUSMALLINT nSrcCol, SQLUSMALLINT nDstCol)
676
MYSQL_RES *result = srcStmt->result;
677
ulong transfer_length,precision,display_size;
678
MYSQL_FIELD *field = mysql_fetch_field_direct(result,nSrcCol);
679
MYSQL_ROW row_data = result->data_cursor->data + nSrcCol;
681
param=dynamic_element(&dstStmt->params,nDstCol,PARAM_BIND*);
683
param->SqlType = unireg_to_sql_datatype(srcStmt,field,0,
684
&transfer_length,&precision,
686
param->CType = SQL_C_CHAR;
687
param->buffer = (SQLCHAR *)*row_data;
688
param->ValueMax = strlen(*row_data);
689
param->actual_len = NULL;
690
param->real_param_done = TRUE;
691
set_dynamic(&dstStmt->params,(gptr)param,nDstCol);
695
** checks whether the SQL statement contains WHERE CURRENT OF CURSOR
698
my_bool check_if_positioned_cursor_exists(STMT FAR *stmt,STMT FAR **stmtNew)
700
if (stmt->query && stmt->query_end)
702
char *szQueryEnd = stmt->query_end;
703
char *szQuery = stmt->query;
704
const char *szCursor = mystr_get_prev_token((const char **)&szQueryEnd,
707
if (!my_casecmp(mystr_get_prev_token((const char **)&szQueryEnd,
708
stmt->query),"OF",2) &&
709
!my_casecmp(mystr_get_prev_token((const char **)&szQueryEnd,
710
stmt->query),"CURRENT",7) &&
711
!my_casecmp(mystr_get_prev_token((const char **)&szQueryEnd,
712
stmt->query),"WHERE",5))
716
Driver needs to setup the active stmt which has the cursor
717
specified in the query.
719
Find out the cursor from all the stmts and make that as
720
the active stmt..becuase this cursor is applicable
721
for all stmts in the current DBC level
723
LIST *list_element,*next_element;
724
DBC FAR *dbc=(DBC FAR*) stmt->dbc;
726
for (list_element=dbc->statements ; list_element ;
727
list_element=next_element)
729
next_element=list_element->next;
730
*stmtNew = (HSTMT)list_element->data;
732
/* might have the cursor in the stmt without any resultset, so
733
avoid crashes, by keeping check on (*stmtNew)->result)
735
if (!my_strcasecmp((*stmtNew)->cursor_name,szCursor) &&
745
strxmov(buff,"Cursor '",szCursor,"' does not exist",NullS);
746
set_stmt_error(stmt,"3400",buff,ER_INVALID_CURSOR_NAME);
750
} /* END OF if (stmt->query && stmt->query_end) */
755
** checks whether the Primary Key column exists in the table
756
** if it exists, returns the PK column name
759
SQLRETURN my_if_pk_exits(STMT FAR *stmt)
766
DBUG_ENTER("my_if_pk_exists");
768
if(stmt->my_pk_validated)
769
DBUG_RETURN(stmt->pk_count);
771
if(my_SQLAllocStmt(stmt->dbc, &hStmtTemp) != SQL_SUCCESS)
774
stmtTemp = (STMT FAR *)hStmtTemp;
776
strxmov(buff,"show keys from ",stmt->result->fields->table,NullS);
777
pthread_mutex_lock(&stmtTemp->dbc->lock);
778
if( mysql_query(&stmtTemp->dbc->mysql,buff) ||
779
!(stmtTemp->result=mysql_store_result(&stmtTemp->dbc->mysql)))
781
set_stmt_error(stmt,"S1000",mysql_error(&stmtTemp->dbc->mysql),
782
mysql_errno(&stmtTemp->dbc->mysql));
783
pthread_mutex_unlock(&stmtTemp->dbc->lock);
784
my_SQLFreeStmt(hStmtTemp,SQL_DROP);
787
pthread_mutex_unlock(&stmtTemp->dbc->lock);
789
/* right now take care of only PK's */
790
while ((row = mysql_fetch_row(stmtTemp->result)) &&
791
!(my_casecmp(row[2],"PRIMARY",7)) &&
792
(stmt->pk_count < MY_MAX_PK_PARTS))
794
strmov(stmt->pk_col[stmt->pk_count++].name,row[4]);
796
stmt->my_pk_validated = TRUE;
797
my_SQLFreeStmt(hStmtTemp,SQL_DROP);
798
DBUG_RETURN(stmt->pk_count);
803
** checks whether the Primary Key column exists in the result
804
** if it exists, takes that data and binds it,else does gets the
805
** temporary resultset and takes the data
808
SQLRETURN my_pk_param_bind(STMT FAR *stmtNew,STMT FAR *stmt,
809
SQLUSMALLINT irow,SQLUSMALLINT nColParam)
811
MYSQL_RES *result = stmt->result;
815
DBUG_ENTER("my_pk_param_bind");
817
/* check for any pk columns exists in the current resultset,
818
if exists, take data from it and bind it
820
for (ncol = 0; ncol < result->field_count; ncol++)
822
field=result->fields+ncol;
823
for (index=0; index < stmt->pk_count; index++)
825
if(!my_strcasecmp(stmt->pk_col[index].name,field->name))
827
my_param_bind(stmtNew,stmt,index,(SQLUSMALLINT)(nColParam+index));
828
stmt->pk_col[index].bind_done = TRUE;
832
}/* END OF for(ncol = 1 ; ncol <= stmt->result->field_count; ncol++)*/
834
/* if PK doesn't exists in the current result set means, create a temp result
835
set, and take the data from it.
840
DYNAMIC_STRING query;
841
my_bool pk_not_in_set = FALSE;
843
if (init_dynamic_string(&query, "SELECT ", 1024,1024))
844
DBUG_RETURN(set_stmt_error(stmt,"S1001","Not enough memory",4001));
846
for(index=0; index < stmt->pk_count; index++)
848
if(!stmt->pk_col[index].bind_done)
850
dynstr_append(&query,stmt->pk_col[index].name);
851
dynstr_append_mem(&query,",",1);
852
pk_not_in_set = TRUE;
855
/* if all the PK columns exists in the result set itself,
856
return back, by inserting
860
stmtNew->query = insert_params(stmtNew);
864
/* else get the data for other PK columns */
865
query.length-=1; /* Remove last ', ' */
866
dynstr_append(&query," FROM ");
867
dynstr_append(&query,stmt->table_name);
869
if(my_SQLAllocStmt(stmt->dbc, &hStmtTemp) != SQL_SUCCESS)
872
stmtTemp = (STMT FAR *)hStmtTemp;
873
pthread_mutex_lock(&stmtTemp->dbc->lock);
874
if( mysql_query(&stmtTemp->dbc->mysql,query.str) ||
875
!(stmtTemp->result=mysql_store_result(&stmtTemp->dbc->mysql)))
877
set_stmt_error(stmt,"S1000",mysql_error(&stmtTemp->dbc->mysql),
878
mysql_errno(&stmtTemp->dbc->mysql));
879
pthread_mutex_unlock(&stmtTemp->dbc->lock);
880
my_SQLFreeStmt(hStmtTemp,SQL_DROP);
883
pthread_mutex_unlock(&stmtTemp->dbc->lock);
885
for(index=1;index <irow;index++)
886
stmtTemp->result->data_cursor = stmtTemp->result->data_cursor->next;
888
for(index=0; index < stmt->pk_count; index++)
890
if(!stmt->pk_col[index].bind_done)
892
my_param_bind(stmtNew,stmtTemp,0,(SQLUSMALLINT)(nColParam+index));
895
stmtNew->query = insert_params(stmtNew);
896
my_SQLFreeStmt(hStmtTemp,SQL_DROP);
902
* Building where search clause
904
my_bool my_build_where_clause(STMT FAR *stmt,
905
DYNAMIC_STRING *dynQuery)
907
MYSQL_RES *result = stmt->result;
908
my_bool pk_exists = FALSE;
911
/* WHERE clause building.. */
912
dynstr_append(dynQuery," WHERE ");
914
/* build the WHERE caluse... , if Primary Key exists
915
take that column for searching, else use all columns
917
if (my_if_pk_exits(stmt))
919
for(index=0; index < stmt->pk_count; index++)
921
dynstr_append(dynQuery,stmt->pk_col[index].name);
922
dynstr_append_mem(dynQuery,"=? AND ",7);
928
MYSQL_FIELD *field, *end;
929
for (field=result->fields, end=field+ result->field_count;
930
field < end ; field++)
932
dynstr_append(dynQuery,field->name);
933
dynstr_append_mem(dynQuery,"=? AND ",7);
937
dynQuery->length-=5; /* Remove last ' AND ' */
938
dynstr_append(dynQuery," LIMIT 1");
943
** Returns the table used by this query.
944
** Ensures that all columns are from the same table
947
static const char *find_used_table(STMT *stmt)
949
MYSQL_FIELD *field, *end;
950
const char *table_name;
951
MYSQL_RES *result = stmt->result;
952
DBUG_ENTER("find_used_table");
954
if (stmt->table_name)
955
DBUG_RETURN(stmt->table_name); /* Return cached name */
958
for (field=result->fields, end=field+ result->field_count;
959
field < end ; field++)
964
table_name=field->table;
965
if (strcmp(field->table, table_name))
967
set_stmt_error(stmt,"34000",
968
"Can't modify a row from a statement that uses more than one table",
969
ER_MULTIPLE_TABLE_IN_RESULT);
974
stmt->table_name=table_name;
975
DBUG_RETURN(stmt->table_name);
979
** position the data cursor to appropriate row
981
void my_set_cursor_data(STMT FAR *stmt)
984
MYSQL_RES *result=stmt->result;
985
MYSQL_ROWS *dcursor = result->data->data;
987
if(!stmt->data_cursor)
989
for(irow=0; irow < stmt->current_row; irow++)
990
dcursor = dcursor->next;
992
stmt->data_cursor = TRUE;
993
result->data_cursor = dcursor;