/*************************************************************************
*
*       retrieve.c              6/10/93
*
*       This file is about SQLRetrieve for WinWord ODBC
*
*		7/27/95 - added SQLQueryFetch()
*						SQLQueryRetrieve()
*						SQLRetrieveColSize()
*						SQLSetRowPos()
*
*************************************************************************/

#include "wbodbc.h"
#include "wdcmds.h"
#include "wdfid.h"

/*************************************************************************
*
*       sql_retrieve_rows -- the entrance of SQLRetrieveRows function
*
*************************************************************************/
SWORD WINAPI _loadds SQLRetrieveRows(SWORD connection_num)
{
	ODBCHNDL	*hConnect;
	DLLLIST		*dlllist_temp;
	
	dlllist_temp = wdGetVBlock(TRUE);
	if (dlllist_temp == NULL)
		{
		if(henv)
			return(SQL_OutOfMemory);
		else
			return(0);
		}
	
	hConnect = wdCheckConnect(dlllist_temp->hODBC, connection_num);
	if(hConnect == NULL)
		return(SQL_NoMoreData);
		
	if(hConnect->synchronize_flag)
		return(SQL_SynchronizeError);
	
	if(hConnect->lpDBList)
		return(hConnect->lpDBList->nrows);
		
	return(SQL_NoMoreData);
}

/*************************************************************************
*
*       sql_retrieve_columns -- the entrance of SQLRetrieveColumns function
*
*************************************************************************/
SWORD WINAPI _loadds SQLRetrieveColumns(SWORD connection_num)
{
	ODBCHNDL    *hConnect;
	DLLLIST     *dlllist_temp;
	
	dlllist_temp = wdGetVBlock(TRUE);
	if (dlllist_temp == NULL)
		{
		if(henv)
			return(SQL_OutOfMemory);
		else
			return(0);
		}
	
	hConnect = wdCheckConnect(dlllist_temp->hODBC, connection_num);
	if(hConnect == NULL)
		return(SQL_NoMoreData);
		
	if(hConnect->synchronize_flag)
		return(SQL_SynchronizeError);
	
	if(hConnect->lpDBList)
		return(hConnect->lpDBList->ncols);
		
	return(SQL_NoMoreData);
}



/*************************************************************************
*
*       sql_retrieve_item -- the entrance of SQLRetrieveItem function
*
*************************************************************************/
LPSTR WINAPI _loadds SQLRetrieveItem$(SWORD connection_num, SWORD col, SWORD row)
{
    ODBCHNDL    *hConnect;
    DLLLIST     *dlllist_temp;
    DBROW       *lpRowCurr;
    LPSTR       lpCurr;

	if(row<1 || col<1)
		return(wdNullString());
		
	dlllist_temp = wdGetVBlock(TRUE);
	if (dlllist_temp == NULL) 
		return(wdNullString());
	
	hConnect = wdCheckConnect(dlllist_temp->hODBC, connection_num);
	if(hConnect == NULL)
		return(wdNullString());
		
	if(hConnect->synchronize_flag)
		return(wdNullString());
	
	if(hConnect->lpDBList)
		{
		if(row>hConnect->lpDBList->nrows||col>hConnect->lpDBList->ncols)
			return(wdNullString());
			
		lpRowCurr = hConnect->lpDBList->lpRow;
		
		while(--row)
			{
			if(lpRowCurr)
				lpRowCurr = lpRowCurr->next;
			else
				break;
			}
			
		if(lpRowCurr)
			{
			if(lpRowCurr->hGlobal==NULL)
				return(wdNullString());
			if(hConnect->lpDBList->hCurrLock!=lpRowCurr->hGlobal)
				{
				if(hConnect->lpDBList->hCurrLock)
					GlobalUnlock(hConnect->lpDBList->hCurrLock);
					
				lpCurr = GlobalLock(lpRowCurr->hGlobal);
				if(lpCurr==NULL)
					return(wdNullString());
					
				hConnect->lpDBList->hCurrLock = lpRowCurr->hGlobal;
				hConnect->lpDBList->lpCurrLock = lpCurr;
				}
			else
				lpCurr = hConnect->lpDBList->lpCurrLock;
				
			lpCurr+=lpRowCurr->offset;
			col = *(SWORD *)(lpCurr+(col<<1)-2);
			if(col==0)
				return(wdNullString());
				
			return(lpCurr+col);
			}
		}
	return(wdNullString());
}

