Hi,

YES!, ripping out parse related code from the parser and using it
independently would be superb. Roy and I talked about this a little
bit last week and he seems to be interested in doing so too.

> I would actually prefer that the interface for parsing not get wrapped up in
> the Session object.  This is not be possible right away (explained below),
> but I would prefer to see a pointer to a more lightweight and
> parser-specific object passed to a parser plugin.  For instance, a Node in
> an abstract syntax tree.

Agreed, I guess there is no need to "work around" the current
limitation of the core. We should really redesign this area, since we
can :)

> So, all of the above functions would need to be altered to not need the
> Session object (all of them can be.) and we'd want to pass in the mem_root
> pointer to the parse function instead of the Session object.

Thanks for pointing out the bits and pieces! I guess I can start
looking into this but it might take some time since I haven't quite
mastered this area of the codebase yet. After that, I'll try and
design a structure and API for the Parse Tree that the parser will
work with... though I suspect its not going to be easy.

>From your feedback, its now clear in my mind that we need to make
various baby-steps to the core before we can seriously consider
pushing the parser out... fun.

> The basic idea being that the parser should focus on *parsing* and nothing
> else.  Just parse the query into a tree and pass it back to the caller.
>  That's it.  No need to figure out how to send warnings to a client.  No
> need for the parser to try and figure out whether the session has access to
> an object or not.  Just build the parse tree and pass it back.  Let other
> functions validate the tree.  Parsers should parse.  That's it. :)

++

> It will be going away shortly, since the frm is almost completely gone.

Great news!

> I have lots more to talk about, but I'll leave it there for now...just to
> get the ideas flowing.

Thanks! yeah, would be cool to hear what ideas others have in mind.

Cheers,
Toru

