|
@@ -34,7 +34,7 @@ enum ProjectExprKind
|
|
|
CreateRecordLRActivity, // creates a record, can remove fields from output at will, has left and right input
|
|
|
CompoundActivity, // a compound source, so inserting a project before it is assumed to have no cost
|
|
|
CompoundableActivity, // a source that could become a compound activity, so worth adding projects after
|
|
|
- TransformRecordActivity, // contains a transform, but input must match output
|
|
|
+ RollupTransformActivity, // contains a transform, but input must match output
|
|
|
FixedInputActivity, // can't change input to this activity. E.g., pipe, output
|
|
|
// or input/output record contains ifblocks.
|
|
|
SourceActivity, // No inputs, so no need to do any calculations.
|
|
@@ -42,93 +42,60 @@ enum ProjectExprKind
|
|
|
PassThroughActivity, // input always equals output.
|
|
|
ScalarSelectActivity, // <someDataset>[n].field
|
|
|
DenormalizeActivity, // contains a transform, but left must match output
|
|
|
- ActionSinkActivity, // a sink, but that doesn't necessarily use all input fields.
|
|
|
+ SinkActivity, // a sink, but that doesn't necessarily use all input fields.
|
|
|
CreateRecordSourceActivity, // a source activity containing a transform i.e., inline table
|
|
|
ComplexNonActivity,
|
|
|
AnyTypeActivity, // can be created any type.
|
|
|
};
|
|
|
|
|
|
+//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
-class UsedFieldSet
|
|
|
-{
|
|
|
-public:
|
|
|
- UsedFieldSet() { all = false; }
|
|
|
-
|
|
|
- void addUnique(IHqlExpression * field);
|
|
|
- void append(IHqlExpression & field);
|
|
|
- void clone(const UsedFieldSet & source);
|
|
|
- void cloneFields(const UsedFieldSet & source);
|
|
|
- int compareOrder(IHqlExpression * left, IHqlExpression * right) const;
|
|
|
- bool contains(IHqlExpression & field) const;
|
|
|
- void getFields(HqlExprArray & target) const;
|
|
|
- void getText(StringBuffer & s) const;
|
|
|
- void intersectFields(const UsedFieldSet & source);
|
|
|
- void set(const UsedFieldSet & source);
|
|
|
- void setAll() { all = true; }
|
|
|
- void setAll(IHqlExpression * record);
|
|
|
- void sort(ICompare & compare);
|
|
|
-
|
|
|
- inline unsigned ordinality() const { return fields.ordinality(); }
|
|
|
- inline bool includeAll() const { return all; }
|
|
|
- inline IHqlExpression & item(unsigned i) const { return fields.item(i); }
|
|
|
-
|
|
|
-protected:
|
|
|
- void kill();
|
|
|
-
|
|
|
-protected:
|
|
|
-#ifdef USE_IPROJECT_HASH
|
|
|
- HqlExprHashTable hash;
|
|
|
-#endif
|
|
|
- HqlExprArray fields;
|
|
|
- bool all;
|
|
|
-};
|
|
|
-
|
|
|
-//Save memory allocation if only a single item in the list. Could conceiv
|
|
|
+//Save memory allocation if only a single item in the list.
|
|
|
class OptimizeSingleExprCopyArray : private HqlExprCopyArray
|
|
|
{
|
|
|
public:
|
|
|
OptimizeSingleExprCopyArray() { singleValue = NULL; }
|
|
|
|
|
|
- unsigned ordinality() const
|
|
|
- {
|
|
|
- return singleValue ? 1 : HqlExprCopyArray::ordinality();
|
|
|
+ unsigned ordinality() const
|
|
|
+ {
|
|
|
+ return singleValue ? 1 : HqlExprCopyArray::ordinality();
|
|
|
}
|
|
|
- IHqlExpression & item(unsigned i) const
|
|
|
+ IHqlExpression & item(unsigned i) const
|
|
|
{
|
|
|
if (singleValue && i == 0)
|
|
|
return *singleValue;
|
|
|
- return HqlExprCopyArray::item(i);
|
|
|
+ return HqlExprCopyArray::item(i);
|
|
|
}
|
|
|
void ensure(unsigned max)
|
|
|
{
|
|
|
if (max > 1)
|
|
|
- HqlExprCopyArray::ensure(max);
|
|
|
+ HqlExprCopyArray::ensure(max);
|
|
|
}
|
|
|
- unsigned find(IHqlExpression & cur) const
|
|
|
- {
|
|
|
+ unsigned find(IHqlExpression & cur) const
|
|
|
+ {
|
|
|
if (singleValue)
|
|
|
return &cur == singleValue ? 0 : NotFound;
|
|
|
- return HqlExprCopyArray::find(cur);
|
|
|
+ return HqlExprCopyArray::find(cur);
|
|
|
}
|
|
|
- void remove(unsigned i)
|
|
|
- {
|
|
|
+ void remove(unsigned i)
|
|
|
+ {
|
|
|
if (singleValue && i == 0)
|
|
|
singleValue = NULL;
|
|
|
else
|
|
|
- HqlExprCopyArray::remove(i);
|
|
|
+ HqlExprCopyArray::remove(i);
|
|
|
}
|
|
|
- void append(IHqlExpression & cur)
|
|
|
- {
|
|
|
+ void append(IHqlExpression & cur)
|
|
|
+ {
|
|
|
if (singleValue)
|
|
|
{
|
|
|
- HqlExprCopyArray::append(*singleValue);
|
|
|
- HqlExprCopyArray::append(cur);
|
|
|
+ HqlExprCopyArray::append(*singleValue);
|
|
|
+ HqlExprCopyArray::append(cur);
|
|
|
singleValue = NULL;
|
|
|
}
|
|
|
else if (HqlExprCopyArray::ordinality() == 0)
|
|
|
singleValue = &cur;
|
|
|
else
|
|
|
- HqlExprCopyArray::append(cur);
|
|
|
+ HqlExprCopyArray::append(cur);
|
|
|
}
|
|
|
|
|
|
protected:
|
|
@@ -137,6 +104,112 @@ protected:
|
|
|
|
|
|
typedef OptimizeSingleExprCopyArray SelectUsedArray;
|
|
|
|
|
|
+//---------------------------------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
+class NestedField;
|
|
|
+
|
|
|
+//NB: Once all is set this structure should not be modified. That allows the un-modified definitions to be shared
|
|
|
+//by other expressions.
|
|
|
+class UsedFieldSet
|
|
|
+{
|
|
|
+public:
|
|
|
+ UsedFieldSet() { all = false; maxGathered = 0; originalFields = NULL; }
|
|
|
+
|
|
|
+ void addUnique(IHqlExpression * field);
|
|
|
+ NestedField * addNested(IHqlExpression * field);
|
|
|
+ bool allGathered() const;
|
|
|
+ void appendField(IHqlExpression & ownedField);
|
|
|
+ void appendNested(IHqlExpression & ownedField, NestedField * ownedNested);
|
|
|
+ void clone(const UsedFieldSet & source);
|
|
|
+ bool checkAllFieldsUsed();
|
|
|
+
|
|
|
+ int compareOrder(IHqlExpression * left, IHqlExpression * right) const;
|
|
|
+ void createDifference(const UsedFieldSet & left, const UsedFieldSet & right);
|
|
|
+ IHqlExpression * createFilteredTransform(IHqlExpression * transform, const UsedFieldSet * exceptions) const;
|
|
|
+ void calcFinalRecord(bool canPack, bool ignoreIfEmpty);
|
|
|
+ NestedField * findNested(IHqlExpression * field) const;
|
|
|
+ void gatherTransformValuesUsed(HqlExprArray * selfSelects, SelectUsedArray * parentSelects, HqlExprArray * values, IHqlExpression * selector, IHqlExpression * transform);
|
|
|
+ void getText(StringBuffer & s) const;
|
|
|
+ void intersectFields(const UsedFieldSet & source);
|
|
|
+ bool isEmpty() const;
|
|
|
+ void noteGatheredAll() { maxGathered = (unsigned)-1; }
|
|
|
+ void optimizeFieldsToBlank(const UsedFieldSet & allAssigned, IHqlExpression * transform);
|
|
|
+ bool requiresFewerFields(const UsedFieldSet & other) const;
|
|
|
+ void set(const UsedFieldSet & source);
|
|
|
+ void setAll();
|
|
|
+ void setRecord(IHqlExpression * record);
|
|
|
+ void unionFields(const UsedFieldSet & source);
|
|
|
+
|
|
|
+ inline unsigned numFields() const { return fields.ordinality(); }
|
|
|
+ inline void clear() { kill(); }
|
|
|
+ inline bool includeAll() const { return all; }
|
|
|
+ inline IHqlExpression * queryOriginalRecord() const {
|
|
|
+ assertex(originalFields);
|
|
|
+ return originalFields->queryFinalRecord();
|
|
|
+ }
|
|
|
+ inline const UsedFieldSet * queryOriginal() const { return originalFields; }
|
|
|
+ inline IHqlExpression * queryFinalRecord() const { return finalRecord; }
|
|
|
+ inline void setAllIfAny() { if (originalFields) setAll(); }
|
|
|
+ inline void setOriginal(const UsedFieldSet * _originalFields) { originalFields = _originalFields; }
|
|
|
+
|
|
|
+protected:
|
|
|
+ bool contains(IHqlExpression & field) const;
|
|
|
+ bool contains(_ATOM name) const; // debugging only
|
|
|
+ IHqlExpression * createFilteredAssign(IHqlExpression * field, IHqlExpression * value, IHqlExpression * newSelf, const UsedFieldSet * exceptions) const;
|
|
|
+ void createFilteredAssigns(HqlExprArray & assigns, IHqlExpression * transform, IHqlExpression * newSelf, const UsedFieldSet * exceptions) const;
|
|
|
+ IHqlExpression * createRowTransform(IHqlExpression * row, const UsedFieldSet * exceptions) const;
|
|
|
+ void kill();
|
|
|
+ void gatherExpandSelectsUsed(HqlExprArray * selfSelects, SelectUsedArray * parentSelects, IHqlExpression * selector, IHqlExpression * source);
|
|
|
+ unsigned getOriginalPosition(IHqlExpression * field) const;
|
|
|
+
|
|
|
+protected:
|
|
|
+ OwnedHqlExpr finalRecord;
|
|
|
+ const UsedFieldSet * originalFields;
|
|
|
+#ifdef USE_IPROJECT_HASH
|
|
|
+ HqlExprHashTable hash;
|
|
|
+#endif
|
|
|
+ HqlExprArray fields;
|
|
|
+ CIArrayOf<NestedField> nested;
|
|
|
+ unsigned maxGathered;
|
|
|
+ bool all;
|
|
|
+};
|
|
|
+
|
|
|
+class RecordOrderComparer : public ICompare
|
|
|
+{
|
|
|
+public:
|
|
|
+ RecordOrderComparer(const UsedFieldSet & _fields) : fields(_fields) {}
|
|
|
+
|
|
|
+ virtual int docompare(const void * l,const void * r) const;
|
|
|
+
|
|
|
+protected:
|
|
|
+ const UsedFieldSet & fields;
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+class NestedField : public CInterface
|
|
|
+{
|
|
|
+public:
|
|
|
+ NestedField(IHqlExpression * _field, const UsedFieldSet * _original) : field(_field) { used.setOriginal(_original); }
|
|
|
+
|
|
|
+ NestedField * clone()
|
|
|
+ {
|
|
|
+ //MORE: The following needs testing - for correctness and speed improvements.
|
|
|
+ //if (used.includeAll())
|
|
|
+ // return LINK(this);
|
|
|
+ NestedField * ret = new NestedField(field, used.queryOriginal());
|
|
|
+ ret->used.clone(used);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ void clear() { used.clear(); }
|
|
|
+
|
|
|
+ inline bool isEmpty() const { return used.isEmpty(); }
|
|
|
+ inline bool includeAll() const { return used.includeAll(); }
|
|
|
+
|
|
|
+public:
|
|
|
+ IHqlExpression * field;
|
|
|
+ UsedFieldSet used;
|
|
|
+};
|
|
|
+
|
|
|
struct ImplicitProjectOptions
|
|
|
{
|
|
|
unsigned insertProjectCostLevel;
|
|
@@ -146,6 +219,7 @@ struct ImplicitProjectOptions
|
|
|
bool autoPackRecords;
|
|
|
bool optimizeSpills;
|
|
|
bool enableCompoundCsvRead;
|
|
|
+ bool projectNestedTables;
|
|
|
};
|
|
|
|
|
|
class ImplicitProjectInfo;
|
|
@@ -209,34 +283,35 @@ public:
|
|
|
bool canReorderOutput:1;
|
|
|
bool calcedReorderOutput:1;
|
|
|
bool visitedAllowingActivity:1;
|
|
|
-
|
|
|
- byte childDatasetType;
|
|
|
};
|
|
|
|
|
|
typedef ICopyArrayOf<ComplexImplicitProjectInfo> ProjectInfoArray;
|
|
|
-class ComplexImplicitProjectInfo : public ImplicitProjectInfo, public ICompare
|
|
|
+class ComplexImplicitProjectInfo : public ImplicitProjectInfo
|
|
|
{
|
|
|
public:
|
|
|
ComplexImplicitProjectInfo(IHqlExpression * _original, ProjectExprKind _kind);
|
|
|
IMPLEMENT_IINTERFACE
|
|
|
|
|
|
virtual ComplexImplicitProjectInfo * queryComplexInfo() { return this; }
|
|
|
- virtual int docompare(const void *,const void *) const; // compare within output record
|
|
|
|
|
|
void addAllOutputs();
|
|
|
- bool addOutputField(IHqlExpression * field);
|
|
|
IHqlExpression * createOutputProject(IHqlExpression * ds);
|
|
|
void finalizeOutputRecord();
|
|
|
- void inheritRequiredFields(UsedFieldSet * requiredList);
|
|
|
+ void inheritRequiredFields(const UsedFieldSet & requiredList);
|
|
|
bool safeToReorderInput();
|
|
|
bool safeToReorderOutput();
|
|
|
void setMatchingOutput(ComplexImplicitProjectInfo * other);
|
|
|
void setReorderOutput(bool ok) { canReorderOutput = ok; calcedReorderOutput = true; }
|
|
|
+ void setOriginalRecord(ComplexImplicitProjectInfo * outputInfo) { outputFields.setOriginal(&outputInfo->outputFields); }
|
|
|
|
|
|
void stopOptimizeCompound(bool cascade);
|
|
|
void trace();
|
|
|
|
|
|
- inline bool outputChanged() const { return newOutputRecord != original->queryRecord() && okToOptimize(); }
|
|
|
+ inline bool outputChanged() const
|
|
|
+ {
|
|
|
+ return (queryOutputRecord() != original->queryRecord()) && okToOptimize();
|
|
|
+ }
|
|
|
+ inline IHqlExpression * queryOutputRecord() const { return outputFields.queryFinalRecord(); }
|
|
|
|
|
|
virtual void notifyRequiredFields(ComplexImplicitProjectInfo * whichInput);
|
|
|
|
|
@@ -251,9 +326,6 @@ protected:
|
|
|
public:
|
|
|
//later: create a derived class - if is activity or has child dataset
|
|
|
|
|
|
- ComplexImplicitProjectInfo * outputInfo;
|
|
|
- HqlExprAttr newOutputRecord; // Once set it indicates it won't be changed again
|
|
|
-
|
|
|
ProjectInfoArray inputs;
|
|
|
ProjectInfoArray outputs;
|
|
|
UsedFieldSet outputFields;
|
|
@@ -290,8 +362,6 @@ protected:
|
|
|
|
|
|
void calculateFieldsUsed(IHqlExpression * expr);
|
|
|
void connect(IHqlExpression * source, IHqlExpression * sink);
|
|
|
- void createFilteredAssigns(HqlExprArray & assigns, IHqlExpression * transform, const UsedFieldSet & fields, IHqlExpression * newSelf, const UsedFieldSet * exceptions);
|
|
|
- IHqlExpression * createFilteredTransform(IHqlExpression * transform, const UsedFieldSet & fields, IHqlExpression * record, const UsedFieldSet * exceptions = NULL);
|
|
|
void finalizeFields();
|
|
|
void finalizeFields(IHqlExpression * expr);
|
|
|
void gatherFieldsUsed(IHqlExpression * expr, ImplicitProjectInfo * extra);
|
|
@@ -307,14 +377,14 @@ protected:
|
|
|
const SelectUsedArray & querySelectsUsedForField(IHqlExpression * transform, IHqlExpression * field);
|
|
|
void traceActivities();
|
|
|
IHqlExpression * updateSelectors(IHqlExpression * newExpr, IHqlExpression * oldExpr);
|
|
|
- IHqlExpression * updateChildSelectors(IHqlExpression * expr, IHqlExpression * oldSelector, IHqlExpression * newSelector, unsigned firstChild);
|
|
|
|
|
|
- void processSelectsUsedForCreateRecord(ComplexImplicitProjectInfo * extra, SelectUsedArray const & selectsUsed, IHqlExpression * ds, IHqlExpression * leftSelect, IHqlExpression * rightSelect);
|
|
|
- void processSelectsUsedForDenormalize(ComplexImplicitProjectInfo * extra, SelectUsedArray const & selectsUsed, IHqlExpression * leftSelect, IHqlExpression * rightSelect);
|
|
|
- void processSelectsUsedForTransformRecord(ComplexImplicitProjectInfo * extra, SelectUsedArray const & selectsUsed, IHqlExpression * ds, IHqlExpression * leftSelect, IHqlExpression * rightSelect);
|
|
|
+ void processSelect(ComplexImplicitProjectInfo * extra, IHqlExpression * curSelect, IHqlExpression * ds, IHqlExpression * leftSelect, IHqlExpression * rightSelect);
|
|
|
+ void processSelects(ComplexImplicitProjectInfo * extra, SelectUsedArray const & selectsUsed, IHqlExpression * ds, IHqlExpression * leftSelect, IHqlExpression * rightSelect);
|
|
|
+ void processTransform(ComplexImplicitProjectInfo * extra, IHqlExpression * transform, IHqlExpression * ds, IHqlExpression * leftSelect, IHqlExpression * rightSelect);
|
|
|
|
|
|
protected:
|
|
|
const SelectUsedArray & querySelectsUsed(IHqlExpression * expr);
|
|
|
+ void setOriginal(UsedFieldSet & fields, IHqlExpression * ds) { fields.setOriginal(&queryBodyComplexExtra(ds->queryRecord())->outputFields); }
|
|
|
|
|
|
protected:
|
|
|
HqlCppTranslator & translator;
|