DBD-Firebird

 view release on metacpan or  search on metacpan

dbdimp.c  view on Meta::CPAN


*/

#include "Firebird.h"
#include <stdint.h>

#ifndef _MSC_VER
#include <inttypes.h>
#endif

DBISTATE_DECLARE;

#define ERRBUFSIZE  255

#define IB_SQLtimeformat(xxh, format, sv)                             \
do {                                                                  \
    STRLEN len;                                                       \
    char *frmt = NULL;                                                \
    char *buf = SvPV(sv, len);                                        \
    if (len < 2 || len > 30)  break;                                  \
    Newx(frmt, len + 1, char);                                        \
    strcpy(frmt, buf);                                                \
    if (format) Safefree(format);                                     \
    format = frmt;                                                    \
} while (0)

#define IB_alloc_sqlda(sqlda, n)                             \
do {                                                         \
    short len = n;                                           \
    char *tmp;                                               \
    if (sqlda)                                               \
    {                                                        \
        Safefree(sqlda);                                     \
        sqlda = NULL;                                        \
    }                                                        \
    Newxz(tmp, XSQLDA_LENGTH(len), char);                    \
    sqlda = (XSQLDA*)tmp;                                    \
    sqlda->sqln = len;                                       \
    sqlda->version = SQLDA_OK_VERSION;                       \
} while (0)

#ifndef is_ascii_string
#warning "Using built-in implementation of is_ascii_string."
#warning "Upgrading perl to 5.12 is suggested."
// for perl before 5.12.0 RC1
// taken straight from the perl source
bool is_ascii_string(const U8 *s, STRLEN len) {
    const U8* const send = s + (len ? len : strlen((const char *)s));
    const U8* x = s;

    for (; x < send; ++x) {
        if (!UTF8_IS_INVARIANT(*x))
            break;

    }

    return x == send;
}
#endif

int create_cursor_name(SV *sth, imp_sth_t *imp_sth)
{
    ISC_STATUS status[ISC_STATUS_LENGTH];
#define CURSOR_NAME_LEN 22

    Newxz(imp_sth->cursor_name, CURSOR_NAME_LEN, char);
    snprintf(imp_sth->cursor_name, CURSOR_NAME_LEN, "perl%16.16X", (uint32_t)imp_sth->stmt);
    isc_dsql_set_cursor_name(status, &(imp_sth->stmt), imp_sth->cursor_name, 0);
    if (ib_error_check(sth, status))
        return FALSE;
    return TRUE;
}

void maybe_upgrade_to_utf8(imp_dbh_t *imp_dbh, SV *sv) {
    if (imp_dbh->ib_enable_utf8) {
        U8 *p;
        STRLEN len;
        p = (U8*)SvPV(sv, len);

        if (!is_ascii_string(p, len)
                && is_utf8_string(p, len)) {
            SvUTF8_on(sv);
        }
    }
}

void dbd_init(dbistate_t *dbistate)
{
    DBISTATE_INIT;
}


void ib_cleanup_st_prepare (imp_sth_t *imp_sth)
{
    FREE_SETNULL(imp_sth->in_sqlda);
    FREE_SETNULL(imp_sth->out_sqlda);
    FREE_SETNULL(imp_sth->dateformat);
    FREE_SETNULL(imp_sth->timeformat);
    FREE_SETNULL(imp_sth->timestampformat);
}


void ib_cleanup_st_execute (imp_sth_t *imp_sth)
{
    if (imp_sth->in_sqlda)
    {
        int i;
        XSQLVAR *var = imp_sth->in_sqlda->sqlvar;

        for (i = 0; i < imp_sth->in_sqlda->sqln; i++, var++)
        {
            Safefree(var->sqldata);
            var->sqldata = NULL;
            if (var->sqlind)
                *(var->sqlind) = -1;    /* isNULL */
        }
    }
}


