Search in sources :

Example 16 with DdlResult

use of com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult in project canal by alibaba.

the class LogEventConvert method parseRowsQueryEvent.

private Entry parseRowsQueryEvent(RowsQueryLogEvent event) {
    if (filterQueryDml) {
        return null;
    }
    // mysql5.6支持,需要设置binlog-rows-query-log-events=1,可详细打印原始DML语句
    String queryString = null;
    try {
        queryString = new String(event.getRowsQuery().getBytes(ISO_8859_1), charset.name());
        String tableName = null;
        if (useDruidDdlFilter) {
            List<DdlResult> results = DruidDdlParser.parse(queryString, null);
            if (results.size() > 0) {
                tableName = results.get(0).getTableName();
            }
        }
        return buildQueryEntry(queryString, event.getHeader(), tableName);
    } catch (UnsupportedEncodingException e) {
        throw new CanalParseException(e);
    }
}
Also used : UnsupportedEncodingException(java.io.UnsupportedEncodingException) ByteString(com.google.protobuf.ByteString) CanalParseException(com.alibaba.otter.canal.parse.exception.CanalParseException) DdlResult(com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult)

Example 17 with DdlResult

use of com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult in project canal by alibaba.

the class LogEventConvert method processFilter.

private boolean processFilter(String queryString, DdlResult result) {
    String schemaName = result.getSchemaName();
    String tableName = result.getTableName();
    // 更新下table meta cache
    if (tableMetaCache != null && (result.getType() == EventType.ALTER || result.getType() == EventType.ERASE || result.getType() == EventType.RENAME)) {
        // 对外返回,保证兼容,还是返回QUERY类型,这里暂不解析tableName,所以无法支持过滤
        for (DdlResult renameResult = result; renameResult != null; renameResult = renameResult.getRenameTableResult()) {
            String schemaName0 = renameResult.getSchemaName();
            String tableName0 = renameResult.getTableName();
            if (StringUtils.isNotEmpty(tableName0)) {
                // 如果解析到了正确的表信息,则根据全名进行清除
                tableMetaCache.clearTableMeta(schemaName0, tableName0);
            } else {
                // 如果无法解析正确的表信息,则根据schema进行清除
                tableMetaCache.clearTableMetaWithSchemaName(schemaName0);
            }
        }
    }
    // fixed issue https://github.com/alibaba/canal/issues/58
    if (result.getType() == EventType.ALTER || result.getType() == EventType.ERASE || result.getType() == EventType.CREATE || result.getType() == EventType.TRUNCATE || result.getType() == EventType.RENAME || result.getType() == EventType.CINDEX || result.getType() == EventType.DINDEX) {
        if (filterQueryDdl) {
            return true;
        }
        if (StringUtils.isEmpty(tableName) || (result.getType() == EventType.RENAME && StringUtils.isEmpty(result.getOriTableName()))) {
            // 如果解析不出tableName,记录一下日志,方便bugfix,目前直接抛出异常,中断解析
            throw new CanalParseException("SimpleDdlParser process query failed. pls submit issue with this queryString: " + queryString + " , and DdlResult: " + result.toString());
        // return null;
        } else {
            // check name filter
            String name = schemaName + "." + tableName;
            if (nameFilter != null && !nameFilter.filter(name)) {
                if (result.getType() == EventType.RENAME) {
                    // rename校验只要源和目标满足一个就进行操作
                    if (nameFilter != null && !nameFilter.filter(result.getOriSchemaName() + "." + result.getOriTableName())) {
                        return true;
                    }
                } else {
                    // 其他情况返回null
                    return true;
                }
            }
            if (nameBlackFilter != null && nameBlackFilter.filter(name)) {
                if (result.getType() == EventType.RENAME) {
                    // rename校验只要源和目标满足一个就进行操作
                    if (nameBlackFilter != null && nameBlackFilter.filter(result.getOriSchemaName() + "." + result.getOriTableName())) {
                        return true;
                    }
                } else {
                    // 其他情况返回null
                    return true;
                }
            }
        }
    } else if (result.getType() == EventType.INSERT || result.getType() == EventType.UPDATE || result.getType() == EventType.DELETE) {
        // 对外返回,保证兼容,还是返回QUERY类型,这里暂不解析tableName,所以无法支持过滤
        if (filterQueryDml) {
            return true;
        }
    } else if (filterQueryDcl) {
        return true;
    }
    return false;
}
Also used : ByteString(com.google.protobuf.ByteString) CanalParseException(com.alibaba.otter.canal.parse.exception.CanalParseException) DdlResult(com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult)

Example 18 with DdlResult

use of com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult in project canal by alibaba.

the class LogEventConvert method parseQueryEvent.

