CastInstruction.h

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/calculator/CastInstruction.h#5 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2004-2009 SQLstream, Inc.
00006 // Copyright (C) 2009-2009 LucidEra, Inc.
00007 //
00008 // This program is free software; you can redistribute it and/or modify it
00009 // under the terms of the GNU General Public License as published by the Free
00010 // Software Foundation; either version 2 of the License, or (at your option)
00011 // any later version approved by The Eigenbase Project.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 #ifndef Fennel_CastInstruction_Included
00023 #define Fennel_CastInstruction_Included
00024 
00025 #include "fennel/calculator/NativeInstruction.h"
00026 #include <boost/cast.hpp>
00027 
00028 FENNEL_BEGIN_NAMESPACE
00029 
00035 template<typename RESULT_T, typename SOURCE_T>
00036 class CastInstruction : public Instruction
00037 {
00038 public:
00039     explicit
00040     CastInstruction(
00041         RegisterRef<RESULT_T>* result,
00042         RegisterRef<SOURCE_T>* op,
00043         StandardTypeDescriptorOrdinal resultType,
00044         StandardTypeDescriptorOrdinal sourceType)
00045         : mResult(result),
00046           mOp1(op),
00047           mOp2(NULL)
00048     {}
00049 
00050     virtual
00051     ~CastInstruction() {}
00052 
00053 protected:
00054     RegisterRef<RESULT_T>* mResult;
00055     RegisterRef<SOURCE_T>* mOp1;
00056     RegisterRef<SOURCE_T>* mOp2; // may be unused
00057 };
00058 
00059 template<typename RESULT_T, typename SOURCE_T>
00060 class CastCast : public CastInstruction<RESULT_T, SOURCE_T>
00061 {
00062 public:
00063     explicit
00064     CastCast(
00065         RegisterRef<RESULT_T>* result,
00066         RegisterRef<SOURCE_T>* op1,
00067         StandardTypeDescriptorOrdinal resultType,
00068         StandardTypeDescriptorOrdinal sourceType)
00069         : CastInstruction<RESULT_T, SOURCE_T>(
00070             result, op1, resultType, sourceType)
00071     {}
00072 
00073     virtual
00074     ~CastCast() {}
00075 
00076     virtual void exec(TProgramCounter& pc) const {
00077         // See SQL99 Part 2 Section 6.22 for specification of CAST() operator
00078         pc++;
00079         if (CastInstruction<RESULT_T, SOURCE_T>::mOp1->isNull()) {
00080             // SQL99 Part 2 Section 6.22 General Rule 2.c.
00081             CastInstruction<RESULT_T, SOURCE_T>::mResult->toNull();
00082         } else {
00083             // TODO: Update Boost library to fix the following
00084             // TODO: problem:
00085             // TODO: See lists.boost.org/MailArchives/boost/msg63700.php
00086             // TODO: for details. In short, exceptions are thrown
00087             // TODO: for cases where data is lost and the target is
00088             // TODO: unsigned, but not thrown for lost data to signed.
00089             // TODO: Also some problems with approx being cast to exact.
00090 
00091             // HACK: Add some extra tests before numeric_cast to try
00092             // HACK: to catch some of the more henious and obvious errors.
00093 
00094             SOURCE_T src = CastInstruction<RESULT_T, SOURCE_T>::mOp1->value();
00095             bool thr = false;
00096             bool resultSigned = numeric_limits<RESULT_T>::is_signed;
00097             bool sourceSigned = numeric_limits<SOURCE_T>::is_signed;
00098 
00099             // Note: min() for approx type is the smallest positive
00100             // number, not the most negative number.
00101             RESULT_T min = (numeric_limits<RESULT_T>::is_integer ?
00102                             numeric_limits<RESULT_T>::min() :
00103                             - numeric_limits<RESULT_T>::max());
00104             RESULT_T max = numeric_limits<RESULT_T>::max();
00105 
00106             if (resultSigned == sourceSigned) {
00107                 // Both signed or both unsigned (including approx)
00108                 if (max < src || min > src) {
00109                     thr = true;
00110                 }
00111             } else if (resultSigned && !sourceSigned) {
00112                 // Unsigned to signed
00113                 if (max < src) {
00114                     thr = true;
00115                 }
00116             } else {
00117                 // Signed to unsigned
00118                 // RESULT_T is unsigned, SOURCE is signed
00119                 if (max < src || min > src) {
00120                     thr = true;
00121                 }
00122             }
00123             if (thr) {
00124                 throw CalcMessage("22003", pc - 1);
00125             }
00126             // HACK: End. (Phew.)
00127 
00128             try {
00129                 CastInstruction<RESULT_T, SOURCE_T>::mResult->value(
00130                     boost::numeric_cast<RESULT_T>(
00131                         CastInstruction<RESULT_T, SOURCE_T>::mOp1->value()));
00132             } catch (boost::bad_numeric_cast) {
00133                 // class contains no useful information about what went wrong
00134                 // SQL99 Part 2 Section 6.2 General Rule 6.a.ii, 7.a.ii
00135                 // 22003 - Data Exception -- Numeric Value Out of Range
00136                 throw CalcMessage("22003", pc - 1);
00137             }
00138         }
00139     }
00140 
00141     static const char* longName()
00142     {
00143         return "NativeCast";
00144     }
00145 
00146     static const char* shortName()
00147     {
00148         return "CAST";
00149     }
00150 
00151     static int numArgs()
00152     {
00153         return 2;
00154     }
00155 
00156     void describe(string& out, bool values) const {
00157         RegisterRef<char> dummy;
00158         describeHelper(
00159             out, values, longName(), shortName(),
00160             CastInstruction<RESULT_T, SOURCE_T>::mResult,
00161             CastInstruction<RESULT_T, SOURCE_T>::mOp1,
00162             CastInstruction<RESULT_T, SOURCE_T>::mOp2);
00163     }
00164 
00165     static InstructionSignature
00166     signature(
00167         StandardTypeDescriptorOrdinal type1,
00168         StandardTypeDescriptorOrdinal type2)
00169     {
00170         vector<StandardTypeDescriptorOrdinal> v;
00171         v.push_back(type1);
00172         v.push_back(type2);
00173         return InstructionSignature(shortName(), v);
00174     }
00175 
00176     static Instruction*
00177     create(InstructionSignature const & sig)
00178     {
00179         assert(sig.size() == numArgs());
00180         return new CastCast(
00181             static_cast<RegisterRef<RESULT_T>*> (sig[0]),
00182             static_cast<RegisterRef<SOURCE_T>*> (sig[1]),
00183             (sig[0])->type(),
00184             (sig[1])->type());
00185     }
00186 };
00187 
00188 #define TTT(a)
00189 
00190 class FENNEL_CALCULATOR_EXPORT CastInstructionRegister
00191     : InstructionRegister {
00192 
00193     // TODO: Refactor registerTypes to class InstructionRegister
00194     template < template <typename, typename > class INSTCLASS2 >
00195     static void
00196     registerTypes(
00197         vector<StandardTypeDescriptorOrdinal> const & t1,
00198         vector<StandardTypeDescriptorOrdinal> const & t2)
00199     {
00200         for (uint i = 0; i < t1.size(); i++) {
00201             for (uint j = 0; j < t2.size(); j++) {
00202                 StandardTypeDescriptorOrdinal type1 = t1[i];
00203                 StandardTypeDescriptorOrdinal type2 = t2[j];
00204                 // Types <char,char> below is a placeholder and is ignored.
00205                 InstructionSignature sig =
00206                     INSTCLASS2<char, char>::signature(type1, type2);
00207 #include "fennel/calculator/InstructionRegisterSwitchCast.h"
00208                 // Note: Above .h includes a throw std::logic_error if
00209                 // type combination cannot be found.
00210             }
00211         }
00212     }
00213 
00214 public:
00215     static void
00216     registerInstructions() {
00217         vector<StandardTypeDescriptorOrdinal> t;
00218         t = InstructionSignature::typeVector
00219             (StandardTypeDescriptor::isNativeNotBool);
00220 
00221         // Have to do full fennel:: qualification of template
00222         // arguments below to prevent template argument 'TMPLT', of
00223         // this encapsulating class, from perverting NativeAdd into
00224         // NativeAdd<TMPLT> or something like
00225         // that. Anyway. Fennel::NativeAdd works just fine.
00226         registerTypes<fennel::CastCast>(t, t);
00227     }
00228 };
00229 
00230 
00231 FENNEL_END_NAMESPACE
00232 
00233 #endif
00234 
00235 // End CastInstruction.h
00236 

Generated on Mon Jun 22 04:00:17 2009 for Fennel by  doxygen 1.5.1