/* lower level error handling */
void do_error(SV *h, int rc, char *what)
{
    D_imp_xxh(h);
    SV *errstr = DBIc_ERRSTR(imp_xxh);

    sv_setiv(DBIc_ERR(imp_xxh), (IV)rc);
    sv_setpv(errstr, what);

dbdimp.c  view on Meta::CPAN


    if (ib_error_check(sth, status))
    {
        ib_cleanup_st_prepare(imp_sth);
        return;
    }

    /* realloc in_sqlda and rebind if not enough XSQLVAR for bind params */
    if (imp_sth->in_sqlda->sqld > imp_sth->in_sqlda->sqln)
    {
        IB_alloc_sqlda(imp_sth->in_sqlda, imp_sth->in_sqlda->sqld);
        if (imp_sth->in_sqlda == NULL)
        {
            do_error(sth, 1, "Fail to reallocate in_slqda");
            ib_cleanup_st_prepare(imp_sth);
            return;
        }
        else
        {
            isc_dsql_describe_bind(status, &(imp_sth->stmt), 1, imp_sth->in_sqlda);
            if (ib_error_check(sth, status))
            {
                ib_cleanup_st_prepare(imp_sth);
                return;
            }
        }
    }

    DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_preparse: describe_bind passed.\n"
                  "dbd_preparse: exit; in_sqlda: sqld: %d, sqln: %d.\n",
                      imp_sth->in_sqlda->sqld, imp_sth->in_sqlda->sqln));

    DBIc_NUM_PARAMS(imp_sth) = imp_sth->in_sqlda->sqld;
}


int dbd_st_prepare(SV *sth, imp_sth_t *imp_sth, char *statement, SV *attribs)
{
    D_imp_dbh_from_sth;
    ISC_STATUS  status[ISC_STATUS_LENGTH];
    int         i;
    short       dtype;
    static char stmt_info[1];
    char        info_buffer[20], count_item;
    XSQLVAR     *var;

    DBI_TRACE_imp_xxh(imp_sth, 2, (DBIc_LOGPIO(imp_sth), "Enter dbd_st_prepare\n"));

    if (!DBIc_ACTIVE(imp_dbh))
    {
        do_error(sth, -1, "Database disconnected");
        return FALSE;
    }

    /* init values */
    count_item = 0;
    imp_sth->count_item  = 0;
    imp_sth->affected    = -1;
    imp_sth->in_sqlda    = NULL;
    imp_sth->out_sqlda   = NULL;
    imp_sth->cursor_name = NULL;

    imp_sth->dateformat      = NULL;
    imp_sth->timestampformat = NULL;
    imp_sth->timeformat      = NULL;

    /* double linked list */
    imp_sth->prev_sth = NULL;
    imp_sth->next_sth = NULL;

    if (attribs)
    {
        SV **svp;

        if ((svp = DBD_ATTRIB_GET_SVP(attribs, "ib_time_all", 11)) != NULL)
        {
            IB_SQLtimeformat(sth, imp_sth->dateformat, *svp);
            IB_SQLtimeformat(sth, imp_sth->timestampformat, *svp);
            IB_SQLtimeformat(sth, imp_sth->timeformat, *svp);
        }


        if ((svp = DBD_ATTRIB_GET_SVP(attribs, "ib_dateformat", 13)) != NULL)
            IB_SQLtimeformat(sth, imp_sth->dateformat, *svp);

        if ((svp = DBD_ATTRIB_GET_SVP(attribs, "ib_timestampformat", 18)) != NULL)
            IB_SQLtimeformat(sth, imp_sth->timestampformat, *svp);

        if ((svp = DBD_ATTRIB_GET_SVP(attribs, "ib_timeformat", 13)) != NULL)
            IB_SQLtimeformat(sth, imp_sth->timeformat, *svp);
    }


    /* allocate 1 XSQLVAR to in_sqlda */
    IB_alloc_sqlda(imp_sth->in_sqlda, 1);
    if (imp_sth->in_sqlda == NULL)
    {
        do_error(sth, 2, "Fail to allocate in_sqlda");
        return FALSE;
    }

    /* allocate 1 XSQLVAR to out_sqlda */
    IB_alloc_sqlda(imp_sth->out_sqlda, 1);
    if (imp_sth->out_sqlda == NULL)
    {
        do_error(sth, 2, "Fail to allocate out_sqlda");
        ib_cleanup_st_prepare(imp_sth);
        return FALSE;
    }

    /* init statement handle */
    isc_dsql_alloc_statement2(status, &(imp_dbh->db), &(imp_sth->stmt));
    if (ib_error_check(sth, status))
    {
        ib_cleanup_st_prepare(imp_sth);
        return FALSE;
    }

    DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_prepare: sqldialect: %d.\n", imp_dbh->sqldialect));

    if (!imp_dbh->tr)

dbdimp.c  view on Meta::CPAN

    }
    else if (imp_sth->out_sqlda->sqld == 0) /* not a select statement */
    {
        Safefree(imp_sth->out_sqlda);
        imp_sth->out_sqlda = NULL;
    }

    if (imp_sth->out_sqlda)
    {
        for (i = 0, var = imp_sth->out_sqlda->sqlvar;
             i < imp_sth->out_sqlda->sqld;
             i++, var++)
        {
            dtype = (var->sqltype & ~1);
            var->sqlind = NULL;

            DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_prepare: field type: %d.\n", dtype));

            /* Alloc space for sqldata */
            Newx(var->sqldata,
                 var->sqllen + (dtype == SQL_VARYING ? sizeof(short) : 0),
                 ISC_SCHAR);

            /* Nullable? */
            if (var->sqltype & 1)
                Newx(var->sqlind, 1, short);
        }
    }


    /* statment is valid -> insert into linked list (at begin) */
    imp_sth->next_sth = imp_dbh->first_sth;

    if (imp_dbh->first_sth == NULL)
        imp_dbh->last_sth = imp_sth;
    else
        imp_dbh->first_sth->prev_sth = imp_sth;

    imp_dbh->first_sth = imp_sth;

    DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_prepare: sth inserted into linked list.\n"));

    /* tell DBI that we have a real statement handle now */
    DBIc_IMPSET_on(imp_sth);
    return TRUE;
}