/*************************************************************************
*
*       sql_retrieve_flush -- the entrance of SQLRetrieveFlush function
*
*************************************************************************/
SWORD WINAPI _loadds SQLRetrieveFlush(SWORD connection_num)
{
	ODBCHNDL    *hConnect;
	DLLLIST     *dlllist_temp;
	
	dlllist_temp = wdGetVBlock(TRUE);
	if (dlllist_temp == NULL)
		{
		if(henv)
			return(SQL_OutOfMemory);
		else
			return(0);
		}
	
	hConnect = wdCheckConnect(dlllist_temp->hODBC, connection_num);
	if(hConnect == NULL)
		return(SQL_NoMoreData);
		
	if(hConnect->synchronize_flag)
		return(SQL_SynchronizeError);
		
	wdFreeDBList(hConnect->lpDBList);
	hConnect->lpDBList = NULL;

	if (hConnect->hstmt) {
		if (SQLFreeStmt(hConnect->hstmt, SQL_CLOSE) != SQL_SUCCESS) {
			wdSQLError(henv, hConnect->hdbc, hConnect->hstmt);		 
			return(0);
			}
	}

	return(1);
}

/*************************************************************************
*
*       sql_retrieve_to_document -- the entrance of SQLRetrieveDocument function
*
*************************************************************************/
SWORD WINAPI _loadds SQLRetrieveToDocument(SWORD connection_num)
{
	ODBCHNDL *hConnect;
	DLLLIST  *dlllist_temp;
	WCB      wcb;
	SWORD    err;
	DBROW    *lpRowCurr;
	LPSTR    lpCurr;
	SWORD    col,row;
	
	dlllist_temp = wdGetVBlock(TRUE);
	if (dlllist_temp == NULL)
		{
		if(henv)
		return(SQL_OutOfMemory);
		else
		return(0);
		}
	
	hConnect = wdCheckConnect(dlllist_temp->hODBC, connection_num);
	if(hConnect == NULL)
		return(SQL_NoMoreData);
		
	if(hConnect->synchronize_flag)
		return(SQL_SynchronizeError);
		
	if(hConnect->lpDBList==NULL)
		return(SQL_NoMoreData);

	if (hConnect->lpDBList->nrows==0)
		return(SQL_NoMoreData);
				  
	InitWcbFields(&wcb, TypeShort);
	AddShortField(&wcb, hConnect->lpDBList->ncols, fidNumColumns);
//	AddShortField(&wcb, hConnect->lpDBList->nrows, fidNumRows);
	err = wdCommandDispatch(wdTableInsertTable, 2, wcb.cArgs, wcb.wdoprArgs, lpwdoprNil);
	if(err){
/*		char foo[255];

		sprintf(foo,"%d",err);
 		MessageBox(NULL,foo,"SQLRetrieveToDocument",MB_OK); */
		return(SQL_CAPIError);
	}
		
	for(row=0,lpRowCurr = hConnect->lpDBList->lpRow; row < hConnect->lpDBList->nrows; row++)
		{
		if(!lpRowCurr)
			break;
			
		if(lpRowCurr->hGlobal==NULL)
			break;
			
		if(hConnect->lpDBList->hCurrLock!=lpRowCurr->hGlobal)
			{
			if(hConnect->lpDBList->hCurrLock)
				GlobalUnlock(hConnect->lpDBList->hCurrLock);
				
			lpCurr = GlobalLock(lpRowCurr->hGlobal);
			if(lpCurr==NULL)
				return(SQL_OutOfMemory);
				
			hConnect->lpDBList->hCurrLock = lpRowCurr->hGlobal;
			hConnect->lpDBList->lpCurrLock = lpCurr;
			}
			
		lpCurr=hConnect->lpDBList->lpCurrLock + lpRowCurr->offset;
		for(col=0; col < hConnect->lpDBList->ncols; col++)
			{
			err = *(SWORD *)(lpCurr+(col<<1));
			if(err == 0)
				break;
				
			InitWcbFields(&wcb, TypeShort);
			AddStringField(&wcb, lpCurr+err, elkNil);
			err = wdCommandDispatch(wdInsert, 0, wcb.cArgs, wcb.wdoprArgs, lpwdoprNil);
			if(err)
				return(SQL_CAPIError);
				
			if(row!=hConnect->lpDBList->nrows-1||col!=hConnect->lpDBList->ncols-1)
				{
				InitWcbFields(&wcb, TypeShort);
				err = wdCommandDispatch(wdNextCell, 0, wcb.cArgs, wcb.wdoprArgs, lpwdoprNil);
				if(err)
					return(SQL_CAPIError);
				}
			}
		lpRowCurr = lpRowCurr->next;
		}
	
	return(1);
}


