/****************************************************************************

  module      : batchtest.cpp

  -------------------------------------------------------------------------

  responsible : D039759

  special area: Interface Runtime
  description : Batch execute tests.


  last changed: 2001-01-20
  see also    :

  -------------------------------------------------------------------------





    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

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

    This program 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 General Public License for more details.

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








*****************************************************************************/

#include "SAPDB/Interfaces/sapdbifr.h"
#include "SAPDB/Interfaces/tests/TestUtils.h"

class BatchTest
    : public IFR_TestCase
{
public:
    int testcount;
    
    BatchTest()
    :IFR_TestCase("BatchTest")
    {
        testcount=30000;
    }

    IFR_Bool run()
    {
        loginfo("Testing batch insert.");
        m_success = m_success && runBatchInsert();
        loginfo("Testing batch delete.");
        m_success = m_success && runBatchDelete();
        loginfo("Testing batch with constraint violation.");
        m_success = m_success && runBatchViolation();
        loginfo("Testing parameter by address in batch.");
        m_success = m_success && runParameterAddr();
        loginfo("Testing rowwise binding and batch.");
        m_success = m_success && runRowWiseBinding();
        return m_success;
    }
    
    IFR_Bool runBatchInsert()
    {
        dropTable("BATCHINSERT_TEST");
        m_success = m_success && execSQL("CREATE TABLE BATCHINSERT_TEST (A INT PRIMARY KEY)");
        IFR_PreparedStmt *ps=tc_errorcheck(connection())->createPreparedStatement();
        IFR_Length *lengthindicator = new IFR_Length[testcount];
        IFR_Int4 *data = new IFR_Int4[testcount];
        for(IFR_Int4 i=1; i<=testcount; ++i) {
            data[i-1]=i;
            lengthindicator[i-1]=sizeof(IFR_Int4);
        }
        IFR_Retcode rc;
        
        { tc_errorcheck(ps)->bindParameter(1, IFR_HOSTTYPE_INT4, data, lengthindicator, sizeof(IFR_Int4)); }
        { tc_errorcheck(ps)->setRowArraySize(testcount); }
        { tc_errorcheck(ps)->prepare("INSERT INTO BATCHINSERT_TEST VALUES (?)", IFR_StringEncodingAscii); }
        { rc = tc_errorcheck(ps)->executeBatch(); }
        
        if(rc!= IFR_OK) {
            logerror("executeBatch() returned %d", rc);
            return m_success;
        }
        
        const IFR_Int4 *statusarray=ps->getRowStatus();
        for(IFR_Int4 j=0; j<testcount; ++j) {
            if(statusarray[j] != IFR_SUCCESS_NO_INFO) {
                logerror("Status array contains error at pos %d, aborting.", (j+1));
                break;
            }
        }
        connection()->releaseStatement(ps);
        execSQL("COMMIT");
        delete [] lengthindicator;
        delete [] data;
        return m_success;
    }
    
    IFR_Bool runBatchDelete()
    {
        // will and must run after the 'batchinsert' test
        IFR_PreparedStmt *ps=tc_errorcheck(connection())->createPreparedStatement();
        IFR_Length *lengthindicator = new IFR_Length[testcount];
        IFR_Int4 *data = new IFR_Int4[testcount];
        for(IFR_Int4 i=1; i<=testcount; ++i) {
            data[i-1]=i;
            lengthindicator[i-1]=sizeof(IFR_Int4);
        }
        { tc_errorcheck(ps)->bindParameter(1, IFR_HOSTTYPE_INT4, data, lengthindicator, sizeof(IFR_Int4)); }
        { tc_errorcheck(ps)->setRowArraySize(testcount); }
        { tc_errorcheck(ps)->prepare("DELETE FROM BATCHINSERT_TEST WHERE A=?", IFR_StringEncodingAscii); }
        { tc_errorcheck(ps)->executeBatch(); }
        
        const IFR_Int4 *statusarray=ps->getRowStatus();
        for(IFR_Int4 j=0; j<testcount; ++j) {
            if(statusarray[j] != IFR_SUCCESS_NO_INFO) {
                logerror("Status array contains error at pos %d, aborting.", (j+1));
                break;
            }
        }
        connection()->releaseStatement(ps);
        execSQL("COMMIT");
        delete [] lengthindicator;
        delete [] data;
        return m_success;
    }
    

    IFR_Bool runBatchViolation()
    {
        // will and must run after the 'batchinsert' test
        IFR_PreparedStmt *ps=tc_errorcheck(connection())->createPreparedStatement();
        IFR_Length *lengthindicator = new IFR_Length[testcount];
        IFR_Int4 *data = new IFR_Int4[10];
        for(IFR_Int4 i=1; i<=10; ++i) {
            data[i-1]=i;
            lengthindicator[i-1]=sizeof(IFR_Int4);
        }
        data[8-1]=7; // 
        
        { tc_errorcheck(ps)->bindParameter(1, IFR_HOSTTYPE_INT4, data, lengthindicator, sizeof(IFR_Int4)); }
        { tc_errorcheck(ps)->setRowArraySize(10); }
        { tc_errorcheck(ps)->prepare("INSERT INTO BATCHINSERT_TEST VALUES(?)", IFR_StringEncodingAscii); }
        { tc_expectederrorcheck(ps, 200)->executeBatch(); }
        
        const IFR_Int4 *statusarray=ps->getRowStatus();
        for(IFR_Int4 j=0; j<10; ++j) {
            if(statusarray[j] != IFR_SUCCESS_NO_INFO && j < 7) {
                logerror("Status array contains error for pos %d ", (j+1));
            } else if(statusarray[j] != IFR_EXECUTE_FAILED && j >= 7) {
                logerror("Status array contains no error for pos %d ", (j+1));
            }
        }
        connection()->releaseStatement(ps);
        execSQL("COMMIT");
        delete [] lengthindicator;
        delete [] data;
        return m_success;
    }
    
    IFR_Bool runParameterAddr()
    {
        IFR_PreparedStmt *ps=tc_errorcheck(connection())->createPreparedStatement();
        IFR_Length *lengthindicator=new IFR_Length[3];
        lengthindicator[0]=lengthindicator[1]=lengthindicator[2]=sizeof(IFR_Int4);
        IFR_Int4 **data=new IFR_Int4*[3];
        IFR_Int4 data1=192;
        IFR_Int4 data2=178;
        IFR_Int4 data3=234;
        data[0]=&data1;
        data[1]=&data2;
        data[2]=&data3;            
        
        { tc_errorcheck(ps)->bindParameterAddr(1, IFR_HOSTTYPE_INT4, data, lengthindicator, sizeof(IFR_Int4)); }
        { tc_errorcheck(ps)->setRowArraySize(3); }
        { tc_errorcheck(ps)->prepare("INSERT INTO BATCHINSERT_TEST VALUES(?)", IFR_StringEncodingAscii); }
        { tc_errorcheck(ps)->executeBatch(); }
        
        const IFR_Int4 *statusarray=ps->getRowStatus();
        for(IFR_Int4 j=0; j<3; ++j) {
            if(statusarray[j] != IFR_SUCCESS_NO_INFO) {
                logerror("Status array contains error for pos %d ", (j+1));
            } 
        }
        connection()->releaseStatement(ps);
        execSQL("COMMIT");
        delete [] lengthindicator;
        delete [] data;
        return m_success;

    }

    IFR_Bool runRowWiseBinding()
    {
        struct rowdata {
            IFR_Int4 data;
            IFR_Length indicator;
            char     padding[37];
        };
        struct rowdata rows[3];
        rows[0].data=19;
        rows[1].data=20;
        rows[2].data=21;
        rows[0].indicator = rows[1].indicator = rows[2].indicator = sizeof(IFR_Int4);
        IFR_PreparedStmt *ps=tc_errorcheck(connection())->createPreparedStatement();
        { tc_errorcheck(ps)->bindParameter(1, IFR_HOSTTYPE_INT4, & (rows[0].data), &(rows[0].indicator), sizeof(IFR_Int4)); }
        { tc_errorcheck(ps)->setRowArraySize(3); }
        { tc_errorcheck(ps)->setBindingType(sizeof(struct rowdata)); }
        { tc_errorcheck(ps)->prepare("INSERT INTO BATCHINSERT_TEST VALUES(?)", IFR_StringEncodingAscii); }
        { tc_errorcheck(ps)->executeBatch(); }
        
        const IFR_Int4 *statusarray=ps->getRowStatus();
        for(IFR_Int4 j=0; j<3; ++j) {
            if(statusarray[j] != IFR_SUCCESS_NO_INFO) {
                logerror("Status array contains error for pos %d ", (j+1));
            } 
        }
        connection()->releaseStatement(ps);
        execSQL("COMMIT");
        return m_success;
    }
    
};

