/*- * 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 { //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- DSQLParam::~DSQLParam() { clear(); } //--------------------------------------------------------------------------- DSQLParam::DSQLParam(DSQLStatement * statement,const utf8::String & name) : statement_(statement), name_(name), head_(NULL), next_(NULL), index_(-1), sqlind_(-1), sqlscale_(0) { data_ = NULL; id_.gds_quad_low = 0; id_.gds_quad_high = 0; handle_ = 0; } //--------------------------------------------------------------------------- ksys::Mutant DSQLParam::getMutant() { if( sqlind_ < 0 ) return ksys::Mutant(); ldouble v; switch( sqltype_ & ~1 ){ case SQL_VARYING : case SQL_TEXT : return text_; case SQL_SHORT : if( sqlscale_ != 0 ){ v = (short) bigInt_; for( intptr_t j = sqlscale_; j < 0; j++ ) v /= 10; return v; } return (short) bigInt_; case SQL_LONG : if( sqlscale_ != 0 ){ v = (int) bigInt_; for( intptr_t j = sqlscale_; j < 0; j++ ) v /= 10; return v; } return (int) bigInt_; case SQL_FB_FLOAT : return float_; case SQL_FB_DOUBLE : case SQL_D_FLOAT : return double_; case SQL_FB_TYPE_TIME : case SQL_FB_TYPE_DATE : case SQL_FB_TIMESTAMP : return iscTimeStamp2Timeval(timeStamp_); case SQL_QUAD : case SQL_INT64 : if( sqlscale_ != 0 ){ v = (ldouble) bigInt_; for( intptr_t j = sqlscale_; j < 0; j++ ) v /= 10; return v; } return bigInt_; case SQL_BLOB : case SQL_ARRAY : return ksys::Mutant(); } newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); exit(ENOSYS); } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::setMutant(const ksys::Mutant & value) { if( next_ != NULL ) next_->setMutant(value); if( value.type() == ksys::mtNull ){ sqlind_ = -1; return *this; } switch( sqltype_ & ~1 ){ case SQL_VARYING : case SQL_TEXT : text_ = value; break; case SQL_SHORT : case SQL_LONG : case SQL_QUAD : case SQL_INT64 : if( sqlscale_ != 0 && value.type() == ksys::mtFloat ){ ldouble v = value; for( long j = sqlscale_; j < 0; j++ ) v *= 10; bigInt_ = (int64_t) v; } else { bigInt_ = value; } break; case SQL_FB_FLOAT : float_ = value; break; case SQL_FB_DOUBLE : case SQL_D_FLOAT : double_ = value; break; case SQL_FB_TYPE_TIME : case SQL_FB_TYPE_DATE : case SQL_FB_TIMESTAMP : timeStamp_ = timeval2IscTimeStamp(value); break; case SQL_BLOB : cancelBlob().createBlob().writeBuffer(utf8::String(value).c_str(),utf8::String(value).size()).closeBlob(); break; case SQL_ARRAY : sqlind_ = -1; return *this; default : newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); } sqlind_ = 0; return *this; } //--------------------------------------------------------------------------- utf8::String DSQLParam::getString() { ldouble v; if( sqlind_ >= 0 ){ switch( sqltype_ & ~1 ){ case SQL_VARYING : case SQL_TEXT : return text_; case SQL_SHORT : case SQL_LONG : case SQL_QUAD : case SQL_INT64 : if( sqlscale_ != 0 ){ v = (ldouble) bigInt_; for( intptr_t j = sqlscale_; j < 0; j++ ) v /= 10; return ksys::Mutant(v); } return utf8::int2Str(bigInt_); case SQL_FB_FLOAT : return utf8::float2Str(float_); case SQL_FB_DOUBLE : case SQL_D_FLOAT : return utf8::float2Str(double_); case SQL_FB_TYPE_TIME : case SQL_FB_TYPE_DATE : case SQL_FB_TIMESTAMP : return utf8::time2Str(iscTimeStamp2Time(timeStamp_)); case SQL_BLOB : case SQL_ARRAY : break; default : newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); } } return utf8::String(); } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::setString(const utf8::String & value) { if( next_ != NULL ) next_->setString(value); switch( sqltype_ & ~1 ){ case SQL_VARYING : case SQL_TEXT : text_ = value; break; case SQL_SHORT : case SQL_LONG : case SQL_QUAD : case SQL_INT64 : if( !utf8::tryStr2Int(value,bigInt_) ){ ldouble v = utf8::str2Float(value); for( intptr_t j = sqlscale_; j < 0; j++ ) v *= 10; bigInt_ = (int64_t) v; } break; case SQL_FB_FLOAT : float_ = (float) utf8::str2Float(value); break; case SQL_FB_DOUBLE : case SQL_D_FLOAT : double_ = (double) utf8::str2Float(value); break; case SQL_FB_TYPE_TIME : case SQL_FB_TYPE_DATE : case SQL_FB_TIMESTAMP : timeStamp_ = time2IscTimeStamp(utf8::str2Time(value)); break; case SQL_BLOB : cancelBlob().createBlob().writeBuffer(value.c_str(), value.size()).closeBlob(); break; case SQL_ARRAY : sqlind_ = -1; return *this; default : newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); } sqlind_ = 0; return *this; } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::clear() { ksys::xfree(data_); data_ = NULL; return *this; } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::checkData() { if( data_ == NULL ){ intptr_t i; dataSize_ = arrayDesc_.array_desc_length; if( arrayDesc_.array_desc_dtype == blr_varying ) dataSize_ += 2; elementSize_ = dataSize_; for( i = arrayDesc_.array_desc_dimensions - 1; i >= 0; i-- ){ dimElements_[i] = arrayDesc_.array_desc_bounds[i].array_bound_upper - arrayDesc_.array_desc_bounds[i].array_bound_lower + 1; dataSize_ *= dimElements_[i]; } memmove(dimElements_,dimElements_ + 1,sizeof(dimElements_) - sizeof(dimElements_[0])); dimElements_[arrayDesc_.array_desc_dimensions - 1] = 1; for( i = arrayDesc_.array_desc_dimensions - 1; i > 0; i-- ){ dimElements_[i - 1] = uint16_t(dimElements_[i - 1] * dimElements_[i]); } ksys::xmalloc(data_,dataSize_); memset(data_,0,dataSize_); } return *this; } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::checkDim(bool inRange) { if( !inRange ) newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); return *this; } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::setDataFromMutant(uintptr_t absIndex, const ksys::Mutant & value) { if( next_ != NULL ) next_->setDataFromMutant(absIndex,value); checkData(); uintptr_t elementOffset = elementSize_ * absIndex, len; if( elementOffset >= (uintptr_t) dataSize_ ) newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); char * data = (char *) data_ + elementOffset; utf8::String tempString; ldouble v; switch( arrayDesc_.array_desc_dtype ){ case blr_varying : tempString = value; len = tempString.size(); if( len > uintptr_t(elementSize_ - 2) ) len = elementSize_ - 2; *(int16_t *) (data + elementSize_ - 2) = (int16_t) len; memcpy(data,tempString.c_str(), len); break; case blr_text : tempString = value; if( tempString.size() < (uintptr_t) elementSize_ ){ memcpy(data, tempString.c_str(), tempString.size()); memset(data + tempString.size(), ' ', elementSize_ - tempString.size()); } else{ memcpy(data,tempString.c_str(),elementSize_); } break; case blr_short : if( arrayDesc_.array_desc_scale != 0 && value.type() == ksys::mtFloat ){ v = value; for( intptr_t j = arrayDesc_.array_desc_scale; j < 0; j++ ) v *= 10; *(int16_t *) data = (int16_t) v; } else{ *(int16_t *) data = value; } break; case blr_long : if( arrayDesc_.array_desc_scale != 0 && value.type() == ksys::mtFloat ){ v = value; for( intptr_t j = arrayDesc_.array_desc_scale; j < 0; j++ ) v *= 10; *(int32_t *) data = (int32_t) v; } else{ *(int32_t *) data = (int32_t) value; } break; case blr_float : *(float *) data = value; break; case blr_double : case blr_d_float : *(double *) data = value; break; case blr_sql_time : case blr_sql_date : case blr_timestamp : *(ISC_TIMESTAMP *) data = timeval2IscTimeStamp(value); break; case blr_quad : case blr_int64 : if( arrayDesc_.array_desc_scale != 0 && value.type() == ksys::mtFloat ){ v = value; for( intptr_t j = arrayDesc_.array_desc_scale; j < 0; j++ ) v *= 10; *(int64_t *) data = (int64_t) v; } else{ *(int64_t *) data = value; } break; default : newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); } return *this; } //--------------------------------------------------------------------------- ksys::Mutant DSQLParam::getMutantFromArray(uintptr_t absIndex) { if( sqlind_ < 0 ) return ksys::Mutant(); checkData(); uintptr_t elementOffset = elementSize_ * absIndex; ldouble v; if( elementOffset < (uintptr_t) dataSize_ ){ const char * data = (char *) data_ + elementOffset; switch( arrayDesc_.array_desc_dtype ){ case blr_varying : return utf8::plane(data + sizeof(short),uintptr_t(*(short *) data)); case blr_text : return utf8::plane(data,elementSize_); case blr_short : if( arrayDesc_.array_desc_scale != 0 ){ v = *(int16_t *) data; for( intptr_t j = arrayDesc_.array_desc_scale; j < 0; j++ ) v /= 10; return v; } return *(int16_t *) data; case blr_long : if( arrayDesc_.array_desc_scale != 0 ){ v = *(int32_t *) data; for( intptr_t j = arrayDesc_.array_desc_scale; j < 0; j++ ) v /= 10; return v; } return *(int32_t *) data; case blr_float : return *(float *) data; case blr_double : case blr_d_float : return *(double *) data; case blr_sql_time : case blr_sql_date : case blr_timestamp : return iscTimeStamp2Timeval(*(ISC_TIMESTAMP *) data); case blr_quad : case blr_int64 : if( arrayDesc_.array_desc_scale != 0 ){ v = (ldouble) * (int64_t *) data; for( intptr_t j = arrayDesc_.array_desc_scale; j < 0; j++ ) v /= 10; return v; } return *(int64_t *) data; } } newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); exit(ENOSYS); } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::writeBuffer(const void * buf,uintptr_t size) { if( next_ != NULL ) next_->writeBuffer(buf,size); while( size > 0 ){ uintptr_t asize = size > 32767 ? 32767 : size; ISC_STATUS_ARRAY status; if( api.isc_put_segment(status,&handle_,(short) asize,(char *) buf) != 0 ) statement_->database_->exceptionHandler( newObjectV1C2(status, __PRETTY_FUNCTION__) ); buf = (const char *) buf + asize; size -= asize; } sqlind_ = 0; return *this; } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::setNull() { if( next_ != NULL ) next_->setNull(); sqlind_ = -1; cancelBlob(); clear(); return *this; } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::putSlice() { if( sqlind_ >= 0 ) statement_->arrayPutSlice(id_,arrayDesc_,data_,dataSize_); return *this; } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::createBlob() { statement_->createBlob(handle_,id_,0,NULL); return *this; } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::closeBlob() { statement_->closeBlob(handle_); return *this; } //--------------------------------------------------------------------------- DSQLParam & DSQLParam::cancelBlob() { statement_->cancelBlob(handle_); return *this; } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- DSQLParams::~DSQLParams() { } //--------------------------------------------------------------------------- DSQLParams::DSQLParams() : statement_(NULL), paramsAutoDrop_(params_) { } //--------------------------------------------------------------------------- DSQLParams & DSQLParams::bind() { for( intptr_t j, i = indexToParam_.count() - 1; i >= 0; i-- ){ DSQLParam * param = indexToParam_[i]; XSQLVAR & v = sqlda_.sqlda()->sqlvar[i]; switch( v.sqltype & ~1 ){ case SQL_VARYING : case SQL_TEXT : v.sqltype = (int16_t) (SQL_TEXT | (v.sqltype & 1)); v.sqllen = (int16_t) param->text_.size(); v.sqldata = param->text_.c_str(); break; case SQL_SHORT : case SQL_LONG : v.sqldata = (char *) ¶m->bigInt_; break; case SQL_FB_FLOAT : v.sqldata = (char *) ¶m->float_; for( j = v.sqlscale; j < 0; j++ ) param->float_ *= 10; break; case SQL_FB_DOUBLE : case SQL_D_FLOAT : v.sqldata = (char *) ¶m->double_; for( j = v.sqlscale; j < 0; j++ ) param->double_ *= 10; break; case SQL_FB_TYPE_TIME : case SQL_FB_TYPE_DATE : case SQL_FB_TIMESTAMP : v.sqldata = (char *) ¶m->timeStamp_; break; case SQL_QUAD : case SQL_INT64 : v.sqldata = (char *) ¶m->bigInt_; break; case SQL_BLOB : v.sqldata = (char *) ¶m->id_; break; case SQL_ARRAY : v.sqldata = (char *) ¶m->id_; param->putSlice(); } v.sqlind = ¶m->sqlind_; param->sqltype_ = v.sqltype; param->sqlscale_ = (char) v.sqlscale; } return *this; } //--------------------------------------------------------------------------- DSQLParam * DSQLParams::checkParamIndex(uintptr_t i) { if( i >= indexToParam_.count() ) newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); return indexToParam_[i]; } //--------------------------------------------------------------------------- DSQLParam * DSQLParams::checkParamName(const utf8::String & paramName) { DSQLParam fp(NULL,paramName); DSQLParam * param = params_.find(fp); if( param == NULL ) newObjectV1C2((const ISC_STATUS *) NULL, __PRETTY_FUNCTION__)->throwSP(); return param; } //--------------------------------------------------------------------------- } // namespace fbcpp //---------------------------------------------------------------------------