/*************************************************************************
*
*       SQLQueryFetch() positions the cursor on the next row of the result set
*			and loads the next set of columns for retrieval by
*			SQLQueryRetrieve()
*
*		returns 1 on success
*		returns 0 or negative value on error
*
*************************************************************************/
SWORD WINAPI _loadds SQLQueryFetch(SWORD connection_num)
{
	ODBCHNDL	*hConnect;
	DLLLIST		*dlllist_temp;
	RETCODE		retcode;
	
	dlllist_temp = wdGetVBlock(TRUE);
	if (dlllist_temp == NULL)
		{
		if(henv)
			return(SQL_OutOfMemory);
		else
			return(0);
		}
	
	hConnect = wdCheckConnect(dlllist_temp->hODBC, connection_num);
	if(hConnect == NULL)
		return(SQL_NoMoreData);
		
	if(hConnect->synchronize_flag)
		return(SQL_SynchronizeError);

	if (SupportsScrollableCursors(hConnect)) {
		while ((retcode = SQLExtendedFetch(hConnect->hstmt,SQL_FETCH_NEXT,0,NULL,NULL))
				==SQL_STILL_EXECUTING)
			if(dlllist_temp->synFlag==0)
				return(SQL_StillExecuting); }
	else {
		while ((retcode = SQLFetch(hConnect->hstmt))==SQL_STILL_EXECUTING)
			if(dlllist_temp->synFlag==0)
				return(SQL_StillExecuting);
	}

	if (retcode!=SQL_SUCCESS)
		wdSQLError(henv, hConnect->hdbc, hConnect->hstmt);

	if (retcode==SQL_NO_DATA_FOUND)
		return (SQL_NoMoreData);
	else
		return(retcode==SQL_SUCCESS);
} /* SQLQueryFetch() */


/*************************************************************************
*
*		SQLQueryRetrieve - puts the data item specified by _col_ on the
*			current row in the string _dest_.
*			The current row can be incremented by SQLQueryFetch.
*
*			returns 1 on success, 0 or negative value on error
*
*************************************************************************/
SWORD WINAPI _loadds SQLQueryRetrieve(SWORD connection_num, SWORD col,LPSTR dest,SWORD destSize)
{
    ODBCHNDL    *hConnect;
    DLLLIST     *dlllist_temp;
	RETCODE		retcode;


	dlllist_temp = wdGetVBlock(TRUE);
	if (dlllist_temp == NULL) {
		if(henv)
			return(SQL_OutOfMemory);
		else
			return(0);
	}

	if (dest == NULL)     /* caller forgot to allocate string; should never happen */
		return(0);

	
	hConnect = wdCheckConnect(dlllist_temp->hODBC, connection_num);
	if(hConnect == NULL)
		return(SQL_NoMoreData);
		
	if(hConnect->synchronize_flag)
		return(SQL_SynchronizeError);

	if(hConnect->lpDBList==NULL)
		return(0);

/*  SQLGetData will return a more descriptive error message if the
	column number is invalid, so don't bother checking the bounds*/


	/* get the specified column */
	while((retcode=SQLGetData(hConnect->hstmt, col, (SWORD)SQL_C_CHAR, 
		dest, destSize, &(hConnect->synLength)))==SQL_STILL_EXECUTING)
		{
		if(dlllist_temp->synFlag==0)
			return(SQL_StillExecuting);
			
		if(wdPeekMessage())
			{
			hConnect->synchronize_flag=0;
			return(0);
			}
		}		/* while (SQL_STILL_EXECUTING) */
			
	hConnect->synchronize_flag=0;

	if (hConnect->synLength==SQL_NULL_DATA)
		_fmemset(dest,'\0',1);			// clear it out if it was a null field
	
	if(retcode != SQL_SUCCESS)
		wdSQLError(henv, hConnect->hdbc, hConnect->hstmt);
	
	return(retcode==SQL_SUCCESS);
} /* SQLQueryRetrieve() */