On Mon, Mar 2, 2009 at 1:11 AM, Jay Pipes <[email protected]> wrote:
> First of all, before I get to comments inline, I'd like to say...great work
> so far!  I'm really looking forward to the development of this plugin. :)
>  The below are more of a stream-of-thought comments, not particularly
> well-structured, but hopefully get some thoughts circling.
>
> Toru Maesaka wrote:
>>
>> G'day!
>>
>> As some of you already know, lately I've been experimenting on
>> making the current parser pluggable. I've managed to write a demo
>> that passes the test suite so I wanted to get some feedbacks on
>> what you all think.
>>
>> The tree is at:
>>  http://bazaar.launchpad.net/~tmaesaka/drizzle/pluggable-parser
>>
>> So, what I've done in this tree is simple. I replaced the current entry
>> point of the parser (mysql_parse) with a plugin entry point and pushed
>> out what was behind mysql_parse() into a mandatory module.
>>
>> The idea is that a module implements a parser that populates the session
>> object using the provided query string, query length and a variable for
>> the
>> discovered semicolon with this interface:
>>
>>
>> bool (*sql_parse)(Session *session, const char *query,
>>                         const size_t query_len, const char
>> **found_semicolon);
>
> OK, I'll start off with my "big picture" spiel, and then move on to a more
> realistic approach... :)
>
> I would actually prefer that the interface for parsing not get wrapped up in
> the Session object.  This is not be possible right away (explained below),
> but I would prefer to see a pointer to a more lightweight and
> parser-specific object passed to a parser plugin.  For instance, a Node in
> an abstract syntax tree.
>
> The idea here is that a plugin should not be passed any more information
> than it needs to do its job.  Clean interfaces ensure that the boundaries of
> information are clearly defined and that objects only access those things
> about which they "know".
>
> A parser knows the following:
>
> * The input type it expects (typically a string of characters)
> * A set of tokens (actually this is more the domain of the lexer, but bear
> with me...)
> * A set of rules -- the grammar of the language
> * The production is should output -- the "parse tree"
>
> What it does *not* need to know about (or care about) is the myriad other
> things which are attached to the Session object:
>
> * Status variables
> * Configuration variables
> * Diagnostics arenas
> * Lock information
> * Protocol information for communicating with the client socket
> * Security contexts (ACL, RBAC)
> * Replicator information
> * Transaction information
> * Much more, as you know...
>
> By passing a pointer to the Session object, which is, unfortunately,
> designed in a very open, member-public, way, we risk the parser getting
> entangled in the ABI for the Session, which is an object bigger than the
> parser needs to care about.
>
> That said, our existing parser unfortunately has the Session object
> thingsentangled in itself...which is obvious as soon as you open up the Yacc
> file and see things like this all over the place:
>
>  Session *session= YYSession;
>  session->lex->sql_command= SQLCOM_EMPTY_QUERY;
>
> The macros at the top of the Yacc file are telling:
>
> %{
> /* session is passed as an argument to yyparse(), and subsequently
> ** to yylex().
> ** The type will be void*, so it must be  cast to (Session*) when used.
> ** Use the YYSession macro for this.
> */
> #define YYPARSE_PARAM yysession
> #define YYLEX_PARAM yysession
> #define YYSession ((Session *)yysession)
> ...
> #define Lex (YYSession->lex)
> #define Select Lex->current_select
>
> There are a number of functions that the session object is passed to from
> within the parser:
>
> push_warning_printf()
> select_lex->add_table_to_list()
> ha_resolve_by_name()
> add_field_to_list()
> select_lex->alloc_index_hints()
> session->add_item_to_list()
> negate_expression()
> handle_2003_note184_exception()
> create_func_cast()
> select_lex->nest_last_join()
> push_new_name_resolution_context()
> select_lex->init_nested_join()
> select_lex->end_nested_join()
> prepare_schema_table()
>
> In addition, the session object's mem_root is supplied as an allocator to
> most of the Item constructors.
>
> So, all of the above functions would need to be altered to not need the
> Session object (all of them can be.) and we'd want to pass in the mem_root
> pointer to the parse function instead of the Session object.
>
> I'm thinking a goal for the *interface* would be something like the
> following for a C plugin:
>
> bool (*sql_parse)
> (ParseTree* node, MEM_ROOT *alloc, const char *query, const size_t
> query_len);
>
> and this for a C++ plugin:
>
> class SqlParseEvent
> {
>  public:
>    bool operator()(ParseTree *node, MEM_ROOT *root, std::string query);
> }
>
> The basic idea being that the parser should focus on *parsing* and nothing
> else.  Just parse the query into a tree and pass it back to the caller.
>  That's it.  No need to figure out how to send warnings to a client.  No
> need for the parser to try and figure out whether the session has access to
> an object or not.  Just build the parse tree and pass it back.  Let other
> functions validate the tree.  Parsers should parse.  That's it. :)
>
> After looking hard today at the current parser (which is, BTW, smaller than
> MySQL 4.1's parser and less than a third of the size of MySQL 6.0's) I
> strongly believe we can reduce the parser by at least another third (not the
> grammar, but the productions in the grammar rules) by removing the Session
> from the parser and reducing the amount of validation and checking the
> parser is doing and pulling that stuff out into separate functions...
>
>>
>> Saying that, things weren't as simple as I wanted it to be and I had to do
>> the following to modularize the parser:
>>
>> - Separate mysql_execute_command() from the parser for a "clean"
>>  separation of the parser from the core. I've added a wrapper function
>>  within the core called sql_parse_and_execute() to replace where
>>  previously parsing and query execution occurred at the same place.
>>
>> Also, although my original intention was to only introduce one plugin
>> function, I had to unfortunately add another one called:
>>
>>
>> sql_parse_vcol_expr(Session *session, const char *vcol_expr,
>>                               const size_t length);
>>
>>
>> this is due to the way unpack_vcol_info_from_frm() in table.cc relies
>> on a direct call to the parser to translate the virtual column expression
>> from a .frm file into an Item object. So, I needed a way to directly call
>> the raw parser without going through housekeeping.
>>
>> I reaaaaaally don't want this function but to kill this thing, we need to
>> come up with a way to create a virtual column object without relying
>> on the parser. Either that or I think we can kill this function when
>> Drizzle doesn't need .frm files anymore. I think this is currently being
>> worked on?
>
> It will be going away shortly, since the frm is almost completely gone.
>
>> Anyhow, that's all I have to say for now! It would be great if you guys
>> could tell me whether I screwed up miserably or if its worth considering
>> :)
>
> I have lots more to talk about, but I'll leave it there for now...just to
> get the ideas flowing.
>
> Cheers!
>
> Jay
>
>

_______________________________________________
Mailing list: https://launchpad.net/~drizzle-discuss
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~drizzle-discuss
More help   : https://help.launchpad.net/ListHelp

Reply via email to