int dbd_st_finish_internal(SV *sth, imp_sth_t *imp_sth, int honour_auto_commit)
{
    D_imp_dbh_from_sth;
    ISC_STATUS status[ISC_STATUS_LENGTH];

    DBI_TRACE_imp_xxh(imp_sth, 2, (DBIc_LOGPIO(imp_sth), "dbd_st_finish\n"));

    if (!DBIc_ACTIVE(imp_sth)) /* already finished */
    {
        DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_finish: nothing to do (not active)\n"));
        return TRUE;
    }

    /* Close the cursor, not drop the statement! */
    if (imp_sth->type != isc_info_sql_stmt_exec_procedure) {
        isc_dsql_free_statement(status, (isc_stmt_handle *)&(imp_sth->stmt), DSQL_close);

        /* Ignore errors when closing already closed cursor (sqlcode -501).
           May happen when closing "select * from sample" statement, which was
           closed by the server because of a "drop table sample" statement.
           There is no point to error-out here, since nothing bad has happened --
           the statement is closed, just without we knowing. There is no resource
           leak and the user can't and needs not do anything.
         */
        if ((status[0] == 1) && (status[1] > 0)) {
            long sqlcode = isc_sqlcode(status);

            if (sqlcode != -501) {
                if (ib_error_check(sth, status))
                    return FALSE;
            }
            else
            {
                DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_finish: ignoring error -501 from isc_dsql_free_statement.\n"));
            }
        }

        DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_finish: isc_dsql_free_statement passed.\n"));
    }

    /* set statement to inactive - must be before ib_commit_transaction 'cos
       commit can call dbd_st_finish function again */
    DBIc_ACTIVE_off(imp_sth);

    if ( imp_sth->param_values != NULL )
        hv_clear(imp_sth->param_values);

    /* if AutoCommit on */
    if (DBIc_has(imp_dbh, DBIcf_AutoCommit) && honour_auto_commit)
    {
        DBI_TRACE_imp_xxh(imp_sth, 4, (DBIc_LOGPIO(imp_sth), "dbd_st_finish: Trying to call ib_commit_transaction.\n"));

        if (!ib_commit_transaction(sth, imp_dbh))
        {
            DBI_TRACE_imp_xxh(imp_sth, 4, (DBIc_LOGPIO(imp_sth), "dbd_st_finish: Call ib_commit_transaction finished returned FALSE.\n"));
            return FALSE;
        }
        DBI_TRACE_imp_xxh(imp_sth, 4, (DBIc_LOGPIO(imp_sth), "dbd_st_finish: Call ib_commit_transaction succeeded.\n"));
    }

    return TRUE;
}

