v0.24.0的版本增加了bltVersionCompare,mysqlAffectedRows模块函数。此外,还为bltStr模块函数增加了format可选参数(可以在将整数,浮点数转为字符串时,对其进行格式化操作)。

项目下载地址:

    zenglServer源代码的相关地址:https://github.com/zenglong/zenglServer  当前版本对应的tag标签为:v0.24.0

zenglServer v0.24.0:

    v0.24.0的版本增加了bltVersionCompare,mysqlAffectedRows模块函数。此外,还为bltStr模块函数增加了format可选参数(可以在将整数,浮点数转为字符串时,对其进行格式化操作)。

bltVersionCompare模块函数:

    当前版本增加了bltVersionCompare模块函数,可以用于对版本号进行比较,该模块函数定义在module_builtin.c文件中:

/**
 * bltVersionCompare模块函数,用于对版本号进行比较
 * 第一个参数version1必须是字符串类型,表示需要进行比较的第一个版本号
 * 第二个参数version2也必须是字符串类型,表示需要进行比较的第二个版本号
 * 	当返回值大于0时,表示version1大于version2
 * 	当返回值等于0时,表示version1等于version2
 * 	当返回值小于0时,表示version1小于version2
 *
 * 示例:
	use builtin;
	fun compare(v1, v2)
		c = bltVersionCompare(v1, v2);
		if(c > 0)
			print v1 + ' > ' + v2;
		elif(c < 0)
			print v1 + ' < ' + v2;
		else
			print v1 + ' == ' + v2;
		endif
	endfun

	fun compare2(v1, v2)
		if(bltVersionCompare(v1, v2) >= 0) // bltVersionCompare模块函数返回值大于或等于0,则说明v1版本号大于或等于v2版本号
			print v1 + ' >= ' + v2;
		else
			print v1 + ' < ' + v2;
		endif
	endfun

	compare('v0.1.0', 'v0.2.0');
	compare('v1.2.3', 'v1.2');
	compare('v2.2.3', 'v2.2.2');
	compare('2.3.0', 'v2.3');
	print '';

	compare2('3.2.1', '3.2');
	compare2('3.2.0', '3.2');
	compare2('3.2.0', '3.2.1');
	print '';

	执行结果如下:

	v0.1.0 < v0.2.0
	v1.2.3 > v1.2
	v2.2.3 > v2.2.2
	2.3.0 == v2.3

	3.2.1 >= 3.2
	3.2.0 >= 3.2
	3.2.0 < 3.2.1

	模块函数版本历史:
	 - v0.24.0版本新增此模块函数
 */
ZL_EXP_VOID module_builtin_version_compare(ZL_EXP_VOID * VM_ARG, ZL_EXP_INT argcount)
{
	ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
	const char * func_name = "bltVersionCompare";
	if(argcount < 2)
		zenglApi_Exit(VM_ARG,"usage: %s(version1, version2)", func_name);
	zenglApi_GetFunArg(VM_ARG,1,&arg);
	if(arg.type != ZL_EXP_FAT_STR) {
		zenglApi_Exit(VM_ARG,"the first argument [version1] of %s must be string", func_name);
	}
	char * version1 = (char *)arg.val.str;
	zenglApi_GetFunArg(VM_ARG,2,&arg);
	if(arg.type != ZL_EXP_FAT_STR) {
		zenglApi_Exit(VM_ARG,"the second argument [version2] of %s must be string", func_name);
	}
	char * version2 = (char *)arg.val.str;
	int retval = builtin_version_compare(version1, version2);
	zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, retval, 0);
}

    从上面C代码的注释中可以看到,将需要比较的版本号作为参数传递给该模块函数,当模块函数的返回值大于0时,表示第一个参数对应的版本号大于第二个参数对应的版本号,当返回值等于0时,则表示两个参数对应的版本号是相等的,当返回值小于0时,则表示第一个参数对应的版本号小于第二个参数对应的版本号。

