2012-02-11 10 views
6

Tengo un script que uso para construir las tablas y los procedimientos almacenados. Por ejemplo, tengo una columna del tipo varchar. varchar requiere un parámetro de tamaño, ese tamaño que también uso como parámetros en procedimientos almacenados y dentro de esos procedimientos.Scripts SQL: ¿existe el equivalente de #define?

¿es posible tener el equivalente de #define para su tamaño, por lo que puedo ajustar fácilmente el tamaño sin la necesidad de tener que cambiar ithroughht toda la secuencia de comandos?

Estoy usando MySql workbench.

EDITAR

He tratado SET y DECLARE

Tengo un script - esto es (abreviado)

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

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

Lo que estoy tratando de lograr es sustituir los valores de 25 en la secuencia de comandos con una constante - similar a #define en la parte superior de la secuencia de comandos que crea la tabla y se almacena procedimientos, así que puedo cambiar fácilmente el 25 a otro número.

¿Alguien ha encontrado una solución a este problema?

+0

declarar? http://dev.mysql.com/doc/refman/5.0/en/declare-local-variable.html –

+0

Escribí algunos SW para hacer tal cosa, es gratis y aquí http: // mysql-pre- processor.batcave.net/. Solo ponga algunas cosas en el cubo de la organización benéfica de su elección –

Respuesta

18

El preprocesador de c (CPP) está asociado históricamente con C (de ahí el nombre), pero realmente es un procesador de texto genérico que puede ser utilizado (o abusado) por algo más.

Considere este archivo, llamado location.src (más sobre esto más adelante).

// 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 ; 

y debug.src archivo, que se incluye:

#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 

cuando se compila con:

cpp -E location.src -o location.sql 

se obtiene el código que está buscando, con valores #define CPP expandir .

cuando se compila con:

cpp -E -DHAVE_DEBUG location.src -o location.sql 

se obtiene el mismo, además de la macro ASSERT (publicado como un bono, para mostrar lo que podría hacerse).

Suponiendo una acumulación con HAVE_DEBUG desplegado en un entorno de pruebas (en 5.5 o posterior desde señal se utiliza), el resultado se parece a esto:

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 ? 

Nótese cómo el nombre de archivo, número de línea, y los puntos de condición justo en el lugar en el código fuente en location.src donde se eleva la afirmación, gracias de nuevo al preprocesador C.

Ahora, sobre la extensión de archivo ".src":

  • puede utilizar cualquier cosa.
  • Tener una extensión de archivo diferente ayuda con makefiles, etc., y evita confusiones.

EDITAR: Originalmente publicado como .xql, renombrado como .src para mayor claridad. No hay nada relacionado con las consultas xml aquí.

Como con cualquier herramienta, usar cpp puede llevar a cosas buenas, y el caso de uso para mantener LOCATION_LEN de una manera portátil parece muy razonable. También puede llevar a cosas malas, con demasiados #include, #fdef hell anidados, macros, etc. que al final ofuscan el código, por lo que su kilometraje puede variar.

Con esta respuesta, se obtiene toda la cosa (#define, #include, #ifdef, __FILE__, __LINE__, #C, opciones de línea de comandos para construir), así que espero que debe cubrir todo.

+4

Ingenioso.Nunca pensé en usar un pre-procesador en archivos SQL. – njr101

+0

Esperaba una solución que no requiera el uso de un preprocesador. Pero exploraré esta opción. –

1

¿Has probado SET?

aquí es un ejemplo:

SET @var_name = expr 

más ejemplos aquí: http://dev.mysql.com/doc/refman/5.0/en/user-variables.html

+0

He intentado tanto declarar como establecer. Solo quiero poner en la parte superior del script los tamaños para los diferentes campos. El resto de la secuencia de comandos para crear las tablas/vistas/procedimientos almacenados/funciones basadas en esos valores. Solo para facilitar la reconstrucción de la base de datos con diferentes tamaños de los diversos campos. –

+0

Ah ... tal vez quiera leer este http://stackoverflow.com/questions/1009954/mysql-variable-vs-variable-whats-the-difference y puede asignar una variable global con 'SET' http://dev.mysql.com/doc/refman/5.1/en/set-option.html –

1

Parece que usted está buscando tipos de datos definidos por el usuario. Desafortunadamente para nosotros, mySQL aún no admite tipos de datos definidos por el usuario como SQL Server, Oracle y otros.

He aquí una lista de tipos de datos soportados: http://dev.mysql.com/doc/refman/5.0/en/data-types.html

0

Para aquellos que estén interesados:

terminé escribiendo un script PHP porque:

a) La máquina que se puede acceder a la base de datos no pertenece a mí y no se puede acceder al preprocesador C b) La otra las dos respuestas no funcionan. c) Parecía la solución más simple

Aquí está el guión para aquellos que puedan encontrarlo útil. Lo estoy usando para definir las anchuras de la columna de tablas y luego utilizo esos mismos valores en los procedimientos almacenados. Esto se debe a que la columna no se ha decidido por completo para la producción.

También he incorporado que puede definir cadenas que duran unas pocas líneas. Esto tiene la ventaja de que puedo obedecer el ancho de 80 columnas (por lo tanto, la impresión parece legible).

Aquí es el guión

<?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); 
?> 
Cuestiones relacionadas