int dbd_st_finish(SV *sth, imp_sth_t *imp_sth)
{
    return dbd_st_finish_internal(sth, imp_sth, TRUE);
}


int dbd_st_execute(SV *sth, imp_sth_t *imp_sth)
{
    D_imp_dbh_from_sth;
    ISC_STATUS status[ISC_STATUS_LENGTH];
    int        result = -2;
    int        row_count = 0;

    if (DBIc_ACTIVE(imp_sth))
        dbd_st_finish_internal( sth, imp_sth, TRUE);

dbdimp.c  view on Meta::CPAN

    {
        DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_execute: calling isc_dsql_execute..\n"));

        /* check for valid in_sqlda */
        if (!imp_sth->in_sqlda)
            return FALSE;

        isc_dsql_execute(status, &(imp_dbh->tr), &(imp_sth->stmt),
                         imp_dbh->sqldialect,
                         imp_sth->in_sqlda->sqld > 0 ? imp_sth->in_sqlda: NULL);

        if (ib_error_check(sth, status))
        {
            ib_cleanup_st_execute(imp_sth);

            /* rollback any active transaction */
            if (DBIc_has(imp_dbh, DBIcf_AutoCommit) && imp_dbh->tr)
                ib_commit_transaction(sth, imp_dbh);

            return result;
        }

        DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_execute: isc_dsql_execute succeed.\n"));
    }

    if (imp_sth->count_item)
    {
        //PerlIO_printf(PerlIO_stderr(), "calculating row count\n");
        row_count = ib_rows(sth, &(imp_sth->stmt), imp_sth->count_item);
        if (row_count <= -2)
            ib_cleanup_st_execute(imp_sth);
        else
            result = imp_sth->affected = row_count;
    }
    else if (imp_sth->type == isc_info_sql_stmt_select)
        result = row_count = imp_sth->affected = 0;
    else
        result = -1;

    /* Jika AutoCommit On, commit_transaction() (bukan retaining),
     * dan reset imp_dbh->tr == 0L
     * For SELECT statement, commit_transaction() is called after fetch,
     * or within finish()
     */
    if (DBIc_has(imp_dbh, DBIcf_AutoCommit)
        && imp_sth->type != isc_info_sql_stmt_select
        && imp_sth->type != isc_info_sql_stmt_select_for_upd
        && imp_sth->type != isc_info_sql_stmt_exec_procedure)
    {
        DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_execute: calling ib_commit_transaction..\n"));

        if (!ib_commit_transaction(sth, imp_dbh))
        {
            ib_cleanup_st_execute(imp_sth);
            return result;
        }

        DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_execute: ib_commit_transaction succeed.\n"));
    }

    /* Declare a unique cursor for this query */
    if (imp_sth->type == isc_info_sql_stmt_select_for_upd)
    {
        /* We free the cursor_name buffer in dbd_st_destroy. */
        if (!create_cursor_name(sth, imp_sth))
        {
            ib_cleanup_st_execute(imp_sth);
            return result;
        }
    }


    switch (imp_sth->type)
    {
        case isc_info_sql_stmt_select:
        case isc_info_sql_stmt_select_for_upd:
        case isc_info_sql_stmt_exec_procedure:
            DBIc_NUM_FIELDS(imp_sth) = (imp_sth->out_sqlda)?
                                        imp_sth->out_sqlda->sqld: 0;
            DBIc_ACTIVE_on(imp_sth);
            break;
    }

    DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_execute: row count: %d.\n"
                            "dbd_st_execute: count_item: %d.\n",
                            row_count, imp_sth->count_item));

    return result;
}

unsigned get_charset_bytes_per_char(const ISC_SHORT subtype, SV *sth);

