SQL脚本 - 是否存在#define的等价物?

时间:2012-02-11 08:54:09

标签: mysql sql scripting

我有一个脚本用于构建表和存储过程。例如,我有一个varchar类型的列。 varchar需要一个size参数,该大小我也用作存储过程和这些过程中的参数。

是否可以为其大小设置#define的等价,因此我可以轻松调整大小而无需通过整个脚本进行更改?

我正在使用MySql工作台。

修改

我尝试了SETDECLARE

我有一个脚本 - 这是(删节)

CREATE TABLE `locations`
(
   `location`  VARCHAR(25)        NOT NULL
);

...
CREATE PROCEDURE AddLocation (IN  location VARCHAR(25)
BEGIN
...
END$$

我想要实现的是使用常量替换脚本中的值25 - 类似于创建表和存储过程的脚本顶部的#define,所以我可以轻松地将25更改为另一个数字。

有人找到了解决这个问题的方法吗?

4 个答案:

答案 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”文件扩展名:

  • 你可以使用任何东西。
  • 使用不同的文件扩展名有助于makefile等,并防止混淆。
编辑:最初发布为.xql,为了清楚起见重命名为.src。这里没有与xml查询相关的内容。

与任何工具一样,使用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);
?>