123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #include "platform.h"
- #include "jlib.hpp"
- #include "jexcept.hpp"
- #include "jmisc.hpp"
- #include "workunit.hpp"
- #include "hql.hpp"
- #include "hqlexpr.hpp"
- #include "hqlfold.hpp"
- #include "hqlstmt.hpp"
- #include "hqltrans.ipp"
- #include "hqlutil.hpp"
- #include "hqlattr.hpp"
- #include "hqlcatom.hpp"
- #include "hqlfunc.hpp"
- #include "hqlcpp.ipp"
- #include "hqlcpputil.hpp"
- //===========================================================================
- static ITypeInfo * cachedVoidType;
- static IHqlExpression * cachedZero;
- static IHqlExpression * cachedNullChar;
- static IHqlExpression * defaultAttrExpr;
- static IHqlExpression * selfAttrExpr;
- ITypeInfo * boolType;
- ITypeInfo * sizetType;
- ITypeInfo * signedType;
- ITypeInfo * unsignedType;
- ITypeInfo * defaultIntegralType;
- ITypeInfo * counterType;
- ITypeInfo * unknownDataType;
- ITypeInfo * unknownStringType;
- ITypeInfo * unknownVarStringType;
- ITypeInfo * unknownUtf8Type;
- ITypeInfo * constUnknownVarStringType;
- ITypeInfo * unknownUnicodeType;
- ITypeInfo * fposType;
- ITypeInfo * doubleType;
- IHqlExpression * skipActionMarker;
- IHqlExpression * skipReturnMarker;
- IHqlExpression * subGraphMarker;
- IHqlExpression * removedAssignTag;
- IHqlExpression * internalAttrExpr;
- IHqlExpression * activityIdMarkerExpr;
- IHqlExpression * conditionalRowMarkerExpr;
- //===========================================================================
- MODULE_INIT(INIT_PRIORITY_STANDARD)
- {
- boolType = makeBoolType();
- signedType = makeIntType(sizeof(signed), true);
- unsignedType = makeIntType(sizeof(unsigned), false);
- sizetType = makeIntType(sizeof(size32_t), false);
- defaultIntegralType = makeIntType(8, true);
- counterType = makeIntType(8, false);
- unknownDataType = makeDataType(UNKNOWN_LENGTH);
- unknownStringType = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
- unknownVarStringType = makeVarStringType(UNKNOWN_LENGTH);
- unknownUtf8Type = makeUtf8Type(UNKNOWN_LENGTH, 0);
- constUnknownVarStringType = makeConstantModifier(LINK(unknownVarStringType));
- unknownUnicodeType = makeUnicodeType(UNKNOWN_LENGTH, 0);
- fposType = makeIntType(8, false);
- doubleType = makeRealType(8);
- cachedVoidType = makeVoidType();
- cachedZero = createIntConstant(0);
- cachedNullChar = createConstant(createCharValue(0, makeCharType()));
- defaultAttrExpr = createAttribute(defaultAtom);
- selfAttrExpr = createAttribute(selfAtom);
- skipActionMarker = createAttribute(skipActionMarkerAtom);
- skipReturnMarker = createAttribute(skipReturnMarkerAtom);
- subGraphMarker = createAttribute(subgraphAtom);
- removedAssignTag = createAttribute(_internal_Atom);
- internalAttrExpr = createAttribute(internalAtom);
- activityIdMarkerExpr = createAttribute(activityIdMarkerAtom);
- conditionalRowMarkerExpr = createAttribute(_conditionalRowMarker_Atom);
- return true;
- }
- MODULE_EXIT()
- {
- conditionalRowMarkerExpr->Release();
- activityIdMarkerExpr->Release();
- internalAttrExpr->Release();
- removedAssignTag->Release();
- subGraphMarker->Release();
- skipReturnMarker->Release();
- skipActionMarker->Release();
- selfAttrExpr->Release();
- defaultAttrExpr->Release();
- boolType->Release();
- cachedVoidType->Release();
- cachedZero->Release();
- cachedNullChar->Release();
- unsignedType->Release();
- signedType->Release();
- defaultIntegralType->Release();
- sizetType->Release();
- counterType->Release();
- unknownDataType->Release();
- unknownStringType->Release();
- unknownVarStringType->Release();
- unknownUtf8Type->Release();
- constUnknownVarStringType->Release();
- unknownUnicodeType->Release();
- fposType->Release();
- doubleType->Release();
- }
- //===========================================================================
- IHqlExpression * getZero() { return LINK(cachedZero); }
- ITypeInfo * queryBoolType() { return boolType; }
- ITypeInfo * queryVoidType() { return cachedVoidType; }
- IHqlExpression * queryNullChar() { return cachedNullChar; }
- IHqlExpression * queryZero() { return cachedZero; }
- IHqlExpression * getDefaultAttr() { return LINK(defaultAttrExpr); }
- IHqlExpression * getSelfAttr() { return LINK(selfAttrExpr); }
- IHqlExpression * queryActivityIdMarker() { return activityIdMarkerExpr; }
- IHqlExpression * queryConditionalRowMarker() { return conditionalRowMarkerExpr; }
- //===========================================================================
- ITypeInfo * getArrayElementType(ITypeInfo * itemType)
- {
- // use a var string type to get better C++ generated...
- if (storePointerInArray(itemType))
- return makeVarStringType(UNKNOWN_LENGTH);
- return LINK(itemType);
- }
- ITypeInfo * getConcatResultType(IHqlExpression * expr)
- {
- assertex(!"not sure if this is unicode safe, but appears not to be used");
- //first work out the maximum size of the target
- unsigned max = expr->numChildren();
- unsigned idx;
- unsigned totalSize = 0;
- bool unknown = false;
- type_t resultType = type_string;
- for (idx = 0; idx < max; idx++)
- {
- ITypeInfo * type = expr->queryChild(idx)->queryType();
- unsigned size = type->getStringLen();
- if (size == UNKNOWN_LENGTH)
- unknown = true;
- else
- totalSize += size;
- if (type->getTypeCode() == type_varstring)
- resultType = type_varstring;
- }
- if (unknown)
- totalSize = 1023;
- if (resultType == type_string)
- return makeStringType(totalSize, NULL, NULL);
- return makeVarStringType(totalSize);
- }
- bool isCompare3Valued(ITypeInfo * type)
- {
- type = type->queryPromotedType();
- switch (type->getTypeCode())
- {
- case type_string: case type_data:
- if (type->getSize() != 1)
- return true;
- break;
- case type_qstring:
- case type_varstring:
- case type_unicode:
- case type_varunicode:
- case type_decimal:
- case type_utf8:
- return true;
- }
- return false;
- }
- bool storePointerInArray(ITypeInfo * type)
- {
- return type->isReference() && isTypePassedByAddress(type);
- }
- //---------------------------------------------------------------------------
- bool isSelectSortedTop(IHqlExpression * selectExpr)
- {
- IHqlExpression * index = selectExpr->queryChild(1);
- if (matchesConstantValue(index, 1))
- {
- IHqlExpression * ds = selectExpr->queryChild(0);
- return ((ds->getOperator() == no_sort) || (ds->getOperator() == no_topn));
- }
- return false;
- }
- //---------------------------------------------------------------------------
- ITypeInfo * makeRowReferenceType(IHqlExpression * ds)
- {
- ITypeInfo * recordType = ds ? LINK(ds->queryRecordType()) : NULL;
- ITypeInfo * rowType = makeReferenceModifier(makeRowType(recordType));
- if (ds)
- {
- ITypeInfo * dsType = ds->queryType();
- if (hasLinkedRow(dsType))
- rowType = makeAttributeModifier(rowType, getLinkCountedAttr());
- if (hasOutOfLineModifier(dsType))
- rowType = makeOutOfLineModifier(rowType);
- }
- return rowType;
- }
- ITypeInfo * makeRowReferenceType(const CHqlBoundExpr & bound)
- {
- return makeRowReferenceType(bound.expr);
- }
- IHqlExpression * addMemberSelector(IHqlExpression * expr, IHqlExpression * selector)
- {
- if (!expr)
- return NULL;
- if (expr->getOperator() == no_variable)
- return createValue(no_pselect, expr->getType(), LINK(selector), LINK(expr));
- if (expr->numChildren() == 0)
- return LINK(expr);
- HqlExprArray args;
- ForEachChild(i, expr)
- args.append(*addMemberSelector(expr->queryChild(i), selector));
- return expr->clone(args);
- }
- //Only called on translated expressions
- IHqlExpression * addExpressionModifier(IHqlExpression * expr, typemod_t modifier, IInterface * extra)
- {
- //Not sure which is best implementation...
- #if 1
- return createValue(no_typetransfer, makeModifier(expr->getType(), modifier, LINK(extra)), LINK(expr));
- #else
- HqlExprArray args;
- unwindChildren(args, expr);
- return createValue(expr->getOperator(), makeModifier(expr->getType(), modifier, LINK(extra)), args);
- #endif
- }
- static void expandFieldNames(IErrorReceiver & errorProcessor, StringBuffer & out, IHqlExpression * record, StringBuffer & prefix, const char * sep, IHqlExpression * formatFunc)
- {
- ForEachChild(i, record)
- {
- IHqlExpression * cur = record->queryChild(i);
- switch (cur->getOperator())
- {
- case no_record:
- expandFieldNames(errorProcessor, out, cur, prefix, sep, formatFunc);
- break;
- case no_ifblock:
- expandFieldNames(errorProcessor, out, cur->queryChild(1), prefix, sep, formatFunc);
- break;
- case no_field:
- {
- StringBuffer lowerName;
- lowerName.append(cur->queryName()).toLowerCase();
- if (formatFunc)
- {
- HqlExprArray args;
- args.append(*createConstant(lowerName.str()));
- OwnedHqlExpr bound = createBoundFunction(NULL, formatFunc, args, NULL, true);
- OwnedHqlExpr folded = foldHqlExpression(errorProcessor, bound, NULL, HFOthrowerror|HFOfoldimpure|HFOforcefold);
- assertex(folded->queryValue());
- lowerName.clear();
- getStringValue(lowerName, folded);
- }
- switch (cur->queryType()->getTypeCode())
- {
- case type_record:
- case type_row:
- {
- unsigned len = prefix.length();
- prefix.append(lowerName).append(".");
- expandFieldNames(errorProcessor, out, cur->queryRecord(), prefix, sep, formatFunc);
- prefix.setLength(len);
- break;
- }
- default:
- {
- if (out.length())
- out.append(sep);
- out.append(prefix).append(lowerName);
- break;
- }
- }
- break;
- }
- }
- }
- }
- void expandFieldNames(IErrorReceiver & errorProcessor, StringBuffer & out, IHqlExpression * record, const char * sep, IHqlExpression * formatFunc)
- {
- StringBuffer prefix;
- expandFieldNames(errorProcessor, out, record, prefix, sep, formatFunc);
- }
- IHqlExpression * ensurePositiveOrZeroInt64(IHqlExpression * expr)
- {
- if (!expr->queryType()->isSigned())
- return LINK(expr);
- Owned<ITypeInfo> type = makeIntType(8, true);
- if (isCast(expr) && expr->queryType() == type)
- {
- ITypeInfo * uncastType = expr->queryChild(0)->queryType();
- if (!uncastType->isSigned() && uncastType->isInteger() && uncastType->getSize() < 8)
- return LINK(expr);
- }
- OwnedHqlExpr cast = ensureExprType(expr, type);
- IValue * value = cast->queryValue();
- Owned<IValue> zeroValue = type->castFrom(true, I64C(0));
- OwnedHqlExpr zero = createConstant(LINK(zeroValue));
- if (value)
- {
- if (value->compare(zeroValue) < 0)
- return LINK(zero);
- return LINK(cast);
- }
- //A bit convoluted, but we only want to evaluate impure expressions (e.g., random()!) once.
- //So force them to appear pure (so get commoned up), wrap in an alias, and then create the conditional assignment
- if (!cast->isPure())
- {
- OwnedHqlExpr localAttr = createLocalAttribute();
- OwnedHqlExpr pure = createValue(no_pure, cast->getType(), LINK(cast));
- cast.setown(createAlias(pure, localAttr));
- }
- return createValue(no_if, LINK(type), createBoolExpr(no_lt, LINK(cast), LINK(zero)), LINK(zero), LINK(cast));
- }
- void getOutputLibraryName(SCMStringBuffer & libraryName, IConstWorkUnit * wu)
- {
- wu->getApplicationValue("LibraryModule", "name", libraryName);
- }
- IHqlExpression * projectCreateSetDataset(IHqlExpression * expr)
- {
- IHqlExpression * ds = expr->queryChild(0);
- IHqlExpression * select = expr->queryChild(1);
- IHqlExpression * record = ds->queryRecord();
- //Project down to a single field if necessary. Not needed if selecting the only field in the dataset.
- if (queryRealChild(record, 1) || (select->getOperator() != no_select) || (record->queryChild(0) != select->queryChild(1)) || ds->queryNormalizedSelector() != select->queryChild(0))
- {
- HqlExprArray assigns;
- OwnedHqlExpr targetField;
- if (select->getOperator() == no_select)
- targetField.set(select->queryChild(1));
- else
- targetField.setown(createFieldFromValue(valueId, select));
- IHqlExpression * newRecord = createRecord(targetField);
- assigns.append(*createAssign(createSelectExpr(getSelf(newRecord), LINK(targetField)), LINK(select)));
- IHqlExpression * newTransform = createValue(no_newtransform, makeTransformType(LINK(newRecord->queryRecordType())), assigns);
- HqlExprArray args;
- args.append(*LINK(ds));
- args.append(*newRecord);
- args.append(*newTransform);
- OwnedHqlExpr projectedDs = createDataset(no_newusertable, args);
- return createValue(no_createset, expr->getType(), LINK(projectedDs), createSelectExpr(LINK(projectedDs), LINK(targetField)));
- }
- return LINK(expr);
- }
- bool mustInitializeField(IHqlExpression * field)
- {
- if (hasLinkCountedModifier(field))
- return true;
- return false;
- }
- bool worthGeneratingRowAsSingleActivity(IHqlExpression * expr)
- {
- for (;;)
- {
- switch (expr->getOperator())
- {
- case no_left:
- case no_right:
- case no_activerow:
- case no_createrow:
- case no_getresult:
- return true;
- case no_select:
- if (!isNewSelector(expr))
- return true;
- break;
- case no_alias:
- case no_projectrow:
- break;
- case no_if:
- return worthGeneratingRowAsSingleActivity(expr->queryChild(1)) && worthGeneratingRowAsSingleActivity(expr->queryChild(2));
- default:
- //Do not generate no_getgraph result - better as separate activities
- return false;
- }
- expr = expr->queryChild(0);
- }
- }
|