/* from out_sqlda to AV */
AV *dbd_st_fetch(SV *sth, imp_sth_t *imp_sth)
{
    D_imp_dbh_from_sth;     /* declare imp_dbh from sth */
    ISC_STATUS  fetch = 0;
    ISC_STATUS  status[ISC_STATUS_LENGTH];
    int         chopBlanks; /* chopBlanks ?             */
    AV          *av;        /* array buffer             */
    SV          *sv, **svp; /* buffers */
    XSQLVAR     *var;       /* working pointer XSQLVAR  */
    int         i;          /* loop */
    short       dtype;

    DBI_TRACE_imp_xxh(imp_sth, 2, (DBIc_LOGPIO(imp_sth), "dbd_st_fetch\n"));

    if (!DBIc_ACTIVE(imp_sth))
    {
        do_error(sth, 0, "no statement executing (perhaps you need to call execute first)\n");
        return Nullav;
    }

    chopBlanks = DBIc_is(imp_sth, DBIcf_ChopBlanks);

    av = DBIS->get_fbav(imp_sth);
    svp = AvARRAY(av);

    /*
     * if it's an execute procedure, we've already got the
     * output from the isc_dsql_execute2() call in dbd_st_execute().
     */
    if (imp_sth->type != isc_info_sql_stmt_exec_procedure)
    {
        fetch = isc_dsql_fetch(status, &(imp_sth->stmt), imp_dbh->sqldialect,
                               imp_sth->out_sqlda);

        if (ib_error_check(sth, status))
            return Nullav;

        /*
         * Code 100 means we've reached the end of the set
         * of rows that the SELECT will return.
         */

        DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "dbd_st_fetch: fetch result: %ld\n", fetch));

        if (imp_sth->affected < 0)
            imp_sth->affected = 0;

        if (fetch == 100)
        {
            /* close the cursor */
            isc_dsql_free_statement(status, &(imp_sth->stmt), DSQL_close);

            if (ib_error_check(sth, status))
                return Nullav;

            DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "isc_dsql_free_statement succeed.\n"));

            DBIc_ACTIVE_off(imp_sth); /* dbd_st_finish is no longer needed */

            /* if AutoCommit on XXX. what to return if fails? */
            if (DBIc_has(imp_dbh, DBIcf_AutoCommit))
            {
                if (!ib_commit_transaction(sth, imp_dbh))
                    return Nullav;

                DBI_TRACE_imp_xxh(imp_sth, 3, (DBIc_LOGPIO(imp_sth), "fetch ends: ib_commit_transaction succeed.\n"));
            }

            return Nullav;
        }
        else if (fetch != 0) /* something bad */
        {   do_error(sth, 0, "Fetch error");
            DBIc_ACTIVE_off(imp_sth);
            return Nullav;
        }
    } /* !exec_procedure */
    else
    {
        /* we only fetch one row for exec procedure */
        if (imp_sth->affected)
            return Nullav;
    }

    var = imp_sth->out_sqlda->sqlvar;
    for (i = 0; i < imp_sth->out_sqlda->sqld; i++, var++)
    {
        sv = svp[i];
        dtype = var->sqltype & ~1;

        if ((var->sqltype & 1) && (*(var->sqlind) == -1))
        /* if nullable field */
        {
            /* isNULL */
            SvOK_off(sv);
        }
        else
        {
            /*
             * Got a non-null field.  Got to pass it back to the
             * application, which means some datatype dependant code.
             */
            switch (dtype)
            {
#ifdef SQL_BOOLEAN
                case SQL_BOOLEAN:
                    FB_BOOLEAN b = (*((FB_BOOLEAN *) (var->sqldata)));
#ifdef sv_set_bool
                    sv_set_bool(sv, b == FB_TRUE);
#else
#ifdef sv_setbool

dbdimp.c  view on Meta::CPAN

                    /* Clean up after ourselves. */
                    isc_close_blob(status, &blob_handle);
                    if (ib_error_check(sth, status))
                        return FALSE;

                    if ( blob_type == isc_blob_text
                            || var->sqlsubtype == isc_blob_text )
                        maybe_upgrade_to_utf8(imp_dbh, sv);

                    break;
                }

                case SQL_ARRAY:
#ifdef ARRAY_SUPPORT
            !!! NOT IMPLEMENTED YET !!!
#else
                    sv_setpvn(sv, "** array **", 11);
#endif
                    break;

                default:
                    sv_setpvn(sv, "** unknown **", 13);
            }

        /*
         * I use the column's alias name because in the absence
         * of an alias, it contains the column name anyway.
         * Only if the alias AND the column names are zero-length
         * do I want to use a generic "COLUMN%d" header.
         * This happens, for example, when the column is a
         * computed field and the query doesn't use an AS clause
         * to label the column.
         */
/*
            if (var->aliasname_length > 0)
            {
                sv_setpvn(sv, var->aliasname, var->aliasname_length));
            }
            else
            {
                char s[20];
                snprintf(s, sizeof(s), "COLUMN%d", i);
                sv_setpvn(sv, s, strlen(s));
            }
*/
        }
    }
    imp_sth->affected += 1;
    return av;
}



