Como ejecutar un script SQL desde VFP

From codeWiki
Jump to: navigation, search

Por: VictorEspina


Introducción

Cuando desarrollamos aplicaciones que utilizan a SQL Server como almacén de datos, frecuentemente nos encontramos con el problema de como crear la base de datos y como actualizar posteriormente.

Normalmente, estas labores se logran a través de scripts SQL. los cuales son archivos de texto que contienen una o mas sentencias SQL (bien sea DML o DDL), separadas por el comando GO, y que se ejecutan sobre el servidor.

Tradicionalmente, estos scripts se ejecutan usando:

  • La utilidad de comandos en linea OSQL
  • Un cliente gráfico como QueryAnalizer o el Managment Studio Express


Sin embargo, en muchas situaciones nos encontramos con la necesidad de ejecutar dichos scripts directamente desde nuestras aplicaciones VFP.

A primera vista el problema parece sencillo:

  • Cargamos el contenido de script en una variable, usando el comando FILETOSTR()
  • Ejecutamos el script usando SQLEXEC(conn,var)

El problema es que SQLEXEC() no esta diseñado para ejecutar VARIAS instrucciones, sino solo una.

La solución

La solución es aplicar un "parsing" al script, utilizando el comando GO como separador de instrucciones y enviar cada instrucción por separado usando el comando SQLEXEC().

El siguiente procedimiento CFRunSqlScript hace justamente eso. Su uso es muy sencillo:

LOCAL cScript
cScript = FILETOSTR("myscript.sql")

TRY
 CFRunSqlScript(nConn,cScript)
CATCH TO ex
 MESSAGEBOX(ex.Message)
ENDTRY

donde cScript contiene el texto del script SQL a ejecutar y nConn contiene el handle de la conexión con el servidor donde se desea ejecutar el script.

Como es costumbre en estos casos, el uso de este código queda completamente bajo la responsabilidad del usuario y el autor (o sea, yo) no podrá ser encontrado responsable de ninguna perdida o daño causado por el uso de este fuente.

*******************************************************************
* CFRunSQLScript
* Funcion para ejecutar un script SQL en una conexion dada
*
* Parametros:
* pnConn  : Handle de conexión ODBC
* pcScript: Texto del script a ejecutar, contentivo de una o mas
*           instrucciones SQL separadas por el comando "GO"
*
* Autor: Victor Espina
* Fecha: Mayo 2007
********************************************************************

#DEFINE True    .T.
#DEFINE False   .F.

PROCEDURE sqlRunScript(pnConn,pcScript)
 *
 *--- Se carga el script en memoria divido en lineas
 LOCAL ARRAY aScript[1]
 LOCAL nScriptSize
 nScriptSize = ALINES(aScript,pcScript + CHR(13) + CHR(10) + "GO")
 
 
 *-- Se recorre el script. Se acumula en un buffer cada linea
 *   del script (que no sea comentario) hasta llegar a una 
 *   linea en blanco o a un GO. En ese momento se enviar el
 *   contenido del buffer al servidor y se limpia
 *
 LOCAL cBuffer,nCommentDeep,i,cLine,lError,oEX,nResult,aOdbcError[1]
 nCommentDeep = 0
 cBuffer = ""
 lError = False
 FOR i = 1 TO nScriptSize 
  *
  cLine = aScript[i]
   
  *-- Si la linea empieza por "--", se descarta
  IF LEFT(LTRIM(cLine),2) == "--"
   LOOP
  ENDIF
   
  *-- Si la linea empieza por /* se marca el inicio de un bloque de comentario
  IF LEFT(LTRIM(cLine),2) == "/*"
   nCommentDeep = nCommentDeep + 1
   LOOP
  ENDIF
   
  *-- Si la linea empieza por "*/" se marca el final de un bloque de comentarios
  IF AT("*/",cLine)<>0
   nCommentDeep = nCommentDeep - 1
   LOOP
  ENDIF
   
  *-- Si esta activo un bloque de comentario, se pasa a la siguiente linea
  IF nCommentDeep > 0
   LOOP
  ENDIF
   
  *-- Si es una linea GO, se ejecuta el buffer 
  IF UPPER(ALLTRIM(cLine))=="GO"
   *
   IF NOT EMPTY(cBuffer)
    nResult = SQLEXEC(pnConn,cBuffer)
    IF nResult < 0
     oEx = CREATEOBJECT("CFLastErrorException")
     lError = True
    ENDIF
    DOEVENTS
   ENDIF
   cBuffer = ""
   
   IF lError
    EXIT
   ENDIF
   
   LOOP
   *
  ENDIF
  
  IF lError
   EXIT
  ENDIF
  
  *-- Se incluye la linea en el buffer
  cBuffer = cBuffer + cLine + CRLF
  *
 ENDFOR
 

 
 *-- Si ocurrio un error, se propaga al nivel superior
 *
 IF lError
  THROW oEX
 ENDIF
 *
ENDPROC



*-- CFLastErrorException
*   Excepcion con los datos del ultimo error ocurrido
*
DEFINE CLASS CFLastErrorException AS Exception
 *
 PROCEDURE Init
  *
  DODEFAULT()
  
  LOCAL ARRAY aErrInfo[1]
  AERROR(aErrInfo)

  DO CASE
     CASE INLIST(aErrInfo[1],1427,1429)   && OLE Error
          THIS.ErrorNo = aErrInfo[7]
          THIS.Message = aErrInfo[3]
     
     CASE aErrInfo[1] = 1526              && ODBC Error
          THIS.ErrorNo = aErrInfo[5]
          THIS.Message = aErrInfo[3]
     
     OTHERWISE                            && VFP Error
          THIS.ErrorNo = aErrInfo[1]
          THIS.Message = aErrInfo[2]
  ENDCASE      
  *
 ENDPROC
 *
ENDDEFINE
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox