/*- * Copyright 2005-2007 Guram Dukashvili * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ //--------------------------------------------------------------------------- #include //--------------------------------------------------------------------------- namespace fbcpp { //--------------------------------------------------------------------------- #if _MSC_VER #pragma warning(disable:4305) #pragma warning(disable:4309) #endif //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- SPB::SPBParam SPB::params[] = { { "version1", isc_spb_version1 }, { "current_version", isc_spb_current_version }, { "version", isc_spb_version }, { "user_name", isc_spb_user_name }, { "sys_user_name", isc_spb_sys_user_name }, { "sys_user_name_enc", isc_spb_sys_user_name_enc }, { "password", isc_spb_password }, { "password_enc", isc_spb_password_enc }, { "command_line", isc_spb_command_line }, { "dbname", isc_spb_dbname }, { "verbose", isc_spb_verbose }, { "options", isc_spb_options }, { "connect_timeout", isc_spb_connect_timeout }, { "dummy_packet_interval", isc_spb_dummy_packet_interval }, { "sql_role_name", isc_spb_sql_role_name }, { "sec_userid", isc_spb_sec_userid }, { "sec_groupid", isc_spb_sec_groupid }, { "sec_username", isc_spb_sec_username }, { "sec_password", isc_spb_sec_password }, { "sec_groupname", isc_spb_sec_groupname }, { "sec_firstname", isc_spb_sec_firstname }, { "sec_middlename", isc_spb_sec_middlename }, { "sec_lastname", isc_spb_sec_lastname }, { "lic_key", isc_spb_lic_key }, { "lic_id", isc_spb_lic_id }, { "lic_desc", isc_spb_lic_desc }, { "bkp_file", isc_spb_bkp_file | 0x8000 }, { "bkp_factor", isc_spb_bkp_factor | 0x8000 }, { "bkp_length", isc_spb_bkp_length | 0x8000 }, { "bkp_expand", isc_spb_bkp_expand }, { "prp_page_buffers", isc_spb_prp_page_buffers | 0x4000 }, { "prp_sweep_interval", isc_spb_prp_sweep_interval | 0x4000 }, { "prp_shutdown_db", isc_spb_prp_shutdown_db | 0x4000 }, { "prp_deny_new_attachments", isc_spb_prp_deny_new_attachments | 0x4000 }, { "prp_deny_new_transactions", isc_spb_prp_deny_new_transactions | 0x4000 }, { "prp_reserve_space", isc_spb_prp_reserve_space | 0x4000 }, { "prp_write_mode", isc_spb_prp_write_mode | 0x4000 }, { "prp_access_mode", isc_spb_prp_access_mode | 0x4000 }, { "prp_set_sql_dialect", isc_spb_prp_set_sql_dialect | 0x4000 }, { "rpr_commit_trans", isc_spb_rpr_commit_trans }, { "rpr_rollback_trans", isc_spb_rpr_rollback_trans }, { "rpr_recover_two_phase", isc_spb_rpr_recover_two_phase }, { "rpr_list_limbo_trans", isc_spb_rpr_list_limbo_trans }, { "tra_id", isc_spb_tra_id }, { "single_tra_id", isc_spb_single_tra_id }, { "multi_tra_id", isc_spb_multi_tra_id }, { "tra_state", isc_spb_tra_state }, { "tra_state_limbo", isc_spb_tra_state_limbo }, { "tra_state_commit", isc_spb_tra_state_commit }, { "tra_state_rollback", isc_spb_tra_state_rollback }, { "tra_state_unknown", isc_spb_tra_state_unknown }, { "tra_host_site", isc_spb_tra_host_site }, { "tra_remote_site", isc_spb_tra_remote_site }, { "tra_db_path", isc_spb_tra_db_path }, { "tra_advise", isc_spb_tra_advise }, { "tra_advise_commit", isc_spb_tra_advise_commit }, { "tra_advise_rollback", isc_spb_tra_advise_rollback }, { "tra_advise_unknown", isc_spb_tra_advise_unknown }, { "res_buffers", isc_spb_res_buffers | 0x8000 }, { "res_page_size", isc_spb_res_page_size | 0x8000 }, { "res_length", isc_spb_res_length | 0x8000 }, { "res_access_mode", isc_spb_res_access_mode | 0x8000 }, { "res_am_readonly", isc_spb_res_am_readonly }, { "res_am_readwrite", isc_spb_res_am_readwrite }, { "num_att", isc_spb_num_att }, { "num_db", isc_spb_num_db }, { "sts_record_versions", isc_spb_sts_record_versions }, { "isc_spb_sts_table", isc_spb_sts_table } }; //--------------------------------------------------------------------------- SPB::SPB() : spb_(NULL), spbLen_(0) { writeChar(isc_spb_version).writeChar(isc_spb_current_version); } //--------------------------------------------------------------------------- SPB::~SPB() { ksys::xfree(spb_); } //--------------------------------------------------------------------------- SPB & SPB::clear() { ksys::xfree(spb_); spb_ = NULL; spbLen_ = 0; writeChar(isc_spb_version).writeChar(isc_spb_current_version); return *this; } //--------------------------------------------------------------------------- SPB & SPB::writeChar(uintptr_t code) { ksys::xrealloc(spb_, spbLen_ + 1); spb_[spbLen_++] = char(code); return *this; } //--------------------------------------------------------------------------- SPB & SPB::writeLong(uintptr_t a) { ksys::xrealloc(spb_, spbLen_ + sizeof(ISC_LONG)); *(ISC_LONG *) (spb_ + spbLen_) = (ISC_LONG) a; spbLen_ += sizeof(ISC_LONG); return *this; } //--------------------------------------------------------------------------- intptr_t SPB::writeISCCode(const utf8::String & name) { intptr_t i; for( i = sizeof(params) / sizeof(params[0]) - 1; i >= 0; i-- ){ if( name.strcasecmp(params[i].name_) == 0 ){ ksys::xrealloc(spb_, spbLen_ + 1); spb_[spbLen_++] = char(params[i].number & ~0xC000); return params[i].number; } } return i; } //--------------------------------------------------------------------------- SPB & SPB::writeBuffer(const void * buf, uintptr_t size) { ksys::xrealloc(spb_, spbLen_ + size); memcpy(spb_ + spbLen_, buf, size); spbLen_ += size; return *this; } //--------------------------------------------------------------------------- SPB & SPB::add(const utf8::String & name, const ksys::Mutant & value) { utf8::String sValue; switch( writeISCCode(name) ){ case isc_spb_user_name : case isc_spb_sys_user_name : case isc_spb_sys_user_name_enc : case isc_spb_password : case isc_spb_password_enc : // case isc_spb_command_line : // case isc_spb_dbname : // case isc_spb_options : // case isc_spb_connect_timeout : // case isc_spb_dummy_packet_interval : case isc_spb_sql_role_name : sValue = value; writeChar(sValue.size()).writeBuffer(sValue.c_str(), sValue.size()); break; // case isc_spb_verbose : // break; } return *this; } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- ServiceRequest::RequestParam ServiceRequest::params[] = { { "action_svc_backup", isc_action_svc_backup }, { "action_svc_restore", isc_action_svc_restore }, { "action_svc_repair", isc_action_svc_repair }, { "action_svc_add_user", isc_action_svc_add_user }, { "action_svc_delete_user", isc_action_svc_delete_user }, { "action_svc_modify_user", isc_action_svc_modify_user }, { "action_svc_display_user", isc_action_svc_display_user }, { "action_svc_properties", isc_action_svc_properties }, { "action_svc_add_license", isc_action_svc_add_license }, { "action_svc_remove_license", isc_action_svc_remove_license }, { "action_svc_db_stats", isc_action_svc_db_stats }, { "action_svc_get_ib_log", isc_action_svc_get_ib_log } }; //--------------------------------------------------------------------------- ServiceRequest::ServiceRequest() : request_(NULL), requestLen_(0) { } //--------------------------------------------------------------------------- ServiceRequest::~ServiceRequest() { ksys::xfree(request_); } //--------------------------------------------------------------------------- ServiceRequest & ServiceRequest::clear() { ksys::xfree(request_); request_ = NULL; requestLen_ = 0; return *this; } //--------------------------------------------------------------------------- ServiceRequest & ServiceRequest::writeChar(uintptr_t code) { ksys::xrealloc(request_, requestLen_ + 1); request_[requestLen_++] = char(code); return *this; } //--------------------------------------------------------------------------- ServiceRequest & ServiceRequest::writeShort(short a) { ksys::xrealloc(request_, requestLen_ + sizeof(short)); *(short *) (request_ + requestLen_) = a; requestLen_ += sizeof(short); return *this; } //--------------------------------------------------------------------------- ServiceRequest & ServiceRequest::writeLong(uintptr_t a) { ksys::xrealloc(request_, requestLen_ + sizeof(ISC_LONG)); *(ISC_LONG *) (request_ + requestLen_) = (ISC_LONG) a; requestLen_ += sizeof(ISC_LONG); return *this; } //--------------------------------------------------------------------------- intptr_t ServiceRequest::writeISCCode(const utf8::String & name) { intptr_t i; for( i = sizeof(SPB::params) / sizeof(SPB::params[0]) - 1; i >= 0; i-- ){ if( name.strcasecmp(SPB::params[i].name_) == 0 ){ ksys::xrealloc(request_, requestLen_ + 1); request_[requestLen_++] = char(SPB::params[i].number & ~0xC000); return SPB::params[i].number; } } if( i < 0 ){ for( i = sizeof(params) / sizeof(params[0]) - 1; i >= 0; i-- ){ if( name.strcasecmp(params[i].name_) == 0 ){ ksys::xrealloc(request_, requestLen_ + 1); request_[requestLen_++] = params[i].number; return params[i].number; } } } return i; } //--------------------------------------------------------------------------- ServiceRequest & ServiceRequest::writeBuffer(const void * buf, uintptr_t size) { ksys::xrealloc(request_, requestLen_ + size); memcpy(request_ + requestLen_, buf, size); requestLen_ += size; return *this; } //--------------------------------------------------------------------------- ServiceRequest & ServiceRequest::add(const utf8::String & name, const ksys::Mutant & value) { intptr_t a; utf8::String sValue; switch( (a = writeISCCode(name)) ){ case isc_action_svc_backup : case isc_action_svc_restore : case isc_action_svc_repair : case isc_action_svc_add_user : case isc_action_svc_delete_user : case isc_action_svc_modify_user : case isc_action_svc_display_user : case isc_action_svc_properties : case isc_action_svc_add_license : case isc_action_svc_remove_license : case isc_action_svc_db_stats : case isc_action_svc_get_ib_log : requestAction_ = a; break; case isc_spb_verbose : case isc_spb_rpr_commit_trans : case isc_spb_rpr_rollback_trans : case isc_spb_rpr_recover_two_phase : break; case isc_spb_dbname : case isc_spb_bkp_file | 0x8000 : case isc_spb_bkp_length | 0x8000 : sValue = value; writeShort((short) sValue.size()).writeBuffer(sValue.c_str(),sValue.size()); break; case isc_spb_bkp_factor | 0x8000 : case isc_spb_options : case isc_spb_res_length | 0x8000 : case isc_spb_res_buffers | 0x8000 : case isc_spb_res_page_size | 0x8000 : case isc_spb_prp_page_buffers | 0x4000 : case isc_spb_prp_sweep_interval | 0x4000 : case isc_spb_prp_shutdown_db | 0x4000 : case isc_spb_prp_deny_new_transactions | 0x4000 : case isc_spb_prp_deny_new_attachments | 0x4000 : case isc_spb_prp_set_sql_dialect | 0x4000 : case isc_spb_tra_id : writeLong(value); break; case isc_spb_res_access_mode | 0x8000 : case isc_spb_prp_reserve_space | 0x4000 : case isc_spb_prp_write_mode | 0x4000 : case isc_spb_prp_access_mode | 0x4000 : writeChar(value); break; } return *this; } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- Service::Service() : handle_(0), queryResponse_(NULL), queryResponseLen_(0) { } //--------------------------------------------------------------------------- Service::~Service() { detach(); ksys::xfree(queryResponse_); } //--------------------------------------------------------------------------- Service & Service::attach(const utf8::String & name) { if( !attached() ){ api.open(); ISC_STATUS_ARRAY status; if( api.isc_service_attach(status, 0, (char *) name.c_str(), &handle_, (short) spb_.spbLen_, spb_.spb_) != 0 ){ ksys::AutoPtr e( newObjectV1C2(status, __PRETTY_FUNCTION__) ); api.close(); exceptionHandler(e.ptr(NULL)); } name_ = name; } return *this; } //--------------------------------------------------------------------------- Service & Service::detach() { if( attached() ){ ISC_STATUS_ARRAY status; if( api.isc_service_detach(status, &handle_) != 0 && !iscIsFatalError(status) ) exceptionHandler(newObjectV1C2(status, __PRETTY_FUNCTION__)); handle_ = 0; api.close(); } return *this; } //--------------------------------------------------------------------------- Service & Service::invoke() { if( attached() ){ ISC_LONG ret; ISC_STATUS_ARRAY status; switch( request_.requestAction_ ){ case isc_action_svc_backup : case isc_action_svc_restore : case isc_action_svc_repair : case isc_action_svc_add_user : case isc_action_svc_delete_user : case isc_action_svc_modify_user : case isc_action_svc_display_user : case isc_action_svc_properties : case isc_action_svc_add_license : case isc_action_svc_remove_license : for(;;){ ret = api.isc_service_start(status,&handle_,NULL,(short) request_.requestLen_,request_.request_); if( ret == 0 ) break; if( status[1] != isc_svc_in_use ) exceptionHandler(newObjectV1C2(status, __PRETTY_FUNCTION__)); ksys::ksleep1(); } break; case isc_action_svc_db_stats : case isc_action_svc_get_ib_log : ksys::xrealloc(queryResponse_, getpagesize()); queryResponseLen_ = getpagesize(); for( ; ; ){ if( api.isc_service_query(status, &handle_, NULL, (short) spb_.spbLen_, spb_.spb_, (short) queryResponseLen_, queryResponse_, (short) request_.requestLen_, request_.request_) != 0 ) exceptionHandler(newObjectV1C2(status,__PRETTY_FUNCTION__)); if( *queryResponse_ != isc_info_truncated ) break; ksys::xrealloc(queryResponse_, queryResponseLen_ << 1); queryResponseLen_ <<= 1; } break; } } return *this; } //--------------------------------------------------------------------------- void Service::staticExceptionHandler(ksys::Exception * e) { EClientServer * p = dynamic_cast(e); if( p != NULL && p->isFatalError() && attached() ){ ISC_STATUS_ARRAY status; api.isc_service_detach(status,&handle_); handle_ = 0; api.close(); } e->throwSP(); } //--------------------------------------------------------------------------- void Service::exceptionHandler(ksys::Exception * e) { staticExceptionHandler(e); } //--------------------------------------------------------------------------- } // namespace fbcpp //---------------------------------------------------------------------------