DBD-ODBC
view release on metacpan or search on metacpan
char errstr[256];
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 4))
TRACE3(imp_sth, " sql_type_case %s %"IVdf" %lx\n", neatsvpv(sv, fbh->datalen+5), fbh->req_type, fbh->bind_flags);
sts = DBIc_DBISTATE(imp_sth)->sql_type_cast_svpv(
aTHX_ sv, fbh->req_type, (U32)fbh->bind_flags, NULL);
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 4))
TRACE1(imp_sth, " sql_type_cast=%d\n", sts);
if (sts == 0) {
sprintf(errstr,
"over/under flow converting column %d to type %"IVdf"",
i+1, fbh->req_type);
DBIh_SET_ERR_CHAR(sth, (imp_xxh_t*)imp_sth, Nullch, 1,
errstr, Nullch, Nullch);
return Nullav;
}
else if (sts == -2) {
sprintf(errstr,
"unsupported bind type %"IVdf" for column %d in sql_type_cast_svpv",
fbh->req_type, i+1);
DBIh_SET_ERR_CHAR(sth, (imp_xxh_t*)imp_sth, Nullch, 1,
errstr, Nullch, Nullch);
return Nullav;
}
}
#endif /* DBIXS_REVISION > 13590 */
} /* end of loop through bound columns */
return av;
}
/* /\* SHOULD BE ABLE TO DELETE BOTH OF THESE NOW AND dbd_st_rows macro in dbdimp.h *\/ */
/* int dbd_st_rows(SV *sth, imp_sth_t *imp_sth) */
/* { */
/* return (int)imp_sth->RowCount; */
/* } */
/* IV dbd_st_rows(SV *sth, imp_sth_t *imp_sth) */
/* { */
/* return imp_sth->RowCount; */
/* } */
int dbd_st_finish(SV *sth, imp_sth_t *imp_sth)
{
dTHX;
D_imp_dbh_from_sth;
RETCODE rc;
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 3))
TRACE1(imp_sth, " dbd_st_finish(%p)\n", sth);
/* Cancel further fetches from this cursor. */
/* We don't close the cursor till DESTROY (dbd_st_destroy). */
/* The application may re execute(...) it. */
/* XXX semantics of finish (eg oracle vs odbc) need lots more thought */
/* re-read latest DBI specs and ODBC manuals */
if (DBIc_ACTIVE(imp_sth) && imp_dbh->hdbc != SQL_NULL_HDBC) {
rc = SQLFreeStmt(imp_sth->hstmt, SQL_CLOSE);/* TBD: 3.0 update */
if (!SQL_SUCCEEDED(rc)) {
dbd_error(sth, rc, "finish/SQLFreeStmt(SQL_CLOSE)");
return 0;
}
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 6)) {
TRACE0(imp_dbh, " dbd_st_finish closed query:\n");
}
}
DBIc_ACTIVE_off(imp_sth);
return 1;
}
void dbd_st_destroy(SV *sth, imp_sth_t *imp_sth)
{
dTHX;
D_imp_dbh_from_sth;
RETCODE rc;
/* Free contents of imp_sth */
/* PerlIO_printf(DBIc_LOGPIO(imp_dbh), " dbd_st_destroy\n"); */
Safefree(imp_sth->fbh);
Safefree(imp_sth->RowBuffer);
Safefree(imp_sth->ColNames);
Safefree(imp_sth->statement);
if (imp_sth->out_params_av)
sv_free((SV*)imp_sth->out_params_av);
if (imp_sth->param_status_array) {
Safefree(imp_sth->param_status_array);
imp_sth->param_status_array = NULL;
}
if (imp_sth->all_params_hv) {
HV *hv = imp_sth->all_params_hv;
SV *sv;
char *key;
I32 retlen;
hv_iterinit(hv);
while( (sv = hv_iternextsv(hv, &key, &retlen)) != NULL ) {
if (sv != &PL_sv_undef) {
phs_t *phs_tpl = (phs_t*)(void*)SvPVX(sv);
sv_free(phs_tpl->sv);
if (phs_tpl->strlen_or_ind_array) {
Safefree(phs_tpl->strlen_or_ind_array);
phs_tpl->strlen_or_ind_array = NULL;
}
if (phs_tpl->param_array_buf) {
Safefree(phs_tpl->param_array_buf);
phs_tpl->param_array_buf = NULL;
}
if (retl == SQL_NO_TOTAL) { /* unknown length! */
(void)SvOK_off(bufsv);
return 0;
}
#endif
SvCUR_set(bufsv, destoffset+retl);
*SvEND(bufsv) = '\0'; /* consistent with perl sv_setpvn etc */
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 4))
TRACE1(imp_sth, " blob_read: SvCUR=%"UVuf"\n", (UV)SvCUR(bufsv));
return 1;
}
/*======================================================================*/
/* */
/* S_db_storeOptions */
/* ================= */
/* S_db_fetchOptions */
/* ================= */
/* */
/* An array of options/attributes we support on database handles for */
/* storing and fetching. */
/* */
/*======================================================================*/
enum paramdir { PARAM_READ = 1, PARAM_WRITE = 2, PARAM_READWRITE = 3 };
enum gettype {PARAM_TYPE_CUSTOM = 0, PARAM_TYPE_UINT, PARAM_TYPE_STR, PARAM_TYPE_BOOL};
typedef struct {
const char *str;
UWORD fOption;
enum paramdir dir;
enum gettype type;
UDWORD atrue;
UDWORD afalse;
} db_params;
static db_params S_db_options[] = {
{ "AutoCommit", SQL_AUTOCOMMIT, PARAM_READWRITE, PARAM_TYPE_BOOL, SQL_AUTOCOMMIT_ON, SQL_AUTOCOMMIT_OFF },
{ "ReadOnly", SQL_ATTR_ACCESS_MODE, PARAM_READWRITE, PARAM_TYPE_BOOL, SQL_MODE_READ_ONLY, SQL_MODE_READ_WRITE},
{ "RowCacheSize", ODBC_ROWCACHESIZE, PARAM_READ, PARAM_TYPE_CUSTOM },
#if 0 /* not defined by DBI/DBD specification */
{ "TRANSACTION",
SQL_ACCESS_MODE, PARAM_READWRITE, PARAM_TYPE_BOOL, SQL_MODE_READ_ONLY, SQL_MODE_READ_WRITE },
{ "solid_timeout", SQL_LOGIN_TIMEOUT, PARAM_READWRITE, PARAM_TYPE_UINT },
{ "ISOLATION", PARAM_READWRITE, PARAM_TYPE_UINT, SQL_TXN_ISOLATION },
#endif
{ "odbc_SQL_DBMS_NAME", SQL_DBMS_NAME, PARAM_READ, PARAM_TYPE_CUSTOM, },
{ "odbc_SQL_DRIVER_ODBC_VER", SQL_DRIVER_ODBC_VER, PARAM_READ, PARAM_TYPE_CUSTOM },
{ "odbc_SQL_ROWSET_SIZE", SQL_ROWSET_SIZE, PARAM_READWRITE, PARAM_TYPE_UINT },
{ "odbc_ignore_named_placeholders", ODBC_IGNORE_NAMED_PLACEHOLDERS, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_default_bind_type", ODBC_DEFAULT_BIND_TYPE, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_force_bind_type", ODBC_FORCE_BIND_TYPE, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_force_rebind", ODBC_FORCE_REBIND, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_async_exec", ODBC_ASYNC_EXEC, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_err_handler", ODBC_ERR_HANDLER, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_exec_direct", ODBC_EXEC_DIRECT, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_version", ODBC_VERSION, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_cursortype", ODBC_CURSORTYPE, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_query_timeout", ODBC_QUERY_TIMEOUT, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_putdata_start", ODBC_PUTDATA_START, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_column_display_size", ODBC_COLUMN_DISPLAY_SIZE, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_utf8_on", ODBC_UTF8_ON, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_has_unicode", ODBC_HAS_UNICODE, PARAM_READ, PARAM_TYPE_CUSTOM },
{ "odbc_out_connect_string", ODBC_OUTCON_STR, PARAM_READ, PARAM_TYPE_CUSTOM},
{ "odbc_describe_parameters", ODBC_DESCRIBE_PARAMETERS, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_batch_size", ODBC_BATCH_SIZE, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_array_operations", ODBC_ARRAY_OPERATIONS, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{ "odbc_taf_callback", ODBC_TAF_CALLBACK, PARAM_READWRITE, PARAM_TYPE_CUSTOM },
{"odbc_trace", SQL_ATTR_TRACE, PARAM_READWRITE, PARAM_TYPE_BOOL, SQL_OPT_TRACE_ON, SQL_OPT_TRACE_OFF},
{"odbc_trace_file", SQL_ATTR_TRACEFILE, PARAM_READWRITE, PARAM_TYPE_STR, },
{ NULL },
};
/*======================================================================*/
/* */
/* S_dbOption */
/* ========== */
/* */
/* Given a string and a length, locate this option in the specified */
/* array of valid options. Typically used by STORE and FETCH methods */
/* to decide if this option/attribute is supported by us. */
/* */
/*======================================================================*/
static const db_params *
S_dbOption(const db_params *pars, char *key, STRLEN len)
{
/* search option to set */
while (pars->str != NULL) {
if (strncmp(pars->str, key, len) == 0
&& len == strlen(pars->str))
break;
pars++;
}
if (pars->str == NULL) {
return NULL;
}
return pars;
}
/*======================================================================*/
/* */
/* dbd_db_STORE_attrib */
/* =================== */
/* */
/* This function handles: */
/* */
/* $dbh->{$key} = $value */
/* */
/* Method to handle the setting of driver specific attributes and DBI */
/* attributes AutoCommit and ChopBlanks (no other DBI attributes). */
/* */
/* Return TRUE if the attribute was handled, else FALSE. */
/* */
/*======================================================================*/
int dbd_db_STORE_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv)
{
static T_st_params S_st_fetch_params[] =
{
s_A("NUM_OF_PARAMS",1), /* 0 */
s_A("NUM_OF_FIELDS",1), /* 1 */
s_A("NAME",1), /* 2 */
s_A("NULLABLE",1), /* 3 */
s_A("TYPE",1), /* 4 */
s_A("PRECISION",1), /* 5 */
s_A("SCALE",1), /* 6 */
s_A("sol_type",1), /* 7 */
s_A("sol_length",1), /* 8 */
s_A("CursorName",1), /* 9 */
s_A("odbc_more_results",1), /* 10 */
s_A("ParamValues",0), /* 11 */
s_A("LongReadLen",0), /* 12 */
s_A("odbc_ignore_named_placeholders",0), /* 13 */
s_A("odbc_default_bind_type",0), /* 14 */
s_A("odbc_force_rebind",0), /* 15 */
s_A("odbc_query_timeout",0), /* 16 */
s_A("odbc_putdata_start",0), /* 17 */
s_A("ParamTypes",0), /* 18 */
s_A("odbc_column_display_size",0), /* 19 */
s_A("odbc_force_bind_type",0), /* 20 */
s_A("odbc_batch_size",0), /* 21 */
s_A("odbc_array_operations",0), /* 22 */
s_A("",0), /* END */
};
static T_st_params S_st_store_params[] =
{
s_A("odbc_ignore_named_placeholders",0), /* 0 */
s_A("odbc_default_bind_type",0), /* 1 */
s_A("odbc_force_rebind",0), /* 2 */
s_A("odbc_query_timeout",0), /* 3 */
s_A("odbc_putdata_start",0), /* 4 */
s_A("odbc_column_display_size",0), /* 5 */
s_A("odbc_force_bind_type",0), /* 6 */
s_A("odbc_batch_size",0), /* 7 */
s_A("odbc_array_operations",0), /* 8 */
s_A("",0), /* END */
};
#undef s_A
/*======================================================================*/
/* */
/* dbd_st_FETCH_attrib */
/* =================== */
/* */
/*======================================================================*/
SV *dbd_st_FETCH_attrib(SV *sth, imp_sth_t *imp_sth, SV *keysv)
{
dTHX;
STRLEN kl;
char *key = SvPV(keysv,kl);
int i;
SV *retsv = NULL;
T_st_params *par;
char cursor_name[256];
SWORD cursor_name_len;
RETCODE rc;
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 (par->need_describe && !imp_sth->done_desc &&
!dbd_describe(sth, imp_sth,0))
{
/* dbd_describe has already called dbd_error() */
/* we can't return Nullsv here because the xs code will */
/* then just pass the attribute name to DBI for FETCH. */
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 4)) {
TRACE1(imp_sth,
" !!!dbd_st_FETCH_attrib (%s) needed query description, "
"but failed\n", par->str);
}
if (DBIc_WARN(imp_sth)) {
warn("Describe failed during %s->FETCH(%s,%d)",
SvPV(sth,PL_na), key,imp_sth->done_desc);
}
return &PL_sv_undef;
}
i = DBIc_NUM_FIELDS(imp_sth);
switch(par - S_st_fetch_params)
{
AV *av;
case 0: /* NUM_OF_PARAMS */
return Nullsv; /* handled by DBI */
case 1: /* NUM_OF_FIELDS */
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 9)) {
TRACE1(imp_sth, " dbd_st_FETCH_attrib NUM_OF_FIELDS %d\n", i);
}
retsv = newSViv(i);
break;
case 2: /* NAME */
av = newAV();
retsv = newRV_inc(sv_2mortal((SV*)av));
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 9)) {
int j;
TRACE1(imp_sth, " dbd_st_FETCH_attrib NAMES %d\n", i);
for (j = 0; j < i; j++)
TRACE1(imp_sth, "\t%s\n", imp_sth->fbh[j].ColName);
}
while(--i >= 0) {
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 9)) {
TRACE2(imp_sth, " Colname %d => %s\n",
i, imp_sth->fbh[i].ColName);
}
#ifdef WITH_UNICODE
av_store(av, i,
sv_newwvn(aTHX_ (SQLWCHAR *)imp_sth->fbh[i].ColName,
imp_sth->fbh[i].ColNameLen));
#else
av_store(av, i, newSVpv(imp_sth->fbh[i].ColName, 0));
#endif
}
break;
case 3: /* NULLABLE */
av = newAV();
retsv = newRV_inc(sv_2mortal((SV*)av));
while(--i >= 0)
av_store(av, i,
(imp_sth->fbh[i].ColNullable == SQL_NO_NULLS)
? &PL_sv_no : &PL_sv_yes);
break;
case 4: /* TYPE */
av = newAV();
retsv = newRV_inc(sv_2mortal((SV*)av));
while(--i >= 0)
av_store(av, i, newSViv(imp_sth->fbh[i].ColSqlType));
break;
case 5: /* PRECISION */
av = newAV();
retsv = newRV_inc(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_inc(sv_2mortal((SV*)av));
while(--i >= 0)
av_store(av, i, newSViv(imp_sth->fbh[i].ColScale));
break;
case 7: /* sol_type */
av = newAV();
retsv = newRV_inc(sv_2mortal((SV*)av));
while(--i >= 0)
av_store(av, i, newSViv(imp_sth->fbh[i].ColSqlType));
break;
case 8: /* sol_length */
av = newAV();
retsv = newRV_inc(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);
if (!SQL_SUCCEEDED(rc)) {
dbd_error(sth, rc, "st_FETCH/SQLGetCursorName");
return Nullsv;
}
retsv = newSVpv(cursor_name, cursor_name_len);
break;
case 10: /* odbc_more_results */
retsv = newSViv(imp_sth->moreResults);
if (i == 0 && imp_sth->moreResults == 0) {
int outparams = (imp_sth->out_params_av) ?
AvFILL(imp_sth->out_params_av)+1 : 0;
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 4)) {
TRACE0(imp_sth,
" numfields == 0 && moreResults = 0 finish\n");
}
if (outparams) {
odbc_handle_outparams(aTHX_ imp_sth, DBIc_TRACE_LEVEL(imp_sth));
}
imp_sth->done_desc = 0; /* redo describe */
/* XXX need to 'finish' here */
dbd_st_finish(sth, imp_sth);
} else {
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 4)) {
TRACE2(imp_sth,
" fetch odbc_more_results, numfields == %d "
"&& moreResults = %d\n", i, imp_sth->moreResults);
}
}
break;
case 11: /* ParamValues */
{
/* not sure if there's a memory leak here. */
HV *paramvalues = newHV();
if (imp_sth->all_params_hv) {
HV *hv = imp_sth->all_params_hv;
SV *sv;
char *key;
I32 retlen;
hv_iterinit(hv);
while( (sv = hv_iternextsv(hv, &key, &retlen)) != NULL ) {
if (sv != &PL_sv_undef) {
phs_t *phs = (phs_t*)(void*)SvPVX(sv);
(void)hv_store(paramvalues, phs->name, (I32)strlen(phs->name),
newSVsv(phs->sv), 0);
}
}
}
/* ensure HV is freed when the ref is freed */
retsv = newRV_noinc((SV *)paramvalues);
break;
}
case 12: /* LongReadLen */
retsv = newSViv(DBIc_LongReadLen(imp_sth));
break;
case 13: /* odbc_ignore_named_placeholders */
retsv = newSViv(imp_sth->odbc_ignore_named_placeholders);
break;
case 14: /* odbc_default_bind_type */
retsv = newSViv(imp_sth->odbc_default_bind_type);
break;
case 15: /* odbc_force_rebind */
retsv = newSViv(imp_sth->odbc_force_rebind);
break;
case 16: /* odbc_query_timeout */
(PK_CatalogName && *PK_CatalogName) ? PK_CatalogName : 0, SQL_NTS,
(PK_SchemaName && *PK_SchemaName) ? PK_SchemaName : 0, SQL_NTS,
(PK_TableName && *PK_TableName) ? PK_TableName : 0, SQL_NTS,
(FK_CatalogName && *FK_CatalogName) ? FK_CatalogName : 0, SQL_NTS,
(FK_SchemaName && *FK_SchemaName) ? FK_SchemaName : 0, SQL_NTS,
(FK_TableName && *FK_TableName) ? FK_TableName : 0, SQL_NTS);
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 4))
TRACE1(imp_dbh, " SQLForeignKeys=%d\n", rc);
if (!SQL_SUCCEEDED(rc)) {
dbd_error(sth, rc, "odbc_get_foreign_keys/SQLForeignKeys");
return 0;
}
return build_results(aTHX_ sth, imp_sth, dbh, imp_dbh, rc);
}
#ifdef ODBC_NOW_DEPRECATED
int odbc_describe_col(
SV *sth,
int colno,
char *ColumnName,
I16 BufferLength,
I16 *NameLength,
I16 *DataType,
U32 *ColumnSize,
I16 *DecimalDigits,
I16 *Nullable)
{
D_imp_sth(sth);
SQLULEN ColSize;
RETCODE rc;
rc = SQLDescribeCol(imp_sth->hstmt, (SQLSMALLINT)colno,
ColumnName, BufferLength, NameLength,
DataType, &ColSize, DecimalDigits, Nullable);
if (!SQL_SUCCEEDED(rc)) {
dbd_error(sth, rc, "DescribeCol/SQLDescribeCol");
return 0;
}
*ColumnSize = (U32)ColSize;
return 1;
}
#endif /* ODBC_NOW_DEPRECATED */
int odbc_get_type_info(
SV *dbh,
SV *sth,
int ftype)
{
dTHX;
D_imp_dbh(dbh);
D_imp_sth(sth);
RETCODE rc;
int dbh_active;
size_t max_stmt_len;
#if 0
/* TBD: cursorname? */
char cname[128]; /* cursorname */
#endif
imp_sth->henv = imp_dbh->henv; /* needed for dbd_error */
imp_sth->hdbc = imp_dbh->hdbc;
imp_sth->done_desc = 0;
if ((dbh_active = check_connection_active(aTHX_ dbh)) == 0) return 0;
rc = SQLAllocHandle(SQL_HANDLE_STMT, imp_dbh->hdbc, &imp_sth->hstmt);
if (rc != SQL_SUCCESS) {
dbd_error(sth, rc, "odbc_get_type_info/SQLAllocHandle(stmt)");
return 0;
}
/* just for sanity, later. Any internals that may rely on this (including */
/* debugging) will have valid data */
max_stmt_len = strlen(cSqlGetTypeInfo)+(abs(ftype)/10)+2;
imp_sth->statement = (char *)safemalloc(max_stmt_len);
my_snprintf(imp_sth->statement, max_stmt_len, cSqlGetTypeInfo, ftype);
#ifdef WITH_UNICODE
rc = SQLGetTypeInfoW(imp_sth->hstmt, (SQLSMALLINT)ftype);
#else
rc = SQLGetTypeInfo(imp_sth->hstmt, (SQLSMALLINT)ftype);
#endif
if (DBIc_TRACE(imp_sth, DBD_TRACING, 0, 4))
TRACE2(imp_dbh, " SQLGetTypeInfo(%d)=%d\n", ftype, rc);
dbd_error(sth, rc, "odbc_get_type_info/SQLGetTypeInfo");
if (!SQL_SUCCEEDED(rc)) {
SQLFreeHandle(SQL_HANDLE_STMT,imp_sth->hstmt);
imp_sth->hstmt = SQL_NULL_HSTMT;
return 0;
}
return build_results(aTHX_ sth, imp_sth, dbh, imp_dbh, rc);
}
SV *odbc_cancel(SV *sth)
{
dTHX;
D_imp_sth(sth);
RETCODE rc;
rc = SQLCancel(imp_sth->hstmt);
if (!SQL_SUCCEEDED(rc)) {
dbd_error(sth, rc, "odbc_cancel/SQLCancel");
return Nullsv;
}
return newSViv(1);
}
IV odbc_st_lob_read(
SV *sth,
int colno,
}
/************************************************************************/
/* */
/* set_odbc_version */
/* ================ */
/* */
/* Set the ODBC version we require. This defaults to ODBC 3 but if */
/* attr contains the odbc_version atttribute this overrides it. If we */
/* fail for any reason the env handle is freed, the error reported and */
/* 0 is returned. If all ok, 1 is returned. */
/* */
/************************************************************************/
static int set_odbc_version(
pTHX_
SV *dbh,
imp_dbh_t *imp_dbh,
SV* attr)
{
D_imp_drh_from_dbh;
SV **svp;
UV odbc_version = 0;
SQLRETURN rc;
DBD_ATTRIB_GET_IV(
attr, "odbc_version", 12, svp, odbc_version);
if (svp && odbc_version) {
rc = SQLSetEnvAttr(imp_drh->henv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)odbc_version, SQL_IS_INTEGER);
} else {
/* make sure we request a 3.0 version */
rc = SQLSetEnvAttr(imp_drh->henv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
}
if (!SQL_SUCCEEDED(rc)) {
dbd_error2(
dbh, rc, "db_login/SQLSetEnvAttr", imp_drh->henv, 0, 0);
if (imp_drh->connects == 0) {
SQLFreeHandle(SQL_HANDLE_ENV, imp_drh->henv);
imp_drh->henv = SQL_NULL_HENV;
}
return 0;
}
return 1;
}
/*
* post_connect
* ==========
*
* Operations to perform immediately after we have connected.
*
* NOTE: prior to DBI subversion version 11605 (fixed post 1.607)
* DBD_ATTRIB_DELETE segfaulted so instead of calling:
* DBD_ATTRIB_DELETE(attr, "odbc_cursortype",
* strlen("odbc_cursortype"));
* we do the following:
* hv_delete((HV*)SvRV(attr), "odbc_cursortype",
* strlen("odbc_cursortype"), G_DISCARD);
*/
static int post_connect(
pTHX_
SV *dbh,
imp_dbh_t *imp_dbh,
SV *attr)
{
D_imp_drh_from_dbh;
SQLRETURN rc;
SWORD dbvlen;
UWORD supported;
/* default this now before we may change it below */
imp_dbh->switch_to_longvarchar = ODBC_SWITCH_TO_LONGVARCHAR;
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE0(imp_dbh, "Turning autocommit on\n");
/* DBI spec requires AutoCommit on */
rc = SQLSetConnectAttr(imp_dbh->hdbc, SQL_AUTOCOMMIT,
(SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
if (!SQL_SUCCEEDED(rc)) {
dbd_error(dbh, rc, "post_connect/SQLSetConnectAttr(SQL_AUTOCOMMIT)");
SQLFreeHandle(SQL_HANDLE_DBC, imp_dbh->hdbc);
if (imp_drh->connects == 0) {
SQLFreeHandle(SQL_HANDLE_ENV, imp_drh->henv);
imp_drh->henv = SQL_NULL_HENV;
imp_dbh->henv = SQL_NULL_HENV; /* needed for dbd_error */
}
return 0;
}
DBIc_set(imp_dbh,DBIcf_AutoCommit, 1);
/* get the ODBC compatibility level for this driver */
rc = SQLGetInfo(imp_dbh->hdbc, SQL_DRIVER_ODBC_VER, &imp_dbh->odbc_ver,
(SWORD)sizeof(imp_dbh->odbc_ver), &dbvlen);
if (!SQL_SUCCEEDED(rc)) {
dbd_error(dbh, rc, "post_connect/SQLGetInfo(DRIVER_ODBC_VER)");
strcpy(imp_dbh->odbc_ver, "01.00");
}
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE1(imp_dbh, "DRIVER_ODBC_VER = %s\n", imp_dbh->odbc_ver);
/* get ODBC driver name and version */
rc = SQLGetInfo(imp_dbh->hdbc, SQL_DRIVER_NAME, &imp_dbh->odbc_driver_name,
(SQLSMALLINT)sizeof(imp_dbh->odbc_driver_name), &dbvlen);
if (!SQL_SUCCEEDED(rc)) {
dbd_error(dbh, rc, "post_connect/SQLGetInfo(DRIVER_NAME)");
strcpy(imp_dbh->odbc_driver_name, "unknown");
imp_dbh->driver_type = DT_DONT_CARE;
} else {
if (strcmp(imp_dbh->odbc_driver_name, "SQLSRV32.DLL") == 0) {
imp_dbh->driver_type = DT_SQL_SERVER;
} else if ((strcmp(imp_dbh->odbc_driver_name, "sqlncli10.dll") == 0) ||
(strcmp(imp_dbh->odbc_driver_name, "SQLNCLI.DLL") == 0) ||
(memcmp(imp_dbh->odbc_driver_name, "libmsodbcsql", 13) == 0)) {
imp_dbh->driver_type = DT_SQL_SERVER_NATIVE_CLIENT;
} else if (strcmp(imp_dbh->odbc_driver_name, "odbcjt32.dll") == 0) {
imp_dbh->driver_type = DT_MS_ACCESS_JET;
/* flag to see if SQLDescribeParam is supported */
imp_dbh->odbc_sqlmoreresults_supported = -1;
imp_dbh->odbc_defer_binding = 0;
imp_dbh->odbc_force_rebind = 0;
/* default value for query timeout is -1 which means do not set the
query timeout at all. */
imp_dbh->odbc_query_timeout = -1;
imp_dbh->odbc_putdata_start = 32768;
imp_dbh->odbc_batch_size = 10;
imp_dbh->read_only = -1; /* show not set yet */
/*printf("odbc_batch_size defaulted to %d\n", imp_dbh->odbc_batch_size);*/
imp_dbh->odbc_column_display_size = 2001;
imp_dbh->odbc_utf8_on = 0;
imp_dbh->odbc_exec_direct = 0; /* default to not having SQLExecDirect used */
imp_dbh->odbc_describe_parameters = 1;
imp_dbh->RowCacheSize = 1; /* default value for now */
#ifdef WE_DONT_DO_THIS_ANYMORE
if (!strcmp(imp_dbh->odbc_dbms_name, "Microsoft SQL Server")) {
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE0(imp_dbh, "Deferring Binding\n");
imp_dbh->odbc_defer_binding = 1;
}
#endif
/* check to see if SQLMoreResults is supported */
rc = SQLGetFunctions(imp_dbh->hdbc, SQL_API_SQLMORERESULTS, &supported);
if (SQL_SUCCEEDED(rc)) {
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE1(imp_dbh, "SQLMoreResults supported: %d\n", supported);
imp_dbh->odbc_sqlmoreresults_supported = supported ? 1 : 0;
} else {
imp_dbh->odbc_sqlmoreresults_supported = 0;
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE0(imp_dbh,
" !!SQLGetFunctions(SQL_API_SQLMORERESULTS) failed:\n");
AllODBCErrors(imp_dbh->henv, imp_dbh->hdbc, 0,
DBIc_TRACE(imp_dbh, DBD_TRACING, 0, 3), DBIc_LOGPIO(imp_dbh));
}
/* call only once per connection / DBH -- may want to do
* this during the connect to avoid potential threading
* issues */
/* check to see if SQLDescribeParam is supported */
rc = SQLGetFunctions(imp_dbh->hdbc, SQL_API_SQLDESCRIBEPARAM, &supported);
if (SQL_SUCCEEDED(rc)) {
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE1(imp_dbh, "SQLDescribeParam supported: %d\n", supported);
imp_dbh->odbc_sqldescribeparam_supported = supported ? 1 : 0;
} else {
imp_dbh->odbc_sqldescribeparam_supported = 0;
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE0(imp_dbh,
" !!SQLGetFunctions(SQL_API_SQLDESCRIBEPARAM) failed:\n");
AllODBCErrors(imp_dbh->henv, imp_dbh->hdbc, 0,
DBIc_TRACE(imp_dbh, DBD_TRACING, 0, 3),
DBIc_LOGPIO(imp_dbh));
}
/* odbc_cursortype */
{
SV **svp;
UV odbc_cursortype = 0;
DBD_ATTRIB_GET_IV(attr, "odbc_cursortype", 15,
svp, odbc_cursortype);
if (svp && odbc_cursortype) {
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE1(imp_dbh,
" Setting cursor type to: %"UVuf"\n", odbc_cursortype);
/* delete odbc_cursortype so we don't see it again via STORE */
(void)hv_delete((HV*)SvRV(attr), "odbc_cursortype",
strlen("odbc_cursortype"), G_DISCARD);
rc = SQLSetConnectAttr(imp_dbh->hdbc,(SQLINTEGER)SQL_CURSOR_TYPE,
(SQLPOINTER)odbc_cursortype,
(SQLINTEGER)SQL_IS_INTEGER);
if (!SQL_SUCCEEDED(rc) && (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0)))
TRACE1(imp_dbh, " !!Failed to set SQL_CURSORTYPE to %d\n",
(int)odbc_cursortype);
}
}
/* odbc_query_timeout */
{
SV **svp;
UV odbc_timeout = 0;
DBD_ATTRIB_GET_IV(
attr, "odbc_query_timeout", strlen("odbc_query_timeout"),
svp, odbc_timeout);
if (svp && odbc_timeout) {
imp_dbh->odbc_query_timeout = odbc_timeout;
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE1(imp_dbh, " Setting DBH query timeout to %d\n",
(int)odbc_timeout);
/* delete odbc_cursortype so we don't see it again via STORE */
(void)hv_delete((HV*)SvRV(attr), "odbc_query_timeout",
strlen("odbc_query_timeout"), G_DISCARD);
}
}
/* odbc_putdata_start */
{
SV **svp;
IV putdata_start_value;
DBD_ATTRIB_GET_IV(
attr, "odbc_putdata_start", strlen("odbc_putdata_start"),
svp, putdata_start_value);
if (svp) {
imp_dbh->odbc_putdata_start = putdata_start_value;
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE1(imp_dbh, " Setting DBH putdata_start to %d\n",
(int)putdata_start_value);
/* delete odbc_putdata_start so we don't see it again via STORE */
(void)hv_delete((HV*)SvRV(attr), "odbc_putdata_start",
strlen("odbc_putdata_start"), G_DISCARD);
}
}
/* odbc_column_display_size */
{
SV **svp;
IV column_display_size_value;
DBD_ATTRIB_GET_IV(
attr, "odbc_column_display_size",
strlen("odbc_column_display_size"),
svp, column_display_size_value);
if (svp) {
imp_dbh->odbc_column_display_size = column_display_size_value;
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE1(imp_dbh,
" Setting DBH default column display size to %d\n",
(int)column_display_size_value);
/* delete odbc_column_display_size so we don't see it again via STORE */
(void)hv_delete((HV*)SvRV(attr), "odbc_column_display_size",
strlen("odbc_column_display_size"), G_DISCARD);
}
}
/* odbc_utf8_on */
{
SV **svp;
IV utf8_on_value;
DBD_ATTRIB_GET_IV(
attr, "odbc_utf8_on",
strlen("odbc_utf8_on"),
svp, utf8_on_value);
if (svp) {
imp_dbh->odbc_utf8_on = utf8_on_value;
if (DBIc_TRACE(imp_dbh, CONNECTION_TRACING, 0, 0))
TRACE1(imp_dbh,
" Setting UTF8_ON to %d\n",
(int)utf8_on_value);
( run in 0.762 second using v1.01-cache-2.11-cpan-5837b0d9d2c )