Functions:

Construct the dataflow graph with each IN parameter is a separate source,
each OUT or return as a separate sink.

** Every dynamic SQL statement is a separate sink **

If data flows thorugh a function that we don't know, then annotate the
data-flow edge with the function name, in parameter, and out parameter,
e.g. "FuncName/ReturnValue <- Parameter 3"

After parsing the function, each OUT or returnvalue is labelled DANGEROUS
for a subset of IN parameters, and SAFE for a disjoint subset of IN
parameters. Parameters not in either of those sets are CONDITIONAL.

When a function is parsed and reachability is computed, assuming at
least one DANGEROUS or SAFE label, find all functions whose graph has
any conditional edges for that function, and if the edge is now known
DANGEROUS, make the link unconditional. If the edge is now known SAFE,
remove it. Simplify the graph to the extent that it can easily & quickly
be done (collapse links, remove unrechable nodes). Redo rechability in
each graph that changes, and recurse until no more DANGEROUS/SAFE labels
are added.

If at end of all parsing there are still CONDITIONAL links, then we're
missing a compilation unit (warn the user)  (or the code contains
an error). Or just assume dangerous? Report function?

Suggested example for known/unknown function call on line 23:

    foo line 1 -> bar line 6 -> splut line 23 -> zot line 29

    foo line 1 -> bar line 6 -> splut (via unknown FooBarFunc) line 23 -> zot line 29

Cache results --- next time there will be few/no conditional links. Warn
if cached values change (or just re-run?)

QUESTION: How to report results to the user? Maybe skip collapsing graphs,
and then we can report data flow in a function?  Or tell user to add a
dummy, guaranteed safe dynamic SQL usage? Don't want to tell user to add
an injection!
    "exit; " . var  ?

DOING REACHABILITY:
- Cost of labelled edges (that use functions) must be much higher than unlabelled edges
  - Suggest normal cost 1, labelled edge cost SQRT(MAX_INT), or if graph size known, MAX_INT/size


GRAPH SIMPLIFICATION:
(Only done for storing function graphs, so that injection inside a function is
reported with useful details)

We'd like to store as simple a graph as possible, but not do too much work to simplify.
STart with the low-hanging fruit:

- Never touch source or sink nodes, never short-circuit past them (maybe easiest to make sure they are never way-nodes?)
- Remove nodes with no in-links
- Remove nodes with no out-links
- Short-circuit whenever there is a single unlabelled in-edge or single unlabelled out-edge
- If there's a single labelled in-edge or single labelled out-edge, short circuit edges with same label
- Remove duplicate edges with the same start/end
- For all nodes reachable unconditionally, remove in-edges from nodes which are not reachable unconditionally
- Repeat until no more changes


----------------------------------------------------------------------
Mon Jan  6 11:38:44 EST 2020

How to handle 
 implicit cursor attribute 
(saw references in FORALL)