//----------------------------------------------------------------------
class BatchDBSCommand
    : public IFR_TestCase
{
public:
   
    BatchDBSCommand()
    :IFR_TestCase("BatchDBSCommand")
    {}

    IFR_Bool run()
    {
        dropTable("BATCHDBSTEST");
        m_success = m_success && execSQL("CREATE TABLE BATCHDBSTEST (A INTEGER)");
        IFR_Statement *s=tc_errorcheck(connection())->createStatement();
        char buffer[1024];
        for(int i=1; i<1000; ++i) {
            sprintf(buffer, "INSERT INTO BATCHDBSTEST VALUES(%d)", i);
            tc_errorcheck(s)->addBatch(buffer, IFR_StringEncodingAscii);
        }
        tc_errorcheck(s)->executeBatch();
        
        tc_errorcheck(s)->clearBatch();
        tc_errorcheck(s)->addBatch("INSERT INTO BATCHDBSTEST VALUES(1000)", IFR_StringEncodingAscii);
        tc_errorcheck(s)->addBatch("INSERT INTO BATCHDBSTEST VALUES(1001)", IFR_StringEncodingAscii);
        tc_errorcheck(s)->addBatch("WRONG AND FAULTY", IFR_StringEncodingAscii);
        tc_errorcheck(s)->addBatch("INSERT INTO BATCHDBSTEST VALUES(1002)", IFR_StringEncodingAscii);
        if(s->getRowArraySize() != 4) {
            logerror("Expected 4 rows");
        }
        s->executeBatch();
        const IFR_Int4 *rcarray=s->getRowStatus();
        if(rcarray[0] != 1 ||
           rcarray[1] != 1 ||
           rcarray[2] != IFR_EXECUTE_FAILED ||
           rcarray[3] != 1) {
            logerror("Row status array contains not expected values.");
        }
        return m_success;
    }
};
    

int main(int argc, char **argv)
{
    IFR_TestFrame testframe(argc, argv);
    testframe.addTestCase(new BatchTest());
    testframe.addTestCase(new BatchDBSCommand());
    if(testframe.run()) return 0;
    return 1;
}
