DBD-Solid
view release on metacpan or search on metacpan
*dest++ = ch;
continue;
}
*dest = '\0'; /* handy for debugging */
if (laststyle && style != laststyle)
croak("Can't mix placeholder styles (%d/%d)",style,laststyle);
laststyle = style;
if( imp_sth->params_hv == NULL )
imp_sth->params_hv = newHV();
namelen = strlen( name );
svpp = hv_fetch( imp_sth->params_hv, name, namelen, 0 );
if( svpp == NULL )
{
/* create SV holding the placeholder */
phs_tpl.sv = &sv_undef;
phs_sv = newSVpv((char*)&phs_tpl, sizeof(phs_tpl)+namelen+1);
strcpy( ((phs_t*)SvPVX(phs_sv))->name, name);
/* store placeholder to params_hv */
svpp = hv_store( imp_sth->params_hv, name, namelen, phs_sv, 0 );
}
svref = newRV( *svpp );
/* store reference to placeholder to params_av */
if( imp_sth->params_av == NULL )
imp_sth->params_av = newAV();
av_push( imp_sth->params_av, svref );
} /* end while(*src) */
*dest = '\0';
if (imp_sth->params_hv)
{
DBIc_NUM_PARAMS(imp_sth) = (int)HvKEYS(imp_sth->params_hv);
if (dbis->debug >= 2)
fprintf(DBILOGFP, " dbd_preparse scanned %d distinct placeholders\n",
(int)DBIc_NUM_PARAMS(imp_sth));
}
}
/* --------------------------------------------------------
* Prepare SQL statement. Relies on dbd_preparse.
* --------------------------------------------------------- */
int dbd_st_prepare( SV* sth, char* statement, SV* attribs )
{
D_imp_sth(sth);
D_imp_dbh_from_sth;
RETCODE rc;
dTHR;
SV** svp;
char cname[128]; /* cursorname */
imp_sth->done_desc = 0;
/* Deprecated as of ODBC 3.x. --mms */
/*rc = SQLAllocStmt(imp_dbh->hdbc, &imp_sth->hstmt);
solid_error(sth, rc, "st_prepare/SQLAllocStmt"); */
rc = SQLAllocHandle( SQL_HANDLE_STMT, imp_dbh->hdbc, &imp_sth->hstmt );
solid_error( sth, rc, "st_prepare/SQLAllocHandle/Stmt" );
if( rc != SQL_SUCCESS )
{ return 0; }
/* scan statement for '?', ':1' and/or ':foo' style placeholders */
dbd_preparse( imp_sth, statement );
/* parse the (possibly edited) SQL statement */
rc = SQLPrepare( imp_sth->hstmt,
imp_sth->statement,
strlen(imp_sth->statement));
solid_error( sth, rc, "st_prepare/SQLPrepare" );
if( rc != SQL_SUCCESS )
{
/* SQLFreeStmt is deprecated only with option SQL_DROP. --mms
SQLFreeStmt(imp_sth->hstmt, SQL_DROP); */
SQLFreeHandle( SQL_HANDLE_STMT, imp_sth->hstmt );
imp_sth->hstmt = SQL_NULL_HSTMT;
return 0;
}
#if 0 /* use DBIc macros */
imp_sth->long_buflen = 80; /* typical default */
imp_sth->long_trunc_ok = 0; /* can use blob_read() */
#endif
if( dbis->debug >= 2 )
fprintf(DBILOGFP, " dbd_st_prepare'd sql f%d\n\t%s\n",
imp_sth->hstmt, imp_sth->statement);
/* init sth pointers */
imp_sth->fbh = NULL;
imp_sth->ColNames = NULL;
imp_sth->RowBuffer = NULL;
imp_sth->n_result_cols = -1;
imp_sth->RowCount = -1;
imp_sth->eod = -1;
/* @@@ DBI Bug ??? */
DBIc_set( imp_sth, DBIcf_LongTruncOk,
DBIc_is(imp_dbh, DBIcf_LongTruncOk) );
DBIc_LongReadLen(imp_sth) = DBIc_LongReadLen(imp_dbh);
sprintf( cname, "dbd_cursor_%X", imp_sth->hstmt );
rc = SQLSetCursorName( imp_sth->hstmt, cname, strlen(cname) );
if( rc != SQL_SUCCESS )
warn("dbd_prepare: can't set cursor name, rc = %d", rc);
if( dbis->debug >= 2 )
fprintf(DBILOGFP, " CursorName is '%s', rc=%d\n", cname, rc);
if( attribs )
{
if( (svp=hv_fetch((HV*)SvRV(attribs), "blob_size",9, 0)) != NULL )
{
int len = SvIV( *svp );
DBIc_LongReadLen( imp_sth ) = len;
if( DBIc_WARN(imp_sth) )
warn("deprecated feature: blob_size will be replaced by LongReadLen\n");
}
if( (svp=hv_fetch((HV*)SvRV(attribs), "solid_blob_size",15, 0)) != NULL )
{
int len = SvIV(*svp);
DBIc_LongReadLen(imp_sth) = len;
if( DBIc_WARN(imp_sth) )
warn("deprecated feature: solid_blob_size will be replaced by LongReadLen\n");
}
if( (svp=hv_fetch((HV*)SvRV(attribs), "LongReadLen",11, 0)) != NULL )
{
int len = SvIV(*svp);
DBIc_LongReadLen(imp_sth) = len;
}
#if YET_NOT_IMPLEMENTED
if( (svp=hv_fetch((HV*)SvRV(attribs), "concurrency",11, 0)) != NULL )
{
UDWORD param = SvIV( *svp );
rc = SQLSetStmtOption( imp_sth->hstmt, SQL_CONCURRENCY, param );
if( rc != SQL_SUCCESS )
warn("prepare: can't set concurrency, rc = %d", rc);
}
#endif
}
/* Call dbd_describe if this named constant is non-zero */
#if DESCRIBE_IN_PREPARE
if( dbis->debug >= 2 )
fprintf(DBILOGFP, "Describe in prepare: %d\n", DESCRIBE_IN_PREPARE);
if( dbd_describe(sth, imp_sth) <= 0 )
return 0;
#endif
DBIc_IMPSET_on( imp_sth );
return 1;
}
/* -----------------------------------------
* Returns 1 if arg is string, 0 otherwise.
* ------------------------------------------ */
int dbtype_is_string( int bind_type )
{
switch( bind_type )
{
sv_setpv(sv, cvbuf);
break;
default:
if( dbis->debug >= 2 )
fprintf(DBILOGFP, "dbd_st_fetch colsqltype: %d\tlength: %d\n",
fbh->ColSqlType, fbh->datalen);
if( fbh->ColSqlType == SQL_CHAR
&& DBIc_is(imp_sth, DBIcf_ChopBlanks)
&& fbh->datalen > 0 )
{
int len = fbh->datalen;
char* p0 = (char*)(fbh->data);
char* p = (char*)(fbh->data) + len;
if( dbis->debug >= 2 )
fprintf(DBILOGFP, "dbd_st_fetch: got to here\n");
while( p-- != p0 )
{
if( *p != ' ' )
break;
len--;
}
sv_setpvn(sv, p0, len);
break;
}
if( dbis->debug >= 2 )
fprintf( DBILOGFP, "dbd_st_fetch string: %s length: %d\n",
fbh->data, fbh->datalen );
sv_setpvn(sv, (char*)fbh->data, fbh->datalen);
break;
}
}
}
else
{
SvOK_off(sv);
}
} /* end for */
return av;
}
/* -------------------------------
*
* -------------------------------- */
int dbd_st_finish( SV* sth )
{
D_imp_sth( sth );
D_imp_dbh_from_sth;
D_imp_drh_from_dbh;
RETCODE rc;
dTHR;
int ret = 1;
/* Cancel further fetches from this cursor.
* We don't close the cursor till DESTROY (dbd_st_destroy).
* The application may re execute(...) it. */
if( DBIc_ACTIVE(imp_sth) && imp_dbh->hdbc != SQL_NULL_HDBC )
{
rc = SQLFreeStmt( imp_sth->hstmt, SQL_CLOSE );
solid_error( sth, rc, "st_finish/SQLFreeStmt(SQL_CLOSE)" );
if( rc != SQL_SUCCESS )
ret = 0;
#ifdef SOL22_AUTOCOMMIT_BUG
if( DBIc_is(imp_dbh, DBIcf_AutoCommit) )
{
/* Deprecated as of ODBC 3.x. --mms
rc = SQLTransact(imp_drh->henv, imp_dbh->hdbc, SQL_COMMIT); */
rc = SQLEndTran( SQL_HANDLE_DBC, imp_dbh->hdbc, SQL_COMMIT );
}
#endif
}
DBIc_ACTIVE_off( imp_sth );
return ret;
}
/* -----------------------------------------
*
* ------------------------------------------ */
void dbd_st_destroy( SV* sth )
{
D_imp_sth( sth );
D_imp_dbh_from_sth;
D_imp_drh_from_dbh;
RETCODE rc;
dTHR;
/* SQLxxx functions dump core when no connection exists. This happens
* when the db was disconnected before perl ending. */
if( imp_dbh->hdbc != SQL_NULL_HDBC )
{
/* This is deprecated when used with option SQL_DROP --mms */
rc = SQLFreeStmt( imp_sth->hstmt, SQL_DROP );
/* But its replacement does weird things. --mms
SQLFreeHandle(SQL_HANDLE_STMT, imp_sth->hstmt);*/
if( rc != SQL_SUCCESS )
{
warn("warning: DBD::Solid SQLFreeStmt returns %d\n", rc);
}
}
/* Free contents of imp_sth */
Safefree( imp_sth->fbh );
Safefree( imp_sth->ColNames );
Safefree( imp_sth->RowBuffer );
Safefree( imp_sth->statement );
case SQL_OPT_TRACEFILE:
retsv = newSVpv((char*)vParam, 0);
break;
default:
if( vParam == pars->true )
retsv = newSViv(1);
else
retsv = newSViv(0);
break;
}
return sv_2mortal( retsv );
}
#define s_A(str) { str, sizeof(str)-1 }
static T_st_params S_st_fetch_params[] =
{
s_A("NUM_OF_PARAMS"), /* 0 */
s_A("NUM_OF_FIELDS"), /* 1 */
s_A("NAME"), /* 2 */
s_A("NULLABLE"), /* 3 */
s_A("TYPE"), /* 4 */
s_A("PRECISION"), /* 5 */
s_A("SCALE"), /* 6 */
s_A("sol_type"), /* 7 */
s_A("sol_length"), /* 8 */
s_A("CursorName"), /* 9 */
s_A("blob_size"), /* 10 */
s_A("__handled_by_dbi__"), /* 11 */ /* ChopBlanks */
s_A("solid_blob_size"), /* 12 */
s_A("solid_type"), /* 13 */
s_A("solid_length"), /* 14 */
s_A("LongReadLen"), /* 15 */
s_A(""), /* END */
};
static T_st_params S_st_store_params[] =
{
s_A("blob_size"), /* 0 */
s_A("solid_blob_size"), /* 1 */
s_A(""), /* END */
};
#undef s_A
/*----------------------------------------
* dummy routines st_XXXX
*---------------------------------------- */
SV* dbd_st_FETCH( SV* sth, SV* keysv )
{
D_imp_sth( sth );
STRLEN kl;
dTHR;
char* key = SvPV(keysv,kl);
int i;
SV* retsv = NULL;
T_st_params* par;
int n_fields;
imp_fbh_t* fbh;
char cursor_name[256];
SWORD cursor_name_len;
RETCODE rc;
int par_index;
for( par = S_st_fetch_params; par->len > 0; par++ )
if( par->len == kl && strEQ(key, par->str) )
break;
if( par->len <= 0 )
return Nullsv;
if( !imp_sth->done_desc && !dbd_describe(sth, imp_sth) )
{
/* dbd_describe has already called ora_error()
* we can't return Nullsv here because the xs code will
* then just pass the attribute name to DBI for FETCH. */
croak("Describe failed during %s->FETCH(%s)", SvPV(sth,na), key);
}
i = DBIc_NUM_FIELDS(imp_sth);
switch( par_index = par - S_st_fetch_params )
{
AV* av;
case 0: /* NUM_OF_PARAMS */
return Nullsv; /* handled by DBI */
case 1: /* NUM_OF_FIELDS */
retsv = newSViv(i);
break;
case 2: /* NAME */
av = newAV();
retsv = newRV(sv_2mortal((SV*)av));
while(--i >= 0)
av_store(av, i, newSVpv(imp_sth->fbh[i].ColName, 0));
break;
case 3: /* NULLABLE */
av = newAV();
retsv = newRV(sv_2mortal((SV*)av));
while( --i >= 0 )
{
switch( imp_sth->fbh[i].ColNullable )
{
case SQL_NULLABLE:
av_store(av, i, &sv_yes);
break;
case SQL_NO_NULLS:
av_store(av, i, &sv_no);
break;
case SQL_NULLABLE_UNKNOWN:
av_store(av, i, &sv_undef);
break;
}
}
break;
case 4: /* TYPE */
av = newAV();
retsv = newRV(sv_2mortal((SV*)av));
while( --i >= 0 )
{
int type = imp_sth->fbh[i].ColSqlType;
av_store(av, i, newSViv(type));
}
break;
case 5: /* PRECISION */
av = newAV();
retsv = newRV(sv_2mortal((SV*)av));
while( --i >= 0 )
{
av_store(av, i, newSViv(imp_sth->fbh[i].ColDef));
}
break;
case 6: /* SCALE */
av = newAV();
retsv = newRV(sv_2mortal((SV*)av));
while( --i >= 0 )
{
av_store(av, i, newSViv(imp_sth->fbh[i].ColScale));
}
break;
case 7: /* dbd_type */
if( DBIc_WARN(imp_sth) )
warn("Depreciated feature 'sol_type'. "
"Please use 'solid_type' instead.");
/* fall through */
case 13: /* solid_type */
av = newAV();
retsv = newRV( sv_2mortal((SV*)av) );
while( --i >= 0 )
{
av_store(av, i, newSViv(imp_sth->fbh[i].ColSqlType));
}
break;
case 8: /* dbd_length */
if( DBIc_WARN(imp_sth) )
warn("Depreciated feature 'sol_length'. "
"Please use 'solid_length' instead.");
/* fall through */
case 14: /* solid_length */
av = newAV();
retsv = newRV(sv_2mortal((SV*)av));
while( --i >= 0 )
{
av_store(av, i, newSViv(imp_sth->fbh[i].ColLength));
}
break;
case 9: /* CursorName */
rc = SQLGetCursorName( imp_sth->hstmt,
cursor_name,
sizeof(cursor_name),
&cursor_name_len);
solid_error( sth, rc, "st_FETCH/SQLGetCursorName" );
if( rc != SQL_SUCCESS )
{
if( dbis->debug >= 1 )
{
fprintf(DBILOGFP,
"SQLGetCursorName returned %d in dbd_st_FETCH\n", rc);
}
return Nullsv;
}
retsv = newSVpv( cursor_name, cursor_name_len );
break;
case 10: /* blob_size */
if( DBIc_WARN(imp_sth) )
warn("Depreciated feature 'blob_size'. "
"Please use 'solid_blob_size' instead.");
/* fall through */
case 12: /* solid_blob_size */
case 15: /* LongReadLen */
retsv = newSViv(DBIc_LongReadLen(imp_sth));
break;
default:
return Nullsv;
}
return sv_2mortal( retsv );
}
/* -----------------------------------------
*
* ------------------------------------------ */
int dbd_st_STORE( SV* sth, SV* keysv, SV* valuesv )
{
D_imp_sth( sth );
D_imp_dbh_from_sth;
dTHR;
STRLEN kl;
STRLEN vl;
char* key = SvPV( keysv, kl );
char* value = SvPV( valuesv, vl );
T_st_params* par;
RETCODE rc;
for( par = S_st_store_params; par->len > 0; par++ )
if( par->len == kl && strEQ(key, par->str) )
break;
if( par->len <= 0 )
return FALSE;
switch( par - S_st_store_params )
{
case 0: /* blob_size */
case 1: /* solid_blob_size */
#if DESCRIBE_IN_PREPARE
warn("$sth->{blob_size} isn't longer supported.\n"
"You may either use the 'LongReadLen' "
"attribute to prepare()\nor the blob_read() "
"function.\n");
return FALSE;
#endif
DBIc_LongReadLen(imp_sth) = SvIV(valuesv);
return TRUE;
}
return FALSE;
}
( run in 0.698 second using v1.01-cache-2.11-cpan-39bf76dae61 )