我有一个脚本用于构建表和存储过程。例如,我有一个varchar
类型的列。 varchar
需要一个size参数,该大小我也用作存储过程和这些过程中的参数。
是否可以为其大小设置#define
的等价,因此我可以轻松调整大小而无需通过整个脚本进行更改?
我正在使用MySql工作台。
修改
我尝试了SET
和DECLARE
我有一个脚本 - 这是(删节)
CREATE TABLE `locations`
(
`location` VARCHAR(25) NOT NULL
);
...
CREATE PROCEDURE AddLocation (IN location VARCHAR(25)
BEGIN
...
END$$
我想要实现的是使用常量替换脚本中的值25 - 类似于创建表和存储过程的脚本顶部的#define
,所以我可以轻松地将25更改为另一个数字。
有人找到了解决这个问题的方法吗?
答案 0 :(得分:20)
C预处理器(cpp)历史上与C(因此名称)相关联,但它实际上是一个可以用于(或滥用)其他东西的通用文本处理器。
考虑这个名为location.src的文件(稍后会详细介绍)。
// C++ style comments works here
/* C style works also */
-- plain old SQL comments also work,
-- but you should avoid using '#' style of comments,
-- this will confuse the C pre-processor ...
#define LOCATION_LEN 25
/* Debug helper macro */
#include "debug.src"
DROP TABLE IF EXISTS test.locations;
CREATE TABLE test.locations
(
`location` VARCHAR(LOCATION_LEN) NOT NULL
);
DROP PROCEDURE IF EXISTS test.AddLocation;
delimiter $$
CREATE PROCEDURE test.AddLocation (IN location VARCHAR(LOCATION_LEN))
BEGIN
-- example of macro
ASSERT(length(location) > 0, "lost or something ?");
-- do something
select "Hi there.";
END
$$
delimiter ;
和文件debug.src,包括:
#ifdef HAVE_DEBUG
#define ASSERT(C, T) \
begin \
if (not (C)) then \
begin \
declare my_msg varchar(1000); \
set my_msg = concat("Assert failed, file:", __FILE__, \
", line: ", __LINE__, \
", condition ", #C, \
", text: ", T); \
signal sqlstate "HY000" set message_text = my_msg; \
end; \
end if; \
end
#else
#define ASSERT(C, T) begin end
#endif
编译时使用:
cpp -E location.src -o location.sql
你得到了你正在寻找的代码,cpp扩展了#define值。
编译时使用:
cpp -E -DHAVE_DEBUG location.src -o location.sql
你得到的相同,加上ASSERT宏(作为奖励发布,以显示可以做什么)。
假设在测试环境中部署HAVE_DEBUG的构建(使用SIGNAL后在5.5或更高版本中),结果如下所示:
mysql> call AddLocation("Here");
+-----------+
| Hi there. |
+-----------+
| Hi there. |
+-----------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
mysql> call AddLocation("");
ERROR 1644 (HY000): Assert failed, file:location.src, line: 24, condition length(location) > 0, text: lost or something ?
注意文件名,行号和条件如何指向location.src中引发断言的源代码中的位置,再次感谢C预处理器。
现在,关于“.src”文件扩展名:
与任何工具一样,使用cpp可以带来好处,而以便携方式维护LOCATION_LEN的用例看起来非常合理。 它也可能导致坏事,有太多#include,嵌套#ifdef地狱,宏等等,最后会混淆代码,所以你的里程可能会有所不同。
通过这个答案,您可以得到整件事(#define
,#include
,#ifdef
,__FILE__
,__LINE__
,#C
,命令要构建的行选项,所以我希望它应该涵盖所有。
答案 1 :(得分:1)
你试过SET吗?
这是一个例子:
SET @var_name = expr
这里有更多例子: http://dev.mysql.com/doc/refman/5.0/en/user-variables.html
答案 2 :(得分:1)
听起来您正在寻找用户定义的数据类型。不幸的是,我们所有的mySQL还不支持用户定义的数据类型,如SQL Server,Oracle和其他人。
以下是支持的数据类型列表: http://dev.mysql.com/doc/refman/5.0/en/data-types.html
答案 3 :(得分:0)
对于那些感兴趣的人:
我最终编写了一个PHP脚本,因为:
a)可以访问数据库的机器不属于我,我无法访问C 预处理器 b)另外两个答案不起作用。 c)似乎最简单的解决方案
以下是可能会发现它有用的脚本。我用它来定义表列 widths然后在存储过程中使用这些相同的值。这是由于该列 宽度还没有完全确定生产。
我还内置了你可以定义持续几行的字符串。这样做的好处是我可以遵守80列宽(因此打印看起来可读)。
这是脚本
<?php
if (1==count($argv))
{
?>
Processing #defines from stdin and send to SQL server:
This script will remove
1. #define <name> <integer>
2. #define <name> '<string>'
3. #define <name> '<string>' \
'<continuation of string>'
and replace the occurances of name with the #define value as specified
<name> is upper case alpha numberics or underscores, not starting with a
digit.
The arguments of this script is passed to the mysql executable.
<?php
exit(1);
}
function replace(&$newValues, $a, $b, $c)
{
return $a . (array_key_exists($b, $newValues) ? $newValues[$b] : $b) . $c;
}
// The patterns to be used
$numberPattern='/^#define[ \t]+([A-Z_][A-Z0-9_]*)[ \t]+(0|([1-9][0-9]*))'.
'[ \t]*[\r\n]+$/';
$stringPattern= '/^#define[ \t]+([A-Z_][A-Z0-9_]*)[ \t]+\''.
'((\\\'|[^\'\r\n])*)\'[ \t]*(\\\\{0,1})[\n\r]+$/';
$continuationPattern='/^[ \t]*\'((\\\'|[^\'\r\n])*)\'[ \t]*'.
'(\\\\{0,1})[\n\r]+$/';
// String to be evaluated to replace define values with a new value
$evalStr='replace($newValues, \'\1\', \'\2\', \'\3\');';
array_splice($argv, 0, 1);
// Open up the process
$mysql=popen("mysql ".implode(' ', $argv), 'w');
$newValues=array(); // Stores the defines new values
// Variables to control the replacement process
$define=false;
$continuation=false;
$name='';
$value='';
while ($line=fgets(STDIN))
{
$matches=array();
// #define numbers
if (!$define &&
1 == preg_match($numberPattern, $line, $matches))
{
$define = true;
$continuation = false;
$name = $matches[1];
$value = $matches[2];
}
// #define strings
if (!$define &&
1 == preg_match($stringPattern,
$line, $matches))
{
$define = true;
$continuation = ('\\' == $matches[4]);
$name = $matches[1];
$value = $matches[2];
}
// For #define strings that continue over more than one line
if ($continuation &&
1 == preg_match($continuationPattern,
$line, $matches))
{
$value .= $matches[1];
$continuation = ('\\' == $matches[3]);
}
// Have a complete #define, add to the array
if ($define && !$continuation)
{
$define = $continuation = false;
$newValues[$name]=$value;
}
elseif (!$define)
{
// Do any replacements
$line = preg_replace('/(^| |\()([A-Z_][A-Z0-9_]*)(\)| |$)/e',
$evalStr, $line);
echo $line; // In case we need to have pure SQL.
// Send it to be processed.
fwrite($mysql, $line) or die("MySql has failed!");
}
}
pclose($mysql);
?>