Oops, I meant "from the session object", in my first sentence :)

On Mon, Mar 2, 2009 at 11:25 AM, Toru Maesaka <[email protected]> wrote:
> 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
>>
>>
>



-- 
Toru Maesaka <[email protected]>

_______________________________________________
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