void dbd_st_destroy(SV *sth, imp_sth_t *imp_sth)
{
    D_imp_dbh_from_sth;
    ISC_STATUS  status[ISC_STATUS_LENGTH];

    DBI_TRACE_imp_xxh(imp_dbh, 2, (DBIc_LOGPIO(imp_dbh), "dbd_st_destroy\n"));

    /* freeing cursor name */
    FREE_SETNULL(imp_sth->cursor_name);

    if ( imp_sth->param_values != NULL ) {
        hv_undef(imp_sth->param_values);
        imp_sth->param_values = NULL;
    }

    /* freeing in_sqlda */
    if (imp_sth->in_sqlda)
    {
        int i;
        XSQLVAR *var = imp_sth->in_sqlda->sqlvar;

        DBI_TRACE_imp_xxh(imp_dbh, 3, (DBIc_LOGPIO(imp_dbh), "dbd_st_destroy: found in_sqlda..\n"));

        for (i = 0; i < imp_sth->in_sqlda->sqld; i++, var++)
        {
            FREE_SETNULL(var->sqldata);
            FREE_SETNULL(var->sqlind);
        }

        DBI_TRACE_imp_xxh(imp_dbh, 3, (DBIc_LOGPIO(imp_dbh), "dbd_st_destroy: freeing in_sqlda..\n"));

        Safefree(imp_sth->in_sqlda);
        imp_sth->in_sqlda = NULL;
    }

    /* freeing out_sqlda */
    if (imp_sth->out_sqlda)
    {
        int i;
        XSQLVAR *var = imp_sth->out_sqlda->sqlvar;
        for (i = 0; i < imp_sth->out_sqlda->sqld; i++, var++)
        {
            FREE_SETNULL(var->sqldata);
            FREE_SETNULL(var->sqlind);
        }
        Safefree(imp_sth->out_sqlda);
        imp_sth->out_sqlda = NULL;
    }

    /* free all other resources */
    FREE_SETNULL(imp_sth->dateformat);
    FREE_SETNULL(imp_sth->timeformat);
    FREE_SETNULL(imp_sth->timestampformat);

    /* Drop the statement */
    if (imp_sth->stmt)
    {
        isc_dsql_free_statement(status, &(imp_sth->stmt), DSQL_drop);
        if (ib_error_check(sth, status))
        {
            DBI_TRACE_imp_xxh(imp_dbh, 3, (DBIc_LOGPIO(imp_dbh), "dbd_st_destroy: isc_dsql_free_statement failed.\n"));
        }
        else
            DBI_TRACE_imp_xxh(imp_dbh, 3, (DBIc_LOGPIO(imp_dbh), "dbd_st_destroy: isc_dsql_free_statement succeeded.\n"));

        imp_sth->stmt = 0L;
    }

    /* remove sth from linked list */

dbdimp.c  view on Meta::CPAN

        result = newRV_inc(sv_2mortal((SV*)av));
        while(--i >= 0)
            av_store(av, i, newSViv(imp_sth->out_sqlda->sqlvar[i].sqlscale));

    }
    /**************************************************************************/
    else if (kl==9 && strEQ(key, "PRECISION"))
    {
        AV *av;

        if (!imp_sth->in_sqlda || !imp_sth->out_sqlda)
            return Nullsv;

        av = newAV();
        result = newRV_inc(sv_2mortal((SV*)av));
        while(--i >= 0)
            av_store(av, i, newSViv(imp_sth->out_sqlda->sqlvar[i].sqllen));
    }
    /**************************************************************************/
    else if (kl==4 && strEQ(key, "NAME"))
    {
        AV *av;

        if (!imp_sth->in_sqlda || !imp_sth->out_sqlda)
            return Nullsv;

        av = newAV();
        result = newRV_inc(sv_2mortal((SV*)av));
        while(--i >= 0)
        {
            if (imp_sth->out_sqlda->sqlvar[i].aliasname_length > 0)
            {
                av_store(av, i,
                         newSVpvn(imp_sth->out_sqlda->sqlvar[i].aliasname,
                         imp_sth->out_sqlda->sqlvar[i].aliasname_length));
            }
            else
            {
                char s[20];
                snprintf(s, sizeof(s), "COLUMN%d", i);
                av_store(av, i, newSVpvn(s, strlen(s)));
            }
        }
    }
    /**************************************************************************/
    else if (kl==8 && strEQ(key, "NULLABLE"))
    {
        AV *av;

        if (!imp_sth->in_sqlda || !imp_sth->out_sqlda)
            return Nullsv;

        av = newAV();
        result = newRV_inc(sv_2mortal((SV*)av));
        while(--i >= 0)
            av_store(av, i, boolSV((imp_sth->out_sqlda->sqlvar[i].sqltype & 1) != 0));
    }
    /**************************************************************************/
    else if (kl==10 && strEQ(key, "CursorName"))
    {
        if (imp_sth->cursor_name == NULL)
            return Nullsv;
	result = newSVpv(imp_sth->cursor_name, strlen(imp_sth->cursor_name));
    }
    /**************************************************************************/
    else if (kl==11 && strEQ(key, "ParamValues"))
    {
        if (imp_sth->param_values == NULL)
            return Nullsv;
	result = newRV_inc((SV*)imp_sth->param_values);
    }
    else
        return Nullsv;

    if (cacheit)
    { /* cache for next time (via DBI quick_FETCH)  */
        SV **svp = hv_fetch((HV*)SvRV(sth), key, kl, 1);
        sv_free(*svp);
        *svp = result;
        (void)SvREFCNT_inc(result); /* so sv_2mortal won't free it  */
    }
    return sv_2mortal(result);
}


