Index: prepare.c =================================================================== --- prepare.c (revision 249) +++ prepare.c (working copy) @@ -59,6 +59,9 @@ SQLINTEGER cbSqlStr) { MYODBCDbgEnter; + STMT FAR *stmt= (STMT FAR*) hstmt; + if (stmt->orig_query) + my_free(stmt->orig_query,MYF(0)); MYODBCDbgReturnReturn( my_SQLPrepare( hstmt, szSqlStr, cbSqlStr ) ); } @@ -185,6 +188,7 @@ *pcLastCloseBrace = ' '; stmt->param_count= param_count; + stmt->current_param= 0; stmt->query_end= pos; stmt->state= ST_PREPARED; MYODBCDbgInfo( "Parameter count: %ld", stmt->param_count ); Index: execute.c =================================================================== --- execute.c (revision 249) +++ execute.c (working copy) @@ -129,6 +129,13 @@ pthread_mutex_unlock(&stmt->dbc->lock); if ( query != stmt->query ) my_free((gptr) query,MYF(0)); + if (stmt->orig_query) + { + my_free((gptr) stmt->query,MYF(0)); + stmt->query= stmt->orig_query; + stmt->query_end= stmt->orig_query_end; + stmt->orig_query= NULL; + } MYODBCDbgReturnReturn( error ); } @@ -597,6 +616,7 @@ SQLRETURN my_SQLExecute( STMT FAR *pStmt ) { char * query; + const char *cursor_pos; uint i; uint nIndex; PARAM_BIND *param; @@ -614,8 +634,13 @@ if ( !pStmt->query ) MYODBCDbgReturnReturn( set_error( pStmt, MYERR_S1010, "No previous SQLPrepare done", 0 ) ); - if ( check_if_positioned_cursor_exists( pStmt, &pStmtCursor ) ) + if (cursor_pos= check_if_positioned_cursor_exists(pStmt, &pStmtCursor)) { + pStmt->orig_query= my_strdup(pStmt->query, MYF(0)); + pStmt->orig_query_end= pStmt->orig_query + (pStmt->query_end - + pStmt->query); + /* qqq check allocation */ + *(char *)cursor_pos= '\0'; MYODBCDbgReturnReturn( do_my_pos_cursor( pStmt, pStmtCursor ) ); } Index: myodbc3.h =================================================================== --- myodbc3.h (revision 249) +++ myodbc3.h (working copy) @@ -335,6 +335,7 @@ STMT_OPTIONS stmt_options; const char *table_name; char *query,*query_end; + char *orig_query,*orig_query_end; my_ulonglong affected_rows; long current_row; long cursor_row; Index: cursor.c =================================================================== --- cursor.c (revision 249) +++ cursor.c (working copy) @@ -124,74 +124,71 @@ } -/* - @type : myodbc3 internal - @purpose : checks whether the SQL statement contains WHERE CURRENT OF CURSOR -*/ +/** + Check if a statement involves a positioned cursor using the WHERE CURRENT + OF syntax. -my_bool check_if_positioned_cursor_exists( STMT FAR *pStmt, STMT FAR **pStmtCursor ) + @param[in] pStmt Handle of the statement + @param[out] pStmtCursor Pointer to the statement referred to by the cursor + + @return Pointer to the beginning of 'WHERE CURRENT OF' +*/ +const char *check_if_positioned_cursor_exists(STMT *pStmt, STMT **pStmtCursor) { - if ( pStmt->query && pStmt->query_end ) + if (pStmt->query && pStmt->query_end) + { + const char *pszQueryTokenPos= pStmt->query_end; + const char *pszCursor= mystr_get_prev_token((const char**)&pszQueryTokenPos, + pStmt->query); + + if (!myodbc_casecmp(mystr_get_prev_token(&pszQueryTokenPos, + pStmt->query),"OF",2) && + !myodbc_casecmp(mystr_get_prev_token(&pszQueryTokenPos, + pStmt->query),"CURRENT",7) && + !myodbc_casecmp(mystr_get_prev_token(&pszQueryTokenPos, + pStmt->query),"WHERE",5) ) { - char * pszQueryTokenPos = pStmt->query_end; - const char *pszCursor = mystr_get_prev_token( (const char **)&pszQueryTokenPos, pStmt->query ); + LIST *list_element; + DBC *dbc= (DBC *)pStmt->dbc; + /* + Scan the list of statements for this connection and see if we + can find the cursor name this statement is referring to - it + must have a result set to count. + */ + for (list_element= dbc->statements; + list_element; + list_element= list_element->next) + { + *pStmtCursor= (HSTMT)list_element->data; + /* - Return TRUE if this statement is doing a 'WHERE CURRENT OF' - even when - we can not find the cursor this statement is referring to. + Even if the cursor name matches, the statement must have a + result set to count. */ - if ( !myodbc_casecmp(mystr_get_prev_token((const char **)&pszQueryTokenPos, - pStmt->query),"OF",2) && - !myodbc_casecmp(mystr_get_prev_token((const char **)&pszQueryTokenPos, - pStmt->query),"CURRENT",7) && - !myodbc_casecmp(mystr_get_prev_token((const char **)&pszQueryTokenPos, - pStmt->query),"WHERE",5) ) + if ((*pStmtCursor)->result && + (*pStmtCursor)->cursor.name && + !myodbc_strcasecmp((*pStmtCursor)->cursor.name, + pszCursor)) { - LIST * list_element; - LIST * next_element; - DBC FAR * dbc = (DBC FAR*)pStmt->dbc; + return pszQueryTokenPos; + } + } - /* - Scan the list of statements for this connection and see if we can - find the cursor name this statement is referring to - it must have - a result set to count. - */ - for ( list_element = dbc->statements; list_element; list_element = next_element ) - { - next_element = list_element->next; - *pStmtCursor = (HSTMT)list_element->data; + /* Did we run out of statements without finding a viable cursor? */ + if (!list_element) + { + char buff[200]; + strxmov(buff,"Cursor '", pszCursor, + "' does not exist or does not have a result set.", NullS); + set_stmt_error(pStmt, "34000", buff, ER_INVALID_CURSOR_NAME); + } - /* - Might have the cursor in the pStmt without any resultset, so - avoid crashes, by keeping check on (*pStmtCursor)->result) - */ - if ( (*pStmtCursor)->cursor.name && - !myodbc_strcasecmp( (*pStmtCursor)->cursor.name, pszCursor ) && - (*pStmtCursor)->result ) - { - /* - \todo - - Well we have found a match so we truncate the 'WHERE CURRENT OF cursorname' - but the truncation may be a bad way to go as it may make it broken for future - use. - */ - *pszQueryTokenPos = '\0'; - return ( TRUE ); - } - } - /* Did we run out of statements without finding a viable cursor? */ - if ( !list_element ) - { - char buff[200]; - strxmov( buff,"Cursor '", pszCursor, "' does not exist or does not have a result set.", NullS ); - set_stmt_error( pStmt, "34000", buff, ER_INVALID_CURSOR_NAME ); - } - return ( TRUE ); - } + return pszQueryTokenPos; } + } - return ( FALSE ); + return NULL; } @@ -957,10 +955,20 @@ pStmt->affected_rows = mysql_affected_rows( &pStmtTemp->dbc->mysql ); nReturn = update_status( pStmt, SQL_ROW_UPDATED ); } + else if (nReturn == SQL_NEED_DATA) + { + /* + Re-prepare the statement, which will leave us with a prepared + statement that is a non-positioned update. + */ + if (my_SQLPrepare(pStmt, (SQLCHAR *)dynQuery->str, dynQuery->length) != + SQL_SUCCESS) + return SQL_ERROR; + } my_SQLFreeStmt( pStmtTemp, SQL_DROP ); - return ( nReturn ); + return nReturn; } Index: myutil.h =================================================================== --- myutil.h (revision 249) +++ myutil.h (working copy) @@ -84,8 +84,8 @@ SQLUSMALLINT irow,DYNAMIC_STRING *dynStr); SQLRETURN my_pos_update(STMT FAR *stmt,STMT FAR *stmtParam, SQLUSMALLINT irow,DYNAMIC_STRING *dynStr); -my_bool check_if_positioned_cursor_exists(STMT FAR *stmt, - STMT FAR **stmtNew); +const char *check_if_positioned_cursor_exists(STMT FAR *stmt, + STMT FAR **stmtNew); char *insert_param(MYSQL *mysql, char *to,PARAM_BIND *param); char *add_to_buffer(NET *net,char *to,char *from,ulong length); SQLRETURN copy_lresult(SQLSMALLINT HandleType, SQLHANDLE handle, Index: handle.c =================================================================== --- handle.c (revision 249) +++ handle.c (working copy) @@ -462,7 +462,8 @@ /* At this point, only MYSQL_RESET and SQL_DROP left out */ x_free((gptr) stmt->query); - stmt->query= 0; + x_free((gptr) stmt->orig_query); + stmt->query= stmt->orig_query= 0; stmt->param_count= 0; if (fOption == MYSQL_RESET)