Está en la página 1de 11

ua de Ejercicios en Prolog

Leccin 3 - Manipulacin de la Base de Datos y Archivos


Carga la siguiente base de datos de pases con sus respectivas capitales.

:- dynamic capital_of/2.

capital_of(suiza, berna).
capital_of(chile, santiago).
capital_of(eeuu, washington).
capital_of(estados_unidos, washington).
capital_of(italia, roma).
capital_of(francia, paris).
capital_of(austria, viena).
capital_of(alemania, berlin).
capital_of(espaa, madrid).
capital_of(peru, lima).
capital_of(mexico, cuidad_de_mexico).

1.- read/1 permite leer expresiones Prolog desde el teclado. Intenta lo siguiente: verifica
las respuestas que te entrega Prolog para las siguientes entradas.

hola.
'hola que tal'.
hola que tal.
hola(hermano).
Hola.
f(X) :- g(Y).

Puedes explicar a qu se deben las respuestas de Prolog?

2.- Veamos cmo un programa Prolog es capaz de aquirir nuevas clusulas en tiempo de
ejecucin.

?- capital_of(hawaii, X).

Como puedes ver, no se pudo unificar la variable X. Ahora, prueba con

?- listing.
Qu ocurre? listing muestra todas las clusulas que conforman el programa en memoria.
Ahora prueba

?- listing(capital_of).

sto slo muestra aquellas clusulas asociadas al predicado indicado como parmetro.

Se pueden incluir ms clusulas a la base de datos mediante el predicado assert/1:

?- assert(capital_of(hawaii, honolulu)).

Sin embargo, sto slo funciona para predicados que han sido marcados como dnamicos
mediante el predicado dynamic/1.

Ojo, pues en Prolog dos predicados con el mismo functor (i.e. el nombre del predicado) son
distintos si tienen aridad (i.e. nombre de argumentos) distintos. Es algo similar a lo que le
llaman la firma de una funcin en Java por ejemplo. En consecuencia, a(X) y a(X,Y) son
distintos predicados (a/1 y a/2 respectivamente, segn la notacin Prolog).

El predicado capital_of/2 ha sido declarado previamente como dinmico. Puedes


verificarlo ejecutando listing. Un predicado que no es dinmico es esttico. Los
predicados estticos no pueden ser alterados en tiempo de ejecucin.

Prolog internamente compila las clusulas estticas para mejorar la eficiencia. Es por esta
razn que debe hacerse la diferencia.

Ahora, si preguntas por

?- capital_of(hawaii, X).

debiera resultar la unificacin de la variable en forma exitosa.

3.- Obsevemos que assert agrega la clusula al final de la lista de predicados del mismo
nombre. Existe tambien asserta/1 y assertz/1, que agregan la clusula al comienzo y al final
respectivamente.

Agrega dos clusulas nuevas a la base de datos, y verifica luego que stas fueron
efectivamente includas. Qu ocurre si agregas una clsula con un predicado nuevo, por
ejemplo, assert(hola)? Verifica consultando por listing(hola).

retract/1 permite eliminar una clusula de la base de datos.

?- retract(capital_of(hawaii, honolulu)).
Existen ms predicados que permiten inspeccionar el estado de la base de datos, inclusive
para construir y ejecutar dinmicamente predicados en tiempo de ejecucin. Para mayor
informacin, puedes revisar la base de datos.

4.- Ahora veamos algunos predicados de manejo sencillo de archivos. stos son: see/1,
seen/1, tell/1 y told/1.

see('mi_archivo') abre el archivo 'mi_archivo' y lo establece como fuente de los


comandos de lectura, tales como read/1. Para cerrarlo, aplicar seen/0.

Por otro lado, tell('mi_archivo') abre al archivo 'mi_archivo' y redirige la escritura


hacia l, anlogo a see. Para cerrar al archivo, aplicar told/0.

?- tell('mi_archivo'), write('andrea.'), nl, write('javier.'), nl,


told.

Tras ejecutar la consulta anterior, revisa si existe el archivo 'mi_archivo' y si su


contenido es el esperado.

Ahora, vuelve a leer los datos escritos mediante:

?- see('mi_archivo'), read(X), read(Y).

Qu habra ocurrido si se hubiese escrito write('andrea') en vez de


write('andrea.')?

Intenta escribir el contenido de la base de datos actualmente residente en memoria dentro


de algn archivo. Verifica que sto haya funcionado bien abriendo el archivo y revisando su
contenido.

5.- Ahora carga el programa 'learner.pl' y ejecuta start. Juega un rato con l. Para
finalizarlo, ingresa stop.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%
% File learner.pl
%
% Un pequeo programa que modifica su propia base de
conocimientos. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%

start :- consult('bdc.pl'),
nl,
write('Escribe los nombres completamente en
minsculas,'), nl,
write('seguidos de un punto.'), nl,
nl,
process_a_query.

process_a_query :- write('Pas? '),


read(Pais),
answer(Pais).

% Si el usuario ingresa "stop.", entonces grabar la nueva


% base de conocimientos y salir.
answer(stop) :- write('Grabando la base de conocimientos...'), nl,
tell('bdc.pl'),
listing(capital_of),
told,
write('Listo.'), nl.

% Si el pas ya est en la base de conocimientos, entonces


retornar
% el nombre de su capital.
answer(Pais) :- capital_of(Pais, Ciudad),
write('La capital de '),
write(Pais),
write(' es '),
write(Ciudad), nl,
nl,
process_a_query.

% Si el pas no est en la base de conocimientos, entonces pedir


% el nombre de la capital e ingresar este fact a la base.
answer(Pais) :- \+ capital_of(Pais, Ciudad),
write('No conozco la capital de ese pas.'), nl,
write('Por favor, dime cual es.'), nl,
write('Capital? '),
read(Ciudad),
write('Gracias.'), nl, nl,
assert(capital_of(Pais, Ciudad)),
process_a_query.

Revisa el programa y explica cmo funciona. Modifcalo, de manera que al ingresar


delete, el programa borre un pas de la base de datos, tal como indica el siguiente dilogo:

...
Pas? chile.
La capital de chile es santiago

Pas? delete.
Qu pas deseas borrar? chile.
Se borr chile.

Pas? chile.
No conozco la capital de ese pas.
...

Librerias ...
import java.sql.*;
public class BaseDatos {
// Atributos de la clase.
private String url = "jdbc:mysql://localhost/miBaseDatos";
private Connection Conexion = null;
private Statement Consulta;
private PreparedStatement ConsultaPrepare;
private ResultSet Resultados;
private int NumRegistros;
public BaseDatos(String login , String password) throws
SQLException, ClassNotFoundException {
try {

Class.forName("com.mysql.jdbc.Driver").newInstance();
Conexion = DriverManager.getConnection(url, login,
password);
Consulta = Conexion.createStatement();
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) { }
} // fin del construcor
public void Ver_Registros (String Sql) throws SQLException {
Resultados = Consulta.executeQuery(Sql);
// Imprimir Resultados ...........
System.out.println("Resultados de la Consulta /n");
while (Resultados.next()) {
System.out.println("Id = " +
Resultados.getInt("Id"));
System.out.println("Nombre = " +
Resultados.getString("Nombre"));
System.out.println("Direccion= " +
Resultados.getString("Direccion"));
System.out.println("Correo = " +
Resultados.getString("Correo"));
} // fin del while
} // fin del metodo.
public void Insertar_Registro (int Id , String Nombre ,
String Direccion , String Correo) throws
SQLException {
ConsultaPrepare = Conexion.prepareStatement("INSERT INTO
ALUMNO " +
"(ID, Nombre , Direccion ,Correo) "
+ "VALUES (?,?,?,?)");
ConsultaPrepare.setInt(1, Id);
ConsultaPrepare.setString(2, Nombre);
ConsultaPrepare.setString(3, Direccion);
ConsultaPrepare.setString(4, Correo);
NumRegistros = ConsultaPrepare.executeUpdate();
} // fin del metodo conexion
public void Cerrar_Conexion () throws SQLException {
Resultados.close();
Consulta.close();
ConsultaPrepare.close();
Conexion.close();
} // fin del metodo.
} // fin del metodo

3. Motor de bases de datos PostgreSQL


PostgreSQL es un motor de bases de datos relacionales (RDBMS) que verifica integridad
referencial con gran funcionalidad como base de datos, aunque un poco ms lenta que otros
motores. Su licencia es tipo BSD. En esta seccin describimos brevemente la instalacin y
uso en un sistema OpenBSD.

3.1. Primera instalacin del servidor


Para emplearlo por primera vez instale el paquete postgresql-server-8.3.7 (tambin es
recomendable postgresql-docs-8.3.7).

Este paquete deja instrucciones especficas para inicializar la base de datos, permitir
conexiones de red e inicializar la base de datos cada vez que arranque el sistema en:
/usr/local/share/doc/postgresql/README.OpenBSD. Los pasos que este escrito
describe son:

Opcional. El paquete de PostgreSQL disponible crea el usuario del sistema


_postgresql, sin embargo si est actualizando o lo requiere puede crearlo con:

# useradd -c "Administrador de PostgreSQL" -g =uid -m -d


/var/postgresql \
-s /bin/sh -u 503 _postgresql
# passwd _postgresql

A diferencia de versiones anteriores, este paquete ya no inicializa la base.


Inicialicela con:

# mkdir -p /var/postgresql/data
# chown -R _postgresql:_postgresql /var/postgresql
# su - _postgresql
$ initdb -D /var/postgresql/data

Antes de la versin 4.1 de OpenBSD los paquetes oficiales de PostgreSQL emplean


autenticacin de confianza (trust) que no requiere dar claves si se ingresa desde el
mismo computador donde correo el servidor. Sin embargo desde OpenBSD 4.1
emplea por defecto autenticacin md5, que requiere suministrar clave cada vez que
se carga la interfaz psql o abre conexiones. Si prefiere autenticacin md5 al
inicializar la base con initdb emplee la opcin --auth=trust. Una vez inicializada
puede cambiar de un mtodo a otro en el archivo
/var/postgresql/data/pg_hba.conf

Altamente Recomendado. Agregue a /etc/sysctl.conf:

kern.seminfo.semmni=256
kern.seminfo.semmns=2048
kern.shminfo.shmmax=50331648
Configurar scripts de arranque y detencin del sistema para que inicien y detengan
el servidor de PostgreSQL. En /etc/rc.conf.local agregar:

pg_ctl_flags="start \
-D /var/postgresql/data -l /var/postgresql/logfile \
-o '-D /var/postgresql/data'"
En /etc/rc.local agregue:

pgrep post > /dev/null


if [ "$?" != "0" -a X"$pg_ctl_flags" != X"NO" -a \
-x /usr/local/bin/pg_ctl ]; then
su -l _postgresql -c "/usr/local/bin/pg_ctl $pg_ctl_flags"
echo -n ' postgresql'
fi
y en /etc/rc.shutdown agregue:

if [ -f /var/postgresql/data/postmaster.pid ]; then
su -l _postgresql -c "/usr/local/bin/pg_ctl stop -m fast \
-D /var/postgresql/data"
rm -f /var/postgresql/data/postmaster.pid
fi
Inicialmente el servidor queda configurado con sockets Unix (solo desde la misma
mquina). Puede comprobar que est corriendo el servidor (postmaster) con:

# pgrep post

Para emplear el protocolo TCP/IP para conexiones desde algunas mquinas de su eleccin,
edite /var/postgresql/data/pg_hba.conf y agregue por ejemplo mquinas y usuarios
que puedan hacer conexiones. Tambin edite /var/postgresql/data/postgresql.conf
para que incluya lneas de configuracin como:

tcpip_socket = true
max_connections = 32
superuser_reserved_connections = 2
port = 5432
hostname_lookup = false
show_source_port = false

Para mejorar desempeo especialmente en sitios que atiendan bastantes conexiones


simultneamente, consulte primero
/usr/local/share/doc/postgresql/README.OpenBSD.

Si por seguridad (e.g cuando ejecuta Apache con chroot en /var/www) decide no permitir
conexiones TCP/IP y emplea una ruta para los sockets diferente a la ruta por defecto (i.e
/tmp), defina la nueva ruta (por ejemplo /var/www/tmp) en
/var/postgresql/data/postgresql.conf en la variable unix_socket_directory (si
en el archivo la lnea tiene comentario, quite el signo # del comienzo de la lnea). Antes de
reiniciar PostgreSQL asegrese de crear el directorio:

# mkdir /var/www/tmp
# chmod a+w /var/www/tmp
# chmod +t /var/www/tmp

Tambin tenga en cuenta que las diversas herramientas reciben como parmetro adicional
-h ruta. Por ejemplo si ejecuta Apache con chroot en /var/www/ puede tener configurado
su directorio para sockets en /var/www/tmp, en ese caso puede iniciar psql con la base
prueba usando:

psql -h /var/www/tmp prueba


En paquetes anteriores al de OpenBSD 4.1 el superusuario de la base coincida con el
usuario del sistema _postgresql, desde 4.1 el superusuario de la base es postgres, as
que para realizar operaciones debe agregarse la opcin -U postgres

3.2. Habilitando autenticacin


Por defecto la forma de inicializar PostgreSQL no establecer una clave de administrador ni
exigir autenticacin para cuentas que se conecten desde la misma mquina. Sin embargo
esto debe mejorarse si tiene varias cuentas en el mismo servidor.

Una manera es en el momento de la inicializacin de la base de datos con las opciones


--auth y --pwfile o -W de initdb, por ejemplo:

su - _postgresql
echo "MiClave" > clave.txt
initdb --auth=md5 --pwfile=clave.txt -D/var/postgresql/data

que inicializar PostgreSQL con autenticacin md5 y clave de administrador MiClave

Otra posibilidad es cambiar la configuracin despus de haber inicializado sin


autenticacin. Para esto cambie la clave del administrador con[8]:

# psql -U postgres template1


template1=# alter user postgres with password 'MiClave';
Despus edite /var/postgresql/data/pg_hba.conf y cambie en las lineas de acceso la
palabra trusted por md5, por ejemplo:

local all all md5


host all all 127.0.0.1/32 md5
host all all ::1/128 md5
Detenga el servidor y vuelvalo a iniciar, notar que todo intento de ingreso exige la clave.

El listado de bases de datos puede consultarse con:


SELECT * FROM pg_database ;

y el listado de los usuarios con:

SELECT usename FROM pg_users;

Las claves de los diversos usuarios pueden cambiarse de forma anloga a la presentada para
postgres:

ALTER ROLE pablo with UNENCRYPTED PASSWORD 'clave-plana';

Desde PostgreSQL 8.1 se emplea un esquema de roles que unifica los conceptos de usuario
y grupo. Adems de exigir clave para cada ingreso, cada rol de PostgreSQL que crea
objetos puede modificar permisos para restringir o dar acceso a otros roles. Por ejemplo
para restringir el acceso a una tabla cuenta:

REVOKE ALL ON cuenta FROM PUBLIC;

Cuando un rol crea una base de datos, queda como dueo de todas las tablas y en principio
es el nico que puede acceder a estas. Otro rol en principio no podr ni siquiera examinar
los datos de las tablas:

SELECT * FROM solicitud;


ERROR: permission denied for relation solicitud

Para dar permiso a otro rol puede usarse:

GRANT ALL on solicitud TO rodrigo;

3.3. Creacin de una base de datos


Para crear la base de datos prueba puede usar el superusuario con la opcin -U postgres
o desde una cuenta que tenga permiso para crear bases de datos:

createdb prueba
psql prueba
Desde la interfaz psql, pueden darse comandos SQL y otros especficos de PostgreSQL (ver
Seccin 3.4, Uso de una base de datos). En particular el usuario postgres y desde
cuentas con permiso para crear usuarios, puede crear otros usuarios (globales para todas las
bases de datos manejadas por el servidor). Por ejemplo para crear un usuario normal sin
clave, desde psql ingresar:

CREATE USER usejemplo

El comando CREATE USER presentado puede ir seguido de CREATEUSER para crear un


superusuario (sin restriccin alguna), o CREATEDB para crear un usuario que pueda crear
bases de datos o PASSWORD 'clave' para crear un usuario con una clave (emplea
autenticacin configurada). Desde la lnea de comandos puede crearse un usuario con:

createuser usejemplo

Para eliminar un usario desde psql se usa:

DROP USER usejemplo;

y para eliminarlo desde lnea de comandos:

dropuser usejemplo

Puede ejecutarse un script SQL (crea.sql) desde la lnea de comandos a un base de datos
con

psql -d test -U ejusuario --password -f crea.sql

3.4. Uso de una base de datos


Puede emplear psql, la interfaz texto que acepta comandos SQL y que se distribuye con
PostgreSQL. Para esto, entre a una base (digamos b1908) como un usuario (digamos
u1908) con:

psql -U u1908 -d b1908


En esta interfaz puede dar comandos SQL y algunos comandos internos que puede listar
con \h. Algunos ejemplos de operaciones tiles son:

\dt

para ver tablas disponibles.

\d usuarios

Describe la estructura de la tabla usuarios

SELECT victim_nombre,victim_apellido FROM victimas WHERE victim_edad<=12;

Que muestre los nombres de nios de 12 aos o menos listados en la tabla


victimas

\h update

Da ayuda sobre el comando {\tt update} (que permite actualizar registros de una
tabla.)
3.5. Copias de respaldo
Para sacar una copia de respaldo de todas las base de datos manejadas con PostgreSQL (y
suponiendo que el socket est en /var/www/tmp):

pg_dumpall -U postgres -h /var/www/tmp/ \


--inserts --attribute-inserts > /respaldos/pgdump.sql

Puede restablecer una copia con

psql -U postgres -h /var/www/tmp/ \


-f /respaldos/pgdump.sql template1

3.6. Referencias y lecturas recomendadas


Documentacin del paquete postgresql (README.OpenBSD, INSTALL).

Documentacin disponible en el paquete postgresql-doc (ver [postgresql-doc]) y


en http://www.postgresql.org/docs.

Pginas del manual de Unix: psql(1)