private Entry parseQueryEvent(QueryLogEvent event, boolean isSeek) {
    String queryString = event.getQuery();
    if (StringUtils.startsWithIgnoreCase(queryString, XA_START)) {
        // xa start use TransactionBegin
        TransactionBegin.Builder beginBuilder = TransactionBegin.newBuilder();
        beginBuilder.setThreadId(event.getSessionId());
        beginBuilder.addProps(createSpecialPair(XA_TYPE, XA_START));
        beginBuilder.addProps(createSpecialPair(XA_XID, getXaXid(queryString, XA_START)));
        TransactionBegin transactionBegin = beginBuilder.build();
        Header header = createHeader(event.getHeader(), "", "", null);
        return createEntry(header, EntryType.TRANSACTIONBEGIN, transactionBegin.toByteString());
    } else if (StringUtils.startsWithIgnoreCase(queryString, XA_END)) {
        // xa start use TransactionEnd
        TransactionEnd.Builder endBuilder = TransactionEnd.newBuilder();
        endBuilder.setTransactionId(String.valueOf(0L));
        endBuilder.addProps(createSpecialPair(XA_TYPE, XA_END));
        endBuilder.addProps(createSpecialPair(XA_XID, getXaXid(queryString, XA_END)));
        TransactionEnd transactionEnd = endBuilder.build();
        Header header = createHeader(event.getHeader(), "", "", null);
        return createEntry(header, EntryType.TRANSACTIONEND, transactionEnd.toByteString());
    } else if (StringUtils.startsWithIgnoreCase(queryString, XA_COMMIT)) {
        // xa commit
        Header header = createHeader(event.getHeader(), "", "", EventType.XACOMMIT);
        RowChange.Builder rowChangeBuider = RowChange.newBuilder();
        rowChangeBuider.setSql(queryString);
        rowChangeBuider.addProps(createSpecialPair(XA_TYPE, XA_COMMIT));
        rowChangeBuider.addProps(createSpecialPair(XA_XID, getXaXid(queryString, XA_COMMIT)));
        rowChangeBuider.setEventType(EventType.XACOMMIT);
        return createEntry(header, EntryType.ROWDATA, rowChangeBuider.build().toByteString());
    } else if (StringUtils.startsWithIgnoreCase(queryString, XA_ROLLBACK)) {
        // xa rollback
        Header header = createHeader(event.getHeader(), "", "", EventType.XAROLLBACK);
        RowChange.Builder rowChangeBuider = RowChange.newBuilder();
        rowChangeBuider.setSql(queryString);
        rowChangeBuider.addProps(createSpecialPair(XA_TYPE, XA_ROLLBACK));
        rowChangeBuider.addProps(createSpecialPair(XA_XID, getXaXid(queryString, XA_ROLLBACK)));
        rowChangeBuider.setEventType(EventType.XAROLLBACK);
        return createEntry(header, EntryType.ROWDATA, rowChangeBuider.build().toByteString());
    } else if (StringUtils.endsWithIgnoreCase(queryString, BEGIN)) {
        TransactionBegin transactionBegin = createTransactionBegin(event.getSessionId());
        Header header = createHeader(event.getHeader(), "", "", null);
        return createEntry(header, EntryType.TRANSACTIONBEGIN, transactionBegin.toByteString());
    } else if (StringUtils.endsWithIgnoreCase(queryString, COMMIT)) {
        // MyISAM可能不会有xid事件
        TransactionEnd transactionEnd = createTransactionEnd(0L);
        Header header = createHeader(event.getHeader(), "", "", null);
        return createEntry(header, EntryType.TRANSACTIONEND, transactionEnd.toByteString());
    } else {
        boolean notFilter = false;
        EventType type = EventType.QUERY;
        String tableName = null;
        String schemaName = null;
        if (useDruidDdlFilter) {
            List<DdlResult> results = DruidDdlParser.parse(queryString, event.getDbName());
            for (DdlResult result : results) {
                if (!processFilter(queryString, result)) {
                    // 只要有一个数据不进行过滤
                    notFilter = true;
                }
            }
            if (results.size() > 0) {
                // 如果针对多行的DDL,只能取第一条
                type = results.get(0).getType();
                schemaName = results.get(0).getSchemaName();
                tableName = results.get(0).getTableName();
            }
        } else {
            DdlResult result = SimpleDdlParser.parse(queryString, event.getDbName());
            if (!processFilter(queryString, result)) {
                notFilter = true;
            }
            type = result.getType();
            schemaName = result.getSchemaName();
            tableName = result.getTableName();
        }
        if (!notFilter) {
            // 如果是过滤的数据就不处理了
            return null;
        }
        boolean isDml = (type == EventType.INSERT || type == EventType.UPDATE || type == EventType.DELETE);
        if (!isSeek && !isDml) {
            // 使用新的表结构元数据管理方式
            EntryPosition position = createPosition(event.getHeader());
            tableMetaCache.apply(position, event.getDbName(), queryString, null);
        }
        Header header = createHeader(event.getHeader(), schemaName, tableName, type);
        RowChange.Builder rowChangeBuilder = RowChange.newBuilder();
        rowChangeBuilder.setIsDdl(!isDml);
        rowChangeBuilder.setSql(queryString);
        if (StringUtils.isNotEmpty(event.getDbName())) {
            // 可能为空
            rowChangeBuilder.setDdlSchemaName(event.getDbName());
        }
        rowChangeBuilder.setEventType(type);
        return createEntry(header, EntryType.ROWDATA, rowChangeBuilder.build().toByteString());
    }
}
Also used : Header(com.alibaba.otter.canal.protocol.CanalEntry.Header) LogHeader(com.taobao.tddl.dbsync.binlog.event.LogHeader) RowChange(com.alibaba.otter.canal.protocol.CanalEntry.RowChange) EventType(com.alibaba.otter.canal.protocol.CanalEntry.EventType) TransactionBegin(com.alibaba.otter.canal.protocol.CanalEntry.TransactionBegin) List(java.util.List) ByteString(com.google.protobuf.ByteString) EntryPosition(com.alibaba.otter.canal.protocol.position.EntryPosition) TransactionEnd(com.alibaba.otter.canal.protocol.CanalEntry.TransactionEnd) DdlResult(com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult)

