/*############################################################################## 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 "jliball.hpp" #include "hql.hpp" #include "platform.h" #include "jlib.hpp" #include "jexcept.hpp" #include "jmisc.hpp" #include "hql.hpp" #include "hqlexpr.hpp" #include "hqlfunc.hpp" #include "hqlcpputil.hpp" #include "hqlfold.hpp" #include "hqlutil.hpp" #include "hqlstmt.hpp" #include "hqlwcpp.hpp" #include "hqlcpp.ipp" #include "hqltcppc.ipp" #include "hqlhtcpp.ipp" #include "hqlcerrors.hpp" #include "hqlcatom.hpp" #include "hqlpmap.hpp" #include "hqlthql.hpp" #include "hqlattr.hpp" #include "hqlusage.hpp" //#define TraceExprPrintLog(x, expr) PrintLog(x ": %s", expr->toString(StringBuffer()).str()); //--------------------------------------------------------------------------- CChildSetColumnInfo::CChildSetColumnInfo(CContainerInfo * _container, CMemberInfo * _prior, IHqlExpression * _column) : CColumnInfo(_container, _prior, _column) { } void CChildSetColumnInfo::buildColumnExpr(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, CHqlBoundExpr & bound) { OwnedHqlExpr address = getColumnAddress(translator, ctx, selector, boolType, 0); OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, sizeof(bool)); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(bool)+sizeof(size32_t)); bound.isAll.setown(convertAddressToValue(address, boolType)); bound.length.setown(convertAddressToValue(addressSize, sizetType)); bound.expr.setown(convertAddressToValue(addressData, queryType())); } void CChildSetColumnInfo::gatherSize(SizeStruct & target) { addVariableSize(sizeof(bool) + sizeof(size32_t), target); } IHqlExpression * CChildSetColumnInfo::buildSizeOfUnbound(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector) { OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, sizeof(bool)); OwnedHqlExpr length = convertAddressToValue(addressSize, sizetType); OwnedHqlExpr boundSize = translator.getBoundSize(column->queryType(), length, NULL); return createValue(no_translated, LINK(sizetType), adjustValue(boundSize, sizeof(bool)+sizeof(size32_t))); } void CChildSetColumnInfo::buildDeserialize(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * helper) { OwnedHqlExpr address = getColumnAddress(translator, ctx, selector, boolType, 0); OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, sizeof(bool)); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(bool)+sizeof(size32_t)); size32_t sizeExtra = sizeof(bool)+sizeof(size32_t); //Read the all flag and the size OwnedHqlExpr sizeAllSizet = getSizetConstant(sizeExtra); callDeserializeGetN(translator, ctx, helper, sizeAllSizet, address); OwnedHqlExpr targetSize = convertAddressToValue(addressSize, sizetType); OwnedHqlExpr unboundSize = createTranslated(targetSize); checkAssignOk(translator, ctx, selector, unboundSize, sizeExtra); callDeserializeGetN(translator, ctx, helper, targetSize, addressData); OwnedHqlExpr sizeOfExpr = createValue(no_sizeof, LINK(sizetType), LINK(selector->queryExpr())); OwnedHqlExpr srcSize = adjustValue(targetSize, sizeExtra); ctx.associateExpr(sizeOfExpr, srcSize); } bool CChildSetColumnInfo::buildReadAhead(HqlCppTranslator & translator, BuildCtx & ctx, ReadAheadState & state) { OwnedHqlExpr sizeAllFlag = getSizetConstant(1); callDeserializerSkipInputTranslatedSize(translator, ctx, state.helper, sizeAllFlag); OwnedHqlExpr sizeOfItems = callDeserializerGetSize(translator, ctx, state.helper); callDeserializerSkipInputTranslatedSize(translator, ctx, state.helper, sizeOfItems); return true; } void CChildSetColumnInfo::setColumn(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * _value) { OwnedHqlExpr address = getColumnAddress(translator, ctx, selector, boolType, 0); OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, sizeof(bool)); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(bool)+sizeof(size32_t)); OwnedHqlExpr isAllTarget = convertAddressToValue(address, boolType); OwnedHqlExpr lengthTarget = convertAddressToValue(addressSize, sizetType); ITypeInfo * columnType = column->queryType(); ITypeInfo * elementType = columnType->queryChildType(); OwnedHqlExpr value = ensureExprType(_value, columnType); OwnedHqlExpr inlineSize; switch (value->getOperator()) { case no_list: if ((value->numChildren() != 0) && ::isFixedSize(elementType)) inlineSize.setown(getSizetConstant(value->numChildren() * elementType->getSize())); break; } if (inlineSize) { checkAssignOk(translator, ctx, selector, inlineSize, sizeof(size32_t)+sizeof(bool)); Owned builder = translator.createInlineSetBuilder(elementType, isAllTarget, inlineSize, addressData); builder->buildDeclare(ctx); translator.buildSetAssign(ctx, builder, value); CHqlBoundTarget boundTarget; boundTarget.length.set(lengthTarget); builder->buildFinish(ctx, boundTarget); } else { CHqlBoundExpr bound; if ((value->getOperator() == no_list) && value->numChildren()) { CHqlBoundTarget tempTarget; translator.createTempFor(ctx, columnType, tempTarget, typemod_none, FormatNatural); translator.buildExprAssign(ctx, tempTarget, value); bound.setFromTarget(tempTarget); } else translator.buildExpr(ctx, value, bound); ensureSimpleLength(translator, ctx, bound); OwnedHqlExpr isAll = bound.getIsAll(); OwnedHqlExpr length = translator.getBoundLength(bound); OwnedHqlExpr size = createValue(no_translated, LINK(sizetType), translator.getBoundSize(bound)); checkAssignOk(translator, ctx, selector, size, sizeof(size32_t)+sizeof(bool)); translator.assignBoundToTemp(ctx, isAllTarget, isAll); translator.assignBoundToTemp(ctx, lengthTarget, length); translator.buildBlockCopy(ctx, addressData, bound); ensureSimpleLength(translator, ctx, bound); OwnedHqlExpr boundSize = translator.getBoundSize(bound); associateSizeOf(ctx, selector, boundSize, sizeof(size32_t)+sizeof(bool)); } } //--------------------------------------------------------------------------- IHqlExpression * CMemberInfo::addDatasetLimits(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * _value) { LinkedHqlExpr value = _value; IHqlExpression * choosen = column->queryProperty(choosenAtom); if (choosen) { LinkedHqlExpr choosenValue = choosen->queryChild(0); if (!choosenValue->queryValue()) { OwnedHqlExpr self = container->getRelativeSelf(); OwnedHqlExpr absoluteExpr = replaceSelector(choosenValue, querySelfReference(), self); choosenValue.setown(selector->queryRootRow()->bindToRow(absoluteExpr, querySelfReference())); } else { if (hasNoMoreRowsThan(value, getIntValue(choosenValue))) choosenValue.clear(); } if (choosenValue) value.setown(createDataset(no_choosen, LINK(value), LINK(choosenValue))); } IHqlExpression * maxCount = queryPropertyChild(column, maxCountAtom, 0); if (maxCount && !hasNoMoreRowsThan(value, getIntValue(maxCount))) { //Generate a limit test if there isn't a limit that ensures it is small enough StringBuffer failText, columnText; expandSelectPathText(columnText, true).toLowerCase(); failText.appendf("Too many rows assigned to field %s", columnText.str()); OwnedHqlExpr fail = translator.createFailAction(failText.str(), maxCount, NULL, translator.queryCurrentActivityId(ctx)); value.setown(createDataset(no_limit, LINK(value), createComma(LINK(maxCount), LINK(fail)))); } return value.getClear(); } bool CMemberInfo::hasDatasetLimits() const { if (column->queryProperty(choosenAtom)) return true; if (queryPropertyChild(column, maxCountAtom, 0)) return true; return false; } CChildDatasetColumnInfo::CChildDatasetColumnInfo(CContainerInfo * _container, CMemberInfo * _prior, IHqlExpression * _column, RecordOffsetMap & map, unsigned defaultMaxRecordSize) : CColumnInfo(_container, _prior, _column) { ColumnToOffsetMap * offsetMap = map.queryMapping(column->queryRecord(), defaultMaxRecordSize); maxChildSize = offsetMap->getMaxSize(); #ifdef _DEBUG assertex(!recordRequiresSerialization(column->queryRecord())); #endif } void CChildDatasetColumnInfo::buildColumnExpr(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, CHqlBoundExpr & bound) { OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, 0); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(size32_t)); bound.length.setown(convertAddressToValue(addressSize, sizetType)); bound.expr.setown(convertAddressToValue(addressData, queryType())); } void CChildDatasetColumnInfo::gatherSize(SizeStruct & target) { addVariableSize(sizeof(size32_t), target); } void CColumnInfo::buildDeserializeChildLoop(HqlCppTranslator & translator, BuildCtx & loopctx, IReferenceSelector * selector, IHqlExpression * helper) { OwnedHqlExpr endMarker = loopctx.getTempDeclare(sizetType, NULL); HqlExprArray args; args.append(*LINK(helper)); OwnedHqlExpr beginCall = translator.bindTranslatedFunctionCall(deserializerBeginNestedAtom, args); loopctx.addAssign(endMarker, beginCall); args.append(*LINK(helper)); args.append(*LINK(endMarker)); OwnedHqlExpr loopCall = createBoolExpr(no_not, translator.bindTranslatedFunctionCall(deserializerFinishedNestedAtom, args)); loopctx.addLoop(loopCall, NULL, false); } void CColumnInfo::buildDeserializeToBuilder(HqlCppTranslator & translator, BuildCtx & ctx, IHqlCppDatasetBuilder * builder, IReferenceSelector * selector, IHqlExpression * helper) { BuildCtx loopctx(ctx); buildDeserializeChildLoop(translator, loopctx, selector, helper); BoundRow * selfRow = builder->buildDeserializeRow(loopctx, helper); builder->finishRow(loopctx, selfRow); } void CColumnInfo::buildDeserializeDatasetUsingBuilder(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * helper) { Owned builder = translator.createBlockedDatasetBuilder(column->queryRecord()); builder->buildDeclare(ctx); buildDeserializeToBuilder(translator, ctx, builder, selector, helper); CHqlBoundExpr bound; builder->buildFinish(ctx, bound); OwnedHqlExpr translated = bound.getTranslatedExpr(); setColumn(translator, ctx, selector, translated); } void CChildDatasetColumnInfo::buildDeserialize(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * helper) { IHqlExpression * record = column->queryRecord(); if (recordRequiresSerialization(record)) { buildDeserializeDatasetUsingBuilder(translator, ctx, selector, helper); return; } if (isConditional()) checkAssignOk(translator, ctx, selector, queryZero(), sizeof(size32_t)); OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, 0); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(size32_t)); //Read the all flag and the size OwnedHqlExpr sizeSizet = getSizetConstant(sizeof(size32_t)); callDeserializeGetN(translator, ctx, helper, sizeSizet, addressSize); OwnedHqlExpr targetSize = convertAddressToValue(addressSize, sizetType); OwnedHqlExpr simpleSize = translator.ensureSimpleTranslatedExpr(ctx, targetSize); OwnedHqlExpr unboundSize = createTranslated(simpleSize); checkAssignOk(translator, ctx, selector, unboundSize, sizeof(size32_t)); callDeserializeGetN(translator, ctx, helper, simpleSize, addressData); OwnedHqlExpr sizeOfExpr = createValue(no_sizeof, LINK(sizetType), LINK(selector->queryExpr())); OwnedHqlExpr srcSize = adjustValue(simpleSize, sizeof(size32_t)); ctx.associateExpr(sizeOfExpr, srcSize); } bool CChildDatasetColumnInfo::buildReadAhead(HqlCppTranslator & translator, BuildCtx & ctx, ReadAheadState & state) { OwnedHqlExpr sizeOfDataset = callDeserializerGetSize(translator, ctx, state.helper); callDeserializerSkipInputTranslatedSize(translator, ctx, state.helper, sizeOfDataset); return true; } IHqlExpression * CChildDatasetColumnInfo::buildSizeOfUnbound(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector) { OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, 0); OwnedHqlExpr length = convertAddressToValue(addressSize, sizetType); OwnedHqlExpr boundSize = translator.getBoundSize(column->queryType(), length, NULL); return createValue(no_translated, LINK(sizetType), adjustValue(boundSize, sizeof(size32_t))); } void CChildDatasetColumnInfo::setColumn(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * _value) { OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, 0); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(size32_t)); OwnedHqlExpr lengthTarget = convertAddressToValue(addressSize, sizetType); ITypeInfo * columnType = column->queryType(); OwnedHqlExpr value = LINK(_value); //ensureExprType(_value, columnType); ITypeInfo * valueType = value->queryType(); assertex(recordTypesMatch(valueType, columnType)); bool assignInline = false; // canEvaluateInline(value); // MORE: What is the test // bool assignInline = canAssignInline(&ctx, value) && !canEvaluateInline(&ctx, value); value.setown(addDatasetLimits(translator, ctx, selector, value)); IHqlExpression * record = column->queryRecord(); if (assignInline) { OwnedHqlExpr inlineSize = getSizetConstant(0); checkAssignOk(translator, ctx, selector, inlineSize, sizeof(size32_t)); //Can only assign inline if we know the maximum length that will be assigned is 0. Owned builder = translator.createInlineDatasetBuilder(record, inlineSize, addressData); builder->buildDeclare(ctx); translator.buildDatasetAssign(ctx, builder, value); CHqlBoundTarget boundTarget; boundTarget.length.set(lengthTarget); builder->buildFinish(ctx, boundTarget); } else { CHqlBoundExpr bound; translator.buildDataset(ctx, value, bound, FormatBlockedDataset); translator.normalizeBoundExpr(ctx, bound); ensureSimpleLength(translator, ctx, bound); OwnedHqlExpr length = translator.getBoundLength(bound); OwnedHqlExpr size = createValue(no_translated, LINK(sizetType), translator.getBoundSize(bound)); checkAssignOk(translator, ctx, selector, size, sizeof(size32_t)); translator.assignBoundToTemp(ctx, lengthTarget, length); translator.buildBlockCopy(ctx, addressData, bound); //Use the size just calculated for the field OwnedHqlExpr sizeOfExpr = createValue(no_sizeof, LINK(sizetType), LINK(selector->queryExpr())); OwnedHqlExpr boundSize = translator.getBoundSize(bound); OwnedHqlExpr srcSize = adjustValue(boundSize, sizeof(size32_t)); ctx.associateExpr(sizeOfExpr, srcSize); } } AColumnInfo * CChildDatasetColumnInfo::lookupColumn(IHqlExpression * search) { throwError1(HQLERR_LookupNotActiveDataset, search->queryName()->str()); return NULL; } //--------------------------------------------------------------------------- CChildLimitedDatasetColumnInfo::CChildLimitedDatasetColumnInfo(CContainerInfo * _container, CMemberInfo * _prior, IHqlExpression * _column, RecordOffsetMap & map, unsigned defaultMaxRecordSize) : CColumnInfo(_container, _prior, _column) { IHqlExpression * count = column->queryProperty(countAtom); if (count) countField.setown(foldHqlExpression(column->queryProperty(countAtom)->queryChild(0))); else { IHqlExpression * size = column->queryProperty(sizeofAtom); if (size) sizeField.setown(foldHqlExpression(size->queryChild(0))); else countField.setown(createConstantOne()); } if (countField) countField.setown(ensureExprType(countField, sizetType)); if (sizeField) sizeField.setown(ensureExprType(sizeField, sizetType)); ColumnToOffsetMap * offsetMap = map.queryMapping(column->queryRecord(), defaultMaxRecordSize); maxChildSize = offsetMap->getMaxSize(); fixedChildSize = offsetMap->isFixedWidth() ? maxChildSize : UNKNOWN_LENGTH; } void CChildLimitedDatasetColumnInfo::buildColumnExpr(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, CHqlBoundExpr & bound) { OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), 0); if (countField) { OwnedHqlExpr mappedCount = replaceSelector(countField, querySelfReference(), selector->queryExpr()->queryChild(0)); CHqlBoundExpr boundCount; translator.buildExpr(ctx, mappedCount, boundCount); bound.count.set(boundCount.expr); } else { OwnedHqlExpr mappedSize = replaceSelector(sizeField, querySelfReference(), selector->queryExpr()->queryChild(0)); CHqlBoundExpr boundSize; translator.buildExpr(ctx, mappedSize, boundSize); bound.length.set(boundSize.expr); } bound.expr.setown(convertAddressToValue(addressData, queryType())); } void CChildLimitedDatasetColumnInfo::gatherSize(SizeStruct & target) { if (isFixedSize()) { unsigned fixedSize; if (sizeField && sizeField->queryValue()) fixedSize = (unsigned)getIntValue(sizeField); else { fixedSize = (unsigned)getIntValue(countField) * fixedChildSize; } if (isConditional()) addVariableSize(fixedSize, target); else target.addFixed(fixedSize); } else { addVariableSize(0, target); } } IHqlExpression * CChildLimitedDatasetColumnInfo::buildSizeOfUnbound(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector) { CHqlBoundExpr bound; buildColumnExpr(translator, ctx, selector, bound); OwnedHqlExpr length = translator.getBoundLength(bound); return createTranslated(length); } bool CChildLimitedDatasetColumnInfo::isFixedSize() { if (sizeField && sizeField->queryValue()) return true; if (countField && countField->queryValue() && (fixedChildSize != UNKNOWN_LENGTH)) return true; return false; //MORE: } void CChildLimitedDatasetColumnInfo::buildDeserializeChildLoop(HqlCppTranslator & translator, BuildCtx & loopctx, IReferenceSelector * selector, IHqlExpression * helper) { OwnedHqlExpr mappedCount = replaceSelector(countField, querySelfReference(), selector->queryExpr()->queryChild(0)); CHqlBoundExpr bound; translator.buildTempExpr(loopctx, mappedCount, bound); OwnedHqlExpr test = createValue(no_postdec, LINK(bound.expr)); loopctx.addLoop(test, NULL, false); } bool CChildLimitedDatasetColumnInfo::prepareReadAhead(HqlCppTranslator & translator, ReadAheadState & state) { OwnedHqlExpr self = container->getRelativeSelf(); if (sizeField) { OwnedHqlExpr mappedSize = replaceSelector(sizeField, querySelfReference(), self); gatherSelectExprs(state.requiredValues, mappedSize); } else if (countField) { OwnedHqlExpr mappedCount = replaceSelector(countField, querySelfReference(), self); gatherSelectExprs(state.requiredValues, mappedCount); } return true; } bool CChildLimitedDatasetColumnInfo::buildReadAhead(HqlCppTranslator & translator, BuildCtx & ctx, ReadAheadState & state) { try { OwnedHqlExpr self = container->getRelativeSelf(); if (sizeField) { OwnedHqlExpr mappedSize = replaceSelector(sizeField, querySelfReference(), self); OwnedHqlExpr replacedSize = quickFullReplaceExpressions(mappedSize, state.requiredValues, state.mappedValues); if (containsSelector(replacedSize, queryRootSelf())) return false; callDeserializerSkipInputSize(translator, ctx, state. helper, replacedSize); return true; } else { OwnedHqlExpr mappedCount = replaceSelector(countField, querySelfReference(), self); OwnedHqlExpr replacedCount = quickFullReplaceExpressions(mappedCount, state.requiredValues, state.mappedValues); if (containsSelector(replacedCount, queryRootSelf())) return false; if (fixedChildSize != UNKNOWN_LENGTH) { OwnedHqlExpr scaledSize = multiplyValue(replacedCount, fixedChildSize); callDeserializerSkipInputSize(translator, ctx, state. helper, scaledSize); return true; } BuildCtx loopctx(ctx); CHqlBoundExpr bound; translator.buildTempExpr(loopctx, replacedCount, bound); OwnedHqlExpr test = createValue(no_postdec, LINK(bound.expr)); loopctx.addLoop(test, NULL, false); StringBuffer prefetcherInstanceName; translator.ensureRowPrefetcher(prefetcherInstanceName, ctx, column->queryRecord()); StringBuffer s; s.append(prefetcherInstanceName).append("->readAhead("); translator.generateExprCpp(s, state.helper).append(");"); loopctx.addQuoted(s); return true; } } catch (IException * e) { //yuk yuk yuk!! Couldn't resolve the dataset count/size for some strange reason e->Release(); } return false; } void CChildLimitedDatasetColumnInfo::buildDeserialize(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * helper) { if (sizeField || !countField) { ctx.addQuoted("rtlFailUnexpected();"); return; } //NB: The serialized form of a dataset with an external count is not the same as a normal dataset IHqlExpression * record = column->queryRecord(); if (recordRequiresSerialization(record) || !translator.isFixedRecordSize(record)) { Owned builder = translator.createBlockedDatasetBuilder(column->queryRecord()); builder->buildDeclare(ctx); buildDeserializeToBuilder(translator, ctx, builder, selector, helper); CHqlBoundExpr bound; builder->buildFinish(ctx, bound); setColumnFromBuilder(translator, ctx, selector, builder); } else CColumnInfo::buildDeserialize(translator, ctx, selector, helper); } void CChildLimitedDatasetColumnInfo::setColumn(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * value) { if (sizeField) translator.throwError(HQLERR_CannotCreateSizedChildDataset); if (countField) { IHqlExpression * record = column->queryRecord(); OwnedHqlExpr mappedCount = replaceSelector(countField, querySelfReference(), selector->queryExpr()->queryChild(0)); Owned builder = translator.createLimitedDatasetBuilder(record, mappedCount); builder->buildDeclare(ctx); translator.buildDatasetAssign(ctx, builder, value); setColumnFromBuilder(translator, ctx, selector, builder); } } void CChildLimitedDatasetColumnInfo::setColumnFromBuilder(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlCppDatasetBuilder * builder) { CHqlBoundExpr bound; builder->buildFinish(ctx, bound); if (bound.length) bound.length.setown(translator.ensureSimpleTranslatedExpr(ctx, bound.length)); OwnedHqlExpr size = createValue(no_translated, LINK(sizetType), translator.getBoundSize(bound)); checkAssignOk(translator, ctx, selector, size, 0); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), 0); translator.buildBlockCopy(ctx, addressData, bound); //Use the size just calculated for the field OwnedHqlExpr sizeOfExpr = createValue(no_sizeof, LINK(sizetType), LINK(selector->queryExpr())); OwnedHqlExpr srcSize = translator.getBoundSize(bound); ctx.associateExpr(sizeOfExpr, srcSize); } AColumnInfo * CChildLimitedDatasetColumnInfo::lookupColumn(IHqlExpression * search) { throwError1(HQLERR_LookupNotActiveDataset, search->queryName()->str()); return NULL; } //-------------------------------------------------------------------------------------------- CChildLinkedDatasetColumnInfo::CChildLinkedDatasetColumnInfo(CContainerInfo * _container, CMemberInfo * _prior, IHqlExpression * _column, RecordOffsetMap & map, unsigned defaultMaxRecordSize) : CColumnInfo(_container, _prior, _column) { ColumnToOffsetMap * offsetMap = map.queryMapping(column->queryRecord(), defaultMaxRecordSize); maxChildSize = offsetMap->getMaxSize(); } void CChildLinkedDatasetColumnInfo::buildColumnExpr(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, CHqlBoundExpr & bound) { OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, 0); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(size32_t)); bound.count.setown(convertAddressToValue(addressSize, sizetType)); bound.expr.setown(convertAddressToValue(addressData, queryType())); } void CChildLinkedDatasetColumnInfo::gatherSize(SizeStruct & target) { unsigned thisSize = sizeof(size32_t) + sizeof(byte * *); if (isConditional()) addVariableSize(thisSize, target); // the size is used for ensure if condition is true else target.addFixed(thisSize); } IHqlExpression * CChildLinkedDatasetColumnInfo::buildSizeOfUnbound(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector) { return getSizetConstant(sizeof(size32_t) + sizeof(byte * *)); } void CChildLinkedDatasetColumnInfo::buildDeserialize(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * helper) { if (isConditional()) checkAssignOk(translator, ctx, selector, queryZero(), sizeof(size32_t) + sizeof(byte * *)); OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, 0); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(size32_t)); IHqlExpression * record = column->queryRecord(); CHqlBoundTarget boundTarget; boundTarget.count.setown(convertAddressToValue(addressSize, sizetType)); boundTarget.expr.setown(convertAddressToValue(addressData, queryType())); HqlExprArray args; args.append(*translator.createRowSerializer(ctx, record, deserializerAtom)); args.append(*LINK(helper)); OwnedHqlExpr call = translator.bindFunctionCall(deserializerRowsetHelperAtom, args, queryType()); translator.buildExprAssign(ctx, boundTarget, call); } bool CChildLinkedDatasetColumnInfo::buildReadAhead(HqlCppTranslator & translator, BuildCtx & ctx, ReadAheadState & state) { OwnedHqlExpr sizeOfDataset = callDeserializerGetSize(translator, ctx, state.helper); callDeserializerSkipInputTranslatedSize(translator, ctx, state.helper, sizeOfDataset); return true; } void CChildLinkedDatasetColumnInfo::buildSerialize(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * helper) { IHqlExpression * record = column->queryRecord(); HqlExprArray args; args.append(*LINK(helper)); args.append(*translator.createRowSerializer(ctx, record, serializerAtom)); args.append(*LINK(selector->queryExpr())); OwnedHqlExpr call = translator.bindTranslatedFunctionCall(serializerRowsetHelperAtom, args); translator.buildStmt(ctx, call); } bool CChildLinkedDatasetColumnInfo::modifyColumn(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * value, node_operator op) { if (hasDatasetLimits() || (op != no_assign_addfiles)) return false; OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, 0); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(size32_t)); ITypeInfo * resultType = queryType(); ITypeInfo * valueType = value->queryType(); assertex(recordTypesMatch(valueType, resultType)); CHqlBoundTarget boundTarget; boundTarget.count.setown(convertAddressToValue(addressSize, sizetType)); boundTarget.expr.setown(convertAddressToValue(addressData, queryType())); HqlExprArray args; args.append(*LINK(value)); OwnedHqlExpr call = translator.bindFunctionCall(appendRowsToRowsetAtom, args, resultType); translator.buildDatasetAssign(ctx, boundTarget, call); return true; } void CChildLinkedDatasetColumnInfo::setColumn(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * _value) { OwnedHqlExpr addressSize = getColumnAddress(translator, ctx, selector, sizetType, 0); OwnedHqlExpr addressData = getColumnAddress(translator, ctx, selector, queryType(), sizeof(size32_t)); ITypeInfo * resultType = queryType(); LinkedHqlExpr value = _value; ITypeInfo * valueType = value->queryType(); assertex(recordTypesMatch(valueType, resultType)); value.setown(addDatasetLimits(translator, ctx, selector, value)); CHqlBoundTarget boundTarget; boundTarget.count.setown(convertAddressToValue(addressSize, sizetType)); boundTarget.expr.setown(convertAddressToValue(addressData, queryType())); if (value->getOperator() == no_null) value.setown(createNullExpr(resultType)); translator.buildDatasetAssign(ctx, boundTarget, value); } AColumnInfo * CChildLinkedDatasetColumnInfo::lookupColumn(IHqlExpression * search) { throwError1(HQLERR_LookupNotActiveDataset, search->queryName()->str()); return NULL; }