//This parses the stream comment. func parseStreamComment(dmlComment string, autoincId uint64) (EventNode *parser.Node) { EventNode = parser.NewSimpleParseNode(parser.NODE_LIST, "") tokenizer := parser.NewStringTokenizer(dmlComment) var node *parser.Node var pkTuple *parser.Node node = tokenizer.Scan() if node.Type == parser.ID { //Table Name EventNode.Push(node) } for node = tokenizer.Scan(); node.Type != ';'; node = tokenizer.Scan() { switch node.Type { case '(': //pkTuple is a list of pk value Nodes pkTuple = parsePkTuple(tokenizer, &autoincId) EventNode.Push(pkTuple) default: panic(NewBinlogParseError(EVENT_ERROR, fmt.Sprintf("Error in parsing stream comment: illegal node type %v %v", node.Type, string(node.Value)))) } } return EventNode }
// Example query: insert into vtocc_e(foo) values ('foo') /* _stream vtocc_e (eid id name ) (null 1 'bmFtZQ==' ); */ // the "null" value is used for auto-increment columns. func parseStreamComment(dmlComment string) (eventNode EventNode, err error) { tokenizer := sqlparser.NewStringTokenizer(dmlComment) typ, val := tokenizer.Scan() if typ != sqlparser.ID { return eventNode, fmt.Errorf("expecting table name in stream comment") } eventNode.Table = string(val) eventNode.Columns, err = parsePkNames(tokenizer) if err != nil { return eventNode, err } for typ, val = tokenizer.Scan(); typ != ';'; typ, val = tokenizer.Scan() { switch typ { case '(': // pkTuple is a list of pk value Nodes pkTuple, err := parsePkTuple(tokenizer) if err != nil { return eventNode, err } eventNode.Tuples = append(eventNode.Tuples, pkTuple) default: return eventNode, fmt.Errorf("expecting '('") } } return eventNode, nil }
// Example query: insert into vtocc_e(foo) values ('foo') /* _stream vtocc_e (eid id name ) (null 1 'bmFtZQ==' ); */ // the "null" value is used for auto-increment columns. func parseStreamComment(dmlComment string) (EventNode *sqlparser.Node, err error) { EventNode = sqlparser.NewSimpleParseNode(sqlparser.NODE_LIST, "") tokenizer := sqlparser.NewStringTokenizer(dmlComment) node := tokenizer.Scan() if node.Type != sqlparser.ID { return nil, fmt.Errorf("expecting table name in stream comment") } EventNode.Push(node) for node = tokenizer.Scan(); node.Type != ';'; node = tokenizer.Scan() { switch node.Type { case '(': // pkTuple is a list of pk value Nodes pkTuple, err := parsePkTuple(tokenizer) if err != nil { return nil, err } EventNode.Push(pkTuple) default: return nil, fmt.Errorf("expecting '('") } } return EventNode, nil }
// Example query: insert into _table_(foo) values ('foo') /* _stream _table_ (eid id name ) (null 1 'bmFtZQ==' ); */ // the "null" value is used for auto-increment columns. func (evs *EventStreamer) buildDMLEvent(sql string, insertid int64) (*binlogdatapb.StreamEvent, int64, error) { // first extract the comment commentIndex := strings.LastIndex(sql, streamCommentStart) if commentIndex == -1 { return nil, insertid, fmt.Errorf("missing stream comment") } dmlComment := sql[commentIndex+streamCommentStartLen:] // then strat building the response dmlEvent := &binlogdatapb.StreamEvent{ Category: binlogdatapb.StreamEvent_SE_DML, } tokenizer := sqlparser.NewStringTokenizer(dmlComment) // first parse the table name typ, val := tokenizer.Scan() if typ != sqlparser.ID { return nil, insertid, fmt.Errorf("expecting table name in stream comment") } dmlEvent.TableName = string(val) // then parse the PK names var err error dmlEvent.PrimaryKeyFields, err = parsePkNames(tokenizer) hasNegatives := make([]bool, len(dmlEvent.PrimaryKeyFields)) if err != nil { return nil, insertid, err } // then parse the PK values, one at a time for typ, val = tokenizer.Scan(); typ != ';'; typ, val = tokenizer.Scan() { switch typ { case '(': // pkTuple is a list of pk values var pkTuple *querypb.Row pkTuple, insertid, err = parsePkTuple(tokenizer, insertid, dmlEvent.PrimaryKeyFields, hasNegatives) if err != nil { return nil, insertid, err } dmlEvent.PrimaryKeyValues = append(dmlEvent.PrimaryKeyValues, pkTuple) default: return nil, insertid, fmt.Errorf("expecting '('") } } return dmlEvent, insertid, nil }