int main()
|
{
|
|
::MYSQL *mysql = defalt_init_mysql();
|
|
// 清理测试数据
|
drop_table(mysql, "test_times");
|
|
// 创建测试表,只包含枚举字段
|
const char *create_sql = R"(
|
CREATE TABLE test_times (
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
last_login TIMESTAMP NULL
|
)
|
)";
|
execute_sql(mysql, create_sql);
|
|
// NOTE: bulk OK
|
{
|
// 准备插入语句
|
const char *insert_sql = "INSERT INTO test_times (id,created_at, updated_at, "
|
"last_login) VALUES (?,?, ?, ?)";
|
MYSQL_STMT *stmt = mysql_stmt_init(mysql);
|
|
if (mysql_stmt_prepare(stmt, insert_sql, strlen(insert_sql)))
|
{
|
show_mysql_error(mysql, "准备语句失败");
|
return -1;
|
}
|
|
// 设置批量大小
|
constexpr unsigned int array_size = 3;
|
mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size);
|
|
// 准备数据数组
|
MYSQL_TIME created_at[array_size]{}; // created_at 时间戳
|
MYSQL_TIME updated_at[array_size]{}; // updated_at 时间戳
|
MYSQL_TIME last_login[array_size]{}; // last_login 时间戳
|
my_bool created_at_null[array_size]{}; // created_at NULL 标记
|
my_bool updated_at_null[array_size]{}; // updated_at NULL 标记
|
my_bool last_login_null[array_size]{}; // last_login NULL 标记
|
|
created_at[0].year = 2023;
|
created_at[0].month = 5;
|
created_at[0].day = 15;
|
created_at[0].hour = 14;
|
created_at[0].minute = 30;
|
created_at[0].second = 45;
|
|
created_at[1].year = 2023;
|
created_at[1].month = 5;
|
created_at[1].day = 16;
|
created_at[1].hour = 15;
|
created_at[1].minute = 31;
|
created_at[1].second = 46;
|
|
created_at[2].year = 2023;
|
created_at[2].month = 5;
|
created_at[2].day = 17;
|
created_at[2].hour = 16;
|
created_at[2].minute = 32;
|
created_at[2].second = 47;
|
created_at[2].second_part = 123456;
|
|
updated_at[0].year = 2023;
|
updated_at[0].month = 5;
|
updated_at[0].day = 15;
|
updated_at[0].hour = 14;
|
updated_at[0].minute = 30;
|
updated_at[0].second = 45;
|
|
updated_at[1].year = 2023;
|
updated_at[1].month = 5;
|
updated_at[1].day = 16;
|
updated_at[1].hour = 15;
|
updated_at[1].minute = 31;
|
updated_at[1].second = 46;
|
|
updated_at[2].year = 2023;
|
updated_at[2].month = 5;
|
updated_at[2].day = 17;
|
updated_at[2].hour = 16;
|
updated_at[2].minute = 32;
|
updated_at[2].second = 47;
|
updated_at[2].second_part = 123456;
|
|
std::vector<MYSQL_TIME *> created_at_ptr{&created_at[0], &created_at[1],
|
&created_at[2]};
|
std::vector<MYSQL_TIME *> updated_at_ptr{&updated_at[0], &updated_at[1],
|
&updated_at[2]};
|
|
// 绑定参数
|
MYSQL_BIND bind[4]{};
|
memset(bind, 0, sizeof(bind));
|
char null_ind[] = {::STMT_INDICATOR_NULL, ::STMT_INDICATOR_NULL,
|
::STMT_INDICATOR_NULL};
|
char default_ind[] = {::STMT_INDICATOR_DEFAULT, ::STMT_INDICATOR_DEFAULT,
|
::STMT_INDICATOR_DEFAULT};
|
bind[0].buffer_type = MYSQL_TYPE_LONG;
|
bind[0].u.indicator = null_ind;
|
|
// created_at 参数
|
// bind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
bind[1].buffer_type = MYSQL_TYPE_STRING;
|
// bind[1].buffer = created_at_ptr.data();
|
// bind[1].u.indicator = null_ind; // NOTE: 会是null
|
bind[1].u.indicator = default_ind; // NOTE: 会填默认值
|
|
// updated_at 参数
|
// bind[2].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
bind[2].buffer_type = MYSQL_TYPE_STRING;
|
// bind[2].buffer = updated_at_ptr.data();
|
// bind[2].u.indicator = null_ind; // NOTE: 会是null
|
bind[2].u.indicator = default_ind; // NOTE: 会填默认值
|
|
// last_login 参数
|
bind[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
// bind[3].buffer = last_login;
|
bind[3].u.indicator = null_ind;
|
|
if (mysql_stmt_bind_param(stmt, bind))
|
{
|
show_mysql_error(mysql, "绑定参数失败");
|
mysql_stmt_close(stmt);
|
return -1;
|
}
|
|
// 执行插入
|
if (mysql_stmt_execute(stmt))
|
{
|
show_mysql_error(mysql, "执行失败");
|
}
|
else
|
{
|
std::cout << "插入成功!" << std::endl;
|
}
|
mysql_stmt_close(stmt);
|
}
|
|
// NOTE: has bug
|
{
|
const char *insert_sql = "INSERT INTO test_times (id,created_at, updated_at, "
|
"last_login) VALUES (?,?,?,?)";
|
MYSQL_STMT *stmt = mysql_stmt_init(mysql);
|
char null_ind = STMT_INDICATOR_NULL;
|
char default_ind = ::STMT_INDICATOR_DEFAULT;
|
|
MYSQL_BIND bind[4]{};
|
bind[0].buffer_type = MYSQL_TYPE_LONG;
|
bind[0].u.indicator = &null_ind;
|
|
bind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
bind[1].u.indicator = &default_ind;
|
|
bind[2].buffer_type = MYSQL_TYPE_STRING;
|
bind[2].u.indicator = &default_ind;
|
|
bind[3].buffer_type = MYSQL_TYPE_STRING;
|
// NOTE: if TEST_BUG==0 ,It is NULL instead of DEFAULT in(created_at,updated_at)
|
#define TEST_BUG 1
|
#define TEST_CRASH 0
|
|
#if TEST_BUG
|
|
#if TEST_CRASH
|
bind[3].is_null_value = 1;
|
#else
|
bind[3].u.indicator = &null_ind;
|
#endif
|
|
#else
|
bind[3].is_null_value = 1;
|
#endif
|
|
if (mysql_stmt_prepare(stmt, insert_sql, strlen(insert_sql)))
|
{
|
show_mysql_error(mysql, "准备语句失败");
|
return -1;
|
}
|
|
#if TEST_BUG
|
// NOTE: requires all column'attr-indicator be set. other crash
|
constexpr unsigned int array_size = 1;
|
mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size);
|
#endif
|
|
if (mysql_stmt_bind_param(stmt, bind))
|
{
|
show_mysql_error(mysql, "绑定参数失败");
|
mysql_stmt_close(stmt);
|
return -1;
|
}
|
|
// 执行插入
|
if (mysql_stmt_execute(stmt))
|
{
|
show_mysql_error(mysql, "执行失败");
|
}
|
else
|
{
|
std::cout << "插入成功!" << std::endl;
|
}
|
mysql_stmt_close(stmt);
|
}
|
// NOTE: Single insertion cannot work with mix indicator
|
|
::mysql_close(mysql);
|
std::cout << "main done\n";
|
return 0;
|
}
|