/*
**    Name: storeb.c
**
**    Date: Thu Jan 17 12:02:13 2002
**
*/

#include "ODBC.h"
#include "rmamem.h"
#include "sqlext.h"
#include "sql.h"
#include <string.h>

/* Store a bound buffer; the RMA copy lives until the binding is released */

int store_bound_parameter(int stmt,int parameter,int size,ODBCBoundInfo *info)
    {
    ODBCLibParameter *p;

    int index;

    int slot;

    int len;

    char *copy;

    if (odbcparameter_index >= ODBCLIBMAXPARAMETERS)
        {
        request_error(&odbcerror_parameters);
        return -1;
        }

    p = &odbcquerytype.parameters[odbcparameter_index];

    odbcparameter_copyback[odbcparameter_index] = 0;
    odbcparameter_index++;

    p->type  = ODBC_VALUE;
    p->size  = size;
    p->value = 0;

    if (parameter <= 0 || size <= 0)
        {
        return -1;
        }

    slot = -1;

    for (index = 0;index < ODBCLIBMAXBOUNDPARAMETERS;index++)
        {
        if (odbcquerytype.boundparameters[index].stmt == 0)
            {
            slot = index;
            break;
            }
        }

    if (slot < 0 || odbcnewbound_count >= ODBC_MAX_NEW_BOUND)
        {
        request_error(&odbcerror_bound);
        return -1;
        }

    copy = rmamalloc(size);

    if (copy == NULL)
        {
        request_error(&odbcerror_memory);
        return -1;
        }

    memset(copy,0,size);

    odbcquerytype.boundparameters[slot].stmt    = stmt;
    odbcquerytype.boundparameters[slot].data    = parameter;
    odbcquerytype.boundparameters[slot].rmadata = (int)copy;
    odbcquerytype.boundparameters[slot].size    = size;

    odbcboundinfo[slot] = *info;
    odbcboundinfo[slot].indslot    = -1;
    odbcboundinfo[slot].superseded = 0;

    odbcnewbound[odbcnewbound_count++] = slot;

    if (info->kind == ODBC_BOUND_INPUT || info->kind == ODBC_BOUND_INOUT)
        {
        copy_bound_input_slot(slot);
        }
    else
        {
        len = bound_capacity(slot);

        if (len > 0)
            {
            memcpy(copy,(void *)parameter,len);
            }
        }

    p->type  = ODBC_BOUNDREFERENCE;
    p->value = (int)copy;

    return slot;
    }

int bound_parameter_kind(int iotype)
    {
    switch (iotype)
        {
        case SQL_PARAM_OUTPUT:
            return ODBC_BOUND_OUTPUT;

        case SQL_PARAM_INPUT_OUTPUT:
            return ODBC_BOUND_INOUT;
        }

    return ODBC_BOUND_INPUT;
    }

/* Is the indicator set for data at execution? Then the value is a token */

int bound_data_at_exec(int indicator)
    {
    int value;

    if (indicator <= 0)
        {
        return 0;
        }

    value = *(int *)indicator;

    return value == SQL_DATA_AT_EXEC || value <= SQL_LEN_DATA_AT_EXEC_OFFSET;
    }

/* Bytes the RMA copy of a bound parameter needs */

int bound_parameter_size(int kind,int ctype,int columnsize,int bufferlength,int indicator,int data)
    {
    int size;

    int len;

    int value;

    char *end;

    size = data_size(ctype,0);

    if (size > 0)
        {
        return size;
        }

    size = bufferlength > 0 ? bufferlength : 0;

    if (columnsize > 0 && columnsize < ODBC_MAX_COLUMN_COPY)
        {
        len = ctype == SQL_C_CHAR ? columnsize + 1 : columnsize;

        if (len > size)
            {
            size = len;
            }
        }

    if ((kind == ODBC_BOUND_INPUT || kind == ODBC_BOUND_INOUT) && data > 0)
        {
        len = 0;

        value = indicator > 0 ? *(int *)indicator : SQL_NTS;

        if (value >= 0)
            {
            len = value;
            }
        else if (value == SQL_NTS && (ctype == SQL_C_CHAR || indicator > 0))
            {
            if (bufferlength > 0)
                {
                end = (char *)memchr((char *)data,0,bufferlength);
                len = end == NULL ? bufferlength : end - (char *)data;
                }
            else
                {
                len = strlen((char *)data);
                }
            }

        if (bufferlength > 0 && len > bufferlength)
            {
            len = bufferlength;
            }

        if (ctype == SQL_C_CHAR && len < ODBC_MAX_COLUMN_COPY)
            {
            len++;
            }

        if (len > size)
            {
            size = len;
            }
        }

    return size;
    }

/* Mark existing buffers bound to the same column or parameter for release */

void supersede_bound_parameters(int stmt,int number,int kind)
    {
    int index;

    int column;

    column = kind == ODBC_BOUND_COLUMN;

    for (index = 0;index < ODBCLIBMAXBOUNDPARAMETERS;index++)
        {
        if (odbcquerytype.boundparameters[index].stmt == stmt &&
            odbcboundinfo[index].number == number &&
            (odbcboundinfo[index].kind == ODBC_BOUND_COLUMN) == column)
            {
            odbcboundinfo[index].superseded = 1;
            }
        }
    }

/* After the driver has processed a bind, keep whichever buffers it now holds */

void commit_bound_parameters(int stmt)
    {
    int index;

    if (request_succeeded())
        {
        for (index = 0;index < ODBCLIBMAXBOUNDPARAMETERS;index++)
            {
            if (odbcquerytype.boundparameters[index].stmt == stmt &&
                odbcboundinfo[index].superseded)
                {
                free_bound_slot(index);
                }
            }
        }
    else
        {
        for (index = 0;index < odbcnewbound_count;index++)
            {
            free_bound_slot(odbcnewbound[index]);
            }

        for (index = 0;index < ODBCLIBMAXBOUNDPARAMETERS;index++)
            {
            if (odbcquerytype.boundparameters[index].stmt == stmt)
                {
                odbcboundinfo[index].superseded = 0;
                }
            }
        }

    odbcnewbound_count = 0;
    }
