MXS-2263: Retain integer sign information

The unsignedness of a column is now retained in the Column type as well as
the JSON schema. This allows correct conversion of unsigned integer types
which will be done in a later commit.
This commit is contained in:
Markus Mäkelä
2019-09-25 12:55:44 +03:00
parent 117e2e7e88
commit e1ff978b80
4 changed files with 53 additions and 10 deletions

View File

@ -231,7 +231,7 @@ char* json_new_schema_from_table(const STableMapEvent& map, const STableCreateEv
json_array_append_new(array,
json_pack_ex(&err,
0,
"{s:s, s:[s, s], s:s, s:i}",
"{s:s, s:[s, s], s:s, s:i, s:b}",
"name",
create->columns[i].name.c_str(),
"type",
@ -240,7 +240,9 @@ char* json_new_schema_from_table(const STableMapEvent& map, const STableCreateEv
"real_type",
create->columns[i].type.c_str(),
"length",
create->columns[i].length));
create->columns[i].length,
"unsigned",
create->columns[i].is_unsigned));
}
json_object_set_new(schema, "fields", array);
char* rval = json_dumps(schema, JSON_PRESERVE_ORDER);

View File

@ -102,6 +102,11 @@ bool json_extract_field_names(const char* filename, std::vector<Column>& columns
{
MXS_WARNING("No \"length\" value defined. Treating as default length field.");
}
if ((value = json_object_get(val, "unsigned")) && json_is_boolean(value))
{
columns.back().is_unsigned = json_boolean_value(value);
}
}
}
else

View File

@ -77,6 +77,7 @@ json_t* Column::to_json() const
json_object_set_new(obj, "name", json_string(name.c_str()));
json_object_set_new(obj, "type", json_string(type.c_str()));
json_object_set_new(obj, "length", json_integer(length));
json_object_set_new(obj, "is_unsigned", json_boolean(is_unsigned));
return obj;
}
@ -85,14 +86,24 @@ Column Column::from_json(json_t* json)
json_t* name = json_object_get(json, "name");
json_t* type = json_object_get(json, "type");
json_t* length = json_object_get(json, "length");
json_t* is_unsigned = json_object_get(json, "is_unsigned");
if (name && json_is_string(name)
&& type && json_is_string(type)
&& length && json_is_integer(length))
{
// is_unsigned was added in 2.4.3
bool sign = false;
if (is_unsigned && json_is_boolean(is_unsigned))
{
sign = json_boolean_value(is_unsigned);
}
return Column(json_string_value(name),
json_string_value(type),
json_integer_value(length));
json_integer_value(length),
sign);
}
// Invalid JSON, return empty Column
@ -411,7 +422,7 @@ static const char* extract_field_name(const char* ptr, char* dest, size_t size)
return ptr;
}
int extract_type_length(const char* ptr, char* dest)
int extract_type_length_sign(const char* ptr, char* dest, bool* is_unsigned)
{
/** Skip any leading whitespace */
while (*ptr && (isspace(*ptr) || *ptr == '`'))
@ -455,9 +466,26 @@ int extract_type_length(const char* ptr, char* dest)
if (*end == ')')
{
rval = val;
ptr = end + 1;
}
}
/** Skip whitespace */
while (*ptr && isspace(*ptr))
{
ptr++;
}
const char UNSIGNED[] = "unsigned";
const char ZEROFILL[] = "zerofill";
// Start of integer sign definition: https://mariadb.com/kb/en/library/int/
if (strncasecmp(ptr, UNSIGNED, sizeof(UNSIGNED) - 1) == 0
|| strncasecmp(ptr, ZEROFILL, sizeof(ZEROFILL) - 1) == 0)
{
*is_unsigned = true;
}
return rval;
}
@ -486,10 +514,11 @@ static void process_column_definition(const char* nameptr, std::vector<Column>&
while ((nameptr = extract_field_name(nameptr, colname, sizeof(colname))))
{
char type[100] = "";
int len = extract_type_length(nameptr, type);
bool is_unsigned = false;
int len = extract_type_length_sign(nameptr, type, &is_unsigned);
nameptr = next_field_definition(nameptr);
fix_reserved_word(colname);
columns.emplace_back(colname, type, len);
columns.emplace_back(colname, type, len, is_unsigned);
}
}
@ -1302,10 +1331,11 @@ bool Rpl::table_create_alter(STableCreateEvent create, const char* sql, const ch
if (is_new)
{
char field_type[200] = ""; // Enough to hold all types
int field_length = extract_type_length(tok + len, field_type);
bool is_unsigned = false;
int field_length = extract_type_length_sign(tok + len, field_type, &is_unsigned);
create->columns.emplace_back(std::string(avro_token),
std::string(field_type),
field_length);
field_length, is_unsigned);
updates++;
}
tok = get_next_def(tok, end);
@ -1338,10 +1368,14 @@ bool Rpl::table_create_alter(STableCreateEvent create, const char* sql, const ch
char avro_token[len + 1];
make_avro_token(avro_token, tok, len);
char field_type[200] = ""; // Enough to hold all types
int field_length = extract_type_length(tok + len, field_type);
bool is_unsigned = false;
int field_length = extract_type_length_sign(tok + len,
field_type,
&is_unsigned);
it->name = avro_token;
it->type = field_type;
it->length = field_length;
it->is_unsigned = is_unsigned;
updates++;
}
}

View File

@ -56,16 +56,18 @@ struct gtid_pos_t
/** A single column in a CREATE TABLE statement */
struct Column
{
Column(std::string name, std::string type = "unknown", int length = -1)
Column(std::string name, std::string type = "unknown", int length = -1, bool is_unsigned = false)
: name(name)
, type(type)
, length(length)
, is_unsigned(is_unsigned)
{
}
std::string name;
std::string type;
int length;
bool is_unsigned;
json_t* to_json() const;
static Column from_json(json_t* json);