13.03.2019 2:37, Adriano dos Santos Fernandes wrote:
On 12/03/2019 17:22, Vlad Khorsun wrote:


Let me demonstrate it. With this (wrong) patch now the code compiles:

--------------
diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp
index 4ff5253a2b..26f826ae09 100644
--- a/src/dsql/ExprNodes.cpp
+++ b/src/dsql/ExprNodes.cpp
@@ -10836,6 +10836,7 @@ void SubQueryNode::getChildren(NodeRefsHolder&
holder, bool dsql) const
            holder.add(value1);
          holder.add(value2);
+       holder.add(test);
   }
     string SubQueryNode::internalPrint(NodePrinter& printer) const
diff --git a/src/dsql/ExprNodes.h b/src/dsql/ExprNodes.h
index 3478e4056b..38469e826e 100644
--- a/src/dsql/ExprNodes.h
+++ b/src/dsql/ExprNodes.h
@@ -1860,6 +1860,7 @@ public:
          NestConst<ValueExprNode> value1;
          NestConst<ValueExprNode> value2;
          NestConst<SubQuery> subQuery;
+       NestConst<CastNode> test;
   };
--------------

While previously it correctly detected the problem, as a specialized
node cannot become some other node not inherited from it.

   Please, define "specialized node". I assumed it is descendants of the
ExprNode, but it seems it is not enough. What makes node "specialized" ?

...

As the code demonstrate, "NestConst<CastNode> test" should always point
to a CastNode (or a possible descendant). CastNode::pass1 currently
returns this (a CastNode, but doesn't matter), but it declares return
type as ValueExprNode so it can return other things that is not a
CastNode descendant. Some other nodes does that.

And if does that, "NestConst<CastNode> test" will point to a wrong thing
without the compiler detect when doPass1 (or pass2, remap, etc) is
called. NodeRefImpl was there to detect that wrong cases.

  Sorry, it is still not clear - how one could know if node requires 
"specialization" ?
Imagine a new developer who want to create new kind of Nodes - what is formal
criteria of "specialized" node ?

  Currently it could be detected by return type of dsqlFieldRemapper (and
probably dsqlPass, copy, pass1, pass2) virtual function(s) - if at least one
of them returns type of current class (i.e. overrides return type of base 
class).
Is it correct ?

  Anyway, it will be good to have documented formal criteria of "specialized" 
node.

If the change really increases performance, then I suppose it should be
conditionally defined based on DEBUG build, so debug could use NodeRef
with virtual method and NodeRefImpl, and release something like
currently (non-virtual method and no NodeRefImpl usage).

   According to profiler, new\delete of NodeRefImpl takes near 28% of
request compilation time.


It's should be possible to rewrite the code to have the checks and avoid
the performance problem.

  So far i see two possible solutions:

1. what you offer (DEBUG build with old code and RELEASE build with new one)

  I can live with it, but want to try something that will not depend on build
mode, thus:

2. mark specialized classes, for example in this way:

class BoolExprNode : public ExprNode
{
public:
        typedef BoolExprNode mark_t;
...
}

class ValueExprNode : public ExprNode
{
public:
        typedef ValueExprNode mark_t;
...
}

// ... and few more classes, full list:
// WindowClause, Frame, FrameExtent, BoolExprNode, ValueExprNode, 
RecordSourceNode, ValueListNode, RecSourceListNode, RseNode


and check this mark presence at compile time:

explicit NodeRef(const NestConst<T>& node)
        : ptr(NULL)
{
        static_assert(std::is_base_of_v<ExprNode, T>, "T must be derived from 
ExprNode");
        static_assert(std::is_same_v<T, T::mark_t>, "T must be specialized ExprNode 
class");
...
}


  It also allows to remove not needed overridden functions, such as:

virtual ValueExprNode* dsqlFieldRemapper(FieldRemapper& visitor)
{
        ExprNode::dsqlFieldRemapper(visitor);
        return this;
}

  What do you think ?

Regards,
Vlad


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel

Reply via email to