⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 statement.c

📁 postgresql-odbc,跨平台应用
💻 C
📖 第 1 页 / 共 5 页
字号:
			mylog("%s: error\n", func);			switch (conn->status)			{				case CONN_NOT_CONNECTED:				case CONN_DOWN:					SC_set_error(self, STMT_BAD_ERROR, "Error fetching next row", func);					break;				default:					SC_set_error(self, STMT_EXEC_ERROR, "Error fetching next row", func);			}			return SQL_ERROR;		}	}	if (QR_haskeyset(res))	{		SQLLEN	kres_ridx;		kres_ridx = GIdx2KResIdx(self->currTuple, self, res);		if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)		{			UWORD	pstatus = res->keyset[kres_ridx].status;inolog("SC_ pstatus[%d]=%hx fetch_count=" FORMAT_LEN "\n", kres_ridx, pstatus, self->last_fetch_count);			if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))				return SQL_SUCCESS_WITH_INFO;			if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&		    		0 != (pstatus & CURS_OTHER_DELETED))				return SQL_SUCCESS_WITH_INFO;			if (0 != (CURS_NEEDS_REREAD & pstatus))			{				UWORD	qcount;				result = SC_pos_reload(self, self->currTuple, &qcount, 0);				if (SQL_ERROR == result)					return result;				pstatus &= ~CURS_NEEDS_REREAD;			}		}	}	num_cols = QR_NumPublicResultCols(res);	result = SQL_SUCCESS;	self->last_fetch_count++;inolog("%s: stmt=%p ommitted++\n", func, self);	self->last_fetch_count_include_ommitted++;	opts = SC_get_ARDF(self);	/*	 * If the bookmark column was bound then return a bookmark. Since this	 * is used with SQLExtendedFetch, and the rowset size may be greater	 * than 1, and an application can use row or column wise binding, use	 * the code in copy_and_convert_field() to handle that.	 */	if ((bookmark = opts->bookmark) && bookmark->buffer)	{		char		buf[32];		SQLLEN	offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;		sprintf(buf, FORMAT_ULEN, SC_get_bookmark(self));		SC_set_current_col(self, -1);		result = copy_and_convert_field(self, 0, buf,			 SQL_C_ULONG, bookmark->buffer + offset, 0,			LENADDR_SHIFT(bookmark->used, offset),			LENADDR_SHIFT(bookmark->used, offset));	}	if (self->options.retrieve_data == SQL_RD_OFF)		/* data isn't required */		return SQL_SUCCESS;	gdata = SC_get_GDTI(self);	if (gdata->allocated != opts->allocated)		extend_getdata_info(gdata, opts->allocated, TRUE);	for (lf = 0; lf < num_cols; lf++)	{		mylog("fetch: cols=%d, lf=%d, opts = %p, opts->bindings = %p, buffer[] = %p\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);		/* reset for SQLGetData */		gdata->gdata[lf].data_left = -1;		if (NULL == opts->bindings)			continue;		if (opts->bindings[lf].buffer != NULL)		{			/* this column has a binding */			/* type = QR_get_field_type(res, lf); */			type = CI_get_oid(coli, lf);		/* speed things up */			mylog("type = %d\n", type);			if (SC_is_fetchcursor(self))				value = QR_get_value_backend(res, lf);			else			{				SQLLEN	curt = GIdx2CacheIdx(self->currTuple, self, res);inolog("base=%d curr=%d st=%d\n", QR_get_rowstart_in_cache(res), self->currTuple, SC_get_rowset_start(self));inolog("curt=%d\n", curt);				value = QR_get_value_backend_row(res, curt, lf);			}			mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value);			retval = copy_and_convert_field_bindinfo(self, type, value, lf);			mylog("copy_and_convert: retval = %d\n", retval);			switch (retval)			{				case COPY_OK:					break;		/* OK, do next bound column */				case COPY_UNSUPPORTED_TYPE:					SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func);					result = SQL_ERROR;					break;				case COPY_UNSUPPORTED_CONVERSION:					SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func);					result = SQL_ERROR;					break;				case COPY_RESULT_TRUNCATED:					SC_set_error(self, STMT_TRUNCATED, "Fetched item was truncated.", func);					qlog("The %dth item was truncated\n", lf + 1);					qlog("The buffer size = %d", opts->bindings[lf].buflen);					qlog(" and the value is '%s'\n", value);					result = SQL_SUCCESS_WITH_INFO;					break;					/* error msg already filled in */				case COPY_GENERAL_ERROR:					result = SQL_ERROR;					break;					/* This would not be meaningful in SQLFetch. */				case COPY_NO_DATA_FOUND:					break;				default:					SC_set_error(self, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func);					result = SQL_ERROR;					break;			}		}	}	return result;}RETCODESC_execute(StatementClass *self){	CSTR func = "SC_execute";	CSTR fetch_cmd = "fetch";	ConnectionClass *conn;	IPDFields	*ipdopts;	char		was_ok, was_nonfatal;	QResultClass	*res = NULL;	Int2		oldstatus,				numcols;	QueryInfo	qi;	ConnInfo   *ci;	UDWORD		qflag = 0;	BOOL		is_in_trans, issue_begin, has_out_para;	BOOL		use_extended_protocol;	int		func_cs_count = 0, i;	conn = SC_get_conn(self);	ci = &(conn->connInfo);	/* Begin a transaction if one is not already in progress */	/*	 * Basically we don't have to begin a transaction in autocommit mode	 * because Postgres backend runs in autocomit mode. We issue "BEGIN"	 * in the following cases. 1) we use declare/fetch and the statement	 * is SELECT (because declare/fetch must be called in a transaction).	 * 2) we are in autocommit off state and the statement isn't of type	 * OTHER.	 */#define	return	DONT_CALL_RETURN_FROM_HERE???	ENTER_INNER_CONN_CS(conn, func_cs_count);	oldstatus = conn->status;	if (CONN_EXECUTING == conn->status)	{		SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use.", func);		mylog("%s: problem with connection\n", func);		goto cleanup;	}	is_in_trans = CC_is_in_trans(conn);	/* issue BEGIN ? */	issue_begin = TRUE;	if (self->internal || is_in_trans)		issue_begin = FALSE;	else if (CC_is_in_autocommit(conn) &&		 (!SC_is_fetchcursor(self)	    /* || SC_is_with_hold(self) thiw would lose the performance */		 ))		issue_begin = FALSE;	else	{		switch (self->statement_type)		{			case STMT_TYPE_START:			case STMT_TYPE_SPECIAL:				issue_begin = FALSE;				break;		}	}	if (issue_begin)	{		mylog("   about to begin a transaction on statement = %p\n", self);		if (PG_VERSION_GE(conn, 7.1))			qflag |= GO_INTO_TRANSACTION;                else if (!CC_begin(conn))                {			SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction", func);			goto cleanup;                }	}	/* self->status = STMT_EXECUTING; */	if (!SC_SetExecuting(self, TRUE))	{		SC_set_error(self, STMT_OPERATION_CANCELLED, "Cancel Reuest Accepted", func);		goto cleanup;	}	conn->status = CONN_EXECUTING;	/* If it's a SELECT statement, use a cursor. */	/*	 * Note that the declare cursor has already been prepended to the	 * statement	 */	/* in copy_statement... */	use_extended_protocol = FALSE;	if (PREPARED_PERMANENTLY == self->prepared &&	    PROTOCOL_74(ci))		use_extended_protocol = TRUE;	else if (PREPARED_TEMPORARILY == self->prepared)	{		switch (SC_get_prepare_method(self))		{#ifndef	BYPASS_ONESHOT_PLAN_EXECUTION			case PARSE_TO_EXEC_ONCE:#endif /* BYPASS_ONESHOT_PLAN_EXECUTION */			case NAMED_PARSE_REQUEST:				use_extended_protocol = TRUE;		}		if (!use_extended_protocol)		{			SC_forget_unnamed(self);			SC_set_Result(self, NULL); /* discard the parsed information */		}	}	if (use_extended_protocol)	{		char	*plan_name = self->plan_name;		if (issue_begin)			CC_begin(conn);		res = SC_get_Result(self);inolog("get_Result=%p\n", res);		if (!plan_name)			plan_name = "";		if (!SendBindRequest(self, plan_name))		{			if (SC_get_errornumber(self) <= 0)				SC_set_error(self, STMT_EXEC_ERROR, "Bind request error", func);			goto cleanup;		}		if (!SendExecuteRequest(self, plan_name, 0))		{			if (SC_get_errornumber(self) <= 0)				SC_set_error(self, STMT_EXEC_ERROR, "Execute request error", func);			goto cleanup;		}		if (!(res = SendSyncAndReceive(self, res, "bind_and_execute")))		{			if (SC_get_errornumber(self) <= 0)				SC_set_error(self, STMT_EXEC_ERROR, "Could not receive he response, communication down ??", func);			CC_on_abort(conn, CONN_DEAD);			goto cleanup;		}	}	else if (self->statement_type == STMT_TYPE_SELECT)	{		char		fetch[128];		const char *appendq = NULL;		QueryInfo	*qryi = NULL; 		qflag |= (SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency ? CREATE_KEYSET : 0);		mylog("       Sending SELECT statement on stmt=%p, cursor_name='%s' qflag=%d,%d\n", self, SC_cursor_name(self), qflag, self->options.scroll_concurrency);		/* send the declare/select */		if (SC_is_fetchcursor(self))		{			qi.result_in = NULL;			qi.cursor = SC_cursor_name(self);			qi.row_size = ci->drivers.fetch_max;			sprintf(fetch, "%s " FORMAT_LEN " in \"%s\"", fetch_cmd, qi.row_size, SC_cursor_name(self));			qryi = &qi;			appendq = fetch;		}		res = CC_send_query_append(conn, self->stmt_with_params, qryi, qflag, SC_get_ancestor(self), appendq);		if (SC_is_fetchcursor(self) && QR_command_maybe_successful(res))		{#ifdef NOT_USED			QR_Destructor(res);			qflag &= (~ GO_INTO_TRANSACTION);			/*			 * That worked, so now send the fetch to start getting data			 * back			 */			qi.result_in = NULL;			qi.cursor = SC_cursor_name(self);			qi.row_size = ci->drivers.fetch_max;			/*			 * Most likely the rowset size will not be set by the			 * application until after the statement is executed, so might			 * as well use the cache size. The qr_next_tuple() function			 * will correct for any discrepancies in sizes and adjust the			 * cache accordingly.			 */			sprintf(fetch, "%s " FORMAT_LEN " in \"%s\"", fetch_cmd, qi.row_size, SC_cursor_name(self));			res = CC_send_query(conn, fetch, &qi, qflag, SC_get_ancestor(self));#endif /* NOT_USED */			if (appendq)			{				QResultClass	*qres, *nres;				for (qres = res; qres;)				{					if (qres->command && strnicmp(qres->command, fetch_cmd, 5) == 0)					{						res = qres;						break;					}					nres = qres->next;					qres->next = NULL;					QR_Destructor(qres);					qres = nres;				}			}				if (SC_is_with_hold(self))				QR_set_withhold(res);		}		mylog("     done sending the query:\n");	}	else	{		/* not a SELECT statement so don't use a cursor */		mylog("      it's NOT a select statement: stmt=%p\n", self);		res = CC_send_query(conn, self->stmt_with_params, NULL, qflag, SC_get_ancestor(self));		/*		 * We shouldn't send COMMIT. Postgres backend does the autocommit		 * if neccessary. (Zoltan, 04/26/2000)		 */		/*		 * Above seems wrong. Even in case of autocommit, started		 * transactions must be committed. (Hiroshi, 02/11/2001)		 */		if (CC_is_in_trans(conn))		{			if (!is_in_trans)				CC_set_in_manual_trans(conn);			if (!self->internal && CC_is_in_autocommit(conn) && !CC_is_in_manual_trans(conn))				CC_commit(conn);		}	}	SC_forget_unnamed(self);	if (CONN_DOWN != conn->status)		conn->status = oldstatus;	self->status = STMT_FINISHED;	LEAVE_INNER_CONN_CS(func_cs_count, conn);	/* Check the status of the result */	if (res)	{		was_ok = QR_command_successful(res);		was_nonfatal = QR_command_nonfatal(res);		if (was_ok)			SC_set_errornumber(self, STMT_OK);		else			SC_set_errornumber(self, was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND);		/* set cursor before the first tuple in the list */		self->currTuple = -1;		SC_set_current_col(self, -1);		SC_set_rowset_start(self, -1, FALSE);		/* issue "ABORT" when query aborted */		if (QR_get_aborted(res))		{#ifdef	_LEGACY_MODE_			if (!self->internal)				CC_abort(conn);#endif /* _LEGACY_MODE */		}		else		{			QResultClass	*tres;			/* see if the query did return any result columns */			for (tres = res, numcols = 0; !numcols && tres; tres = tres->next)			{				numcols = QR_NumResultCols(tres);			}			/* now allocate the array to hold the binding info */			if (numcols > 0)			{				ARDFields	*opts = SC_get_ARDF(self);				extend_column_bindings(opts, numcols);				if (opts->bindings == NULL)				{					QR_Destructor(res);					SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information", func);					goto cleanup;				}			}inolog("!!%p->SC_is_concat_pre=%x res=%p\n", self, self->miscinfo, res);			/*			 * special handling of result for keyset driven cursors. 			 * Use the columns info of the 1st query and			 * user the keyset info of the 2nd query.			 */			if (SQL_CURSOR_KEYSET_DRIVEN == self->options.cursor_type &&			    SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency &&			    !SC_is_fetchcursor(self))			{				if (tres = res->next, tres)				{					if (tres->fields)						CI_Destructor(tres->fields);					tres->fields = res->fields;					res->fields = NULL;					tres->num_fields = res->num_fields;					res->next = NULL;					QR_Destructor(res);					SC_init_Result(self);					SC_set_Result(self, tres);					res = tres;				}			}			/* skip the result of PREPARE in 'PREPARE ..:EXECUTE ..' call */			else if (SC_is_concat_prepare_exec(self))			{				tres = res->next;inolog("res->next=%p\n", tres);				res->next = NULL;				if (res != SC_get_Result(self))					QR_Destructor(res);				SC_set_Result(self, tres);				res = tres;				SC_set_prepared(self, PREPARED_PERMANENTLY);				SC_no_concat_prepare_exec(self);			}		}	}	else	{		/* Bad Error -- The error message will be in the Connection */		if (!conn->sock)			SC_set_error(self, STMT_BAD_ERROR, CC_get_errormsg(conn), func);		else if (self->statement_type == STMT_TYPE_CREATE)		{			SC_set_error(self, STMT_CREATE_TABLE_ERROR, "Error creating the table", func);			/*			 * This would allow the table to already exists, thus			 * appending rows to it.  BUT, if the table didn't have the			 * same attributes, it would fail. return			 * SQL_SUCCESS_WITH_INFO;			 */		}		else		{			SC_set_error(self, STMT_EXEC_ERROR, CC_get_errormsg(conn), func);		}#ifdef	_LEGACY_MODE_		if (!self->internal)			CC_abort(conn);#endif /* _LEGACY_MODE_ */	}	if (!SC_get_Result(self))		SC_set_Result(self, res);	else if (res == SC_get_Result(self))		;	else	{		QResultClass	*last;		for (last = SC_get_Result(self); last->next; last = last->next)			;		last->next = res;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -