/*############################################################################## Copyright (C) 2011 HPCC Systems. All rights reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . ############################################################################## */ #include "platform.h" #include #include #include "jmisc.hpp" #include "jlib.hpp" #include "eclhelper.hpp" #include "eclrtl_imp.hpp" #include "rtlfield_imp.hpp" static const char * queryXPath(const RtlFieldInfo * field) { const char * xpath = field->xpath; if (xpath) { const char * sep = strchr(xpath, xpathCompoundSeparatorChar); if (!sep) return xpath; return sep+1; } return field->name->str(); } static bool hasOuterXPath(const RtlFieldInfo * field) { const char * xpath = field->xpath; assertex(xpath); return (*xpath != xpathCompoundSeparatorChar); } static void queryNestedOuterXPath(StringAttr & ret, const RtlFieldInfo * field) { const char * xpath = field->xpath; assertex(xpath); const char * sep = strchr(xpath, xpathCompoundSeparatorChar); assertex(sep); ret.set(xpath, (size32_t)(sep-xpath)); } //------------------------------------------------------------------------------------------------------------------- size32_t RtlTypeInfoBase::size(const byte * self, const byte * selfrow) const { return length; } size32_t RtlTypeInfoBase::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { rtlFailUnexpected(); return 0; } size32_t RtlTypeInfoBase::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & out) const { rtlFailUnexpected(); return 0; } void RtlTypeInfoBase::serialize(IRtlFieldTypeSerializer & out) const { rtlFailUnexpected(); } void RtlTypeInfoBase::deserialize(IRtlFieldTypeDeserializer & in) { rtlFailUnexpected(); } const char * RtlTypeInfoBase::queryLocale() const { return NULL; } const RtlFieldInfo * const * RtlTypeInfoBase::queryFields() const { return NULL; } const RtlTypeInfo * RtlTypeInfoBase::queryChildType() const { return NULL; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlBoolTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { target.processBool(*(const bool *)self, field); return sizeof(bool); } size32_t RtlBoolTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { target.outputBool(*(const bool *)self, queryXPath(field)); return sizeof(bool); } //------------------------------------------------------------------------------------------------------------------- double RtlRealTypeInfo::value(const byte * self) const { if (length == 4) return *(const float *)self; return *(const double *)self; } size32_t RtlRealTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { target.processReal(value(self), field); return length; } size32_t RtlRealTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { target.outputReal(value(self), queryXPath(field)); return length; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlIntTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { if (isUnsigned()) target.processUInt(rtlReadUInt(self, length), field); else target.processInt(rtlReadInt(self, length), field); return length; } size32_t RtlIntTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { if (isUnsigned()) target.outputUInt(rtlReadUInt(self, length), queryXPath(field)); else target.outputInt(rtlReadInt(self, length), queryXPath(field)); return length; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlSwapIntTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { if (isUnsigned()) target.processUInt(rtlReadSwapUInt(self, length), field); else target.processInt(rtlReadSwapInt(self, length), field); return length; } size32_t RtlSwapIntTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { if (isUnsigned()) target.outputUInt(rtlReadSwapUInt(self, length), queryXPath(field)); else target.outputInt(rtlReadSwapInt(self, length), queryXPath(field)); return length; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlPackedIntTypeInfo::size(const byte * self, const byte * selfrow) const { return rtlGetPackedSize(self); } size32_t RtlPackedIntTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { if (isUnsigned()) target.processUInt(rtlGetPackedUnsigned(self), field); else target.processInt(rtlGetPackedSigned(self), field); return rtlGetPackedSize(self); } size32_t RtlPackedIntTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { if (isUnsigned()) target.outputUInt(rtlGetPackedUnsigned(self), queryXPath(field)); else target.outputInt(rtlGetPackedSigned(self), queryXPath(field)); return rtlGetPackedSize(self); } //------------------------------------------------------------------------------------------------------------------- size32_t RtlStringTypeInfo::size(const byte * self, const byte * selfrow) const { if (isFixedSize()) return length; return sizeof(size32_t) + rtlReadUInt4(self); } size32_t RtlStringTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { const char * str = reinterpret_cast(self); unsigned thisLength; unsigned thisSize; if (isFixedSize()) { thisLength = length; thisSize = thisLength; } else { str = reinterpret_cast(self + sizeof(size32_t)); thisLength = rtlReadUInt4(self); thisSize = sizeof(size32_t) + thisLength; } if (isEbcdic()) { unsigned lenAscii; rtlDataAttr ascii; rtlEStrToStrX(lenAscii, ascii.refstr(), thisLength, str); target.processString(lenAscii, ascii.getstr(), field); } else { target.processString(thisLength, str, field); } return thisSize; } size32_t RtlStringTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { const char * str = reinterpret_cast(self); unsigned thisLength; unsigned thisSize; if (isFixedSize()) { thisLength = length; thisSize = thisLength; } else { str = reinterpret_cast(self + sizeof(size32_t)); thisLength = rtlReadUInt4(self); thisSize = sizeof(size32_t) + thisLength; } if (isEbcdic()) { unsigned lenAscii; rtlDataAttr ascii; rtlEStrToStrX(lenAscii, ascii.refstr(), thisLength, str); target.outputString(lenAscii, ascii.getstr(), queryXPath(field)); } else { target.outputString(thisLength, str, queryXPath(field)); } return thisSize; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlDataTypeInfo::size(const byte * self, const byte * selfrow) const { if (isFixedSize()) return length; return sizeof(size32_t) + rtlReadUInt4(self); } size32_t RtlDataTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { const char * str = reinterpret_cast(self); unsigned thisLength; unsigned thisSize; if (isFixedSize()) { thisLength = length; thisSize = thisLength; } else { str = reinterpret_cast(self + sizeof(size32_t)); thisLength = rtlReadUInt4(self); thisSize = sizeof(size32_t) + thisLength; } target.processData(thisLength, str, field); return thisSize; } size32_t RtlDataTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { const char * str = reinterpret_cast(self); unsigned thisLength; unsigned thisSize; if (isFixedSize()) { thisLength = length; thisSize = thisLength; } else { str = reinterpret_cast(self + sizeof(size32_t)); thisLength = rtlReadUInt4(self); thisSize = sizeof(size32_t) + thisLength; } target.outputData(thisLength, str, queryXPath(field)); return thisSize; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlVarStringTypeInfo::size(const byte * self, const byte * selfrow) const { if (isFixedSize()) return length + 1; const char * str = reinterpret_cast(self); return (size32_t)strlen(str)+1; } size32_t RtlVarStringTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { const char * str = reinterpret_cast(self); unsigned thisLength = (size32_t)strlen(str); unsigned thisSize; if (isFixedSize()) thisSize = length+1; else thisSize = thisLength+1; if (isEbcdic()) { unsigned lenAscii; rtlDataAttr ascii; rtlEStrToStrX(lenAscii, ascii.refstr(), thisLength, str); target.processString(lenAscii, ascii.getstr(), field); } else target.processString(thisLength, str, field); return thisSize; } size32_t RtlVarStringTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { const char * str = reinterpret_cast(self); unsigned thisLength = (size32_t)strlen(str); unsigned thisSize; if (isFixedSize()) thisSize = length+1; else thisSize = thisLength+1; if (isEbcdic()) { unsigned lenAscii; rtlDataAttr ascii; rtlEStrToStrX(lenAscii, ascii.refstr(), thisLength, str); target.outputString(lenAscii, ascii.getstr(), queryXPath(field)); } else target.outputString(thisLength, str, queryXPath(field)); return thisSize; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlQStringTypeInfo::size(const byte * self, const byte * selfrow) const { if (isFixedSize()) return rtlQStrSize(length); return sizeof(size32_t) + rtlQStrSize(rtlReadUInt4(self)); } size32_t RtlQStringTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { const char * str = reinterpret_cast(self); unsigned thisLength; unsigned thisSize; if (isFixedSize()) { thisLength = length; thisSize = rtlQStrSize(thisLength); } else { str = reinterpret_cast(self + sizeof(size32_t)); thisLength = rtlReadUInt4(self); thisSize = sizeof(size32_t) + rtlQStrSize(thisLength); } target.processQString(thisLength, str, field); return thisSize; } size32_t RtlQStringTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { const char * str = reinterpret_cast(self); unsigned thisLength; unsigned thisSize; if (isFixedSize()) { thisLength = length; thisSize = rtlQStrSize(thisLength); } else { str = reinterpret_cast(self + sizeof(size32_t)); thisLength = rtlReadUInt4(self); thisSize = sizeof(size32_t) + rtlQStrSize(thisLength); } target.outputQString(thisLength, str, queryXPath(field)); return thisSize; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlDecimalTypeInfo::calcSize() const { if (isUnsigned()) return (getDecimalDigits()+1)/2; return (getDecimalDigits()+2)/2; } size32_t RtlDecimalTypeInfo::size(const byte * self, const byte * selfrow) const { return calcSize(); } size32_t RtlDecimalTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { size32_t thisSize = calcSize(); if (isUnsigned()) target.processUDecimal(self, thisSize, getDecimalPrecision(), field); else target.processDecimal(self, thisSize, getDecimalPrecision(), field); return thisSize; } size32_t RtlDecimalTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { size32_t thisSize = calcSize(); if (isUnsigned()) target.outputUDecimal(self, thisSize, getDecimalPrecision(), queryXPath(field)); else target.outputDecimal(self, thisSize, getDecimalPrecision(), queryXPath(field)); return thisSize; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlCharTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { const char * str = reinterpret_cast(self); char c; if (isEbcdic()) rtlEStrToStr(1, &c, 1, str); else c = *str; target.processString(1, &c, field); return 1; } size32_t RtlCharTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { const char * str = reinterpret_cast(self); char c; if (isEbcdic()) rtlEStrToStr(1, &c, 1, str); else c = *str; target.outputString(1, &c, queryXPath(field)); return 1; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlUnicodeTypeInfo::size(const byte * self, const byte * selfrow) const { if (isFixedSize()) return length * sizeof(UChar); return sizeof(size32_t) + rtlReadUInt4(self) * sizeof(UChar); } size32_t RtlUnicodeTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { const UChar * ustr = reinterpret_cast(self); unsigned thisLength; unsigned thisSize; if (isFixedSize()) { thisLength = length; thisSize = thisLength * sizeof(UChar); } else { ustr = reinterpret_cast(self + sizeof(size32_t)); thisLength = rtlReadUInt4(self); thisSize = sizeof(size32_t) + thisLength * sizeof(UChar); } target.processUnicode(thisLength, ustr, field); return thisSize; } size32_t RtlUnicodeTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { const UChar * ustr = reinterpret_cast(self); unsigned thisLength; unsigned thisSize; if (isFixedSize()) { thisLength = length; thisSize = thisLength * sizeof(UChar); } else { ustr = reinterpret_cast(self + sizeof(size32_t)); thisLength = rtlReadUInt4(self); thisSize = sizeof(size32_t) + thisLength * sizeof(UChar); } target.outputUnicode(thisLength, ustr, queryXPath(field)); return thisSize; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlVarUnicodeTypeInfo::size(const byte * self, const byte * selfrow) const { if (isFixedSize()) return (length+1) * sizeof(UChar); const UChar * ustr = reinterpret_cast(self); return (rtlUnicodeStrlen(ustr)+1) * sizeof(UChar); } size32_t RtlVarUnicodeTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { const UChar * ustr = reinterpret_cast(self); unsigned thisLength = rtlUnicodeStrlen(ustr); unsigned thisSize; if (isFixedSize()) thisSize = (length + 1) * sizeof(UChar); else thisSize = (thisLength + 1) * sizeof(UChar); target.processUnicode(thisLength, ustr, field); return thisSize; } size32_t RtlVarUnicodeTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { const UChar * ustr = reinterpret_cast(self); unsigned thisLength = rtlUnicodeStrlen(ustr); unsigned thisSize; if (isFixedSize()) thisSize = (length + 1) * sizeof(UChar); else thisSize = (thisLength + 1) * sizeof(UChar); target.outputUnicode(thisLength, ustr, queryXPath(field)); return thisSize; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlUtf8TypeInfo::size(const byte * self, const byte * selfrow) const { assertex(!isFixedSize()); return sizeof(size32_t) + rtlUtf8Size(rtlReadUInt4(self), self+sizeof(unsigned)); } size32_t RtlUtf8TypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { assertex(!isFixedSize()); const char * str = reinterpret_cast(self + sizeof(size32_t)); unsigned thisLength = rtlReadUInt4(self); unsigned thisSize = sizeof(size32_t) + rtlUtf8Size(thisLength, str); target.processUtf8(thisLength, str, field); return thisSize; } size32_t RtlUtf8TypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { assertex(!isFixedSize()); const char * str = reinterpret_cast(self + sizeof(size32_t)); unsigned thisLength = rtlReadUInt4(self); unsigned thisSize = sizeof(size32_t) + rtlUtf8Size(thisLength, str); target.outputUtf8(thisLength, str, queryXPath(field)); return thisSize; } //------------------------------------------------------------------------------------------------------------------- inline size32_t sizeFields(const RtlFieldInfo * const * cur, const byte * self, const byte * selfrow) { unsigned offset = 0; loop { const RtlFieldInfo * child = *cur; if (!child) break; offset += child->size(self+offset, selfrow); cur++; } return offset; } inline size32_t processFields(const RtlFieldInfo * const * cur, const byte * self, const byte * selfrow, IFieldProcessor & target) { unsigned offset = 0; loop { const RtlFieldInfo * child = *cur; if (!child) break; child->process(self+offset, selfrow, target); offset += child->size(self+offset, selfrow); cur++; } return offset; } inline size32_t toXMLFields(const RtlFieldInfo * const * cur, const byte * self, const byte * selfrow, IXmlWriter & target) { size32_t offset = 0; loop { const RtlFieldInfo * child = *cur; if (!child) break; size32_t size = child->toXML(self+offset, selfrow, target); offset += size; cur++; } return offset; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlRecordTypeInfo::size(const byte * self, const byte * selfrow) const { return sizeFields(fields, self, self); } size32_t RtlRecordTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { if (target.processBeginRow(field)) { unsigned offset = processFields(fields, self, self, target); target.processEndRow(field); return offset; } return size(self, selfrow); } size32_t RtlRecordTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { const char * xpath = queryXPath(field); if (*xpath) target.outputBeginNested(xpath, false); unsigned thisSize = toXMLFields(fields, self, self, target); if (*xpath) target.outputEndNested(xpath); return thisSize; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlSetTypeInfo::size(const byte * self, const byte * selfrow) const { return sizeof(bool) + sizeof(size32_t) + rtlReadUInt4(self + sizeof(bool)); } size32_t RtlSetTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { unsigned offset = sizeof(bool) + sizeof(size32_t); unsigned max = offset + rtlReadUInt4(self + sizeof(bool)); if (target.processBeginSet(field)) { if (*(bool *)self) target.processSetAll(field); else { while (offset < max) { offset += child->process(self+offset, selfrow, field, target); } } target.processEndSet(field); } return max; } size32_t RtlSetTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { unsigned offset = sizeof(bool) + sizeof(size32_t); unsigned max = offset + rtlReadUInt4(self + sizeof(bool)); StringAttr outerTag; if (hasOuterXPath(field)) { queryNestedOuterXPath(outerTag, field); target.outputBeginNested(outerTag, false); } if (*(bool *)self) target.outputSetAll(); else { while (offset < max) { child->toXML(self+offset, selfrow, field, target); offset += child->size(self+offset, selfrow); } } if (outerTag) target.outputEndNested(outerTag); return max; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlRowTypeInfo::size(const byte * self, const byte * selfrow) const { if (isLinkCounted()) return sizeof(void *); return child->size(self, selfrow); } size32_t RtlRowTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { if (isLinkCounted()) { const byte * row = *(const byte * *)self; if (row) child->process(row, row, field, target); return sizeof(row); } return child->process(self, self, field, target); } size32_t RtlRowTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { if (isLinkCounted()) { const byte * row = *(const byte * *)self; child->toXML(row, row, field, target); return sizeof(row); } return child->toXML(self, self, field, target); } //------------------------------------------------------------------------------------------------------------------- size32_t RtlDatasetTypeInfo::size(const byte * self, const byte * selfrow) const { if (isLinkCounted()) return sizeof(size32_t) + sizeof(void * *); return sizeof(size32_t) + rtlReadUInt4(self); } size32_t RtlDatasetTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { if (isLinkCounted()) { if (target.processBeginDataset(field)) { size32_t thisCount = rtlReadUInt4(self); const byte * * rows = *reinterpret_cast(self + sizeof(size32_t)); for (unsigned i= 0; i < thisCount; i++) { const byte * row = rows[i]; child->process(row, row, field, target); } target.processEndDataset(field); } return sizeof(size32_t) + sizeof(void * *); } else { unsigned offset = sizeof(size32_t); unsigned max = offset + rtlReadUInt4(self); if (target.processBeginDataset(field)) { while (offset < max) { offset += child->process(self+offset, self+offset, field, target); } target.processEndDataset(field); } return max; } } size32_t RtlDatasetTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { StringAttr outerTag; if (hasOuterXPath(field)) { queryNestedOuterXPath(outerTag, field); target.outputBeginNested(outerTag, false); } unsigned thisSize; if (isLinkCounted()) { size32_t thisCount = rtlReadUInt4(self); const byte * * rows = *reinterpret_cast(self + sizeof(size32_t)); for (unsigned i= 0; i < thisCount; i++) { const byte * row = rows[i]; if (row) child->toXML(row, row, field, target); } thisSize = sizeof(size32_t) + sizeof(void * *); } else { unsigned offset = sizeof(size32_t); unsigned max = offset + rtlReadUInt4(self); while (offset < max) { child->toXML(self+offset, self+offset, field, target); offset += child->size(self+offset, self+offset); } thisSize = max; } if (outerTag) target.outputEndNested(outerTag); return thisSize; } //------------------------------------------------------------------------------------------------------------------- size32_t RtlIfBlockTypeInfo::size(const byte * self, const byte * selfrow) const { if (getCondition(selfrow)) return sizeFields(fields, self, selfrow); return 0; } size32_t RtlIfBlockTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { if (getCondition(selfrow)) return processFields(fields, self, selfrow, target); return 0; } size32_t RtlIfBlockTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { if (getCondition(selfrow)) return toXMLFields(fields, self, selfrow, target); return 0; } //------------------------------------------------------------------------------------------------------------------- __int64 RtlBitfieldTypeInfo::signedValue(const byte * self) const { __int64 value = rtlReadInt(self, getBitfieldIntSize()); unsigned shift = getBitfieldShift(); unsigned numBits = getBitfieldNumBits(); value <<= (sizeof(value) - shift - numBits); return value >> numBits; } unsigned __int64 RtlBitfieldTypeInfo::unsignedValue(const byte * self) const { unsigned __int64 value = rtlReadInt(self, getBitfieldIntSize()); unsigned shift = getBitfieldShift(); unsigned numBits = getBitfieldNumBits(); value <<= (sizeof(value) - shift - numBits); return value >> numBits; } size32_t RtlBitfieldTypeInfo::size(const byte * self, const byte * selfrow) const { if (fieldType & RFTMislastbitfield) return getBitfieldIntSize(); return 0; } size32_t RtlBitfieldTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { if (isUnsigned()) target.processUInt(unsignedValue(self), field); else target.processInt(signedValue(self), field); return size(self, selfrow); } size32_t RtlBitfieldTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { if (isUnsigned()) target.outputUInt(unsignedValue(self), queryXPath(field)); else target.outputInt(signedValue(self), queryXPath(field)); return size(self, selfrow); } //------------------------------------------------------------------------------------------------------------------- size32_t RtlUnimplementedTypeInfo::size(const byte * self, const byte * selfrow) const { rtlFailUnexpected(); return 0; } size32_t RtlUnimplementedTypeInfo::process(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IFieldProcessor & target) const { rtlFailUnexpected(); return 0; } size32_t RtlUnimplementedTypeInfo::toXML(const byte * self, const byte * selfrow, const RtlFieldInfo * field, IXmlWriter & target) const { rtlFailUnexpected(); return 0; } //------------------------------------------------------------------------------------------------------------------- RtlFieldStrInfo::RtlFieldStrInfo(const char * _name, const char * _xpath, const RtlTypeInfo * _type) : RtlFieldInfo(rtlCreateFieldNameAtom(_name), _xpath, _type) { } /* Stack: * Change hqlhtcpp so that the correct derived classes are generated. * Test so that toXML calls the default implementaions and check that the same values are generated. (Don't if contains ifblocks/alien) * Release * Think about bitfields - how do I know it is the last bitfield, how am I going to keep track of the offsets. * What code would need to be generated for alien datatypes. * Could have alien int and alien string varieties???? * What would an ecl interpreter look like (a special workunit?) helpers are interpreted? What about the graph? * Could I add associations to register user attributes - so a callback could know when they were assigned to? * Could I add ctx->noteLocation() into the generated code - so could put breakpoints on variables. * Add annotation when a member of the target dataset is updated. ctx->noteFieldAssigned(self, ); - does this include temporary datasets? ctx->noteAttributeX(, Int|String|Unicode| ctx->noteLocation(location); - reduce locations, so only one returned per line for a non-dataset? Should it just be the first item on the line that is tagged?? * Need static information about the breakpoints so debugger knows where to put valid brakpoints.... * Debugger will want to know about the type of the breakpoints. * Should try and compress the location format - possibly have a table of -># with breakpoint as 12:23 Also need some information about which datasets, and stored variables etc. are used so they can be displayed. - Most datasets can be deduced from the parameters passed into the transform - Some are trickier e.g., the extract, could possibly define some mappings - options to disable projects/other more complex operations inline (so easier to walk through) Bitfields: - Two separate questions: i) How is the meta information generated. ii) How is it stored internally in an IHqlExpression * ? * Could store the offset in the type - either in the base type of as a qualifier. + much easier code generation. - Doesn't provie an easy indication of the last field in a bitfield (because can't really modify after the fact) - Problematic when fields are removed to merge them. * Could add a bitfield container to the record. + Makes it easier to handle the last bitfield + Matches the structure used for the cursor. - Everything needs to walk the bitfield containers similar to ifblocks. - Makes it just as tricky to merge - Harder to create the record, unless the code is implicitly handled by appendOperand(). * The type of no_select could contain a modifier to indicate the offset/islast + the type of a no_select would have a 1:1 mapping with type info. - A bit complicated to calculate, especially when it isn't used much of the time => On Reflection is is probably easiest to keep the structure as it is (some comments should go in hqlexpr to avoid revisiting). * interperet bitfield offsets and "is last bitfield" dynamically + Greatly simplifies generating the meta - you can always use the field. - Requires another parameter and significant extra complexity for the uncommon case. (especially incrementing self) * Could generate from the expanded record instead of walking the record structure directly + That already knows how the bitfields are allocated, and could easily know which is the last field. - A field is no longer sufficient as key fr searching for the information. - Best would be a createFieldTypeKey(select-expr) which returns field when approriate, or modified if a bitfield. Then the pain is localised. * Output a bitfield container item into the type information + Solves the size problem - Individual bitfields still need to know their offsets, so doesn't solve the full problem. => Change so that either use meta to generate the information, or use no_select when appropriate to fidn out the nesc. information. Probably the latter for the moment. a) Create a key function and make sure it is always used. b) Need to work out how to generate no_ifblock. - ifblock is context dependent, so need to generate as part of the parent record, and in the parent record context. */