【问题标题】:SQL Scripts - Does the equivalent of a #define exist?SQL 脚本 - 是否存在与 #define 等效的内容?
【发布时间】:2012-03-03 13:59:56
【问题描述】:

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

它的大小是否可以与 #define 等效,因此我可以轻松调整大小而无需更改整个脚本?

我正在使用 MySql 工作台。

编辑

我试过SETDECLARE

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

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

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

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

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

【问题讨论】:

标签: mysql sql scripting


【解决方案1】:

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 的构建(在 5.5 或更高版本中,因为使用了 SIGNAL),结果如下所示:

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

  • 你可以使用任何东西。
  • 具有不同的文件扩展名有助于生成文件等,并防止混淆。

编辑:最初发布为 .xql,为清楚起见重命名为 .src。这里没有与 xml 查询相关的内容。

与任何工具一样,使用 cpp 可以带来好处,并且以可移植方式维护 LOCATION_LEN 的用例看起来非常合理。 它也可能导致不好的事情,有太多的#include、嵌套的#ifdef hell、宏等,最终混淆了代码,所以你的里程可能会有所不同。

有了这个答案,你就得到了全部内容(#define#include#ifdef__FILE____LINE__#C,要构建的命令行选项),所以我希望它应该涵盖这一切。

【讨论】:

  • 巧妙。我从没想过对 SQL 文件使用预处理器。
  • 我希望有一个不需要使用预处理器的解决方案。但我会探索这个选项。
【解决方案2】:

你试过 SET 吗?

这是一个例子:

SET @var_name = expr

这里有更多例子: http://dev.mysql.com/doc/refman/5.0/en/user-variables.html

【讨论】:

【解决方案3】:

听起来您正在寻找用户定义的数据类型。不幸的是,对于我们来说,mySQL 还不支持用户定义的数据类型,如 SQL Server、Oracle 和其他。

以下是支持的数据类型列表: http://dev.mysql.com/doc/refman/5.0/en/data-types.html

【讨论】:

    【解决方案4】:

    对于那些感兴趣的人:

    我最终写了一个 PHP 脚本,因为:

    a) 可以访问数据库的机器不属于我,我无法访问C 预处理器 b)其他两个答案不起作用。 c) 似乎是最简单的解决方案

    这是为那些可能觉得有用的人准备的脚本。我用它来定义表格列 宽度,然后在存储过程中使用这些相同的值。这是由于列 宽度尚未完全确定用于生产。

    我还内置了您可以定义持续几行的字符串。这样做的好处是我可以遵守 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);
    ?>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-09
      • 2018-04-09
      • 2021-11-09
      • 1970-01-01
      • 2021-04-26
      • 2011-11-08
      • 1970-01-01
      • 2011-11-19
      相关资源
      最近更新 更多