the use of variables to pass values between lines of code is indicative of procedural code, as the organization of code into blocks that can be stored and called from other blocks....In fact, in a purely functional language there are no variables at all. The above code would have to be written.

func( func2( func2( func(param1, param2), param3), param4), param4)


This:

func1(func2(func3(p3),p2),p1)

can be represented as:

a = func3(p3)
b = func2(a, p2)
func1(b, p1)

It is just a matter of using names to reference parts instead of using nesting. The query compiler/interpreter can turn one into the other as needed. References are done as a matter of human convenience. Plus, references allow you to reference the same item twice, something that is difficult with nesting (SQL-like).

The thing is, one *can* execute the above as procedural code, and that is one of the selling points of my proposed language: it can be easily implimented, or at least simulated, as native function calls.

Now just like SQL INSERT, UPDATE, and DELETE, there are "data transformation" operations. Such indeed do violate pure functional, like you said. But outside of these, it is non-side-effect.