📄 token.c
字号:
* </tr><tr> * <td>TDS_PARAM_RESULT</td><td>Return parameter results</td> * <td>param_info or cur_dyn->params contain returned parameters</td> * </tr><tr> * <td>TDS_STATUS_RESULT</td><td>Stored procedure status results</td> * <td>tds->ret_status contain the returned code</td> * </tr></table> * @param flag Flags to select token type to stop/return * @todo Complete TDS_DESCRIBE_RESULT description * @retval TDS_SUCCEED if a result set is available for processing. * @retval TDS_FAIL on error. * @retval TDS_NO_MORE_RESULTS if all results have been completely processed. * @retval anything returned by one of the many functions it calls. :-( */inttds_process_tokens(TDSSOCKET *tds, TDS_INT *result_type, int *done_flags, unsigned flag){ int marker; TDSPARAMINFO *pinfo = NULL; TDSCOLUMN *curcol; int rc; TDS_INT8 saved_rows_affected = tds->rows_affected; TDS_INT ret_status; int cancel_seen = 0; unsigned return_flag = 0;#define SET_RETURN(ret, f) \ *result_type = ret; \ return_flag = TDS_RETURN_##f | TDS_STOPAT_##f; \ if (flag & TDS_STOPAT_##f) {\ tds_unget_byte(tds); \ tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens::SET_RETURN stopping on current token\n"); \ break; \ } CHECK_TDS_EXTRA(tds); tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens(%p, %p, %p, 0x%x)\n", tds, result_type, done_flags, flag); if (tds->state == TDS_IDLE) { tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens() state is COMPLETED\n"); *result_type = TDS_DONE_RESULT; return TDS_NO_MORE_RESULTS; } if (tds_set_state(tds, TDS_READING) != TDS_READING) return TDS_FAIL; rc = TDS_SUCCEED; for (;;) { marker = tds_get_byte(tds); tdsdump_log(TDS_DBG_INFO1, "processing result tokens. marker is %x(%s)\n", marker, _tds_token_name(marker)); switch (marker) { case TDS7_RESULT_TOKEN: /* * If we're processing the results of a cursor fetch * from sql server we don't want to pass back the * TDS_ROWFMT_RESULT to the calling API */ if (tds->internal_sp_called == TDS_SP_CURSORFETCH) { rc = tds7_process_result(tds); marker = tds_get_byte(tds); if (marker != TDS_TABNAME_TOKEN) tds_unget_byte(tds); else rc = tds_process_tabname(tds); } else { SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT); rc = tds7_process_result(tds); /* handle browse information (if presents) */ marker = tds_get_byte(tds); if (marker != TDS_TABNAME_TOKEN) { tds_unget_byte(tds); rc = TDS_SUCCEED; break; } rc = tds_process_tabname(tds); } break; case TDS_RESULT_TOKEN: SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT); rc = tds_process_result(tds); break; case TDS_ROWFMT2_TOKEN: SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT); rc = tds5_process_result(tds); break; case TDS_COLNAME_TOKEN: rc = tds_process_col_name(tds); break; case TDS_COLFMT_TOKEN: SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT); rc = tds_process_col_fmt(tds); /* handle browse information (if present) */ marker = tds_get_byte(tds); if (marker != TDS_TABNAME_TOKEN) { tds_unget_byte(tds); break; } rc = tds_process_tabname(tds); break; case TDS_PARAM_TOKEN: tds_unget_byte(tds); if (tds->internal_sp_called) { tdsdump_log(TDS_DBG_FUNC, "processing parameters for sp %d\n", tds->internal_sp_called); while ((marker = tds_get_byte(tds)) == TDS_PARAM_TOKEN) { tdsdump_log(TDS_DBG_INFO1, "calling tds_process_param_result\n"); tds_process_param_result(tds, &pinfo); } tds_unget_byte(tds); tdsdump_log(TDS_DBG_FUNC, "%d hidden return parameters\n", pinfo ? pinfo->num_cols : -1); if (pinfo && pinfo->num_cols > 0) { curcol = pinfo->columns[0]; if (tds->internal_sp_called == TDS_SP_CURSOROPEN && tds->cur_cursor) { TDSCURSOR *cursor = tds->cur_cursor; cursor->cursor_id = *(TDS_INT *) curcol->column_data; tdsdump_log(TDS_DBG_FUNC, "stored internal cursor id %d\n", cursor->cursor_id); cursor->srv_status &= ~(TDS_CUR_ISTAT_CLOSED|TDS_CUR_ISTAT_OPEN|TDS_CUR_ISTAT_DEALLOC); cursor->srv_status |= cursor->cursor_id ? TDS_CUR_ISTAT_OPEN : TDS_CUR_ISTAT_CLOSED|TDS_CUR_ISTAT_DEALLOC; } if (tds->internal_sp_called == TDS_SP_PREPARE && tds->cur_dyn && tds->cur_dyn->num_id == 0 && curcol->column_cur_size > 0) { tds->cur_dyn->num_id = *(TDS_INT *) curcol->column_data; } } tds_free_param_results(pinfo); } else { SET_RETURN(TDS_PARAM_RESULT, PROC); rc = tds_process_param_result_tokens(tds); } break; case TDS_COMPUTE_NAMES_TOKEN: rc = tds_process_compute_names(tds); break; case TDS_COMPUTE_RESULT_TOKEN: SET_RETURN(TDS_COMPUTEFMT_RESULT, COMPUTEFMT); rc = tds_process_compute_result(tds); break; case TDS7_COMPUTE_RESULT_TOKEN: SET_RETURN(TDS_COMPUTEFMT_RESULT, COMPUTEFMT); rc = tds7_process_compute_result(tds); break; case TDS_ROW_TOKEN: /* overstepped the mark... */ if (tds->cur_cursor) { TDSCURSOR *cursor = tds->cur_cursor; tds->current_results = cursor->res_info; tdsdump_log(TDS_DBG_INFO1, "tds_process_tokens(). set current_results to cursor->res_info\n"); } else { /* assure that we point to row, not to compute */ if (tds->res_info) tds->current_results = tds->res_info; } /* I don't know when this it's false but it happened, also server can send garbage... */ if (tds->current_results) tds->current_results->rows_exist = 1; SET_RETURN(TDS_ROW_RESULT, ROW); rc = tds_process_row(tds); break; case TDS_CMP_ROW_TOKEN: /* I don't know when this it's false but it happened, also server can send garbage... */ if (tds->res_info) tds->res_info->rows_exist = 1; SET_RETURN(TDS_COMPUTE_RESULT, COMPUTE); rc = tds_process_compute(tds, NULL); break; case TDS_RETURNSTATUS_TOKEN: ret_status = tds_get_int(tds); marker = tds_peek(tds); if (marker != TDS_PARAM_TOKEN && marker != TDS_DONEPROC_TOKEN && marker != TDS_DONE_TOKEN && marker != TDS5_PARAMFMT_TOKEN && marker != TDS5_PARAMFMT2_TOKEN) break; if (tds->internal_sp_called) { /* TODO perhaps we should use ret_status ?? */ } else { /* TODO optimize */ flag &= ~TDS_STOPAT_PROC; SET_RETURN(TDS_STATUS_RESULT, PROC); tds->has_status = 1; tds->ret_status = ret_status; tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens: return status is %d\n", tds->ret_status); rc = TDS_SUCCEED; } break; case TDS5_DYNAMIC_TOKEN: /* process acknowledge dynamic */ tds->cur_dyn = tds_process_dynamic(tds); /* special case, prepared statement cannot be prepared */ if (!tds->cur_dyn || tds->cur_dyn->emulated) break; marker = tds_get_byte(tds); if (marker != TDS_EED_TOKEN) { tds_unget_byte(tds); break; } tds_process_msg(tds, marker); if (!tds->cur_dyn || !tds->cur_dyn->emulated) break; marker = tds_get_byte(tds); if (marker != TDS_DONE_TOKEN) { tds_unget_byte(tds); break; } rc = tds_process_end(tds, marker, done_flags); if (done_flags) *done_flags &= ~TDS_DONE_ERROR; /* FIXME warning to macro expansion */ SET_RETURN(TDS_DONE_RESULT, DONE); break; case TDS5_PARAMFMT_TOKEN: SET_RETURN(TDS_DESCRIBE_RESULT, PARAMFMT); rc = tds_process_dyn_result(tds); break; case TDS5_PARAMFMT2_TOKEN: SET_RETURN(TDS_DESCRIBE_RESULT, PARAMFMT); rc = tds5_process_dyn_result2(tds); break; case TDS5_PARAMS_TOKEN: SET_RETURN(TDS_PARAM_RESULT, PROC); rc = tds_process_params_result_token(tds); break; case TDS_CURINFO_TOKEN: rc = tds_process_cursor_tokens(tds); break; case TDS_DONE_TOKEN: SET_RETURN(TDS_DONE_RESULT, DONE); rc = tds_process_end(tds, marker, done_flags); break; case TDS_DONEPROC_TOKEN: SET_RETURN(TDS_DONEPROC_RESULT, DONE); rc = tds_process_end(tds, marker, done_flags); switch (tds->internal_sp_called) { case 0: case TDS_SP_PREPARE: case TDS_SP_EXECUTE: case TDS_SP_UNPREPARE: case TDS_SP_EXECUTESQL: break; case TDS_SP_CURSOROPEN: *result_type = TDS_DONE_RESULT; tds->rows_affected = saved_rows_affected; break; case TDS_SP_CURSORCLOSE: tdsdump_log(TDS_DBG_FUNC, "TDS_SP_CURSORCLOSE\n"); if (tds->cur_cursor) { TDSCURSOR *cursor = tds->cur_cursor; cursor->srv_status &= ~TDS_CUR_ISTAT_OPEN; cursor->srv_status |= TDS_CUR_ISTAT_CLOSED|TDS_CUR_ISTAT_DECLARED; if (cursor->status.dealloc == TDS_CURSOR_STATE_SENT) { tds_cursor_deallocated(tds, cursor); } } *result_type = TDS_NO_MORE_RESULTS; rc = TDS_NO_MORE_RESULTS; break; default: *result_type = TDS_NO_MORE_RESULTS; rc = TDS_NO_MORE_RESULTS; break; } break; case TDS_DONEINPROC_TOKEN: switch(tds->internal_sp_called) { case TDS_SP_CURSOROPEN: case TDS_SP_CURSORFETCH: case TDS_SP_PREPARE: case TDS_SP_CURSORCLOSE: rc = tds_process_end(tds, marker, done_flags); if (tds->rows_affected != TDS_NO_COUNT) { saved_rows_affected = tds->rows_affected; } break; default: SET_RETURN(TDS_DONEINPROC_RESULT, DONE); rc = tds_process_end(tds, marker, done_flags); break; } break; case TDS_ERROR_TOKEN: case TDS_INFO_TOKEN: case TDS_EED_TOKEN: SET_RETURN(TDS_MSG_RESULT, MSG); rc = tds_process_default_tokens(tds, marker); break; default: SET_RETURN(TDS_OTHERS_RESULT, OTHERS); rc = tds_process_default_tokens(tds, marker); break; } if (rc == TDS_FAIL) { tds_set_state(tds, TDS_PENDING); return rc; } cancel_seen |= tds->in_cancel; if (cancel_seen) { /* during cancel handle all tokens */ flag = TDS_HANDLE_ALL; } if ((return_flag & flag) != 0) { tds_set_state(tds, TDS_PENDING); return rc; } if (tds->state == TDS_IDLE) return cancel_seen ? TDS_CANCELLED : TDS_NO_MORE_RESULTS; if (tds->state == TDS_DEAD) { /* TODO free all results ?? */ return TDS_FAIL; } }}/** * Process results for simple query as "SET TEXTSIZE" or "USE dbname" * If the statement returns results, beware they are discarded. * * This function was written to avoid direct calls to tds_process_default_tokens * (which caused problems such as ignoring query errors). * Results are read until idle state or severe failure (do not stop for * statement failure). * @return see tds_process_tokens for results (TDS_NO_MORE_RESULTS is never returned) */inttds_process_simple_query(TDSSOCKET * tds){ TDS_INT res_type; TDS_INT done_flags; int rc; int ret = TDS_SUCCEED; CHECK_TDS_EXTRA(tds); while ((rc = tds_process_tokens(tds, &res_type, &done_flags, TDS_RETURN_DONE)) == TDS_SUCCEED) { switch (res_type) { case TDS_DONE_RESULT: case TDS_DONEPROC_RESULT: case TDS_DONEINPROC_RESULT: if ((done_flags & TDS_DONE_ERROR) != 0) ret = TDS_FAIL; break; default: break; } } if (rc != TDS_NO_MORE_RESULTS) { ret = TDS_FAIL; } return ret;}struct namelist{ char *name; struct namelist *next;};static voidtds_free_namelist(struct namelist *head){ struct namelist *cur = head, *prev; while (cur != NULL) { prev = cur; cur = cur->next; free(prev->name); free(prev); }}static inttds_read_namelist(TDSSOCKET * tds, int remainder, struct namelist **p_head, int large){ struct namelist *head = NULL, *cur = NULL, *prev; int num_names = 0; /* * this is a little messy...TDS 5.0 gives the number of columns * upfront, while in TDS 4.2, you're expected to figure it out * by the size of the message. So, I use a link list to get the * colum names and then allocate the result structure, copy * and delete the linked list */ while (remainder > 0) { int namelen; prev = cur; if (!(cur = (struct namelist *) malloc(sizeof(struct namelist)))) { tds_free_namelist(head); return -1; } cur->next = NULL; if (prev) prev->next = cur; else head = cur; if (large) { namelen = tds_get_smallint(tds); remainder -= 2; } else { namelen = tds_get_byte(tds); --remainder; } if (tds_alloc_get_string(tds, &cur->name, namelen) < 0) { tds_free_namelist(head); return -1; } remainder -= namelen; num_names++; } *p_head = head; return num_names;}/** * tds_process_col_name() is one half of the result set under TDS 4.2 * it contains all the column names, a TDS_COLFMT_TOKEN should * immediately follow this token with the datatype/size information * This is a 4.2 only function */static inttds_process_col_name(TDSSOCKET * tds){ int hdrsize; int col, num_names = 0; struct namelist *head = NULL, *cur = NULL, *prev; TDSCOLUMN *curcol; TDSRESULTINFO *info; CHECK_TDS_EXTRA(tds); hdrsize = tds_get_smallint(tds); if ((num_names = tds_read_namelist(tds, hdrsize, &head, 0)) < 0) return TDS_FAIL; /* free results/computes/params etc... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -