/*****************************************************************************
FILE:               O2CI7Cursor.m
LANGUAGE:           Objective-C
SYSTEM:             GNUstep
USER-INTERFACE:     None
DESCRIPTION

    This class is a private class of the GNUstep/db adaptor to the 
    Oracle databases.
    It implements an object interface to the O2CI7 primitives, cursor-related.
    It's implementation is based on the O2CI7 v7, and should be compatible
    with, at least, both Oracle7 and Oracle8 databases.

AUTHORS
    <PJB> Pascal J. Bourguignon <pjb@imaginet.fr>
MODIFICATIONS
    1999/07/25 Creation.
BUGS
    - ...
LEGAL
    Written by:  Pascal J. Bourguignon <pjb@imaginet.fr>
    Funds from:  Orange Concept (http://www.orange-concept.com/)
    Date:        August 1999 - February 2000

    This file is part of the Oracle7 Adaptor, GNUstep Database Library.
    The Oracle7 Adaptor allows access to Oracle[678] databases from GDL.

    Copyright (C) 2000 Free Software Foundation, Inc.

    This  library is  free software;  you can  redistribute  it and/or
    modify it under the terms of the GNU Lesser General Public License
    as published by the Free  Software Foundation; either version 2 of
    the License, or (at your option) any later version.

    This library  is distributed in the  hope that it  will be useful,
    but  WITHOUT ANY WARRANTY;  without even  the implied  warranty of
    MERCHANTABILITY or FITNESS FOR  A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have  received a copy of the  GNU Lesser General Public
    License  along  with this  library;  if  not,  write to  the  Free
    Software  Foundation, Inc.,  59 Temple  Place, Suite  330, Boston,
    MA 02111-1307 USA
*****************************************************************************/

#include <O2CI7Cursor.h>
#include <O2CI7Context.h>
#include <Oracle7Utilities.h>


@implementation O2CI7Cursor


    NSString* stringFromOraType(int type)
    {
        switch(type){
        case SQLT_AFC:  
            return([NSString stringWithFormat:@"#%d SQLT_AFC",type]);
        case SQLT_AVC:  
            return([NSString stringWithFormat:@"#%d SQLT_AVC",type]);
        case SQLT_BIN:  
            return([NSString stringWithFormat:@"#%d SQLT_BIN",type]);
        case SQLT_BLOB: 
            return([NSString stringWithFormat:@"#%d SQLT_BLOB",type]);
        case SQLT_CHR:  
            return([NSString stringWithFormat:@"#%d SQLT_CHR",type]);
        case SQLT_CLOB: 
            return([NSString stringWithFormat:@"#%d SQLT_CLOB",type]);
        case SQLT_DAT:  
            return([NSString stringWithFormat:@"#%d SQLT_DAT",type]);
        case SQLT_FILE: 
            return([NSString stringWithFormat:@"#%d SQLT_FILE",type]);
        case SQLT_FLT:  
            return([NSString stringWithFormat:@"#%d SQLT_FLT",type]);
        case SQLT_INT:  
            return([NSString stringWithFormat:@"#%d SQLT_INT",type]);
        case SQLT_LAB:  
            return([NSString stringWithFormat:@"#%d SQLT_LAB",type]);
        case SQLT_LBI:  
            return([NSString stringWithFormat:@"#%d SQLT_LBI",type]);
        case SQLT_LNG:  
            return([NSString stringWithFormat:@"#%d SQLT_LNG",type]);
        case SQLT_LVB:  
            return([NSString stringWithFormat:@"#%d SQLT_LVB",type]);
        case SQLT_LVC:  
            return([NSString stringWithFormat:@"#%d SQLT_LVC",type]);
        case SQLT_NTY:  
            return([NSString stringWithFormat:@"#%d SQLT_NTY",type]);
        case SQLT_NUM:  
            return([NSString stringWithFormat:@"#%d SQLT_NUM",type]);
        case SQLT_ODT:  
            return([NSString stringWithFormat:@"#%d SQLT_ODT",type]);
        case SQLT_RDD:  
            return([NSString stringWithFormat:@"#%d SQLT_RDD",type]);
        case SQLT_REF:  
            return([NSString stringWithFormat:@"#%d SQLT_REF",type]);
        case SQLT_RID:  
            return([NSString stringWithFormat:@"#%d SQLT_RID",type]);
        case SQLT_STR:  
            return([NSString stringWithFormat:@"#%d SQLT_STR",type]);
        case SQLT_UIN:  
            return([NSString stringWithFormat:@"#%d SQLT_UIN",type]);
        case SQLT_VBI:  
            return([NSString stringWithFormat:@"#%d SQLT_VBI",type]);
        case SQLT_VCS:  
            return([NSString stringWithFormat:@"#%d SQLT_VCS",type]);
        case SQLT_VNU:  
            return([NSString stringWithFormat:@"#%d SQLT_VNU",type]);
        case SQLT_VST:  
            return([NSString stringWithFormat:@"#%d SQLT_VST",type]);
        default:        
            return([NSString stringWithFormat:@"#%d UNKNOWN",type]);
        }
    }//stringFromOraType;




// NSObject methods:


    -(id)init
    {
        [NSException raise:O2CI7Object_eBadInitializer format:@""];
        return(nil);
    }//init;


    -(void)dealloc
    {
        [ociContext autorelease];
        [super dealloc];
    }//dealloc;


// O2CI7Cursor methods:

    -(id)initWithContext:(O2CI7Context*)aContext
    {
        self=[super init];
        if(self!=nil){
            ociContext=[aContext retain];
            memset((void*)&cda,0,sizeof(cda));
            isOpen=NO;
        }
        return(self);
    }//initWithContext:;


    -(BOOL)open
    {
        [self cleanErrorMessages];      
        if(isOpen){
            [self reportErrorAlreadyOpen];
            return(NO);
        }else if(oopen(&cda,[ociContext lda],(text*)0,-1,-1,(text*)0,-1)){
            [self reportErrorFromOCI];
            return(NO);
        }else{
            isOpen=YES;
            return(YES);
        }
    }//open;



    -(BOOL)close
    {
        [self cleanErrorMessages];      
        if(isOpen){
            if(oclose(&cda)){
                [self reportErrorOnClose];
                return(NO);
            }else{
                isOpen=NO;
                return(YES);
            }
        }else{
            [self reportErrorNotOpen];
            return(NO);
        }
    }//close;


    -(BOOL)parseSQL:(NSString*)sqlStatement
    {
        [self cleanErrorMessages];      
        if(isOpen){
            BOOL result;
            text* sqlText=(text*)malloc(sizeof(text)
                                        *([sqlStatement cStringLength]+1));
            [sqlStatement getCString:sqlText];
            // We're not sure that oparse don't change sqlText;
            // it's not (const text*).
            //NSLog(@"oparse(%@)\n",sqlStatement);
            if(oparse(&cda,sqlText,-1,0,1)){
                [self reportErrorFromOCI];
                result=NO;
            }else{
                result=YES;
            }
            free(sqlText);
            return(result);
        }else{
            [self reportErrorNotOpen];
            return(NO);
        }
    }//parseSQL:;


    -(ub2)sqlFunctionType
    {
        return(cda.ft);
    }//sqlFunctionType;


    /* bind placeholder */


    -(BOOL)describeAttributeAtPosition:(sword)attrPosition
           size:(ub4*)attrSize type:(ub2*)attrType
           name:(sb1*)attrName nameSize:(ub4*)attrNameSize
           precision:(sb2*)prec scale:(sb2*)scale
           mayBeNull:(sb2*)attrNull;
    {
        [self cleanErrorMessages];      
        if(isOpen){
            sb4 dsize;
            if(odescr(&cda,attrPosition,attrSize,attrType,
                    attrName,attrNameSize,&dsize,prec,scale,attrNull)){
                [self reportErrorFromOCI];
                return(NO);
            }else{
                return(YES);
            }
        }else{
            [self reportErrorNotOpen];
            return(NO);
        }
    }//describeAttributeAtPosition:size:type:name:nameSize:;




    -(BOOL)defineAttributeAtPosition:(sword)attrPosition
            buffer:(void*)attrBuffer size:(sword)attrSize type:(sword)attrType
            indicator:(sb2*)indicator dataLength:(ub2*)dataLength 
            returnCode:(ub2*)rcode
    {
        [self cleanErrorMessages];      
        if(isOpen){
            // NSLog(@"odefin %d: 0x%08x[%d] (%@) 0x%08x[2] 0x%08x[2] 0x%08x[2]\n",attrPosition,attrBuffer,attrSize,stringFromOraType(attrType),indicator,dataLength,rcode);
            if(odefin(&cda,attrPosition,attrBuffer,attrSize,attrType,
                    (sword)-1,indicator,(text*)0,-1,-1,dataLength,rcode)){
                [self reportErrorFromOCI];
                return(NO);
            }else{  
                return(YES);
            }
        }else{
            [self reportErrorNotOpen];
            return(NO);
        }
    }//defineAttributeAtPosition:buffer:size:type:;


    -(BOOL)fetch
    {
        [self cleanErrorMessages];      
        if(isOpen){
            //NSLog(@"ofetch\n");
            if(ofetch(&cda)){
                if(cda.rc!=1403){ // != no data found
                    [self reportErrorFromOCI];
                }
                return(NO);
            }else{
                return(YES);
            }
        }else{
            [self reportErrorNotOpen];
            return(NO);
        }
    }//fetch;


    -(BOOL)execute
    {
        [self cleanErrorMessages];      
        if(isOpen){
            //NSLog(@"oexecrun\n");
            if(oexec(&cda)){
                [self reportErrorFromOCI];
                return(NO);
            }else{
                return(YES);
            }
        }else{
            [self reportErrorNotOpen];
            return(NO);
        }
    }//execute;


    -(BOOL)cancel
    {
        [self cleanErrorMessages];      
        if(isOpen){
            if(ocan(&cda)){
                [self reportErrorFromOCI];
                return(NO);
            }else{
                return(YES);
            }
        }else{
            [self reportErrorNotOpen];
            return(NO);
        }
    }//cancel;





    -(void)reportErrorFromOCI
    {
        [self reportErrorCode:cda.rc functionCode:cda.fc];
    }//reportErrorFromOCI;


    -(void)reportErrorAlreadyOpen
    {
        [self reportErrorMessage:NSLocalizedStringFromTableInBundle(@"Cursor already open.",@"O2CI7Cursor",Oracle7Utilities_Bundle(),@"Error message given when the client program tries to open twice the cursor.")];
    }//reportErrorAlreadyOpen;


    -(void)reportErrorNotOpen
    {
        [self reportErrorMessage:NSLocalizedStringFromTableInBundle(@"Cursor not open.",@"O2CI7Cursor",Oracle7Utilities_Bundle(),@"Error message given when the client program tries to use a closed cursor.")];
    }//reportErrorNotOpen;


    -(void)reportErrorOnClose
    {
        [self reportErrorMessage:NSLocalizedStringFromTableInBundle(@"Error while closing the cursor.",@"O2CI7Cursor",Oracle7Utilities_Bundle(),@"Error message given when an error occurs while closing a cursor.")];
    }//reportErrorOnClose;



    -(void)reportErrorCode:(ub2)rc functionCode:(ub1)fc
    {
        NSString* errorMessage=[ociContext errorMessageForCode:rc];
        [self reportErrorMessage:errorMessage];
        ///*DEBUG*/     NSLog(@"OCI Error:    %@\n",errorMessage);
        if(fc>0){
            NSString* functionName=[ociContext functionNameForCode:fc];
            [self reportErrorMessage:functionName];
            ///*DEBUG*/ NSLog(@"OCI Function: %@\n",functionName);
        }
    }//reportErrorCode:functionCode:;



@end // O2CI7Cursor;

/*** O2CI7Cursor.m                    -- 2000-02-21 07:11:20 -- PJB ***/