/*************************************************************************
*
*       SQLRetrieveColSize() returns the size of the data that will be
*			returned from a call to SQLGetData for the given column on
*			the current row. Used in conjunction with SQLQueryRetrieve.
*
*			returns a negative value if there's an error, or 0 if
*			the size cannot be determined. 
*
*		NOTE: many ODBC drivers cannot or will not determine the length
*			of a SQL variable length field. In these situations,
*			SQLRetrieveColSize returns 0 and the macro writer is left to
*			guess at the appropriate size.
*
*************************************************************************/
SWORD WINAPI _loadds SQLRetrieveColSize(SWORD connection_num,SWORD col)
{
	ODBCHNDL	*hConnect;
	DLLLIST		*dlllist_temp;
	SWORD		colSize;
	
	dlllist_temp = wdGetVBlock(TRUE);
	if (dlllist_temp == NULL)
		{
		if(henv)
			return(SQL_OutOfMemory);
		else
			return(0);
		}
	
	hConnect = wdCheckConnect(dlllist_temp->hODBC, connection_num);
	if(hConnect == NULL)
		return(SQL_NoMoreData);
		
	if(hConnect->synchronize_flag)
		return(SQL_SynchronizeError);

	colSize = (SWORD)GetColSize(hConnect,col);

	if (colSize<=0)
		return (colSize);
	else	
		return(colSize+1);			  // add one for null termination
} /* SQLRetrieveColSize() */



/*************************************************************************
*
*       SQLSetRowPos() positions the cursor on the given row. Level 2
*				ODBC function; not necessarily supported.
*
*		returns 0 or negative value on error
*
*************************************************************************/
SWORD WINAPI _loadds SQLSetRowPos(SWORD connection_num,SWORD row)
{
	ODBCHNDL	*hConnect;
	DLLLIST		*dlllist_temp;
	RETCODE		retcode;
	UDWORD		pwCursType;
	

		
	dlllist_temp = wdGetVBlock(TRUE);
	if (dlllist_temp == NULL)
		{
		if(henv)
			return(SQL_OutOfMemory);
		else
			return(0);
		}
	
	hConnect = wdCheckConnect(dlllist_temp->hODBC, connection_num);
	if(hConnect == NULL)
		return(SQL_NoMoreData);

	// check to see if we've been using a scrollable cursor
	retcode = SQLGetStmtOption(hConnect->hstmt,SQL_CURSOR_TYPE,&pwCursType);
	if (retcode!=SQL_SUCCESS || pwCursType!=SQL_CURSOR_STATIC)
		return (0);	   // driver does not support this function
			
	if(hConnect->synchronize_flag)
		return(SQL_SynchronizeError);

	while ((retcode = SQLExtendedFetch(hConnect->hstmt,SQL_FETCH_ABSOLUTE,row,NULL,NULL))
				==SQL_STILL_EXECUTING)
		if(dlllist_temp->synFlag==0)
			return(SQL_STILL_EXECUTING);

	if (retcode!=SQL_SUCCESS)
		wdSQLError(henv,hConnect->hdbc,hConnect->hstmt);

	if (retcode==SQL_NO_DATA_FOUND)
		return (SQL_NoMoreData);
	else
		return (retcode==SQL_SUCCESS);
} /* SQLSetRowPos() */		



	
