/* Copyright (C) 2014 InfiniDB, Inc. Copyright (c) 2019 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // $Id: frameboundrange.cpp 3932 2013-06-25 16:08:10Z xlou $ //#define NDEBUG #include #include #include #include using namespace std; #include "idberrorinfo.h" #include "errorids.h" #include "exceptclasses.h" using namespace logging; #include "idborderby.h" using namespace ordering; #include "frameboundrange.h" namespace windowfunction { int64_t FrameBoundRange::getBound(int64_t b, int64_t e, int64_t c) { if (fStart) { while (c > b) { if (!fPeer->operator()(getPointer(fRowData->at(c)), getPointer(fRowData->at(c - 1)))) break; c--; } } else { while (c < e) { if (!fPeer->operator()(getPointer(fRowData->at(c)), getPointer(fRowData->at(c + 1)))) break; c++; } } return c; } const string FrameBoundRange::toString() const { return FrameBound::toString(); } template int64_t FrameBoundConstantRange::getBound(int64_t b, int64_t e, int64_t c) { // set row data fRow.setData(getPointer(fRowData->at(c))); getValue(fValue, fIndex[2]); // make sure the expr is not negative validate(); // calculate the offset, and move if (fIsZero) c = FrameBoundRange::getBound(b, e, c); else if (fBoundType < WF__CURRENT_ROW) c -= getPrecedingOffset(c, b); else c += getFollowingOffset(c, e); return c; } template int64_t FrameBoundConstantRange::getPrecedingOffset(int64_t c, int64_t b) { // test each row to find the bound bool next = true; int64_t i = c; int64_t j = 0; for (i--, j++; i >= b && next; i--, j++) { // set row data, get order by column value fRow.setData(getPointer(fRowData->at(i))); ValueType v; getValue(v, fIndex[0]); if (v.fIsNull) { next = fValue.fIsNull; // let null = null } else if (fValue.fIsNull) { next = false; } else if (fAsc && v.fValue < fValue.fValue) { next = false; } else if (!fAsc && v.fValue > fValue.fValue) { next = false; } else if (!fStart && v.fValue == fValue.fValue) { next = false; } } if (!next) { if (fStart) j -= 2; else j -= 1; } return j; } template int64_t FrameBoundConstantRange::getFollowingOffset(int64_t c, int64_t e) { // test each row to find the bound bool next = true; int64_t i = c; int64_t j = 0; for (i++, j++; i <= e && next; i++, j++) { // set row data, get order by column value fRow.setData(getPointer(fRowData->at(i))); ValueType v; getValue(v, fIndex[0]); if (v.fIsNull) { next = fValue.fIsNull; // let null = null } else if (fValue.fIsNull) { next = false; } else if (fAsc && v.fValue > fValue.fValue) { next = false; } else if (!fAsc && v.fValue < fValue.fValue) { next = false; } else if (fStart && v.fValue == fValue.fValue) { next = false; } } if (!next) { if (fStart) j -= 1; else j -= 2; } return j; } template void FrameBoundConstantRange::getValue(ValueType& v, int64_t i) { v.fIsNull = fRow.isNullValue(i); if (!v.fIsNull) v.fValue = fRow.getIntField(i); } template T FrameBoundConstantRange::getValueByType(int64_t i) { T t; return t; } template<> int64_t FrameBoundConstantRange::getValueByType(int64_t i) { return fRow.getIntField(i); } template<> uint64_t FrameBoundConstantRange::getValueByType(int64_t i) { uint64_t v = fRow.getUintField(i); // convert date to datetime, [refer to treenode.h] if (fRow.getColType(fIndex[0]) == execplan::CalpontSystemCatalog::DATE && i == 0) v = v << 32; return v; } template<> double FrameBoundConstantRange::getValueByType(int64_t i) { return fRow.getDoubleField(i); } template<> float FrameBoundConstantRange::getValueByType(int64_t i) { return fRow.getFloatField(i); } template const string FrameBoundConstantRange::toString() const { ostringstream oss; oss << fValue.fValue << " " << FrameBound::toString(); return oss.str(); } template int64_t FrameBoundExpressionRange::getPrecedingOffset(int64_t c, int64_t b) { return FrameBoundConstantRange::getPrecedingOffset(c, b); } template int64_t FrameBoundExpressionRange::getFollowingOffset(int64_t c, int64_t e) { return FrameBoundConstantRange::getFollowingOffset(c, e); } template void FrameBoundExpressionRange::validate() { bool invalid = false; ostringstream oss; if (this->fRow.isNullValue(this->fIndex[1])) { invalid = true; oss << "NULL"; } else { switch (this->fRow.getColType(this->fIndex[1])) { case execplan::CalpontSystemCatalog::TINYINT: case execplan::CalpontSystemCatalog::SMALLINT: case execplan::CalpontSystemCatalog::MEDINT: case execplan::CalpontSystemCatalog::INT: case execplan::CalpontSystemCatalog::BIGINT: { int64_t tmp = this->fRow.getIntField(this->fIndex[1]); this->fIsZero = (tmp == 0); if (tmp < 0) { invalid = true; oss << tmp; } break; } case execplan::CalpontSystemCatalog::DECIMAL: { if (UNLIKELY(this->fRow.getColumnWidth(this->fIndex[1]) < datatypes::MAXDECIMALWIDTH)) { int64_t tmp = this->fRow.getIntField(this->fIndex[1]); this->fIsZero = (tmp == 0); if (tmp < 0) { invalid = true; oss << ""; } } else { datatypes::TSInt128 tmp = this->fRow.getTSInt128Field(this->fIndex[1]); this->fIsZero = (tmp == 0); if (tmp < 0) { invalid = true; oss << ""; } } break; } case execplan::CalpontSystemCatalog::UDECIMAL: { if (UNLIKELY(this->fRow.getColumnWidth(this->fIndex[1]) < datatypes::MAXDECIMALWIDTH)) { uint64_t tmp = this->fRow.getUintField(this->fIndex[1]); this->fIsZero = (tmp == 0); } else { datatypes::TSInt128 tmp = this->fRow.getTSInt128Field(this->fIndex[1]); this->fIsZero = (tmp == 0); } break; } case execplan::CalpontSystemCatalog::DOUBLE: case execplan::CalpontSystemCatalog::UDOUBLE: { double tmp = this->fRow.getDoubleField(this->fIndex[1]); this->fIsZero = (tmp == 0.0); if (tmp < 0) { invalid = true; oss << tmp; } break; } case execplan::CalpontSystemCatalog::LONGDOUBLE: { long double tmp = this->fRow.getLongDoubleField(this->fIndex[1]); this->fIsZero = (tmp == 0.0); if (tmp < 0) { invalid = true; oss << tmp; } break; } case execplan::CalpontSystemCatalog::FLOAT: case execplan::CalpontSystemCatalog::UFLOAT: { float tmp = this->fRow.getFloatField(this->fIndex[1]); this->fIsZero = (tmp == 0.0); if (tmp < 0) { invalid = true; oss << tmp; } break; } case execplan::CalpontSystemCatalog::UTINYINT: case execplan::CalpontSystemCatalog::USMALLINT: case execplan::CalpontSystemCatalog::UMEDINT: case execplan::CalpontSystemCatalog::UINT: case execplan::CalpontSystemCatalog::UBIGINT: default: { uint64_t tmp = this->fRow.getUintField(this->fIndex[1]); this->fIsZero = (tmp == 0); break; } } } if (invalid) { oss << " (expr)"; throw IDBExcept(IDBErrorInfo::instance()->errorMsg(ERR_WF_BOUND_OUT_OF_RANGE, oss.str()), ERR_WF_BOUND_OUT_OF_RANGE); } } template const string FrameBoundExpressionRange::toString() const { ostringstream oss; oss << " value_expr " << FrameBound::toString(); return oss.str(); } template class FrameBoundConstantRange; template class FrameBoundConstantRange; template class FrameBoundConstantRange; template class FrameBoundConstantRange; template class FrameBoundExpressionRange; template class FrameBoundExpressionRange; template class FrameBoundExpressionRange; template class FrameBoundExpressionRange; } //namespace // vim:ts=4 sw=4: