Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Error en CREATE PROCEDURE desde aplicación (https://www.clubdelphi.com/foros/showthread.php?t=89388)

Angel.Matilla 13-11-2015 13:43:07

Error en CREATE PROCEDURE desde aplicación
 
Sigo con mi "guerra particular" aprendiendo el uso de procedures y triggers. Estoy tratando de crear un procedure desde una aplicación. Este se el código:
Código:

String Codigo = "CREATE PROCEDURE Persona_Bor_Aux(iTabla VARCHAR(10), iProvincia CHAR(2)) AS DECLARE VARIABLE pCodigo VARCHAR(9); DECLARE VARIABLE pLike CHAR(12); DECLARE VARIABLE pSelect VARCHAR(250); BEGIN pCodigo = IIF(iTabla = 'CARGO' OR iTabla = 'PROFESION', 999999, 999); pLike = '%DESCONOCID%'; pSelect = 'SELECT Codigo FROM ' || iTabla || ' WHERE ' || IIF(iTabla = 'PAIS', '', 'CodPrv = :iProvincia AND ') || ' Nombre LIKE ' || pLike || ' INTO :pCodigo'; EXECUTE STATEMENT :pSelect; pSelect = 'UPDATE Personas SET ' || iTabla || ' = :pCodigo WHERE CodPrv = :iProvincia AND ' || iTabla || ' = :OLD.' || iTabla; EXECUTE STATEMENT :pSelect; END"
Para crear el procedure desde código lo hago así con un TIBQuery:
Verifico que no exista.
Código:

Auxiliar->Close();
Auxiliar->SQL->Text = "SELECT COUNT(*) Hay FROM RDB$PROCEDURES WHERE RDB$PROCEDURE_NAME = 'Persona_Bor_Aux'";
Auxiliar->Open();

Si no existe, trato de crearlo con un TIBSQL.
Código:

if (Auxiliar->FieldByName("Hay")->AsInteger == 0)
{
    if (!IbSql->Transaction->InTransaction)
          IbSql->Transaction->StartTransaction();

    IbSql->Close();
    IbSql->SQL->Text = Codigo;
    IbSql->ExecQuery();
    IbSql->Transaction->CommitRetaining();
}

Lo curioso es que si ejecuto ese código tal como lo he puesto, en una sola línea de código, desde EMS SQL Manager se ecrea el procedure sin mayor problema, pero desde la aplicación me da siempre un SQL Code -104, GDS Code 335544569. Este GDS no corresponde a ningún SQL Code -104. Evidentemente la base de datos está conectada.

Casimiro Notevi 13-11-2015 14:19:24

Una pregunta: ¿por qué quieres crear procedures en tiempo de ejecución?
No es "normal" ni "lógico", la estructura de la base de datos debe ser un entorno "cerrado" no modificable desde el exterior.

ecfisa 13-11-2015 17:17:27

Hola Angel.

En principio voy a decirte que estoy totalmente de acuerdo con Casimiro. Pero a modo ilustrativo, ya sea que uses un componente TIBSQL o un TIBQuery, tenes que fijar la propiedad ParamCheck en falso.

Un ejemplo trivial:
Código:

...
{
  // Verificar si ya existe
  IBQuery1->Close();
  IBQuery1->SQL->Clear();
  IBQuery1->SQL->Add("SELECT RDB$PROCEDURE_ID FROM RDB$PROCEDURES");
  IBQuery1->SQL->Add("WHERE RDB$PROCEDURE_NAME = 'SP_MULT'");
  IBQuery1->Open();

  if (IBQuery1->IsEmpty()) {  // si no existe -> crearlo
    IBSQL1->Close();
    IBSQL1->ParamCheck = false;  // <-
    IBSQL1->SQL->Clear();
    IBSQL1->SQL->Add("CREATE PROCEDURE SP_MULT(A INTEGER, B INTEGER)");
    IBSQL1->SQL->Add("RETURNS(RESULT INTEGER) AS");
    IBSQL1->SQL->Add("BEGIN");
    IBSQL1->SQL->Add("RESULT = :A * :B;");
    IBSQL1->SQL->Add("SUSPEND;");
    IBSQL1->SQL->Add("END");
    IBSQL1->ExecQuery();
  } else
    MessageBox(0, "El procedimiento almacenado ya existe", "", MB_ICONWARNING);
...

Saludos :)

Angel.Matilla 13-11-2015 18:01:47

Cita:

Empezado por Casimiro Notevi (Mensaje 499305)
Una pregunta: ¿por qué quieres crear procedures en tiempo de ejecución?
No es "normal" ni "lógico", la estructura de la base de datos debe ser un entorno "cerrado" no modificable desde el exterior.

Gracias por vuestras respuestas. Como siempre (¡y no escarmiento!) doy la información incompleta. Lo que comentaba del código para el procedure (al igual que para las tablas, los índices o las vistas) es cuando se crea la base de datos: La primera vez que se lanza la aplicación se crea la base de datos y todos los elementos asociados a ella, no lo hago cada vez que arranco; con eso me ahorro el tener que "viajar" con la base de datos en el instalador. Disculpadme si me explicado mal que ya veo que sí.
Cita:

Empezado por ecfisa (Mensaje 499316)
En principio voy a decirte que estoy totalmente de acuerdo con Casimiro. Pero a modo ilustrativo, ya sea que uses un componente TIBSQL o un TIBQuery, tenes que fijar la propiedad ParamCheck en falso.

¡Ah! Pues no se me había ocurrido. Haré la prueba y os diré como ha ido.

lbuelvas 13-11-2015 18:06:08

Si es posible crear procedimientos almacenados / triggers desde una aplicación.

Particularmente creo triggers desde la aplicación para configurar trazos de auditoria, es decir, tengo una pantalla donde puedo seleccionar cualquier tabla de la base de datos y luego marcar que campos tendrán un trazo en una bitacora cuando se efectuen modificaciones.

Para hacerlo debe respetarsen las partes que constituyen un procedimiento almacenado / trigger, como son: uso de set term, encabezado, cuerpo, finalizacion, particularmente utilizo componentes IBX y un Script.

Colocas el objeto TIBScript en tu pantalla y lo conectas a la base de datos y a una transacción, el código puede ser más o menos así:

Código Delphi [-]
Var
    Script : TStrings;
    IBScript1: TIBScript;
begin
  with Script do begin
    Clear;
    Add('');
    Add('SET TERM ^ ;');
    Add('');
    Add('CREATE TRIGGER LOG');
    Add('ACTIVE AFTER DELETE POSITION 0');
    Add('AS');
    Add('Declare Variable ID_TS_LOG integer;');
    Add('Declare Variable CADENA VARCHAR(200);');
    Add('begin');
    -- Aca coloca lo que necesite   
    Add('end');
    Add('^');
    Add('');
    Add('SET TERM ; ^');
  end;

  IBScript1.Script.Clear;
  IBScript1.Script.AddStrings(Script);
  IBScript1.ExecuteScript;
end;

Angel.Matilla 13-11-2015 18:08:03

v:-)v Prueba rápida. Funcionó a la perfección. Muchísimas gracias a los dos. Me queda muchísimo por aprender.
Cita:

Empezado por lbuelvas (Mensaje 499319)
Si es posible crear procedimientos almacenados / triggers desde una aplicación.

Gracias por tu aportación. Mientars escribías la respuesta estaba haciendo yo la prueba.

Lepe 13-11-2015 23:07:41

Solo por completar un poquillo más...

Un IBScript, como su nombre indica, puede albergar todo el código de creación de tablas, triggers, etc de la base de datos, TODO en un solo Script. Es más compacto y fácil de leer, sobre todo si lo tienes en un fichero de texto y lo cargas en ejecución.

Se mete todo en la propiedad IBScript1.Script (TStrings) y se ejecuta con IBScript1.ExecuteScript (creo recordar).

Por cierto, en lugar de "create procedure" puedes usar "create or alter procedure", también aplicable a tablas y otros elementos. Así no tienes que chequear si ya existe. No sé que versión de los IBX usas, puede que no deje usar esa sintaxis... por probar no pierdes nada.

Saludos.

Angel.Matilla 14-11-2015 10:06:19

Gracias por los comentarios. Sobre el mensaje de Lepe, que no sé si va dirigido a mi, decir que no uso los componentes IBX.

Casimiro Notevi 14-11-2015 10:29:38

Cita:

Empezado por Angel.Matilla (Mensaje 499347)
... decir que no uso los componentes IBX.

¿Y qué usas?

Angel.Matilla 14-11-2015 11:25:46

Las paletas de componentes que vienen con Builder.

Casimiro Notevi 14-11-2015 11:27:27

Cita:

Empezado por Angel.Matilla (Mensaje 499349)
Las paletas de componentes que vienen con Builder.

¿Cual es, cómo se llama? :)

Angel.Matilla 14-11-2015 11:41:40

En Builder 6 tengo dos paletas: Interbase e Interbase Admin. Son las que uso.

ecfisa 14-11-2015 13:15:24

Hola Angel.

Si usas los componentes de las pestañas que mencionas, son los IBX. Pero la versión C++ Builder 6 que poseo no trae de forma nativa el componente IBScript.

Saludos :)

Casimiro Notevi 14-11-2015 14:12:11

Esos son los IBX :)

EDITO: No había visto el mensaje de ecfisa.

Angel.Matilla 16-11-2015 10:35:09

Cita:

Empezado por ecfisa (Mensaje 499353)
Hola Angel.

Si usas los componentes de las pestañas que mencionas, son los IBX. Pero la versión C++ Builder 6 que poseo no trae de forma nativa el componente IBScript.

Saludos :)

¿Ves? Eso no lo sabía y pensaba que cuando hablabáis de los IBX eran componentes al margen de la instalación de Builder


La franja horaria es GMT +2. Ahora son las 06:37:10.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi