300 lines
7.1 KiB
C++
300 lines
7.1 KiB
C++
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
#include "util/mysql_row_buffer.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "common/logging.h"
|
|
#include "gutil/strings/numbers.h"
|
|
#include "util/mysql_global.h"
|
|
|
|
namespace doris {
|
|
|
|
// the first byte:
|
|
// <= 250: length
|
|
// = 251: NULL
|
|
// = 252: the next two byte is length
|
|
// = 253: the next three byte is length
|
|
// = 254: the next eighth byte is length
|
|
static char* pack_vlen(char* packet, uint64_t length) {
|
|
if (length < 251ULL) {
|
|
int1store(packet, length);
|
|
return packet + 1;
|
|
}
|
|
|
|
/* 251 is reserved for NULL */
|
|
if (length < 65536ULL) {
|
|
*packet++ = 252;
|
|
int2store(packet, length);
|
|
return packet + 2;
|
|
}
|
|
|
|
if (length < 16777216ULL) {
|
|
*packet++ = 253;
|
|
int3store(packet, length);
|
|
return packet + 3;
|
|
}
|
|
|
|
*packet++ = 254;
|
|
int8store(packet, length);
|
|
return packet + 8;
|
|
}
|
|
MysqlRowBuffer::MysqlRowBuffer():
|
|
_pos(_default_buf),
|
|
_buf(_default_buf),
|
|
_buf_size(sizeof(_default_buf)) {
|
|
}
|
|
|
|
MysqlRowBuffer::~MysqlRowBuffer() {
|
|
if (_buf != _default_buf) {
|
|
delete[] _buf;
|
|
}
|
|
}
|
|
|
|
int MysqlRowBuffer::reserve(int size) {
|
|
if (size < 0) {
|
|
LOG(ERROR) << "alloc memory failed. size = " << size;
|
|
return -1;
|
|
}
|
|
|
|
int need_size = size + (_pos - _buf);
|
|
|
|
if (need_size <= _buf_size) {
|
|
return 0;
|
|
}
|
|
|
|
int alloc_size = std::max(need_size, _buf_size * 2);
|
|
char* new_buf = new(std::nothrow) char[alloc_size];
|
|
|
|
if (NULL == new_buf) {
|
|
LOG(ERROR) << "alloc memory failed. size = " << alloc_size;
|
|
return -1;
|
|
}
|
|
|
|
memcpy(new_buf, _buf, _pos - _buf);
|
|
|
|
if (_buf != _default_buf) {
|
|
delete[] _buf;
|
|
}
|
|
|
|
_pos = new_buf + (_pos - _buf);
|
|
_buf = new_buf;
|
|
_buf_size = alloc_size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int MysqlRowBuffer::push_tinyint(int8_t data) {
|
|
// 1 for string trail, 1 for length, 1 for sign, other for digits
|
|
int ret = reserve(3 + MAX_TINYINT_WIDTH);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return ret;
|
|
}
|
|
|
|
int length = snprintf(_pos + 1, MAX_TINYINT_WIDTH + 2, "%d", data);
|
|
|
|
if (length < 0) {
|
|
LOG(ERROR) << "snprintf failed. data = " << data;
|
|
return length;
|
|
}
|
|
|
|
int1store(_pos, length);
|
|
_pos += length + 1;
|
|
return 0;
|
|
}
|
|
|
|
int MysqlRowBuffer::push_smallint(int16_t data) {
|
|
// 1 for string trail, 1 for length, 1 for sign, other for digits
|
|
int ret = reserve(3 + MAX_SMALLINT_WIDTH);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return ret;
|
|
}
|
|
|
|
int length = snprintf(_pos + 1, MAX_SMALLINT_WIDTH + 2, "%d", data);
|
|
|
|
if (length < 0) {
|
|
LOG(ERROR) << "snprintf failed. data = " << data;
|
|
return length;
|
|
}
|
|
|
|
int1store(_pos, length);
|
|
_pos += length + 1;
|
|
return 0;
|
|
}
|
|
|
|
int MysqlRowBuffer::push_int(int32_t data) {
|
|
// 1 for string trail, 1 for length, 1 for sign, other for digits
|
|
int ret = reserve(3 + MAX_INT_WIDTH);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return ret;
|
|
}
|
|
|
|
int length = snprintf(_pos + 1, MAX_INT_WIDTH + 2, "%d", data);
|
|
|
|
if (length < 0) {
|
|
LOG(ERROR) << "snprintf failed. data = " << data;
|
|
return length;
|
|
}
|
|
|
|
int1store(_pos, length);
|
|
_pos += length + 1;
|
|
return 0;
|
|
}
|
|
|
|
int MysqlRowBuffer::push_bigint(int64_t data) {
|
|
// 1 for string trail, 1 for length, 1 for sign, other for digits
|
|
int ret = reserve(3 + MAX_BIGINT_WIDTH);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return ret;
|
|
}
|
|
|
|
int length = snprintf(_pos + 1, MAX_BIGINT_WIDTH + 2, "%ld", data);
|
|
|
|
if (length < 0) {
|
|
LOG(ERROR) << "snprintf failed. data = " << data;
|
|
return length;
|
|
}
|
|
|
|
int1store(_pos, length);
|
|
_pos += length + 1;
|
|
return 0;
|
|
}
|
|
|
|
int MysqlRowBuffer::push_unsigned_bigint(uint64_t data) {
|
|
// 1 for string trail, 1 for length, 1 for sign, other for digits
|
|
int ret = reserve(4 + MAX_BIGINT_WIDTH);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return ret;
|
|
}
|
|
|
|
int length = snprintf(_pos + 1, MAX_BIGINT_WIDTH + 3, "%ld", data);
|
|
|
|
if (length < 0) {
|
|
LOG(ERROR) << "snprintf failed. data = " << data;
|
|
return length;
|
|
}
|
|
|
|
int1store(_pos, length);
|
|
_pos += length + 1;
|
|
return 0;
|
|
}
|
|
|
|
int MysqlRowBuffer::push_float(float data) {
|
|
// 1 for string trail, 1 for length, 1 for sign, other for digits
|
|
int ret = reserve(3 + MAX_FLOAT_STR_LENGTH);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return ret;
|
|
}
|
|
|
|
int length = FloatToBuffer(data, MAX_FLOAT_STR_LENGTH + 2, _pos + 1);
|
|
|
|
if (length < 0) {
|
|
LOG(ERROR) << "gcvt float failed. data = " << data;
|
|
return length;
|
|
}
|
|
|
|
int1store(_pos, length);
|
|
_pos += length + 1;
|
|
return 0;
|
|
}
|
|
|
|
int MysqlRowBuffer::push_double(double data) {
|
|
// 1 for string trail, 1 for length, 1 for sign, other for digits
|
|
int ret = reserve(3 + MAX_DOUBLE_STR_LENGTH);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return ret;
|
|
}
|
|
|
|
int length = DoubleToBuffer(data, MAX_DOUBLE_STR_LENGTH + 2, _pos + 1);
|
|
|
|
if (length < 0) {
|
|
LOG(ERROR) << "gcvt double failed. data = " << data;
|
|
return length;
|
|
}
|
|
|
|
int1store(_pos, length);
|
|
_pos += length + 1;
|
|
return 0;
|
|
}
|
|
|
|
int MysqlRowBuffer::push_string(const char* str, int length) {
|
|
// 9 for length pack max, 1 for sign, other for digits
|
|
if (NULL == str) {
|
|
LOG(ERROR) << "input string is NULL.";
|
|
return -1;
|
|
}
|
|
|
|
int ret = reserve(9 + length);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return ret;
|
|
}
|
|
|
|
_pos = pack_vlen(_pos, length);
|
|
memcpy(_pos, str, length);
|
|
_pos += length;
|
|
return 0;
|
|
}
|
|
|
|
int MysqlRowBuffer::push_null() {
|
|
int ret = reserve(1);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return ret;
|
|
}
|
|
|
|
int1store(_pos, 251);
|
|
_pos += 1;
|
|
return 0;
|
|
}
|
|
|
|
char* MysqlRowBuffer::reserved(int size) {
|
|
int ret = reserve(size);
|
|
|
|
if (0 != ret) {
|
|
LOG(ERROR) << "mysql row buffer reserver failed.";
|
|
return NULL;
|
|
}
|
|
|
|
char* old_buf = _pos;
|
|
_pos += size;
|
|
|
|
return old_buf;
|
|
}
|
|
|
|
}
|
|
|
|
/* vim: set ts=4 sw=4 sts=4 tw=100 */
|