DBD-DBMaker
view release on metacpan or search on metacpan
*p++ = *src++;
*p = 0;
style = 1;
}
else if (isALNUM(*src)) { /* ':foo' */
char *p = name;
idx++; /* #006 */
*dest++ = '?';
while(isALNUM(*src)) /* includes '_' */
*p++ = *src++;
*p = 0;
style = 2;
}
else { /* perhaps ':=' PL/SQL construct */
*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_sv = newSVpv((char*)&phs_tpl, sizeof(phs_tpl)+namelen+1);
phs = (phs_t*)SvPVX(phs_sv);
strcpy(phs->name, name);
phs->idx = idx;
/* store placeholder to params_hv */
svpp = hv_store(imp_sth->params_hv, name, namelen, phs_sv, 0);
}
}
*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));
}
}
int
dbd_st_table_info(dbh, sth, qualifier, table_type)
SV *dbh;
SV *sth;
char *qualifier;
char *table_type;
{
D_imp_dbh(dbh);
D_imp_sth(sth);
RETCODE rc;
SV **svp;
char cname[128]; /* cursorname */
imp_sth->done_desc = 0;
rc = SQLAllocStmt(imp_dbh->hdbc, &imp_sth->hstmt);
dbmaker_error(sth, rc, "st_tables/SQLAllocStmt");
if (rc != SQL_SUCCESS) {
return 0;
}
/* just for sanity, later. Any internals that may rely on this (including */
/* debugging) will have valid data */
imp_sth->statement = (char *)safemalloc(strlen("SQLTables(%s)")+strlen(qualifier)+1);
sprintf(imp_sth->statement, "SQLTables(%s)", qualifier);
if (dbis->debug >= 2)
fprintf(DBILOGFP, " dbd_st_tables type = %s\n", table_type);
rc = SQLTables(imp_sth->hstmt,
0, SQL_NTS, /* qualifier */
0, SQL_NTS, /* schema/user */
0, SQL_NTS, /* table name */
table_type, SQL_NTS /* type (view, table, etc) */
);
dbmaker_error(sth, rc, "st_tables/SQLTables");
if (!SQL_ok(rc)) {
SQLFreeStmt(imp_sth->hstmt, SQL_DROP);
imp_sth->hstmt = SQL_NULL_HSTMT;
return 0;
}
/* init sth pointers */
imp_sth->fbh = NULL;
imp_sth->ColNames = NULL;
imp_sth->RowBuffer = NULL;
imp_sth->RowCount = -1;
imp_sth->eod = -1;
#if DBMAKER_FILE_INOUT /* #004 */
imp_sth->fgfileinput = 1;
imp_sth->fgBindColToFile = 0;
#else
imp_sth->fgfileinput = 0;
imp_sth->fgBindColToFile = 0;
#endif
if (!dbd_describe(sth, imp_sth))
{
SQLFreeStmt(imp_sth->hstmt, SQL_DROP);
imp_sth->hstmt = SQL_NULL_HSTMT;
return 0; /* dbd_describe already called ora_error() */
}
if (dbd_describe(sth, imp_sth) <= 0)
return 0;
DBIc_IMPSET_on(imp_sth);
imp_sth->RowCount = -1;
rc = SQLRowCount(imp_sth->hstmt, &imp_sth->RowCount);
dbmaker_error(sth, rc, "st_tables/SQLRowCount");
if (rc != SQL_SUCCESS) {
return -1;
}
DBIc_ACTIVE_on(imp_sth); /* XXX should only set for select ? */
imp_sth->eod = SQL_SUCCESS;
return 1;
}
int
dbd_st_prepare(sth, statement, attribs)
SV *sth;
char *statement;
SV *attribs;
{
D_imp_sth(sth);
D_imp_dbh_from_sth;
RETCODE rc;
SV **svp;
char cname[128]; /* cursorname */
imp_sth->done_desc = 0;
rc = SQLAllocStmt(imp_dbh->hdbc, &imp_sth->hstmt);
dbmaker_error(sth, rc, "st_prepare/SQLAllocStmt");
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));
dbmaker_error(sth, rc, "st_prepare/SQLPrepare");
if (rc != SQL_SUCCESS)
{
SQLFreeStmt(imp_sth->hstmt, SQL_DROP);
imp_sth->hstmt = SQL_NULL_HSTMT;
return 0;
}
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;
#if DBMAKER_FILE_INOUT /* #004 */
imp_sth->fgfileinput = 1;
imp_sth->fgBindColToFile = 0;
#else
imp_sth->fgfileinput = 0;
imp_sth->fgBindColToFile = 0;
#endif
/* @@@ DBI Bug ??? */
DBIc_set(imp_sth, DBIcf_LongTruncOk,
DBIc_is(imp_dbh, DBIcf_LongTruncOk));
DBIc_LongReadLen(imp_sth) = DBIc_LongReadLen(imp_dbh);
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("depreciated feature: blob_size will be replaced by LongReadLen\n");
}
if ((svp=hv_fetch((HV*)SvRV(attribs), "dbmaker_blob_size",15, 0)) != NULL)
sv_setpvn(sv, p0, len);
break;
}
/* no ChopBlank */
if (fbh->ftype == SQL_C_FILE) /* #007 */
sv_setpvn(sv, (char*)fbh->data, strlen(fbh->data));
else
sv_setpvn(sv, (char*)fbh->data, fbh->datalen);
break;
}
}
else
{
SvOK_off(sv);
}
}
#if DBMAKER_FILE_INOUT
/*
* #004 This can be done by SQLGetData, but use dbmaker's way seems easier.
*/
if (imp_sth->fgBindColToFile)
{
int i;
imp_fbh_t *fbh;
for (fbh=imp_sth->fbh, i=0; i<imp_sth->n_result_cols; i++, fbh++)
{
if (fbh->ftype == SQL_C_FILE)
{
char buf[MAX_FILE_NAME_LEN];
struct stat fbuf;
do {
fbh->file_idxno++;
if (fbh->file_ext)
sprintf(fbh->data, "%s%d%s", fbh->file_prefix, fbh->file_idxno,fbh->file_ext);
else
sprintf(fbh->data, "%s%d", fbh->file_prefix, fbh->file_idxno);
} while(!fbh->fgOverwrite && !stat(fbh->data, &fbuf)); /* #008 */
if (dbis->debug >= 2)
fprintf(DBILOGFP,
"\tRebind/BindColToFile: col#%d to file:[%s]\n", i+1, fbh->data);
}
}
}
#endif
return av;
}
int
dbd_st_finish(sth)
SV *sth;
{
D_imp_sth(sth);
D_imp_dbh_from_sth;
D_imp_drh_from_dbh;
RETCODE rc;
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);
dbmaker_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))
{
rc = SQLTransact(imp_drh->henv,
imp_dbh->hdbc,
SQL_COMMIT);
}
#endif
}
DBIc_ACTIVE_off(imp_sth);
return ret;
}
void
dbd_st_destroy(sth)
SV *sth;
{
D_imp_sth(sth);
D_imp_dbh_from_sth;
D_imp_drh_from_dbh;
RETCODE rc;
/* 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)
{
rc = SQLFreeStmt(imp_sth->hstmt, SQL_DROP);
#if 0
if (rc != SQL_SUCCESS)
{
warn("warning: DBD::DBMaker SQLFreeStmt(SQL_DROP) returns %d\n", rc);
}
#endif
}
/* Free contents of imp_sth */
Safefree(imp_sth->fbh);
Safefree(imp_sth->ColNames);
Safefree(imp_sth->RowBuffer);
Safefree(imp_sth->statement);
if (imp_sth->params_av)
{
av_undef(imp_sth->params_av);
imp_sth->params_av = NULL;
}
if (imp_sth->params_hv)
break;
default:
if (vParam == pars->true)
retsv = newSViv(1);
else
retsv = newSViv(0);
break;
} /* switch */
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("dbm_type"), /* 7 */
s_A("dbm_length"), /* 8 */
s_A("CursorName"), /* 9 */
s_A("blob_size"), /* 10 */
s_A("__handled_by_dbi__"), /* 11 */ /* ChopBlanks */
s_A("dbmaker_blob_size"), /* 12 */
s_A("dbmaker_type"), /* 13 */
s_A("dbmaker_length"), /* 14 */
s_A("LongReadLen"), /* 15 */
s_A("dbmaker_file_input"), /* 16 */ /* #004 */
s_A(""), /* END */
};
static T_st_params S_st_store_params[] =
{
s_A("blob_size"), /* 0 */
s_A("dbmaker_blob_size"), /* 1 */
s_A("dbmaker_file_input"), /* 2 */ /* #004 */
s_A(""), /* END */
};
#undef s_A
/*----------------------------------------
* dummy routines st_XXXX
*----------------------------------------
*/
SV *
dbd_st_FETCH(sth, keysv)
SV *sth;
SV *keysv;
{
D_imp_sth(sth);
STRLEN kl;
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 'dbm_type'. "
"Please use 'dbmaker_type' instead.");
/* fall through */
case 13: /* dbmaker_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 'dbm_length'. "
"Please use 'dbmaker_length' instead.");
/* fall through */
case 14: /* dbmaker_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);
dbmaker_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 'dbmaker_blob_size' instead.");
/* fall through */
case 12: /* dbmaker_blob_size */
case 15: /* LongReadLen */
retsv = newSViv(DBIc_LongReadLen(imp_sth));
break;
case 16: /* dbmaker_file_input #004 */
retsv = newSViv(imp_sth->fgfileinput);
break;
default:
return Nullsv;
}
return sv_2mortal(retsv);
}
int
dbd_st_STORE(sth, keysv, valuesv)
SV *sth;
SV *keysv;
SV *valuesv;
{
D_imp_sth(sth);
D_imp_dbh_from_sth;
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:/* dbmaker_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;
break;
int
build_results(sth)
SV * sth;
{
RETCODE rc;
D_imp_sth(sth);
if (DBIS->debug >= 2)
fprintf(DBILOGFP, " build_results 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->RowCount = -1;
imp_sth->eod = -1;
#if DBMAKER_FILE_INOUT /* #004 */
imp_sth->fgfileinput = 1;
imp_sth->fgBindColToFile = 0;
#else
imp_sth->fgfileinput = 0;
imp_sth->fgBindColToFile = 0;
#endif
if (!dbd_describe(sth, imp_sth)) {
SQLFreeStmt(imp_sth->hstmt, SQL_DROP);
imp_sth->hstmt = SQL_NULL_HSTMT;
return 0; /* dbd_describe already called ora_error() */
}
if (dbd_describe(sth, imp_sth) <= 0)
return 0;
DBIc_IMPSET_on(imp_sth);
imp_sth->RowCount = -1;
rc = SQLRowCount(imp_sth->hstmt, &imp_sth->RowCount);
dbmaker_error(sth, rc, "dbd_st_tables/SQLRowCount");
if (rc != SQL_SUCCESS) {
return -1;
}
DBIc_ACTIVE_on(imp_sth); /* XXX should only set for select ? */
imp_sth->eod = SQL_SUCCESS;
return 1;
}
int
dbd_st_get_type_info(dbh, sth, ftype)
SV *dbh;
SV *sth;
int ftype;
{
dTHR;
D_imp_dbh(dbh);
D_imp_sth(sth);
RETCODE rc;
SV **svp;
char cname[128]; /* cursorname */
imp_sth->done_desc = 0;
rc = SQLAllocStmt(imp_dbh->hdbc, &imp_sth->hstmt);
if (rc != SQL_SUCCESS) {
dbmaker_error(sth, rc, "dbmaker_get_type_info/SQLGetTypeInfo");
return 0;
}
/* just for sanity, later. Any internals that may rely on this (including */
/* debugging) will have valid data */
imp_sth->statement = (char *)safemalloc(strlen(cSqlGetTypeInfo)+ftype/10+1);
sprintf(imp_sth->statement, cSqlGetTypeInfo, ftype);
rc = SQLGetTypeInfo(imp_sth->hstmt, ftype);
dbmaker_error(sth, rc, "dbmaker_get_type_info/SQLGetTypeInfo");
if (!SQL_ok(rc)) {
SQLFreeStmt(imp_sth->hstmt, SQL_DROP);
imp_sth->hstmt = SQL_NULL_HSTMT;
return 0;
}
return build_results(sth);
}
SV *
dbmaker_get_info(dbh, ftype)
SV *dbh;
int ftype;
{
dTHR;
D_imp_dbh(dbh);
RETCODE rc;
SV *retsv = NULL;
int i;
char rgbInfoValue[256];
SWORD cbInfoValue = -2;
/* See fancy logic below */
for (i = 0; i < 6; i++)
rgbInfoValue[i] = 0xFF;
rc = SQLGetInfo(imp_dbh->hdbc, ftype,
rgbInfoValue, sizeof(rgbInfoValue)-1, &cbInfoValue);
if (!SQL_ok(rc)) {
dbmaker_error(dbh, rc, "dbmaker_get_info/SQLGetInfo");
return Nullsv;
}
/* Fancy logic here to determine if result is a string or int */
if (cbInfoValue == -2) /* is int */
retsv = newSViv(*(int *)rgbInfoValue); /* XXX cast */
else if (cbInfoValue != 2 && cbInfoValue != 4) /* must be string */
retsv = newSVpv(rgbInfoValue, 0);
else if (rgbInfoValue[cbInfoValue+1] == '\0') /* must be string */
retsv = newSVpv(rgbInfoValue, 0);
else if (cbInfoValue == 2) /* short */
retsv = newSViv(*(short *)rgbInfoValue); /* XXX cast */
else if (cbInfoValue == 4) /* int */
retsv = newSViv(*(int *)rgbInfoValue); /* XXX cast */
( run in 1.063 second using v1.01-cache-2.11-cpan-39bf76dae61 )