/** * This evenement describe the structure of a table. * It's send before a change append on a table. * A end user of the lib should have no usage of this * * @return TableMapDTO * @throws BinaryDataReaderException * @throws ConfigException */ public function makeTableMapDTO() { $data = []; $data['table_id'] = $this->binaryDataReader->readTableId(); $this->binaryDataReader->advance(2); $data['schema_length'] = $this->binaryDataReader->readUInt8(); $data['schema_name'] = $this->binaryDataReader->read($data['schema_length']); if ([] !== $this->config->getDatabasesOnly() && !in_array($data['schema_name'], $this->config->getDatabasesOnly(), true)) { return null; } $this->binaryDataReader->advance(1); $data['table_length'] = $this->binaryDataReader->readUInt8(); $data['table_name'] = $this->binaryDataReader->read($data['table_length']); if ([] !== $this->config->getTablesOnly() && !in_array($data['table_name'], $this->config->getTablesOnly(), true)) { return null; } $this->binaryDataReader->advance(1); $data['columns_amount'] = $this->binaryDataReader->readCodedBinary(); $data['column_types'] = $this->binaryDataReader->read($data['columns_amount']); // automatically clear table cache to save memory if (count(self::$tableMapCache) > $this->config->getTableCacheSize()) { self::$tableMapCache = array_slice(self::$tableMapCache, ceil($this->config->getTableCacheSize() / 2), null, true); } // already in cache don't parse if (isset(self::$tableMapCache[$data['table_id']])) { return new TableMapDTO($this->eventInfo, self::$tableMapCache[$data['table_id']]); } $this->binaryDataReader->readCodedBinary(); $columns = $this->repository->getFields($data['schema_name'], $data['table_name']); $fields = []; // if you drop tables and parse of logs you will get empty scheme if (!empty($columns)) { $columnLength = strlen($data['column_types']); for ($i = 0; $i < $columnLength; $i++) { // this a dirty hack to prevent row events containing columns which have been dropped if (!isset($columns[$i])) { $columns[$i] = ['COLUMN_NAME' => 'DROPPED_COLUMN_' . $i, 'COLLATION_NAME' => null, 'CHARACTER_SET_NAME' => null, 'COLUMN_COMMENT' => null, 'COLUMN_TYPE' => 'BLOB', 'COLUMN_KEY' => '', 'REFERENCED_TABLE_NAME' => '', 'REFERENCED_COLUMN_NAME' => '']; $type = ConstFieldType::IGNORE; } else { $type = ord($data['column_types'][$i]); } $fields[$i] = Columns::parse($type, $columns[$i], $this->binaryDataReader); } } // save to cache self::$tableMapCache[$data['table_id']] = new TableMap($data['schema_name'], $data['table_name'], $data['table_id'], $data['columns_amount'], $fields); return new TableMapDTO($this->eventInfo, self::$tableMapCache[$data['table_id']]); }
/** * @see https://dev.mysql.com/doc/internals/en/com-binlog-dump.html * @throws BinLogException */ private function setBinLogDump() { $binFilePos = $this->config->getBinLogPosition(); $binFileName = $this->config->getBinLogFileName(); if ('' !== $this->config->getMariaDbGtid()) { $this->execute('SET @mariadb_slave_capability = 4'); $this->execute('SET @slave_connect_state = \'' . $this->config->getMariaDbGtid() . '\''); $this->execute('SET @slave_gtid_strict_mode = 0'); $this->execute('SET @slave_gtid_ignore_duplicates = 0'); } if (0 === $binFilePos || '' === $binFileName) { $master = $this->repository->getMasterStatus(); $binFilePos = $master['Position']; $binFileName = $master['File']; } $prelude = pack('i', strlen($binFileName) + 11) . chr(ConstCommand::COM_BINLOG_DUMP); $prelude .= pack('I', $binFilePos); $prelude .= pack('v', 0); $prelude .= pack('I', $this->config->getSlaveId()); $prelude .= $binFileName; $this->writeToSocket($prelude); $this->getPacket(); }