mysqlAffectedRows模块函数:

    当前版本还增加了mysqlAffectedRows模块函数,可以返回前一次mysql操作所影响的记录行数,该模块函数定义在module_mysql.c文件中:

/**
 * mysqlAffectedRows模块函数,返回前一次mysql操作所影响的记录行数
 * 第一个参数connection必须是整数类型,表示mysql连接相关的指针
 * 模块函数的返回值表示受影响的记录数
 *
 * 示例:
	use builtin, mysql;

	config['db_host'] = 'localhost'; // mysql数据库ip
	config['db_port'] = 3306;        // mysql数据库端口
	config['db_user'] = 'root';      // mysql用户名
	config['db_passwd'] = '123456';  // mysql密码
	config['db_name'] = 'testdb';    // mysql数据库名

	fun finish_with_error(con)
		err = mysqlError(con);
		mysqlClose(con);
		bltExit(err);
	endfun

	fun mysql_query(con, sql)
		if(mysqlQuery(con, sql))
			finish_with_error(con);
		endif
		result = mysqlStoreResult(con);
		return_array = bltArray();
		while(mysqlFetchResultRow(result, &result_array))
			return_array[] = result_array;
		endwhile
		mysqlFreeResult(result);
		return return_array;
	endfun

	con = mysqlInit();
	if(!con)
		bltExit('mysqlInit failed');
	endif

	if(!mysqlRealConnect(con, config['db_host'], config['db_user'], config['db_passwd'], config['db_name'], config['db_port']))
		finish_with_error(con);
	endif

	if(mysqlQuery(con, "CREATE TABLE IF NOT EXISTS `test_table` (
		  id int NOT NULL AUTO_INCREMENT,
		  name varchar(255) NOT NULL DEFAULT '',
		  score int NOT NULL DEFAULT 0,
		  PRIMARY KEY (id)
		) ENGINE=MyISAM DEFAULT CHARSET utf8 COLLATE utf8_general_ci COMMENT='my test table'"))
		finish_with_error(con);
	endif

	for(i=0; i < 3;i++)
		if(mysqlQuery(con, "INSERT INTO `test_table` (`name`,`score`) VALUES('" + bltRandomStr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 4) + "', '" + bltRand(0, 100) + "')"))
			finish_with_error(con);
		endif
		// 通过mysqlAffectedRows模块函数,打印 INSERT 插入语句所添加的记录数
		print 'insert table `test_table`, affected rows: ' + mysqlAffectedRows(con);
	endfor

	if(mysqlQuery(con, "UPDATE `test_table` SET `score` = '50' WHERE score < 50"))
		finish_with_error(con);
	endif
	// 通过mysqlAffectedRows模块函数,打印 UPDATE 更新语句所更新的记录数
	print "update table `test_table`, affected rows: " + mysqlAffectedRows(con);

	if(mysqlQuery(con, "DELETE FROM `test_table` WHERE score > 80"))
		finish_with_error(con);
	endif
	// 通过mysqlAffectedRows模块函数,打印 DELETE 删除语句所删除的记录数
	print "delete from table `test_table`, affected rows: " + mysqlAffectedRows(con);

	data_array = mysql_query(con, "select * from `test_table` order by id desc limit 20");
	// 通过mysqlAffectedRows模块函数,打印 select 查询语句所查找出来的记录数
	print 'select rows num: ' + mysqlAffectedRows(con);
	for(i=0;bltIterArray(data_array,&i,&data);)
		print data['id'] + ': ' + data['name'] + ' (score: ' + data['score'] + ')';
	endfor

	执行结果类似如下所示:

	insert table `test_table`, affected rows: 1
	insert table `test_table`, affected rows: 1
	insert table `test_table`, affected rows: 1
	update table `test_table`, affected rows: 1
	delete from table `test_table`, affected rows: 0
	select rows num: 3
	3: JBCF (score: 60)
	2: REQR (score: 69)
	1: RRTO (score: 50)

	模块函数版本历史:
	 - v0.24.0版本新增此模块函数
 */
