DBD-PgAsync

 view release on metacpan or  search on metacpan

dbdimp.c  view on Meta::CPAN

        SvUTF8_on(payloadsv);
    }
    av_push(ret, payloadsv);

    TRACE_PQFREEMEM;
    PQfreemem(notify);

    retsv = newRV_inc(sv_2mortal((SV*)ret));

    if (TEND_slow) TRC(DBILOGFP, "%sEnd pg_db_pg_notifies\n", THEADER_slow);
    return sv_2mortal(retsv);

} /* end of pg_db_pg_notifies */


/* ================================================================== */
int dbd_st_prepare_sv (SV * sth, imp_sth_t * imp_sth, SV * statement_sv, SV * attribs)
{
    dTHX;
    D_imp_dbh_from_sth;
    STRLEN mypos=0; /* Used to find and set firstword */
    SV **svp; /* To help parse the arguments */

    statement_sv = pg_rightgraded_sv(aTHX_ statement_sv, imp_dbh->pg_utf8_flag);
    char *statement = SvPV_nolen(statement_sv);

    if (TSTART_slow) TRC(DBILOGFP, "%sBegin dbd_st_prepare (statement: %s)\n", THEADER_slow, statement);

    if ('\0' == *statement)
        croak ("Cannot prepare empty statement");

    /* Set default values for this statement handle */
    imp_sth->async_flag        = 0;
    imp_sth->placeholder_type  = PLACEHOLDER_NONE;
    imp_sth->numsegs           = 0;
    imp_sth->numphs            = 0;
    imp_sth->numbound          = 0;
    imp_sth->cur_tuple         = 0;
    imp_sth->rows              = -1; /* per DBI spec */
    imp_sth->totalsize         = 0;
    imp_sth->async_status      = STH_NO_ASYNC;
    imp_sth->prepare_name      = NULL;
    imp_sth->statement         = NULL;
    imp_sth->firstword         = NULL;
    imp_sth->result            = NULL;
    imp_sth->type_info         = NULL;
    imp_sth->seg               = NULL;
    imp_sth->ph                = NULL;
    imp_sth->PQvals            = NULL;
    imp_sth->PQlens            = NULL;
    imp_sth->PQfmts            = NULL;
    imp_sth->PQoids            = NULL;
    imp_sth->prepared_by_us    = DBDPG_FALSE; /* Set to 1 when actually done preparing */
    imp_sth->direct            = DBDPG_FALSE;
    imp_sth->is_dml            = DBDPG_FALSE; /* Not preparable DML until proved otherwise */
    imp_sth->has_binary        = DBDPG_FALSE; /* Are any of the params binary? */
    imp_sth->has_default       = DBDPG_FALSE; /* Are any of the params DEFAULT? */
    imp_sth->has_current       = DBDPG_FALSE; /* Are any of the params DEFAULT? */
    imp_sth->use_inout         = DBDPG_FALSE; /* Are any of the placeholders using inout? */
    imp_sth->all_bound         = DBDPG_FALSE; /* Have all placeholders been bound? */
    imp_sth->number_iterations = 0;

    /* We inherit some preferences from the database handle */
    imp_sth->server_prepare   = imp_dbh->server_prepare;
    imp_sth->switch_prepared  = imp_dbh->switch_prepared;
    imp_sth->prepare_now      = imp_dbh->prepare_now;
    imp_sth->dollaronly       = imp_dbh->dollaronly;
    imp_sth->nocolons         = imp_dbh->nocolons;

    /* Parse and set any attributes passed in */
    if (attribs) {
        if ((svp = hv_fetchs((HV*)SvRV(attribs),"pg_server_prepare", 0)) != NULL) {
            imp_sth->server_prepare = SvTRUE(*svp) ? DBDPG_TRUE : DBDPG_FALSE;
        }
        if ((svp = hv_fetchs((HV*)SvRV(attribs),"pg_direct", 0)) != NULL)
            imp_sth->direct = 0==SvIV(*svp) ? DBDPG_FALSE : DBDPG_TRUE;
        else if ((svp = hv_fetchs((HV*)SvRV(attribs),"pg_prepare_now", 0)) != NULL) {
            imp_sth->prepare_now = 0==SvIV(*svp) ? DBDPG_FALSE : DBDPG_TRUE;
        }
        if ((svp = hv_fetchs((HV*)SvRV(attribs),"pg_placeholder_dollaronly", 0)) != NULL) {
            imp_sth->dollaronly = SvTRUE(*svp) ? DBDPG_TRUE : DBDPG_FALSE;
        }
        if ((svp = hv_fetchs((HV*)SvRV(attribs),"pg_placeholder_nocolons", 0)) != NULL) {
            imp_sth->nocolons = SvTRUE(*svp) ? DBDPG_TRUE : DBDPG_FALSE;
        }
        if ((svp = hv_fetchs((HV*)SvRV(attribs),"pg_async", 0)) != NULL) {
            imp_sth->async_flag = (int)SvIV(*svp);
        }
    }

    /* Figure out the first word in the statement */
    while (isSPACE(statement[mypos]))
        mypos++;

    if (isALPHA(statement[mypos])) {
        STRLEN wordstart = mypos, wordlen;
        while (isALPHA(statement[mypos]))
            mypos++;

        wordlen = mypos-wordstart;
        New(0, imp_sth->firstword, wordlen+1, char); /* freed in dbd_st_destroy */
        Copy(statement+wordstart, imp_sth->firstword, wordlen, char);
        imp_sth->firstword[wordlen] = '\0';

        /* Note whether this is preparable DML */
        if (0 == strcasecmp(imp_sth->firstword, "SELECT") ||
            0 == strcasecmp(imp_sth->firstword, "INSERT") ||
            0 == strcasecmp(imp_sth->firstword, "UPDATE") ||
            0 == strcasecmp(imp_sth->firstword, "DELETE") ||
            0 == strcasecmp(imp_sth->firstword, "MERGE")  ||
            0 == strcasecmp(imp_sth->firstword, "VALUES") ||
            0 == strcasecmp(imp_sth->firstword, "TABLE")  ||
            0 == strcasecmp(imp_sth->firstword, "WITH")
            ) {
            imp_sth->is_dml = DBDPG_TRUE;
        }
    }

    /* Break the statement into segments by placeholder */
    pg_st_split_statement(aTHX_ imp_sth, statement);

dbdimp.c  view on Meta::CPAN

        croak("Must wait for async query to finish before issuing more commands");
    }

    /* If not autocommit, start a new transaction */
    want_begin = 0;
    if (!imp_dbh->done_begin && !DBIc_has(imp_dbh, DBIcf_AutoCommit)) {
        if (use_async)
            want_begin = 1;
        else {
            status = _result(aTHX_ imp_dbh, "begin");
            if (PGRES_COMMAND_OK != status) {
                TRACE_PQERRORMESSAGE;
                pg_error(aTHX_ sth, status, PQerrorMessage(imp_dbh->conn));
                if (TEND_slow) TRC(DBILOGFP, "%sEnd dbd_st_execute (error: begin failed)\n", THEADER_slow);
                return -2;
            }
            imp_dbh->done_begin = DBDPG_TRUE;
            /* If read-only mode, make it so */
            if (imp_dbh->txn_read_only) {
                status = _result(aTHX_ imp_dbh, "set transaction read only");
                if (PGRES_COMMAND_OK != status) {
                    TRACE_PQERRORMESSAGE;
                    pg_error(aTHX_ sth, status, PQerrorMessage(imp_dbh->conn));
                    if (TEND_slow) TRC(DBILOGFP, "%sEnd dbd_st_execute (error: set transaction read only failed)\n", THEADER_slow);
                    return -2;
                }
            }
        }
    }

    /*
      Clear old result (if any), except if starting the
      query asynchronously. Old async results will be
      deleted implicitly the next time pg_db_result is
      called.
    */
    if (imp_sth->result && !use_async) {
        TRACE_PQCLEAR;
        PQclear(imp_sth->result);
        imp_sth->result = NULL;
    }

    /*
      Now, we need to build the statement to send to the backend
      We are using one of PQexec, PQexecPrepared, or PQexecParams
      Let's figure out which we are going to use and set pqtype
    */

    if (TRACE4_slow) TRC(DBILOGFP,
                    "%sPQexec* decision: dml=%d direct=%d server_prepare=%d numbound=%d numphs=%d default=%d current=%d\n",
                    THEADER_slow, 
                    imp_sth->is_dml,
                    imp_sth->direct,
                    imp_sth->server_prepare,
                    imp_sth->numbound,
                    imp_sth->numphs,
                    imp_sth->has_default,
                    imp_sth->has_current);

    /* Increment our count */
    imp_sth->number_iterations++;

    /* We use PQexec if:
       1. The statement is *not* DML (e.g. is DDL, which cannot be prepared)
       2. We have a DEFAULT parameter
       3. We have a CURRENT parameter
       4. pg_direct is true
       5. There are no placeholders
       6. pg_server_prepare is false
    */
    if (NULL != imp_sth->prepare_name)
        pqtype = PQTYPE_PREPARED;
    else if (!imp_sth->is_dml
        || imp_sth->has_default
        || imp_sth->has_current
        || imp_sth->direct
        || !imp_sth->numphs
        || !imp_sth->server_prepare
        )
        pqtype = PQTYPE_EXEC;
    else if (0==imp_sth->switch_prepared || imp_sth->number_iterations < imp_sth->switch_prepared)
        pqtype = PQTYPE_PARAMS;
    else
        pqtype = PQTYPE_PREPARED;

    if (TRACE4_slow) TRC(DBILOGFP, "%sWill use %s\n", 
                         THEADER_slow,
                         pq_x_calls[pqtype][(imp_sth->async_flag & PG_ASYNC) != 0]);

    /* We use the new server_side prepare style if:
       1. The statement is DML (DDL is not preparable)
       2. The attribute "pg_direct" is false
       3. The attribute "pg_server_prepare" is true
       4. There are no DEFAULT or CURRENT values
    */
    execsize = imp_sth->totalsize; /* Total of all segments */

    /* If using plain old PQexec, we need to quote each value ourselves */
    if (PQTYPE_EXEC == pqtype) {
        for (currph=imp_sth->ph; NULL != currph; currph=currph->nextph) {
            if (currph->isdefault) {
                Renew(currph->quoted, 8, char); /* freed in dbd_st_destroy */
                strncpy(currph->quoted, "DEFAULT", 8);
                currph->quotedlen = 7;
            }
            else if (currph->iscurrent) {
                Renew(currph->quoted, 18, char); /* freed in dbd_st_destroy */
                strncpy(currph->quoted, "CURRENT_TIMESTAMP", 18);
                currph->quotedlen = 17;
            }
            else if (NULL == currph->value) {
                Renew(currph->quoted, 5, char); /* freed in dbd_st_destroy */
                strncpy(currph->quoted, "NULL", 5);
                currph->quotedlen = 4;
            }
            else {
                if (currph->quoted)
                    Safefree(currph->quoted);
                currph->quoted = currph->bind_type->quote(
                    aTHX_
                    currph->value,
                    currph->valuelen,
                    &currph->quotedlen,
                    imp_dbh->pg_server_version >= 80100 ? 1 : 0
                                                          ); /* freed in dbd_st_destroy */
            }
        }
        /* Set the size of each actual in-place placeholder */
        for (currseg=imp_sth->seg; NULL != currseg; currseg=currseg->nextseg) {
            if (currseg->placeholder!=0)
                execsize += currseg->ph->quotedlen;
        }
    }
    else { /* We are using a server that can handle PQexecParams/PQexecPrepared */

        /* Put all values into an array to pass to one of the above */
        if (NULL == imp_sth->PQvals) {
            Newz(0, imp_sth->PQvals, (unsigned int)imp_sth->numphs, const char *); /* freed in dbd_st_destroy */
        }
        for (x=0,currph=imp_sth->ph; NULL != currph; currph=currph->nextph) {
            imp_sth->PQvals[x++] = currph->value;



( run in 0.624 second using v1.01-cache-2.11-cpan-71847e10f99 )