Example 19 with DdlResult

use of com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult in project canal by alibaba.

the class DatabaseTableMeta method applyHistoryToDB.

private boolean applyHistoryToDB(EntryPosition position, String schema, String ddl, String extra) {
    Map<String, String> content = new HashMap<>();
    content.put("destination", destination);
    content.put("binlogFile", position.getJournalName());
    content.put("binlogOffest", String.valueOf(position.getPosition()));
    content.put("binlogMasterId", String.valueOf(position.getServerId()));
    content.put("binlogTimestamp", String.valueOf(position.getTimestamp()));
    content.put("useSchema", schema);
    if (content.isEmpty()) {
        throw new RuntimeException("apply failed caused by content is empty in applyHistoryToDB");
    }
    // 待补充
    List<DdlResult> ddlResults = DruidDdlParser.parse(ddl, schema);
    if (ddlResults.size() > 0) {
        DdlResult ddlResult = ddlResults.get(0);
        content.put("sqlSchema", ddlResult.getSchemaName());
        content.put("sqlTable", ddlResult.getTableName());
        content.put("sqlType", ddlResult.getType().name());
        content.put("sqlText", ddl);
        content.put("extra", extra);
    }
    MetaHistoryDO metaDO = new MetaHistoryDO();
    try {
        BeanUtils.populate(metaDO, content);
        // 会建立唯一约束,解决:
        // 1. 重复的binlog file+offest
        // 2. 重复的masterId+timestamp
        metaHistoryDAO.insert(metaDO);
    } catch (Throwable e) {
        if (isUkDuplicateException(e)) {
            // 忽略掉重复的位点
            logger.warn("dup apply for sql : " + ddl);
        } else {
            throw new CanalParseException("apply history to db failed caused by : " + e.getMessage(), e);
        }
    }
    return true;
}
Also used : HashMap(java.util.HashMap) MetaHistoryDO(com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDO) CanalParseException(com.alibaba.otter.canal.parse.exception.CanalParseException) DdlResult(com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult)

Example 20 with DdlResult

use of com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult in project canal by alibaba.

the class SimpleDdlParserTest method testAlert.

@Test
public void testAlert() {
    String queryString = "alter table retl_mark drop index emp_name";
    DdlResult result = SimpleDdlParser.parse(queryString, "retl");
    Assert.assertNotNull(result);
    Assert.assertEquals("retl_mark", result.getTableName());
    queryString = "alter table retl.retl_mark drop index emp_name";
    result = SimpleDdlParser.parse(queryString, "retl");
    Assert.assertNotNull(result);
    Assert.assertEquals("retl_mark", result.getTableName());
    queryString = "alter table \n `retl.retl_mark` drop index emp_name;";
    result = SimpleDdlParser.parse(queryString, "retl");
    Assert.assertNotNull(result);
    Assert.assertEquals("retl_mark", result.getTableName());
}
Also used : DdlResult(com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult) Test(org.junit.Test)

Aggregations

DdlResult (com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult)33 Test (org.junit.Test)29 CanalParseException (com.alibaba.otter.canal.parse.exception.CanalParseException)3 ByteString (com.google.protobuf.ByteString)3 EventType (com.alibaba.otter.canal.protocol.CanalEntry.EventType)2 MetaHistoryDO (com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDO)1 Header (com.alibaba.otter.canal.protocol.CanalEntry.Header)1 RowChange (com.alibaba.otter.canal.protocol.CanalEntry.RowChange)1 TransactionBegin (com.alibaba.otter.canal.protocol.CanalEntry.TransactionBegin)1 TransactionEnd (com.alibaba.otter.canal.protocol.CanalEntry.TransactionEnd)1 EntryPosition (com.alibaba.otter.canal.protocol.position.EntryPosition)1 LogHeader (com.taobao.tddl.dbsync.binlog.event.LogHeader)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 HashMap (java.util.HashMap)1 List (java.util.List)1