ZL_EXP_VOID module_mysql_affected_rows(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
{
	ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
	const char * func_name = "mysqlAffectedRows";
	if(argcount != 1)
		zenglApi_Exit(VM_ARG,"usage: %s(connection)", func_name);
	zenglApi_GetFunArg(VM_ARG,1,&arg);
	if(arg.type != ZL_EXP_FAT_INT) {
		zenglApi_Exit(VM_ARG,"the first argument [connection] of %s must be integer", func_name);
	}
	MYSQL *con = (MYSQL *)arg.val.integer;
	MAIN_DATA * my_data = zenglApi_GetExtraData(VM_ARG, "my_data");
	if(!is_valid_mysql_connection(&(my_data->resource_list), con)) {
		zenglApi_Exit(VM_ARG,"%s runtime error: invalid connection", func_name);
	}
	int rows = (int)mysql_affected_rows(con);
	zenglApi_SetRetVal(VM_ARG,ZL_EXP_FAT_INT, ZL_EXP_NULL, rows, 0);
}

    从上面C代码的相关注释中可以看到,该模块函数需要接受mysql连接相关的指针(可以通过mysqlInit模块函数来获得该连接指针)作为参数,返回的结果表示上一次mysql操作所影响的记录行数,例如,如果是新增操作,则该模块函数的返回值可以表示新增了多少条数据库记录,如果是更新操作,则返回值可以表示更新了多少条数据库记录,如果是删除操作,则返回值表示删除了多少条记录,如果是查询操作,则表示查询出了多少条记录。

bltStr模块函数增加format可选参数:

    当前版本为bltStr模块函数增加了format可选参数,可以在将整数,浮点数转为字符串时,对其进行格式化操作,详情可以参考该模块函数的C代码的注释部分,该模块函数的C源码定义在module_builtin.c文件中:

/**
 * bltStr模块函数,返回第一个参数的字符串形式
 * 第一个参数data|&data,表示需要转成字符串的源数据(可以是整数,浮点数之类的数据)
 * 第二个参数是可选参数
 * 	当第二个参数是整数类型时,表示isSetData即是否将转换的结果赋值给第一个参数(此时还需要将第一个参数的引用传递进来)
 * 	当第二个参数是字符串类型时,表示format即对整数或浮点数进行格式化,当第二个参数是format时,可以提供第三个可选参数来表示isSetData(是否将字符串结果赋值给第一个参数)
 *
 ........................................................................
 *
 * 当第二个参数是字符串类型时,表示format即对整数或浮点数进行格式化
 * 例如:
	use builtin;
	def TRUE 1;
	def FALSE 0;

	value = 1789.800000001;
	print bltStr(value, '%.2f');
	print bltStr(value, '%012.12f');
	print bltStr(value, '%.12E');
	print bltStr(&value, '%012.100f', TRUE);
	print 'value: ' + value + '\n';

	for(i=65;i <= 71;i++)
		print i + bltStr(i, ' - 0x%X') + bltStr(i, ' - %c');
	endfor

	上面会将浮点数进行格式化,例如:'%.2f'表示保留两位小数,此时可以把第三个参数设置为非0的整数值,来表示将转换结果赋值给第一个参数,执行结果类似如下所示:

	1789.80
	1789.800000001000
	1.789800000001E+03
	1789.80000000099994394986424595117568969726562500000000000000000000000000000000
	value: 1789.80000000099994394986424595117568969726562500000000000000000000000000000000

	65 - 0x41 - A
	66 - 0x42 - B
	67 - 0x43 - C
	68 - 0x44 - D
	69 - 0x45 - E
	70 - 0x46 - F
	71 - 0x47 - G

	模块函数版本历史:
	 - v0.8.0版本新增此模块函数
	 - v0.24.0版本增加format可选参数,用于对整数或浮点数进行格式化(格式化的语法请参考snprintf的C库函数,因为该模块函数的底层是通过snprintf来进行格式化的)
 */
ZL_EXP_VOID module_builtin_str(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
{
	ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
	if(argcount < 1)
		zenglApi_Exit(VM_ARG,"usage: bltStr(data|&data[, isSetData=0]) or bltStr(data|&data[, format[, isSetData=0]])");
	zenglApi_GetFunArg(VM_ARG,1,&arg);
	int isSetData = ZL_EXP_FALSE;
	char * format = NULL;
	if(argcount >= 2) {
		ZENGL_EXPORT_MOD_FUN_ARG arg2 = {ZL_EXP_FAT_NONE,{0}};
		zenglApi_GetFunArg(VM_ARG,2,&arg2);
		if(arg2.type == ZL_EXP_FAT_INT)
			isSetData = arg2.val.integer;
		else if(arg2.type == ZL_EXP_FAT_STR)
			format = arg2.val.str;
		else
			zenglApi_Exit(VM_ARG,"the second argument of bltStr must be integer type as isSetData or string type as format");
		if(argcount >= 3 && format != NULL) {
			zenglApi_GetFunArg(VM_ARG,3,&arg2);
			if(arg2.type != ZL_EXP_FAT_INT)
				zenglApi_Exit(VM_ARG,"the third argument [isSetData] of bltStr must be integer");
			isSetData = arg2.val.integer;
		}
	}
	char * retstr;
	char tmpstr[80];
	switch(arg.type) {
	case ZL_EXP_FAT_STR:
		retstr = arg.val.str;
		break;
	case ZL_EXP_FAT_INT:
	case ZL_EXP_FAT_FLOAT:
		if(format == NULL) {
			if(arg.type == ZL_EXP_FAT_INT)
				format = "%ld";
			else
				format = "%.16g";
		}
		else if(strchr(format, '*') || strchr(format, 's')) {
			zenglApi_Exit(VM_ARG,"bltStr format error: can't use * or s in format!");
		}
		int retcount = 0;
		if(arg.type == ZL_EXP_FAT_INT)
			retcount = snprintf(tmpstr, sizeof(tmpstr), format, arg.val.integer);
		else
			retcount = snprintf(tmpstr, sizeof(tmpstr), format, arg.val.floatnum);
		if(retcount < 0) {
			zenglApi_Exit(VM_ARG,"bltStr error: %s", strerror(errno));
		}
		retstr = tmpstr;
		break;
	case ZL_EXP_FAT_MEMBLOCK:
		retstr = "[array or class obj type]";
		break;
	default:
		retstr = "";
		break;
	}
	if(isSetData) {
		if(arg.type != ZL_EXP_FAT_STR) {
			arg.type = ZL_EXP_FAT_STR;
			arg.val.str = retstr;
			zenglApi_SetFunArg(VM_ARG,1,&arg);
		}
	}
	zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, retstr, 0, 0);
}

    从上面的C代码的注释中可以看到,当bltStr模块函数的第二个参数是字符串时,则表示对第一个参数对应的整数或浮点数进行格式化操作,由第二个字符串参数来指定具体的格式,例如,当第二个参数是'%.2f'时,表示将浮点数转为字符串时保留两位小数,当第二个参数是'0x%X'时表示将整数转为十六进制格式等等,具体的格式化语法可以参考snprintf的C库函数,因为该模块函数的底层是通过snprintf来进行格式化的。

test.zl脚本:

    为了测试新增的bltVersionCompare模块函数,以及bltStr模块函数新增的format可选参数,当前版本在 my_webroot/v0_24_0/ 目录中增加了test.zl的测试脚本,该脚本的代码如下:

use builtin;
def TRUE 1;
def FALSE 0;

value = 1789.800000001;
print bltStr(value, '%.2f');
print bltStr(value, '%012.12f');
print bltStr(value, '%.12E');
print bltStr(&value, '%012.100f', TRUE);
print 'value: ' + value + '\n';

for(i=65;i <= 71;i++)
	print i + bltStr(i, ' - 0x%X') + bltStr(i, ' - %c');
endfor

print '';

fun compare(v1, v2)
	c = bltVersionCompare(v1, v2);
	if(c > 0)
		print v1 + ' > ' + v2;
	elif(c < 0)
		print v1 + ' < ' + v2;
	else
		print v1 + ' == ' + v2;
	endif
endfun

fun compare2(v1, v2)
	if(bltVersionCompare(v1, v2) >= 0) // bltVersionCompare模块函数返回值大于或等于0,则说明v1版本号大于或等于v2版本号
		print v1 + ' >= ' + v2;
	else
		print v1 + ' < ' + v2;
	endif
endfun

compare('v0.1.0', 'v0.2.0');
compare('v1.2.3', 'v1.2');
compare('v2.2.3', 'v2.2.2');
compare('2.3.0', 'v2.3');
print '';

compare2('3.2.1', '3.2');
compare2('3.2.0', '3.2');
compare2('3.2.0', '3.2.1');
print '';

    上面的test.zl测试脚本在命令行中的执行结果如下:

[root@localhost zenglServerTest]# ./zenglServer -r "/v0_24_0/test.zl"
1789.80
1789.800000001000
1.789800000001E+03
1789.80000000099994394986424595117568969726562500000000000000000000000000000000
value: 1789.80000000099994394986424595117568969726562500000000000000000000000000000000

65 - 0x41 - A
66 - 0x42 - B
67 - 0x43 - C
68 - 0x44 - D
69 - 0x45 - E
70 - 0x46 - F
71 - 0x47 - G

v0.1.0 < v0.2.0
v1.2.3 > v1.2
v2.2.3 > v2.2.2
2.3.0 == v2.3

3.2.1 >= 3.2
3.2.0 >= 3.2
3.2.0 < 3.2.1

[root@localhost zenglServerTest]# 

test_affected_rows.zl脚本:

    为了测试新增的mysqlAffectedRows模块函数,当前版本在 my_webroot/v0_24_0/ 目录中增加了test_affected_rows.zl测试脚本,该脚本的代码如下:

use builtin, mysql;
inc 'config.zl';

fun finish_with_error(con)
	err = mysqlError(con);
	mysqlClose(con);
	bltExit(err);
endfun

fun mysql_query(con, sql)
	if(mysqlQuery(con, sql))
		finish_with_error(con);
	endif
	result = mysqlStoreResult(con);
	return_array = bltArray();
	while(mysqlFetchResultRow(result, &result_array))
		return_array[] = result_array;
	endwhile
	mysqlFreeResult(result);
	return return_array;
endfun

con = mysqlInit();
if(!con)
	bltExit('mysqlInit failed');
endif

if(!mysqlRealConnect(con, config['db_host'], config['db_user'], config['db_passwd'], config['db_name'], config['db_port']))
	finish_with_error(con);
endif

if(mysqlQuery(con, "CREATE TABLE IF NOT EXISTS `test_table` (
	  id int NOT NULL AUTO_INCREMENT, 
	  name varchar(255) NOT NULL DEFAULT '', 
	  score int NOT NULL DEFAULT 0, 
	  PRIMARY KEY (id)
	) ENGINE=MyISAM DEFAULT CHARSET utf8 COLLATE utf8_general_ci COMMENT='my test table'"))
	finish_with_error(con);
endif

for(i=0; i < 3;i++)
	if(mysqlQuery(con, "INSERT INTO `test_table` (`name`,`score`) VALUES('" + bltRandomStr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 4) + "', '" + bltRand(0, 100) + "')"))
		finish_with_error(con);
	endif
	// 通过mysqlAffectedRows模块函数,打印 INSERT 插入语句所添加的记录数
	print 'insert table `test_table`, affected rows: ' + mysqlAffectedRows(con);
endfor

if(mysqlQuery(con, "UPDATE `test_table` SET `score` = '50' WHERE score < 50"))
	finish_with_error(con);
endif
// 通过mysqlAffectedRows模块函数,打印 UPDATE 更新语句所更新的记录数
print "update table `test_table`, affected rows: " + mysqlAffectedRows(con);

if(mysqlQuery(con, "DELETE FROM `test_table` WHERE score > 80"))
	finish_with_error(con);
endif
// 通过mysqlAffectedRows模块函数,打印 DELETE 删除语句所删除的记录数
print "delete from table `test_table`, affected rows: " + mysqlAffectedRows(con);

data_array = mysql_query(con, "select * from `test_table` order by id desc limit 20");
// 通过mysqlAffectedRows模块函数,打印 select 查询语句所查找出来的记录数
print 'select rows num: ' + mysqlAffectedRows(con);
for(i=0;bltIterArray(data_array,&i,&data);)
	print data['id'] + ': ' + data['name'] + ' (score: ' + data['score'] + ')';
endfor

    该脚本在开头,会去加载config.zl配置脚本,在config.zl配置脚本中包含了和数据库相关的配置信息:

config['db_host'] = 'localhost'; // mysql数据库ip
config['db_port'] = 3306;        // mysql数据库端口
config['db_user'] = 'root';      // mysql用户名
config['db_passwd'] = '123456';  // mysql密码
config['db_name'] = 'testdb';    // mysql数据库名

    所以,要测试test_affected_rows.zl脚本的话,必须先启动mysql数据库服务,还需要先创建好testdb数据库。test_affected_rows.zl脚本在执行时会自动在testdb数据库中创建test_table表结构(如果该表结构不存在的话才会进行创建),并在该表中插入,更新和删除数据,并通过mysqlAffectedRows模块函数来获取这些操作所影响的数据库记录数。该脚本在命令行中的执行结果类似如下所示:

[root@localhost zenglServerTest]# ./zenglServer -r "/v0_24_0/test_affected_rows.zl"
insert table `test_table`, affected rows: 1
insert table `test_table`, affected rows: 1
insert table `test_table`, affected rows: 1
update table `test_table`, affected rows: 1
delete from table `test_table`, affected rows: 1
select rows num: 20
75: FYTS (score: 50)
73: KDRY (score: 66)
72: GWGX (score: 50)
71: IAFE (score: 67)
70: CFHK (score: 50)
69: LEGY (score: 80)
67: KGNI (score: 50)
66: EKFW (score: 50)
65: JVVE (score: 50)
64: FNIL (score: 72)
63: QJDN (score: 50)
62: CFBI (score: 75)
61: BOMN (score: 55)
60: BKGJ (score: 79)
59: IPOE (score: 50)
58: EKBG (score: 67)
57: KAJP (score: 76)
56: UOEL (score: 50)
55: FQUW (score: 50)
54: QLLG (score: 50)
[root@localhost zenglServerTest]# 

    上面测试结果中,向test_table表中插入了三条数据,更新了一条数据,并删除了一条数据,最后从该表中查询了20条数据出来(在本次测试之前,该脚本已经测试过很多次了,因此该表中之前就已经有很多条记录了)。

结束语:

    我喜欢纯粹的创造。

—— 盗梦空间

 

上下篇

下一篇: zenglServer v0.25.0 使用v1.9.0版本的zengl语言库,增加backlog及timezone配置,增加bltSetTimeZone模块函数

上一篇: zenglServer v0.23.0 使用v1.8.3版本的zengl语言,增加bltTrim等模块函数,支持中文url路径等

相关文章

zenglServer v0.23.0 使用v1.8.3版本的zengl语言,增加bltTrim等模块函数,支持中文url路径等

zenglServer v0.11.0 共享内存,crustache转义,magick模块,新增bltDate等内建模块函数

zenglServer v0.13.0 目录入口文件以及模板路径调整

zenglServer v0.14.0 正则表达式模块

zenglServer v0.10.0 使用zengl脚本的编译缓存,跳过编译过程

zenglServer v0.12.0 图形验证码, 新增模块函数