/* * The contents of this file are subject to the Initial * Developer's Public License Version 1.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. * * Software distributed under the License is distributed AS IS, * WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the License for the specific language governing rights * and limitations under the License. * * The Original Code was created by Vlad Khorsun * for the Firebird Open Source RDBMS project. * * Copyright (c) 2007 Vlad Khorsun * and all contributors signed below. * * All Rights Reserved. * Contributor(s): ______________________________________. */ #include "firebird.h" #include "fb_types.h" #include "../common.h" #include "../../include/fb_blk.h" #include "fb_exception.h" #include "iberror.h" #include "../align.h" #include "../dsc.h" #include "../exe.h" #include "IscDS.h" #include "../tra.h" #include "../blb_proto.h" #include "../evl_proto.h" #include "../exe_proto.h" #include "../intl_proto.h" #include "../mov_proto.h" using namespace Jrd; using namespace Firebird; namespace EDS { const char *FIREBIRD_PROVIDER_NAME = "Firebird"; class RegisterFBProvider { public: RegisterFBProvider() { Provider* provider = new FBProvider(FIREBIRD_PROVIDER_NAME); Manager::manager->addProvider(provider); } }; static RegisterFBProvider reg; const SSHORT sqlType[] = { /* dtype_unknown */ -1, /* dtype_text */ SQL_TEXT, /* dtype_cstring */ -1, /* dtype_varying */ SQL_VARYING, /* dtype_none1 */ -1, /* dtype_none2 */ -1, /* dtype_packed */ -1, /* dtype_byte */ -1, /* dtype_short */ SQL_SHORT, /* dtype_long */ SQL_LONG, /* dtype_quad */ SQL_QUAD, /* dtype_real */ SQL_FLOAT, /* dtype_double */ SQL_DOUBLE, /* dtype_d_float */ -1, // Fix to use in VMS /* dtype_sql_date */ SQL_TYPE_DATE, /* dtype_sql_time */ SQL_TYPE_TIME, /* dtype_timestamp */ SQL_TIMESTAMP, /* dtype_blob */ SQL_BLOB, /* dtype_array */ SQL_ARRAY, // Not supported for a while /* dtype_int64 */ SQL_INT64 }; static InitInstance > > > sqlTypeToDscType; static void parseSQLDA(XSQLDA *xsqlda, UCharBuffer &buff, Firebird::Array &descs); // IscProvider void IscProvider::getRemoteError(ISC_STATUS* status, string &err) { err = ""; char buff[512]; ISC_STATUS* p = status, *end = status + ISC_STATUS_LENGTH; while (p < end) { const ISC_STATUS code = *p ? p[1] : 0; if (!m_api.isc_interprete(buff, &p)) break; string rem_err; rem_err.printf("%lu : %s\n", code, buff); err += rem_err; } } Connection* IscProvider::doCreateConnection() { return new IscConnection(*this); } // IscConnection IscConnection::IscConnection(IscProvider &prov) : Connection(prov), m_iscProvider(prov), m_handle(0), m_dpb(getPool(), ClumpletReader::Tagged, MAX_DPB_SIZE) { } IscConnection::~IscConnection() { } void IscConnection::generateDPB(thread_db *tdbb, ClumpletWriter &dpb, const string &dbName, const string &user, const string &pwd) const { dpb.reset(isc_dpb_version1); Firebird::string &attUser = tdbb->getAttachment()->att_user->usr_user_name; if ((m_provider.getFlags() & prvTrustedAuth) && (user.isEmpty() || user == attUser) && pwd.isEmpty()) { dpb.insertString(isc_dpb_trusted_auth, attUser); } else { if (!user.isEmpty()) { dpb.insertString(isc_dpb_user_name, user); } if (!pwd.isEmpty()) { dpb.insertString(isc_dpb_password, pwd); } } CharSet* const cs = INTL_charset_lookup(tdbb, tdbb->getAttachment()->att_charset); if (cs) { dpb.insertString(isc_dpb_lc_ctype, cs->getName()); } } void IscConnection::attach(thread_db *tdbb, const string &dbName, const string &user, const string &pwd) { m_dbName = dbName; generateDPB(tdbb, m_dpb, dbName, user, pwd); ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, *this); m_iscProvider.isc_attach_database(status, m_dbName.length(), (char*) m_dbName.c_str(), &m_handle, m_dpb.getBufferLength(), (char*) m_dpb.getBuffer()); } if (status[1]) { raise(status, tdbb, "attach"); } char buff[8]; { EngineCallbackGuard guard(tdbb, *this); char info[] = {isc_info_db_sql_dialect, isc_info_end}; m_iscProvider.isc_database_info(status, &m_handle, sizeof(info), info, sizeof(buff), buff); } if (status[1]) { raise(status, tdbb, "isc_database_info"); } char *p = buff, *end = buff + sizeof(buff); while (p < end) { const UCHAR item = *p++; const USHORT len = m_iscProvider.isc_vax_integer(p, sizeof(USHORT)); p += sizeof(USHORT); switch(item) { case isc_info_db_sql_dialect: m_sqlDialect = m_iscProvider.isc_vax_integer(p, len); break; case isc_info_truncated: case isc_info_error: ERR_post(isc_random, isc_arg_string, "Unexpected error in isc_database_info"); case isc_info_end: p = end; break; } p += len; } } void IscConnection::detach(thread_db *tdbb) { clearStatements(tdbb); ISC_STATUS_ARRAY status = {0}; if (m_handle) { EngineCallbackGuard guard(tdbb, *this); FB_API_HANDLE h = m_handle; m_handle = 0; m_iscProvider.isc_detach_database(status, &h); m_handle = h; } if (status[1]) { raise(status, tdbb, "detach"); } } // connection is available for the current execution context if it // a) have no active statements or support many active statements // and // b) have no active transactions or have active transaction of given // TraScope bound to current jrd transaction or support many active // transactions bool IscConnection::isAvailable(thread_db *tdbb, TraScope traScope) const { const int flags = m_provider.getFlags(); if (m_used_stmts && !(flags & prvMultyStmts)) return false; if (m_transactions.getCount() && !(flags & prvMultyTrans) && !findTransaction(tdbb, traScope)) return false; return true; } bool IscConnection::isSameDatabase(thread_db *tdbb, const string &dbName, const string &user, const string &pwd) const { if (m_dbName != dbName) return false; ClumpletWriter dpb(ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1); generateDPB(tdbb, dpb, dbName, user, pwd); return m_dpb.simpleCompare(dpb); } Blob* IscConnection::createBlob() { return new IscBlob(*this); } Transaction* IscConnection::doCreateTransaction() { return new IscTransaction(*this); } Statement* IscConnection::doCreateStatement() { return new IscStatement(*this); } // IscTransaction void IscTransaction::doStart(ISC_STATUS* status, thread_db *tdbb, Firebird::ClumpletWriter &tpb) { fb_assert(!m_handle); FB_API_HANDLE& db_handle = m_iscConnection.getAPIHandle(); EngineCallbackGuard guard(tdbb, *this); m_iscProvider.isc_start_transaction(status, &m_handle, 1, &db_handle, tpb.getBufferLength(), tpb.getBuffer()); } void IscTransaction::doPrepare(ISC_STATUS* status, thread_db *tdbb, int info_len, const char* info) { } void IscTransaction::doCommit(ISC_STATUS* status, thread_db *tdbb, bool retain) { EngineCallbackGuard guard(tdbb, *this); if (retain) m_iscProvider.isc_commit_retaining(status, &m_handle); else m_iscProvider.isc_commit_transaction(status, &m_handle); fb_assert(retain && m_handle || !retain && !m_handle || status[1] && m_handle); } void IscTransaction::doRollback(ISC_STATUS* status, thread_db *tdbb, bool retain) { EngineCallbackGuard guard(tdbb, *this); if (retain) m_iscProvider.isc_rollback_retaining(status, &m_handle); else m_iscProvider.isc_rollback_transaction(status, &m_handle); fb_assert(retain && m_handle || !retain && !m_handle || status[1] && m_handle); } // IscStatement IscStatement::IscStatement(IscConnection &conn) : Statement(conn), m_iscConnection(conn), m_iscProvider(*(IscProvider*) conn.getProvider()), m_handle(0), m_in_xsqlda(NULL), m_out_xsqlda(NULL) { // initialize sqlTypeToDscType in the first call to this function if (sqlTypeToDscType().count() == 0) { for (int i = 0; i < FB_NELEM(sqlType); ++i) sqlTypeToDscType().put(sqlType[i], static_cast(i)); } } IscStatement::~IscStatement() { delete[] (char*)m_in_xsqlda; delete[] (char*)m_out_xsqlda; } void IscStatement::doPrepare(thread_db *tdbb, const string &sql) { FB_API_HANDLE& h_conn = m_iscConnection.getAPIHandle(); FB_API_HANDLE& h_tran = getIscTransaction()->getAPIHandle(); ISC_STATUS_ARRAY status; // prepare and get output parameters if (!m_out_xsqlda) { m_out_xsqlda = (XSQLDA*) FB_NEW (getPool()) char [XSQLDA_LENGTH(1)]; m_out_xsqlda->sqln = 1; m_out_xsqlda->version = 1; } const char *sWhereError = NULL; { EngineCallbackGuard guard(tdbb, *this); if (!m_handle) { fb_assert(!m_allocated); if (m_iscProvider.isc_dsql_allocate_statement(status, &h_conn, &m_handle)) { sWhereError = "isc_dsql_allocate_statement"; } m_allocated = (m_handle != 0); } if (!sWhereError) { if (m_iscProvider.isc_dsql_prepare(status, &h_tran, &m_handle, sql.length(), (char*) sql.c_str(), m_connection.getSqlDialect(), m_out_xsqlda)) { sWhereError = "isc_dsql_prepare"; } } } if (sWhereError) { raise(status, tdbb, sWhereError, &sql); } // adjust output parameters if (m_out_xsqlda->sqld > m_out_xsqlda->sqln) { const int n = m_out_xsqlda->sqld; delete (char*) m_out_xsqlda; m_out_xsqlda = (XSQLDA*) FB_NEW (getPool()) char [XSQLDA_LENGTH(n)]; m_out_xsqlda->sqln = n; m_out_xsqlda->version = 1; EngineCallbackGuard guard(tdbb, *this); if (m_iscProvider.isc_dsql_describe(status, &m_handle, 1, m_out_xsqlda)) { sWhereError = "isc_dsql_describe"; } } if (sWhereError) { raise(status, tdbb, sWhereError, &sql); } parseSQLDA(m_out_xsqlda, m_out_buffer, m_outDescs); m_outputs = m_out_xsqlda ? m_out_xsqlda->sqld : 0; // get input parameters if (!m_in_xsqlda) { m_in_xsqlda = (XSQLDA*) FB_NEW (getPool()) char [XSQLDA_LENGTH(1)]; m_in_xsqlda->sqln = 1; m_in_xsqlda->version = 1; } { EngineCallbackGuard guard(tdbb, *this); if (m_iscProvider.isc_dsql_describe_bind(status, &m_handle, 1, m_in_xsqlda)) { sWhereError = "isc_dsql_describe_bind"; } } if (sWhereError) { raise(status, tdbb, sWhereError, &sql); } // adjust input parameters if (m_in_xsqlda->sqld > m_in_xsqlda->sqln) { const int n = m_in_xsqlda->sqld; delete (char*) m_in_xsqlda; m_in_xsqlda = (XSQLDA*) FB_NEW (getPool()) char [XSQLDA_LENGTH(n)]; m_in_xsqlda->sqln = n; m_in_xsqlda->version = 1; EngineCallbackGuard guard(tdbb, *this); if (m_iscProvider.isc_dsql_describe_bind(status, &m_handle, 1, m_in_xsqlda)) { sWhereError = "isc_dsql_describe_bind"; } } if (sWhereError) { raise(status, tdbb, sWhereError, &sql); } parseSQLDA(m_in_xsqlda, m_in_buffer, m_inDescs); m_inputs = m_in_xsqlda ? m_in_xsqlda->sqld : 0; // get statement type const char stmt_info[] = {isc_info_sql_stmt_type}; char info_buff[16]; { EngineCallbackGuard guard(tdbb, *this); if (m_iscProvider.isc_dsql_sql_info(status, &m_handle, sizeof(stmt_info), stmt_info, sizeof(info_buff), info_buff)) { sWhereError = "isc_dsql_sql_info"; } } if (sWhereError) { raise(status, tdbb, sWhereError, &sql); } if (info_buff[0] != stmt_info[0]) { status[0] = isc_arg_gds; status[1] = isc_random; status[2] = isc_arg_string; status[3] = (ISC_STATUS) (IPTR) "Unknown statement type"; status[4] = isc_arg_end; sWhereError = "isc_dsql_sql_info"; raise(status, tdbb, sWhereError, &sql); } { EngineCallbackGuard guard(tdbb, *this); const int len = m_iscProvider.isc_vax_integer(&info_buff[1], 2); const int stmt_type = m_iscProvider.isc_vax_integer(&info_buff[3], len); m_stmt_selectable = (stmt_type == isc_info_sql_stmt_select || stmt_type == isc_info_sql_stmt_select_for_upd); } } void IscStatement::doExecute(thread_db *tdbb) { FB_API_HANDLE& h_tran = getIscTransaction()->getAPIHandle(); ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, *this); m_iscProvider.isc_dsql_execute2(status, &h_tran, &m_handle, 1, m_in_xsqlda, m_out_xsqlda); } if (status[1]) { raise(status, tdbb, "isc_dsql_execute2"); } } void IscStatement::doOpen(thread_db *tdbb) { FB_API_HANDLE& h_tran = getIscTransaction()->getAPIHandle(); ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, *this); m_iscProvider.isc_dsql_execute(status, &h_tran, &m_handle, 1, m_in_xsqlda); } if (status[1]) { raise(status, tdbb, "isc_dsql_execute"); } } bool IscStatement::doFetch(thread_db *tdbb) { ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, *this); const ISC_STATUS res = m_iscProvider.isc_dsql_fetch(status, &m_handle, 1, m_out_xsqlda); if (res == 100) { return false; } } if (status[1]) { raise(status, tdbb, "isc_dsql_fetch"); } return true; } void IscStatement::doClose(thread_db *tdbb, bool drop) { fb_assert(m_handle); ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, *this); m_iscProvider.isc_dsql_free_statement(status, &m_handle, drop ? DSQL_drop : DSQL_close); m_allocated = (m_handle != 0); } if (status[1]) { raise(status, tdbb, "isc_dsql_free_statement"); } } void IscStatement::doSetInParams(thread_db *tdbb, int count, const string *const *names, jrd_nod **params) { Statement::doSetInParams(tdbb, count, names, params); if (names) { XSQLVAR *xVar = m_in_xsqlda->sqlvar; for (int i = 0; i < count; i++, xVar++) { const int max_len = sizeof(xVar->sqlname); const int len = MIN(names[i]->length(), max_len - 1); xVar->sqlname_length = len; strncpy(xVar->sqlname, names[i]->c_str(), len); xVar->sqlname[max_len-1] = 0; } } } // IscBlob IscBlob::IscBlob(IscConnection &conn) : Blob(conn), m_iscProvider(*(IscProvider*) conn.getProvider()), m_iscConnection(conn), m_handle(0) { memset(&m_blob_id, 0, sizeof(m_blob_id)); } IscBlob::~IscBlob() { fb_assert(!m_handle); } void IscBlob::open(thread_db *tdbb, Transaction &tran, const dsc &desc, UCharBuffer *bpb) { fb_assert(!m_handle); fb_assert(sizeof(m_blob_id) == desc.dsc_length); FB_API_HANDLE& h_db = m_iscConnection.getAPIHandle(); FB_API_HANDLE& h_tran = ((IscTransaction&)tran).getAPIHandle(); memcpy(&m_blob_id, desc.dsc_address, sizeof(m_blob_id)); ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, m_iscConnection); ISC_USHORT bpb_len = bpb ? bpb->getCount() : 0; ISC_UCHAR *bpb_buff = bpb ? bpb->begin() : NULL; m_iscProvider.isc_open_blob2(status, &h_db, &h_tran, &m_handle, &m_blob_id, bpb_len, bpb_buff); } if (status[1]) { m_iscConnection.raise(status, tdbb, "isc_open_blob2"); } fb_assert(m_handle); } void IscBlob::create(thread_db *tdbb, Transaction &tran, dsc &desc, UCharBuffer *bpb) { fb_assert(!m_handle); fb_assert(sizeof(m_blob_id) == desc.dsc_length); FB_API_HANDLE& h_db = m_iscConnection.getAPIHandle(); FB_API_HANDLE& h_tran = ((IscTransaction&)tran).getAPIHandle(); ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, m_iscConnection); short bpb_len = bpb ? bpb->getCount() : 0; char *bpb_buff = bpb ? (char*) bpb->begin() : NULL; m_iscProvider.isc_create_blob2(status, &h_db, &h_tran, &m_handle, &m_blob_id, bpb_len, bpb_buff); memcpy(desc.dsc_address, &m_blob_id, sizeof(m_blob_id)); } if (status[1]) { m_iscConnection.raise(status, tdbb, "isc_create_blob2"); } fb_assert(m_handle); } USHORT IscBlob::read(thread_db *tdbb, char *buff, USHORT len) { fb_assert(m_handle); USHORT result = 0; ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, m_iscConnection); m_iscProvider.isc_get_segment(status, &m_handle, &result, len, buff); } if (status[1] == isc_segstr_eof) { fb_assert(result == 0); } else if (status[1] == isc_segment) { } else if (status[1]) { m_iscConnection.raise(status, tdbb, "isc_get_segment"); } return result; } void IscBlob::write(thread_db *tdbb, char *buff, USHORT len) { fb_assert(m_handle); ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, m_iscConnection); m_iscProvider.isc_put_segment(status, &m_handle, len, buff); } if (status[1]) { m_iscConnection.raise(status, tdbb, "isc_put_segment"); } } void IscBlob::close(thread_db *tdbb) { fb_assert(m_handle); ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, m_iscConnection); m_iscProvider.isc_close_blob(status, &m_handle); } if (status[1]) { m_iscConnection.raise(status, tdbb, "isc_close_blob"); } fb_assert(!m_handle); } void IscBlob::cancel(thread_db *tdbb) { if (!m_handle) return; ISC_STATUS_ARRAY status = {0}; { EngineCallbackGuard guard(tdbb, m_iscConnection); m_iscProvider.isc_cancel_blob(status, &m_handle); } if (status[1]) { m_iscConnection.raise(status, tdbb, "isc_close_blob"); } fb_assert(!m_handle); } // IscProvider // isc api ISC_STATUS IscProvider::notImplemented(ISC_STATUS* status) const { status[0] = isc_arg_gds; status[1] = isc_unavailable; status[2] = isc_arg_end; return status[1]; } ISC_STATUS ISC_EXPORT IscProvider::isc_attach_database(ISC_STATUS *user_status, short file_length, char *file_name, isc_db_handle *public_handle, short dpb_length, char *dpb) { if (!m_api.isc_attach_database) return notImplemented(user_status); else return (*m_api.isc_attach_database) (user_status, file_length, file_name, public_handle, dpb_length, dpb); } ISC_STATUS ISC_EXPORT IscProvider::isc_array_gen_sdl(ISC_STATUS *user_status, ISC_ARRAY_DESC *, short *, char *, short *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_array_get_slice(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, ISC_QUAD *, ISC_ARRAY_DESC *, void *, ISC_LONG *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_array_lookup_bounds(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, char *, char *, ISC_ARRAY_DESC *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_array_lookup_desc(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, char *, char *, ISC_ARRAY_DESC *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_array_set_desc(ISC_STATUS *user_status, char *, char *, short *, short *, short *, ISC_ARRAY_DESC *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_array_put_slice(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, ISC_QUAD *, ISC_ARRAY_DESC *, void *, ISC_LONG *) { return notImplemented(user_status); } void ISC_EXPORT IscProvider::isc_blob_default_desc(ISC_BLOB_DESC *, unsigned char *, unsigned char *) { return; } ISC_STATUS ISC_EXPORT IscProvider::isc_blob_gen_bpb(ISC_STATUS *user_status, ISC_BLOB_DESC *, ISC_BLOB_DESC *, unsigned short, unsigned char *, unsigned short *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_blob_info(ISC_STATUS *user_status, isc_blob_handle *blob_handle, short item_length, char *items, short buffer_length, char *buffer) { if (!m_api.isc_blob_info) return notImplemented(user_status); else return (*m_api.isc_blob_info) (user_status, blob_handle, item_length, items, buffer_length, buffer); } ISC_STATUS ISC_EXPORT IscProvider::isc_blob_lookup_desc(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, unsigned char *, unsigned char *, ISC_BLOB_DESC *, unsigned char *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_blob_set_desc(ISC_STATUS *user_status, unsigned char *, unsigned char *, short, short, short, ISC_BLOB_DESC *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_cancel_blob(ISC_STATUS *user_status, isc_blob_handle *blob_handle) { if (!m_api.isc_cancel_blob) return notImplemented(user_status); else return (*m_api.isc_cancel_blob) (user_status, blob_handle); } ISC_STATUS ISC_EXPORT IscProvider::isc_cancel_events(ISC_STATUS *user_status, isc_db_handle *, ISC_LONG *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_close_blob(ISC_STATUS *user_status, isc_blob_handle *blob_handle) { if (!m_api.isc_close_blob) return notImplemented(user_status); else return (*m_api.isc_close_blob) (user_status, blob_handle); } ISC_STATUS ISC_EXPORT IscProvider::isc_commit_retaining(ISC_STATUS *user_status, isc_tr_handle *tra_handle) { if (!m_api.isc_commit_retaining) return notImplemented(user_status); else return (*m_api.isc_commit_retaining) (user_status, tra_handle); } ISC_STATUS ISC_EXPORT IscProvider::isc_commit_transaction(ISC_STATUS *user_status, isc_tr_handle *tra_handle) { if (!m_api.isc_commit_transaction) return notImplemented(user_status); else return (*m_api.isc_commit_transaction) (user_status, tra_handle); } ISC_STATUS ISC_EXPORT IscProvider::isc_create_blob(ISC_STATUS *user_status, isc_db_handle *db_handle, isc_tr_handle *tr_handle, isc_blob_handle *blob_handle, ISC_QUAD *blob_id) { if (!m_api.isc_create_blob) return notImplemented(user_status); else return (*m_api.isc_create_blob) (user_status, db_handle, tr_handle, blob_handle, blob_id); } ISC_STATUS ISC_EXPORT IscProvider::isc_create_blob2(ISC_STATUS *user_status, isc_db_handle *db_handle, isc_tr_handle *tr_handle, isc_blob_handle *blob_handle, ISC_QUAD *blob_id, short bpb_length, char *bpb) { if (!m_api.isc_create_blob2) return notImplemented(user_status); else return (*m_api.isc_create_blob2) (user_status, db_handle, tr_handle, blob_handle, blob_id, bpb_length, bpb); } ISC_STATUS ISC_EXPORT IscProvider::isc_create_database(ISC_STATUS *user_status, short, char *, isc_db_handle *, short, char *, short) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_database_info(ISC_STATUS *user_status, isc_db_handle *db_handle, short info_len, char *info, short res_len, char *res) { if (!m_api.isc_database_info) return notImplemented(user_status); else return (*m_api.isc_database_info) (user_status, db_handle, info_len, info, res_len, res); } void ISC_EXPORT IscProvider::isc_decode_date(ISC_QUAD *, void *) { return ; } void ISC_EXPORT IscProvider::isc_decode_sql_date(ISC_DATE *, void *) { return ; } void ISC_EXPORT IscProvider::isc_decode_sql_time(ISC_TIME *, void *) { return ; } void ISC_EXPORT IscProvider::isc_decode_timestamp(ISC_TIMESTAMP *, void *) { return ; } ISC_STATUS ISC_EXPORT IscProvider::isc_detach_database(ISC_STATUS *user_status, isc_db_handle *public_handle) { if (!m_api.isc_detach_database) return notImplemented(user_status); else return (*m_api.isc_detach_database) (user_status, public_handle); } ISC_STATUS ISC_EXPORT IscProvider::isc_drop_database(ISC_STATUS *user_status, isc_db_handle *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_allocate_statement(ISC_STATUS *user_status, isc_db_handle *db_handle, isc_stmt_handle *stmt_handle) { if (!m_api.isc_dsql_allocate_statement) return notImplemented(user_status); else return (*m_api.isc_dsql_allocate_statement) (user_status, db_handle, stmt_handle); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_alloc_statement2(ISC_STATUS *user_status, isc_db_handle *db_handle, isc_stmt_handle *stmt_handle) { if (!m_api.isc_dsql_alloc_statement2) return notImplemented(user_status); else return (*m_api.isc_dsql_alloc_statement2) (user_status, db_handle, stmt_handle); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_describe(ISC_STATUS *user_status, isc_stmt_handle *stmt_handle, unsigned short dialect, XSQLDA *sqlda) { if (!m_api.isc_dsql_describe) return notImplemented(user_status); else return (*m_api.isc_dsql_describe) (user_status, stmt_handle, dialect, sqlda); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_describe_bind(ISC_STATUS *user_status, isc_stmt_handle *stmt_handle, unsigned short dialect, XSQLDA *sqlda) { if (!m_api.isc_dsql_describe_bind) return notImplemented(user_status); else return (*m_api.isc_dsql_describe_bind) (user_status, stmt_handle, dialect, sqlda); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_exec_immed2(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, unsigned short, char *, unsigned short, XSQLDA *, XSQLDA *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_execute(ISC_STATUS *user_status, isc_tr_handle *tra_handle, isc_stmt_handle *stmt_handle, unsigned short dialect, XSQLDA *sqlda) { if (!m_api.isc_dsql_execute) return notImplemented(user_status); else return (*m_api.isc_dsql_execute) (user_status, tra_handle, stmt_handle, dialect, sqlda); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_execute2(ISC_STATUS *user_status, isc_tr_handle *tra_handle, isc_stmt_handle *stmt_handle, unsigned short dialect, XSQLDA *in_sqlda, XSQLDA *out_sqlda) { if (!m_api.isc_dsql_execute2) return notImplemented(user_status); else return (*m_api.isc_dsql_execute2) (user_status, tra_handle, stmt_handle, dialect, in_sqlda, out_sqlda); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_execute_immediate(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, unsigned short, char *, unsigned short, XSQLDA *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_fetch(ISC_STATUS *user_status, isc_stmt_handle *stmt_handle, unsigned short da_version, XSQLDA *sqlda) { if (!m_api.isc_dsql_fetch) return notImplemented(user_status); else return (*m_api.isc_dsql_fetch) (user_status, stmt_handle, da_version, sqlda); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_finish(isc_db_handle *) { return isc_unavailable; } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_free_statement(ISC_STATUS *user_status, isc_stmt_handle *stmt_handle, unsigned short option) { if (!m_api.isc_dsql_free_statement) return notImplemented(user_status); else return (*m_api.isc_dsql_free_statement) (user_status, stmt_handle, option); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_insert(ISC_STATUS *user_status, isc_stmt_handle *, unsigned short, XSQLDA *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_prepare(ISC_STATUS *user_status, isc_tr_handle *tra_handle, isc_stmt_handle *stmt_handle, unsigned short length, char *str, unsigned short dialect, XSQLDA *sqlda) { if (!m_api.isc_dsql_prepare) return notImplemented(user_status); else return (*m_api.isc_dsql_prepare) (user_status, tra_handle, stmt_handle, length, str, dialect, sqlda); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_set_cursor_name(ISC_STATUS *user_status, isc_stmt_handle *, char *, unsigned short) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_sql_info(ISC_STATUS *user_status, isc_stmt_handle *stmt_handle, short items_len, const char *items, short buffer_len, char *buffer) { if (!m_api.isc_dsql_sql_info) return notImplemented(user_status); else return (*m_api.isc_dsql_sql_info) (user_status, stmt_handle, items_len, items, buffer_len, buffer); } void ISC_EXPORT IscProvider::isc_encode_date(void *, ISC_QUAD *) { return ; } void ISC_EXPORT IscProvider::isc_encode_sql_date(void *, ISC_DATE *) { return ; } void ISC_EXPORT IscProvider::isc_encode_sql_time(void *, ISC_TIME *) { return ; } void ISC_EXPORT IscProvider::isc_encode_timestamp(void *, ISC_TIMESTAMP *) { return ; } ISC_LONG ISC_EXPORT_VARARG IscProvider::isc_event_block(char * *, char * *, unsigned short, ...) { return 0; } void ISC_EXPORT IscProvider::isc_event_counts(ISC_ULONG *, short, char *, char *) { return ; } /* 17 May 2001 - IscProvider::isc_expand_dpb is DEPRECATED */ void ISC_EXPORT_VARARG IscProvider::isc_expand_dpb(char * *, short *, ...) { return ; } int ISC_EXPORT IscProvider::isc_modify_dpb(char * *, short *, unsigned short, char *, short) { return 0; } ISC_LONG ISC_EXPORT IscProvider::isc_free(char *) { return 0; } ISC_STATUS ISC_EXPORT IscProvider::isc_get_segment(ISC_STATUS *user_status, isc_blob_handle *blob_handle, unsigned short *length, unsigned short buffer_length, char *buffer) { if (!m_api.isc_get_segment) return notImplemented(user_status); else return (*m_api.isc_get_segment) (user_status, blob_handle, length, buffer_length, buffer); } ISC_STATUS ISC_EXPORT IscProvider::isc_get_slice(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, ISC_QUAD *, short, char *, short, ISC_LONG *, ISC_LONG, void *, ISC_LONG *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_interprete(char *, ISC_STATUS * *) { return isc_unavailable; } ISC_STATUS ISC_EXPORT IscProvider::isc_open_blob(ISC_STATUS *user_status, isc_db_handle *db_handle, isc_tr_handle *tr_handle, isc_blob_handle *blob_handle, ISC_QUAD *blob_id) { if (!m_api.isc_open_blob) return notImplemented(user_status); else return (*m_api.isc_open_blob) (user_status, db_handle, tr_handle, blob_handle, blob_id); } ISC_STATUS ISC_EXPORT IscProvider::isc_open_blob2(ISC_STATUS *user_status, isc_db_handle *db_handle, isc_tr_handle *tr_handle, isc_blob_handle *blob_handle, ISC_QUAD *blob_id, ISC_USHORT bpb_length, ISC_UCHAR *bpb) { if (!m_api.isc_open_blob2) return notImplemented(user_status); else return (*m_api.isc_open_blob2) (user_status, db_handle, tr_handle, blob_handle, blob_id, bpb_length, bpb); } ISC_STATUS ISC_EXPORT IscProvider::isc_prepare_transaction2(ISC_STATUS *user_status, isc_tr_handle *, ISC_USHORT, ISC_UCHAR *) { return notImplemented(user_status); } void ISC_EXPORT IscProvider::isc_print_sqlerror(ISC_SHORT, ISC_STATUS *) { return ; } ISC_STATUS ISC_EXPORT IscProvider::isc_print_status(ISC_STATUS *) { return isc_unavailable; } ISC_STATUS ISC_EXPORT IscProvider::isc_put_segment(ISC_STATUS *user_status, isc_blob_handle *blob_handle, unsigned short buffer_length, char *buffer) { if (!m_api.isc_put_segment) return notImplemented(user_status); else return (*m_api.isc_put_segment) (user_status, blob_handle, buffer_length, buffer); } ISC_STATUS ISC_EXPORT IscProvider::isc_put_slice(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, ISC_QUAD *, short, char *, short, ISC_LONG *, ISC_LONG, void *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_que_events(ISC_STATUS *user_status, isc_db_handle *, ISC_LONG *, ISC_USHORT, ISC_UCHAR *, isc_callback, void *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_rollback_retaining(ISC_STATUS *user_status, isc_tr_handle *tra_handle) { if (!m_api.isc_rollback_retaining) return notImplemented(user_status); else return (*m_api.isc_rollback_retaining) (user_status, tra_handle); } ISC_STATUS ISC_EXPORT IscProvider::isc_rollback_transaction(ISC_STATUS *user_status, isc_tr_handle *tra_handle) { if (!m_api.isc_rollback_transaction) return notImplemented(user_status); else return (*m_api.isc_rollback_transaction) (user_status, tra_handle); } ISC_STATUS ISC_EXPORT IscProvider::isc_start_multiple(ISC_STATUS *user_status, isc_tr_handle *tra_handle, short count, void *vec) { if (!m_api.isc_start_multiple) return notImplemented(user_status); else return (*m_api.isc_start_multiple) (user_status, tra_handle, count, vec); } struct why_teb { FB_API_HANDLE *teb_database; int teb_tpb_length; UCHAR *teb_tpb; }; typedef why_teb WHY_TEB; ISC_STATUS ISC_EXPORT_VARARG IscProvider::isc_start_transaction(ISC_STATUS *user_status, isc_tr_handle *tra_handle, short count, ...) { if (!m_api.isc_start_multiple) // !!! return notImplemented(user_status); Firebird::HalfStaticArray tebs; WHY_TEB* teb = tebs.getBuffer(count); const WHY_TEB* const end = teb + count; va_list ptr; va_start(ptr, count); for (WHY_TEB* teb_iter = teb; teb_iter < end; teb_iter++) { teb_iter->teb_database = va_arg(ptr, FB_API_HANDLE*); teb_iter->teb_tpb_length = va_arg(ptr, int); teb_iter->teb_tpb = va_arg(ptr, UCHAR *); } va_end(ptr); return (*m_api.isc_start_multiple) (user_status, tra_handle, count, teb); } ISC_STATUS ISC_EXPORT_VARARG IscProvider::isc_reconnect_transaction(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, short, char*) { return notImplemented(user_status); } ISC_LONG ISC_EXPORT IscProvider::isc_sqlcode(ISC_STATUS *) { return isc_unavailable; } void ISC_EXPORT IscProvider::isc_sql_interprete(short, char *, short) { return ; } ISC_STATUS ISC_EXPORT IscProvider::isc_transaction_info(ISC_STATUS *user_status, isc_tr_handle *, short, char *, short, char *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_transact_request(ISC_STATUS *user_status, isc_db_handle *, isc_tr_handle *, unsigned short, char *, unsigned short, char *, unsigned short, char *) { return notImplemented(user_status); } ISC_LONG ISC_EXPORT IscProvider::isc_vax_integer(char *p, short len) { return ::isc_vax_integer(p, len); } ISC_INT64 ISC_EXPORT IscProvider::isc_portable_integer(unsigned char *p, short len) { return ::isc_portable_integer(p, len); } ISC_STATUS ISC_EXPORT IscProvider::isc_seek_blob(ISC_STATUS *user_status, isc_blob_handle *, short, ISC_LONG, ISC_LONG *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_service_attach(ISC_STATUS *user_status, unsigned short, char *, isc_svc_handle *, unsigned short, char *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_service_detach(ISC_STATUS *user_status, isc_svc_handle *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_service_query(ISC_STATUS *user_status, isc_svc_handle *, isc_resv_handle *, unsigned short, char *, unsigned short, char *, unsigned short, char *) { return notImplemented(user_status); } ISC_STATUS ISC_EXPORT IscProvider::isc_service_start(ISC_STATUS *user_status, isc_svc_handle *, isc_resv_handle *, unsigned short, char *) { return notImplemented(user_status); } void IscProvider::loadAPI() { ISC_STATUS_ARRAY status; notImplemented(status); status_exception::raise(status); } // FBProvider #define PROTO(X) (prototype_##X*)&X static FirebirdApiPointers isc_callbacks = { PROTO(isc_attach_database), PROTO(isc_array_gen_sdl), PROTO(isc_array_get_slice), PROTO(isc_array_lookup_bounds), PROTO(isc_array_lookup_desc), PROTO(isc_array_set_desc), PROTO(isc_array_put_slice), PROTO(isc_blob_default_desc), PROTO(isc_blob_gen_bpb), PROTO(isc_blob_info), PROTO(isc_blob_lookup_desc), PROTO(isc_blob_set_desc), PROTO(isc_cancel_blob), PROTO(isc_cancel_events), PROTO(isc_close_blob), PROTO(isc_commit_retaining), PROTO(isc_commit_transaction), PROTO(isc_create_blob), PROTO(isc_create_blob2), PROTO(isc_create_database), PROTO(isc_database_info), PROTO(isc_decode_date), PROTO(isc_decode_sql_date), PROTO(isc_decode_sql_time), PROTO(isc_decode_timestamp), PROTO(isc_detach_database), PROTO(isc_drop_database), PROTO(isc_dsql_allocate_statement), PROTO(isc_dsql_alloc_statement2), PROTO(isc_dsql_describe), PROTO(isc_dsql_describe_bind), PROTO(isc_dsql_exec_immed2), PROTO(isc_dsql_execute), PROTO(isc_dsql_execute2), PROTO(isc_dsql_execute_immediate), PROTO(isc_dsql_fetch), PROTO(isc_dsql_finish), PROTO(isc_dsql_free_statement), PROTO(isc_dsql_insert), PROTO(isc_dsql_prepare), PROTO(isc_dsql_set_cursor_name), PROTO(isc_dsql_sql_info), PROTO(isc_encode_date), PROTO(isc_encode_sql_date), PROTO(isc_encode_sql_time), PROTO(isc_encode_timestamp), PROTO(isc_event_block), PROTO(isc_event_counts), PROTO(isc_expand_dpb), PROTO(isc_modify_dpb), PROTO(isc_free), PROTO(isc_get_segment), PROTO(isc_get_slice), PROTO(isc_interprete), PROTO(isc_open_blob), PROTO(isc_open_blob2), PROTO(isc_prepare_transaction2), PROTO(isc_print_sqlerror), PROTO(isc_print_status), PROTO(isc_put_segment), PROTO(isc_put_slice), PROTO(isc_que_events), PROTO(isc_rollback_retaining), PROTO(isc_rollback_transaction), PROTO(isc_start_multiple), PROTO(isc_start_transaction), PROTO(isc_reconnect_transaction), PROTO(isc_sqlcode), PROTO(isc_sql_interprete), PROTO(isc_transaction_info), PROTO(isc_transact_request), PROTO(isc_vax_integer), PROTO(isc_seek_blob), PROTO(isc_service_attach), PROTO(isc_service_detach), PROTO(isc_service_query), PROTO(isc_service_start), }; void FBProvider::loadAPI() { m_api = isc_callbacks; m_api_loaded = true; } static void parseSQLDA(XSQLDA *xsqlda, UCharBuffer &buff, Firebird::Array &descs) { size_t offset = 0; int i = 0; XSQLVAR* xVar = xsqlda->sqlvar; for (; i < xsqlda->sqld; xVar++, i++) { UCHAR dtype; sqlTypeToDscType().get((xVar->sqltype & ~1), dtype); xVar->sqltype |= 1; if (type_alignments[dtype]) offset = FB_ALIGN(offset, type_alignments[dtype]); offset += xVar->sqllen; const int type = xVar->sqltype & (~1); if (type == SQL_VARYING) { offset += sizeof(SSHORT); } // null indicator offset = FB_ALIGN(offset, type_alignments[dtype_short]); offset += sizeof(SSHORT); } descs.resize(xsqlda->sqld * 2); const UCHAR *p = buff.getBuffer(offset); offset = 0; xVar = xsqlda->sqlvar; for (i = 0; i < xsqlda->sqld; xVar++, i++) { UCHAR dtype; sqlTypeToDscType().get((xVar->sqltype & ~1), dtype); if (type_alignments[dtype]) offset = FB_ALIGN(offset, type_alignments[dtype]); xVar->sqldata = (ISC_SCHAR*) (p + offset); // build the src descriptor dsc &src = descs[i * 2]; src.dsc_dtype = dtype; src.dsc_length = xVar->sqllen; src.dsc_scale = xVar->sqlscale; src.dsc_sub_type = xVar->sqlsubtype; src.dsc_address = (UCHAR*) xVar->sqldata; offset += xVar->sqllen; const int type = xVar->sqltype & (~1); if (type == SQL_VARYING) { offset += sizeof(SSHORT); } // null indicator offset = FB_ALIGN(offset, type_alignments[dtype_short]); xVar->sqlind = (SSHORT*) (p + offset); dsc &null = descs[i * 2 + 1]; null.makeShort(0, xVar->sqlind); offset += sizeof(SSHORT); } } } // namespace EDS