int dbd_st_STORE_attrib(SV *sth, imp_sth_t *imp_sth, SV *keysv, SV *valuesv)
{
    STRLEN  kl;
    char    *key = SvPV(keysv, kl);

    DBI_TRACE_imp_xxh(imp_sth, 2, (DBIc_LOGPIO(imp_sth), "dbd_st_STORE - %s\n", key));

    return FALSE;
}


int dbd_discon_all(SV *drh, imp_drh_t *imp_drh)
{
    dTHR;

    /* The disconnect_all concept is flawed and needs more work */
    if (!SvTRUE(perl_get_sv("DBI::PERL_ENDING", 0)))
    {
        sv_setiv(DBIc_ERR(imp_drh), (IV)1);
        sv_setpv(DBIc_ERRSTR(imp_drh), (char*)"disconnect_all not implemented");
        (void)DBIh_EVENT2(drh, ERROR_event, DBIc_ERR(imp_drh), DBIc_ERRSTR(imp_drh));
        return FALSE;
    }
    if (PL_perl_destruct_level)
        PL_perl_destruct_level = 0;
    return FALSE;
}


int ib_blob_write(SV *sth, imp_sth_t *imp_sth, XSQLVAR *var, SV *value)
{
    D_imp_dbh_from_sth;
    isc_blob_handle handle = 0;
    ISC_STATUS      status[ISC_STATUS_LENGTH];
    STRLEN          total_length;
    char            *p, *seg, *string;
    int             is_text_blob, seg_len;



( run in 0.553 second using v1.01-cache-2.11-cpan-39bf76dae61 )