Uso de la clase StringTokenizer para realizar un analizador sintactico de SQL

Uso de la clase StringTokenizer para realizar una analizador sintactico de las operaciones SQL INSERT, DELETE, UPDATE o SELECT. Como he mostrado anteriormente el uso de la clase StringTokenizer es muy sencillo. Asi que ahora quisiera aportar una idea acerca de como se podria implementar el analizador sintactico para alguna de las 4 operaciones SQL. El ejemplo solamente es una clase y solamente da una idea de como iniciar el analisis de la sintaxis de la Operacion INSERT de SQL, SOLAMENTE ES UNA IDEA y es la siguiente:

/*
 *    Instituto Tecnologico de Zacatepec
 *	Descripcion Ejemplo2 de uso de la clase StringTokenizer
 * author Gonzalo Silverio    gonzasilve@hotmail.com
 * version 1.00 
 * Archivo: EjemploTokenizer2.java
 */

import java.util.StringTokenizer;

public class EjemploTokenizer2
{
	//Guarda las tablas validas donde se puede realizar el INSERT, DELETE, UPDATE o un SELECT
	// este arreglo se puede rellenar con info de alguna fuente exterior a este
	//programa; por ejemplo de una B.D.
	static String tablasValidas[] = {"alumnos","profesores","calificaciones","materias","etc"};
    
    //Analiza la sintaxis de la operacion INSERT de SQL
    public static void analizarOperacionInsert(String cadena)
    {
		StringTokenizer tok1 = new StringTokenizer(cadena);
		String finCadena = new String();
    	//Guardara el token actualmente leido
    	String tokenActual;
    	
    	//salta el INSERT (en el main ya se comprobo que si era la palabra INSERT)
		tok1.nextToken();
		//guarda SEGUNDO token (INTO)
		tokenActual = tok1.nextToken();
		
		//Comprueba si realmente es la palabra INTO
		if(! tokenActual.equals ("INTO") )
		{
			System.out.println ("Se esperaba la palabra clave INTO, no '"+tokenActual+"'");
			return;
		}
		
		//guarda SEGUNDO token (Nombre de la tabla donde se desea hacer el INSERT)
		tokenActual = tok1.nextToken();
		
		//Comprueba si es una tabla valida
		if( ! buscar_tabla(tokenActual) )
		{
			System.out.println ("La tabla '"+tokenActual+"' NO EXISTE o NO es una tabla valida.");
			return;
		}
		
		tokenActual = tok1.nextToken(); 	//guarda lo de values y todo lo demas
		
		StringTokenizer tok2 = new StringTokenizer(tokenActual,"(");
		String cadValues;
		cadValues = tok2.nextToken();
		
		//Comprueba si realmente es la palabra VALUES
		if(! cadValues.equals ("VALUES") )
		{
			System.out.println ("Se esperaba la palabra clave VALUES, no '"+cadValues+"'");
			return;
		}
		//Muestra los tokens que estan despues del parentesis
		System.out.println("\n\n"+tok2.nextToken());
		
		//Y asi sucesivamente se seguiria analizando la sintaxis de la Operacion INSERT de SQL
		//bla, bla, bla
		
    }  // Fin de metodo analizarOperacionDelete();
    
    //Analiza la sintaxis de la operacion DELETE de SQL
    public static void analizarOperacionDelete(String cadena)
    {
    	//Aqui se analizaria la sintaxis del DELETE
    }
    
    //Analiza la sintaxis de la operacion UPDATE de SQL
    public static void analizarOperacionUpdate(String cadena)
    {
    	//etc
    }
    
    //Analiza la sintaxis de la operacion SELECT de SQL
    public static void analizarOperacionSelect(String cadena)
    {
    	
    }
    
   //Devuelve true si la cadena que llega esta dentro de un arreglo de Strings,
   //devuelve  false en caso contrario; busca la tabla que llega dentro de las tablas validas
   public static boolean buscar_tabla(String nomTabla)
   {
      for(int i = 0;i< tablasValidas.length;i++)
      {
         if( tablasValidas[i].equals(nomTabla) )
				return true;
      }
      return false;
   }

    public static void main(String gonza[])
    {
    	//Cadena a ser analizada
    	String cadena = "INSERT INTO alumnos VALUES('s1','intel','cuerna',245)";
    	//String cadena = "Delete FROM alumnos where matricula='00547264'";
    	//String cadena = "UPDATE alumnos SET nombre='Fabian', apellidos='Granados P.' where matricula='00664326'";
    	
    	//Guardara el token actualmente leido
    	String tokenActual;

		StringTokenizer st = new StringTokenizer(cadena);
		
		//Guarda el primer token
		tokenActual = st.nextToken();
		
		//Convertimos toda la cadena a MAYUSCULAS para hacerla case insensitive
		// (NO sensible a las mayusculas/minusculas)
		tokenActual = tokenActual.toUpperCase();
		
		//EMPEZAMOS POR REVISAR EL PRIMER TOKEN, si es una de las 4 Operaciones SQL
		if( tokenActual.equals ("INSERT") || tokenActual.equals ("DELETE")  || tokenActual.equals ("UPDATE") || tokenActual.equals ("SELECT"))
		{
			if (tokenActual.equals ("INSERT"))
				analizarOperacionInsert(cadena);
			else if (tokenActual.equals ("DELETE"))
				analizarOperacionDelete(cadena);
			else	if (tokenActual.equals ("UPDATE"))
				analizarOperacionUpdate(cadena);
			else	if (tokenActual.equals ("SELECT"))
				analizarOperacionSelect(cadena);
		}
		else
			System.out.println("No es una operacion SQL valida, solo se permite INSERT,DELETE,UPDATE o SELECT");
		
		
    }  //Fin del metodo main()
    
    
}

Observa como en el metodo main() se especifica la operacion SQL a analizar (linea 101), obviamente esa cadena se debe obtener de alguna caja de texto donde escribio el usuario o dejar que la teclee el usuario por la consola, yo la he puesto en una variable directamente para fines didacticos y por que solmente quiero mostrar mi idea. Ahora una imagen de la ejecucion y compilacion del ejemplo (sin errores de sintaxis):

Ejecucion1 de ejemplo de analisis sintactico de INSERT de SQL

Ejecucion1 de ejemplo de analisis sintactico de INSERT de SQL

Ahora supongamos que en la cadena escribimos mal la palabra INTO y pusimos INTOO, asi;

String cadena = "INSERT INTOO alumnos VALUES('s1','intel','cuerna',245)";

(esto lo cambias en la linea 101) observa ahora la ejecucion, nos marca error de sintaxis!!!

Ejecucion2 de ejemplo de analisis sintactico de INSERT de SQL

Ejecucion2 de ejemplo de analisis sintactico de INSERT de SQL

Ahora supongamos que escribimos un nombre de tabla que no es ninguna de las tablas validas; escribimos la tabla salarios, asi;

 
String cadena = "INSERT INTO salarios VALUES('s1','intel','cuerna',245)";

(esto lo cambias en la linea 101) observa ahora la ejecucion, nos marca error de sintaxis!!!, la tabla no existe!!

Ejecucion3 de ejemplo de analisis sintactico de INSERT de SQL

Ejecucion3 de ejemplo de analisis sintactico de INSERT de SQL

Ahora supongamos que olvidamos escribir la palabra INTO, asi;

String cadena = "INSERT alumnos VALUES('s1','intel','cuerna',245)";

(esto lo cambias en la linea 101) observa ahora la ejecucion, nos marca error de sintaxis!!!.

Ejecucion4 de ejemplo de analisis sintactico de INSERT de SQL

Ejecucion4 de ejemplo de analisis sintactico de INSERT de SQL

Es todo, y si quieres el .java ya sabes, pidelo en un comentario y te lo envio. hasta pronto.

Uso de la clase StringTokenizer

Uso de los metodos basicos de la clase StringTokenizer; nextToken(),hasMoreTokens(),countTokens(). En esta ocasion voi a mostrar el uso de tres metodos de la clase StringTokenizer. Esta clase permite obtener por separado las palabras (tokens) que conforman una cadena, para obtener las palabras separadas se puede especificar el separador que hay entre estas, por defecto sino se indica Java asume que el separador es el espacio. Esta clase tiene varios constructores pero a mi principalmente me parecen interesantes dos:

El primero recibe como entrada una cadena, la cual es obviamente la cadena que contiene las palabras que se quieren obtener por separado. En este ejemplo voi a suponer que se desea obtener los tokens de una cadena la cual es una de las 4 operaciones SQL (INSERT, DELETE, UPDATE o SELECT). Ejemplos del uso de este constructor:

//La clase se encuentra en el paquete java.util
import java.util.StringTokenizer;
//Ejemplo del uso del contructor1, donde java asume el espacio como separador
StringTokenizer token1 = new StringTokenizer("SELECT nombre,apellidos,edad FROM alumnos");
StringTokenizer token2 = new StringTokenizer("EJEMPLO DE UNA CADENA PARA EFECTOS DE PRUEBA");
StringTokenizer token3 = new StringTokenizer("Instituto Tecnologico de Zacatepec");

Las cadenas anteriores tienen 4,8,4 tokens respectivamente.
El segundo constructor recibe como entrada una cadena y un caracter separador (en realidad puede ser otra cadena). Ejemplos:

//La clase se encuentra en el paquete java.util
import java.util.StringTokenizer;
//Ejemplo del uso del contructor2, donde se especifica explicitamente el separador de los tokens
StringTokenizer token1 = new StringTokenizer("04-04-2011","-");
StringTokenizer token2 = new StringTokenizer("gonzasilve:x:502:502:   Gonzalo Silverio:/home/gonzasilve:/bin/bash",":");

Ahora las cadenas anteriores tienen 3 y 7 tokens respectivamente. Ojo, observa que el espacio ya no es el separador en ninguna de las cadenas anteriores, por eso tienen ese numero de tokens.

Bueno ahora vamos con los metodos, los describo brevemente a continuacion:

nextToken()
Devuelve una subcadena (String) que es el siguiente token de la cadena. Imaginemos que cada vez que se llama a este metodo hay un apuntador y el cual se posiciona en el siguiente token. Observa la siguiente imagen

Uso del metodo nextToken() de la clase StringTokenizer

Uso del metodo nextToken() de la clase StringTokenizer

La primera vez que se llama a este metodo, el apuntador esta posicionado en la primera palabra por lo tanto el metodo devolveria el token «INGENIERIA» y el apuntador se mueve al siguiente token.
La segunda vez que se llama a este metodo, el apuntador esta posicionado en la segunda palabra por lo tanto el metodo devolveria el token «EN» y el apuntador se mueve al siguiente token.
La tercera vez que se llama a este metodo, el apuntador esta posicionado en la tercera palabra por lo tanto el metodo devolveria el token «SISTEMAS» y el apuntador se mueve al siguiente token.
La cuarta vez que se llama a este metodo, el apuntador esta posicionado en la cuarta palabra por lo tanto el metodo devolveria el token «COMPUTACIONALES» y el apuntador se mueve al siguiente token.

Ahora observa la siguiente imagen donde se observa la posicion donde quedo el apuntador despues de llamar por cuarta vez al metodo nextToken():

Uso del metodo nextToken() de la clase StringTokenizer

Uso del metodo nextToken() de la clase StringTokenizer


Si se llama por quinta vez al metodo nextToken() ocurrira una excepcion porque ya no hay un siguiente token.

hasMoreTokens()
Devuelve un valor de tipo boolean (true o false) que indica si hay (true) un siguiente token. Sino hay un siguiente token devuelve false.

countTokens()
Devuelve un entero (int) que es el numero de tokens de la cadena. Bueno a continuacion muestro un ejemplo mas elaborado que muestra el uso de estos tres metodos. No explico el codigo debido a que ya puse comentarios.

/*
 *    Instituto Tecnologico de Zacatepec
 *	Descripcion Ejemplo1 de uso de la clase StringTokenizer
 * author Gonzalo Silverio    gonzasilve@hotmail.com
 * version 1.00 
 * Archivo: EjemploTokenizer1.java
 */

import java.util.StringTokenizer;

public class EjemploTokenizer1
{
	StringTokenizer st;
	//Recine como entrada la cadena de la cual se quieren sacar su tokens
	public EjemploTokenizer1(String cadena)
	{
		st = new StringTokenizer(cadena);
	}
    
    //Muestra en la consola los tokens de la cadena
	public void mostrarTokens()
	{
		//Mientras haya mas tokens
		//hasMoreTokens() devuelve true si hay un siguiente token o  false si ya no hay
		while (st.hasMoreTokens())
		{
		    System.out.println(st.nextToken());
		}		
	}

    //Devuelve un String con el siguiente token
	public String siguienteToken()
	{
		//El metodo nextToken devuelve un string con el siguiente token
		return st.nextToken();
	}
	   
   //Devuelve el numero de tokens que tiene la cadena
	public int contarTokens()
	{
		return st.countTokens();
	}
	
	//hasMoreTokens() devuelve true si hay un siguiente token o  false si ya no hay
	public boolean hayOtroToken()
	{
		return st.hasMoreTokens();		
	}
	
    public static void main(String gonza[])
    {
    	//Reinicializar objeto con cadena SQL
    	EjemploTokenizer1 objeto1 = new EjemploTokenizer1("SELECT nombre,apellidos,edad FROM alumnos");
    	System.out.println("tokens en esta cadena: "+ objeto1.contarTokens () );
    	System.out.println(objeto1.siguienteToken() );	//Muestra SELECT
    	System.out.println(objeto1.siguienteToken() ); 	//Muestra los campos seleccionados
    	System.out.println(objeto1.siguienteToken() );	//Muestra FROM
    	System.out.println(objeto1.siguienteToken() );	//Muestra el nombre de la tabla
    	System.out.println("hay otro token: "+ objeto1.hayOtroToken () );	//Muestra si hay otro token
    	
    	//Se reinicializa el objeto con otra cadena SQL
    	objeto1 = new EjemploTokenizer1("INSERT  INTO S VALUES('s1','intel','cuerna',245)");
    	System.out.println("\ntokens en esta cadena: "+ objeto1.contarTokens () );
    	objeto1.mostrarTokens();
    	
    	
    }
    
}

Ahora una imagen de la compilacion y ejecucion de este ejemplo:

Compilacion  y ejecucion del ejemplo StringTokenizer

Compilacion y ejecucion del ejemplo StringTokenizer

Bueno, eso es todo y ya sabes si quieres el .java basta con pedirlo. Hasta pronto y gracias por tu visita.