Re: contribute pg_get_viewdef2 et al - Mailing list pgadmin-hackers

From Andreas Pflug
Subject Re: contribute pg_get_viewdef2 et al
Date
Msg-id 3EB904D9.5060709@web.de
Whole thread Raw
In response to Re: contribute pg_get_viewdef2 et al  ("Dave Page" <dpage@vale-housing.co.uk>)
List pgadmin-hackers
Dave Page wrote:

>
>
>>-----Original Message-----
>>From: Andreas Pflug [mailto:Andreas.Pflug@web.de]
>>Sent: 07 May 2003 12:54
>>To: Dave Page; pgadmin-hackers@postgresql.org; Tom Lane
>>Subject: contribute pg_get_viewdef2 et al
>>
>>
>>Dave Page wrote:
>>
>>I can imagine... That's why I didn't rely on the existence of the
>>function, but have a fully functional fallback solution.
>>
>>
>
>Which is good, but does make the code more complex. More importantly,
>consider what could happen if the user did a database upgrade to a
>version with different catalogues or whatever, but didn't upgrade the
>extra functions to new versions, just left the old libs there and
>reloaded their database. Or if we used a view or a plpgsql function that
>had the same problem.
>
>I'm not trying to be a pain in the *&% but I've been here before and
>don't particularly want to go through the ensuing pain again.
>
>
>
>>Well that doesn't make sense at all. Indentation and line
>>formatting can
>>be done quite well on the client side, as it is implemented now.
>>
>>
>
>I never really go a chance to look at the backend code, but I kinda
>figured it builds the SQL in a vaguely similar way to what we do (though
>obviously getting the info from the internal representation of the
>object rather than the system catalogues), and that the new functions
>could do the same just with appropriate \n's and spaces added for
>formatting.
>
>Or does pg_get_xxxdef2 just reformat pg_getxxxdef's output?
>
pg_get_xxxdef2 is a copy of pg_get_xxxdef, with some logic to detect
needed parentheses. The way to create the query from the internal
representation isn't too tricky, just recursively traverse a tree of
expression nodes. The pg_get_xxxdef versions won't try to find out if
the parentheses are really needed, they are added always. I'm using my
function isSimpleNode instead, that's all.

static bool isSimpleNode(Node *node, NodeTag parentNodeType)
{
    if (!node)
    return true;

    switch (nodeTag(node))
    {
    // single words: always simple
    case T_Var:
    case T_Const:
    case T_Param:

    // function-like: name(..) or name[..]
    case T_ArrayRef:
    case T_FuncExpr:
    case T_ArrayExpr:
    case T_CoalesceExpr:
    case T_NullIfExpr:
    case T_Aggref:

        // CASE keywords act as parentheses
    case T_CaseExpr:
        return true;

        // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
    case T_FieldSelect:
        return (parentNodeType == T_FieldSelect ? false : true);


        // maybe simple, check args
    case T_CoerceToDomain:
        return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, T_CoerceToDomain);
    case T_RelabelType:
        return isSimpleNode((Node*) ((RelabelType*)node)->arg, T_RelabelType);


    // depends on parent node type; needs further checking
    case T_SubLink:
    case T_NullTest:
    case T_BooleanTest:
    case T_OpExpr:
    case T_DistinctExpr:
        if (parentNodeType == T_BoolExpr)
        return true;
        // else check the same as for T_BoolExpr; no break here!
    case T_BoolExpr:
        switch (parentNodeType)
        {
        case T_ArrayRef:
        case T_FuncExpr:
        case T_ArrayExpr:
        case T_CoalesceExpr:
        case T_NullIfExpr:
        case T_Aggref:
        case T_CaseExpr:
            return true;
        default:
            break;
        }
        return false;

        // these are not completely implemented; so far, they're simple
    case T_SubPlan:
    case T_CoerceToDomainValue:
        return true;

    default:
        break;
    }
    // those we don't know: in dubio complexo
    return false;
}

>I agree your example is, umm, icky, but can you prove that your patch
>will not misintepret anything and produce bad output? Once again, isn't
>this a case of playing it safe?
>
How should I do this? How to PROVE software? The old problem.
You can have a look at the code, and say if there's a case when the
isSimpleNode function will falsely return true; in this case a wrong
query might be created. This function is intentionally made VERY simple,
so it shouldn't be too much work. I've sent this Tom, but he didn't
manage to have a look at it, I think.

>..casts..
>Yes, I do find them annoying sometimes.
>
>
Most of them can be omitted, but I haven't found a way to find out those
2 % which where coded explicitely :-(  Both are stored as T_RelabelType.

>In that case storing the code worked because there were very few ALTER
>TABLE options in those days, and no CREATE OR REPLACES, and the code
>generally worked by completely recreating the modified object each time
>- which the user would always do through pgAdmin. Storing the original
>SQL in the catalogues however won't work because you have to let the
>user use whatever interface they like, and give them access to the ALTER
>statements. This of course means that your SQL is no longer correct as
>soon as someone renames a column or table, or performs any such
>modification of a named object.
>
Right, that's why this only works if  the backend stores the query at
the moment it creates the plan. It's absolutely no option to stick users
to a single creation interface to have the query saved as side-effect;
this must be implemented integrally in the backend.

Regards,
Andreas


pgadmin-hackers by date:

Previous
From: "Dave Page"
Date:
Subject: Re: contribute pg_get_viewdef2 et al
Next
From: "Dave Page"
Date:
Subject: Re: contribute pg_get_viewdef2 et al