Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

sábado, 22 de marzo de 2014

Dibujando matrices con Latex

El código básico para dibujar una matriz lo conseguí de este enlace. Pero yo necesitaba dibujar una matriz como la siguiente:


El código en Latex para dibujarla es:

\[ \left(
\begin{array}{cccc}
b\textsubscript{11} & b\textsubscript{12} & ... & b\textsubscript{1n} \\
b\textsubscript{11} & b\textsubscript{12} & ... & b\textsubscript{1n} \\
\vdots & \vdots & \vdots & \vdots \\
b\textsubscript{n1} & b\textsubscript{n2} & ... & b\textsubscript{nn}
\end{array}
\right)\]



Luego tenía que dibujar una matriz como combinación de columnas multiplicadas por un escalar, como la siguiente:

El código es:

\[b= \left(
\begin{array}{c|c|c|c|c}
&&&& \\
&&&& \\
u\textsubscript{1}\mbox{. \={v}} & u\textsubscript{2}\mbox{. \={v}} & u\textsubscript{3}\mbox{. \={v}} &...& u\textsubscript{n}\mbox{. \={v}}\\
&&&& \\
&&&&
\end{array}
\right)\]


sábado, 1 de marzo de 2014

jueves, 20 de febrero de 2014

Continuando con el Conjunto de Wirth...

Actualización de Electrónica a Martillazos, hallé algunas cosas interesantes con respecto al algoritmo de PuntoPeek para calcular el Conjunto de Wirth.
El enlace aquí.
Un mirror aquí.

lunes, 13 de enero de 2014

Resetear campo autoincrementable (serial) en Postgre 9.3

Tengo una base de datos llamada "Prueba" con una tabla "phonebook", la cual tiene un campo autoincrementable (tipo serial) llamado "ID":


Cuando se crea un dato serial usando el pgAdmin, Postgre automáticamente nos crea una secuencia (en este caso llamada "phonebook_ID_seq") a la cual el campo serial está vinculado mediante la siguiente instrucción:

ALTER TABLE phonebook ALTER COLUMN "ID" SET DEFAULT nextval('"phonebook_ID_seq"'::regclass);

Para Postgre, un dato serial es un dato Integer con la función "nextval".

Esta es mi situación:
Luego de añadir y borrar varios registros a la tabla "phonebook", y finalmente dejarla vacía, quiero resetear el valor del campo "ID" a 1.

Al igual que en MySql, Postgre tiene una función llamada "setval" que me permite ponerle un valor arbitrario a la secuencia desde el cual continuará con los incrementos.
En el pgAdmin seleccionamos el campo "ID", abrimos la ventana de queries mediante el botón "Execute Arbitrary Queries" (el que tiene una lupa y el texto "SQL"), e ingresamos el siguiente query:

select setval('"phonebook_ID_seq"',1);

Hay que notar que lo que se altera es la secuencia, no el campo "ID". Hay que tener cuidado de poner el nombre de la secuencia entre comillas dobles dentro de las comillas simples. Como Postgre es Case Sensitive, saltarán errores si omitimos las comillas dobles y si el nombre de la secuencia contiene mayúsculas.

En la ventana de queries quedará así:


Si todo sale bien, nos aparecerá el valor al que hemos reseteado la secuencia. No tiene que ser 1, puede ser cualquier valor que queramos.

miércoles, 8 de enero de 2014

Postgre 9.3: Errores 42501 y 42703:

Tengo la siguiente base de datos Prueba instalada en un servidor local de Postgre versión 9.3, la cual tiene una sola tabla "phonebook" cuya estructura copié de algún sitio de Internet (al instalar Postgre se tiene la opción de instalar también el pgAdmin):


El Owner de la base de datos y de la tabla es el superusuario "postgre". La base de datos Prueba tiene como esquema por defecto (Default Schema) igual a público (public), también sus privilegios son públicos.

También he creado un usuario "user01" con las siguientes propiedades:


Al conectar una aplicación en C# mediante el usuario "user01", usando Npgsql (el cual se puede instalar junto con el Postgre usando la aplicación Stack Builder que también viene con el instalador del Postgre) y luego de ver los datos de la tabla phonebook todo iba bien; pero cuando quería modificar la tabla phonebook con un update, insert ó delete me arrojaba el siguiente error:


"Error 42501: permiso denegado a la secuencia phonebook_ID_seq"

Este error salta si el usuario con el que intento modificar la tabla no es su dueño (owner). No interesa si la base de datos tiene como dueño al superusuario "postgre", la tabla debe tener como dueño al usuario que intenta modificarla.

Para cambiar al dueño de la tabla phonebook de "postgre" a "user01" basta este script:

ALTER TABLE phonebook
  OWNER TO user01;

Y entonces al usar la siguiente sentencia insert desde C#:

string query = @"insert into phonebook (phone, firstname, lastname, address) values ('1234', 'Wert', 'Asdlo', 'Fake Street 123')";

Los datos se guardaban correctamente, pero al querer actualizar o borrar: 

string query1 = @"Update phonebook set phone ='0000', firstname ='Carry', lastname ='Doe', address = 'No signed' where ID = 1";
string query2 = "delete from phonebook where ID = 1";

Me saltaba el siguiente error:


"Error 42703: no existe la columna id"

Lo extraño es que la tabla phonebook sí tiene una columna llamada "ID". Buscando por internet, hallé aquí la solución: se debe poner el nombre del campo que contiene mayúsculas entre comillas:

string query1 = "Update phonebook set phone ='0000', firstname ='Carry', "
" lastname ='Doe', address = 'No signed' where \"ID\" = 1";
string query2 = "delete from phonebook where \"ID\" = 1";

El caracter \ le indica al C# que la comilla que le sigue no indica el final de la cadena. El motor del Postgre convierte todos los nombres de las columnas en una sentencia sql a minúsculas. Por ahí leí que, internamente, Postgre es Case Sensitive.

sábado, 14 de diciembre de 2013

Cómo Convertir de long a LPCWSTR (puntero largo a Wide String constante) en Visual C++

Todo empezó cuando quise calcular el alto en píxeles de la barra de título de una ventana, ya que éste valor varía dependiendo del tema de Windows que se utilice.

Para calcular el alto de la barra de título utilizo dos apis: GetWindowRect y GetClientRect. La primera devuelve las coordenadas que ocupa la ventana, la segunda devuelve las coordenadas que ocupa la ventana sin la barra de título.

El valor calculado es del tipo long. Faltaba convertirlo a LPCWSTR para pasarlo como parámetro a la api setWindowText que lo escribirá en lugar del título de la ventana.

He usado la información que hallé en estas webs:
La función ltoa (reemplazada por _ltoa)
Convertir de char* a LPCWSTR
La función MultiByteToWideChar

El código es el siguiente:

RECT r1, r2;

GetWindowRect(hWnd, &r1);
GetClientRect(hWnd, &r2);

long alto1 = r1.bottom - r1.top;
long alto2 = r2.bottom - r2.top;

long alto3 = alto1-alto2;

// convertir long a Wide WCHAR*
int size=sizeof(long)*8+1;
char* texto = new char[size];
WCHAR* texto2 = new WCHAR[size];

_ltoa(alto3,texto,10);
MultiByteToWideChar(CP_UTF8, 0, texto, -1, texto2, size);
// fin de la conversión. Para convertir de WCHAR* a LPCWSTR (puntero largo a Const Wide String) basta un casteo
SetWindowText(hWnd, (LPCWSTR)texto2);


En el caso de una aplicación tipo win32, coloqué este código dentro de la función que procesa los mensajes de la ventana (WndProc), exactamente en el mensaje que se envía al crearla:


Al ejecutar el programa, mostrará el alto de la barra de título en el texto de... la barra de título.


sábado, 23 de noviembre de 2013

Implementación Thread-safe de una clase Singleton

Entrada original de WhatILearntToday: "El patrón Singleton se usa cuando queremos que una clase permita definir una, y sólo una, instancia de esa misma clase".

La implementación WhatILearntToday de una clase Singleton Thread-Safe es la siguiente:

public class SingletonClass
    {
        private SingletonClass()
        {
        }

        //Implementation #1 NO Thread-Safe: puede fallar si varios hilos intentan instanciarla al mismo tiempo
        //static SingletonClass _instance = null;
        //public static SingletonClass GetInstance()
        //{
        //    if (_instance == null)
        //    {
        //        _instance = new SingletonClass();
        //    }
        //    return _instance;
        //}

        //Implementation #2 Thread-safe
        static readonly SingletonClass _instance = new SingletonClass();

        public static SingletonClass GetInstance()
        {
            get
            {
                return _instance;
            }
        }

        public string GetWelcomeMessage()
        {
            return "Welcome to the Singleton world!! ";
        }
    }

Mi implementación (también Thread-Safe) es:

public class SingletonClass
    {
        private SingletonClass()
        {
        }

        static readonly SingletonClass _instance = null;
        static object lockThis;

        public static SingletonClass GetInstance()
        {
            lock(lockThis)
            { 
                 if (_instance == null)
                         _instance = new SingletonClass();
            }  
           return _instance;           
        }

        public string GetWelcomeMessage()
        {
            return "Welcome to the Singleton world!! ";
        }
    }

miércoles, 23 de octubre de 2013

Cómo evadir la limitación de tamaño de una ventana en Windows

Por diseño, Microsoft Windows limita el tamaño de las ventanas a (en píxeles):
(12 + ancho de la resolución de pantalla) x (12 + alto de la resolución de pantalla)

Más información en StackOverflow.

Por allí hallé quienes afirman que se puede superar esta restricción. Y entonces me topé con este código, de la misma Microsoft, en Visual Basic 6.

Lo copio aquí para que no se vaya a perder:

En un módulo bas:

 Option Explicit

      Private Const GWL_WNDPROC = -4
      Private Const WM_GETMINMAXINFO = &H24

      Private Type POINTAPI
          x As Long
          y As Long
      End Type

      Private Type MINMAXINFO
          ptReserved As POINTAPI
          ptMaxSize As POINTAPI
          ptMaxPosition As POINTAPI
          ptMinTrackSize As POINTAPI
          ptMaxTrackSize As POINTAPI
      End Type

      Global lpPrevWndProc As Long
      Global gHW As Long

      Private Declare Function DefWindowProc Lib "user32" Alias _
         "DefWindowProcA" (ByVal hwnd As Long, ByVal wMsg As Long, _
          ByVal wParam As Long, ByVal lParam As Long) As Long
      Private Declare Function CallWindowProc Lib "user32" Alias _
         "CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
          ByVal hwnd As Long, ByVal Msg As Long, _
          ByVal wParam As Long, ByVal lParam As Long) As Long
      Private Declare Function SetWindowLong Lib "user32" Alias _
         "SetWindowLongA" (ByVal hwnd As Long, _
          ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
      Private Declare Sub CopyMemoryToMinMaxInfo Lib "KERNEL32" Alias _
         "RtlMoveMemory" (hpvDest As MINMAXINFO, ByVal hpvSource As Long, _
          ByVal cbCopy As Long)
      Private Declare Sub CopyMemoryFromMinMaxInfo Lib "KERNEL32" Alias _
         "RtlMoveMemory" (ByVal hpvDest As Long, hpvSource As MINMAXINFO, _
          ByVal cbCopy As Long)

      Public Sub Hook()
          'Start subclassing.
          lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, _
             AddressOf WindowProc)
      End Sub

      Public Sub Unhook()
          Dim temp As Long

          'Cease subclassing.
          temp = SetWindowLong(gHW, GWL_WNDPROC, lpPrevWndProc)
      End Sub

      Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, _
         ByVal wParam As Long, ByVal lParam As Long) As Long
          Dim MinMax As MINMAXINFO

          'Check for request for min/max window sizes.
          If uMsg = WM_GETMINMAXINFO Then
              'Retrieve default MinMax settings
              CopyMemoryToMinMaxInfo MinMax, lParam, Len(MinMax)

              'Specify new minimum size for window.
              MinMax.ptMinTrackSize.x = 200
              MinMax.ptMinTrackSize.y = 200

              'Specify new maximum size for window.
              MinMax.ptMaxTrackSize.x = 500
              MinMax.ptMaxTrackSize.y = 500

              'Copy local structure back.
              CopyMemoryFromMinMaxInfo lParam, MinMax, Len(MinMax)

              WindowProc = DefWindowProc(hw, uMsg, wParam, lParam)
          Else
              WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, _
                 wParam, lParam)
          End If
      End Function


El truco es fácil: donde están los números en rojo, escribimos nuestros números enormes favoritos. Yo probé con 10000, y luego le puse por código a una ventana (Form) dimensiones de 2050*1600 píxeles, en una resolución de pantalla de 1024*768 (la restricción por defecto sería 1036*780).

Para hacer esto en el form ponemos:

      Option Explicit

      Private Sub Form_Load()
          'Save handle to the form.
          gHW = Me.hwnd

          'Begin subclassing.
          Hook 
          ' le ponemos un tamaño ENORME 
          Me.Height = 1600
          Me.Width = 2050
      End Sub

      Private Sub Form_Unload(Cancel As Integer)
          'Stop subclassing.
          Unhook
      End Sub 


Y funcionó.

Ya no intenté con dimensiones mayores porque una ventana con aproximadamente el doble de alto y ancho que la resolución de pantalla parece ser suficientemente grande. Deduzco que el máximo que puede aguantar el sistema operativo depende de la memoria máxima que le puede asignar a semejante ventanón y antes que la RAM empiece a echar humo.

Como son puras llamadas a Apis de WIndows, se puede traducir este código a Visual C++ o a .Net usando DLLImport.

Probado en Windows XP SP3 y Win 7 SP1.

sábado, 12 de octubre de 2013

Cómo importar datos con carácteres internacionales desde xls a SQLite

Tengo el siguiente archivo xls:


y quiero pasar los datos a una tabla en SQLite.
Después de probar distintas aplicaciones para SQLite, descubrí que ninguna importa directamente desde el formato xls (al menos no las que son gratuitas), pero sí importan desde el formato csv.

Tanto MSExcel como OpenOffice Calc pueden exportar datos al formato csv. Pero hay que tener en consideración un par de detalles para no perder los carácteres internacionales.

Para este ejemplo estoy usando OpenOffice Calc 3, pero el procedimiento es muy similar para MS Excel.

En "Guardar Como" elegimos el formato csv. Aparecerá la siguiente ventana:


Los datos deben exportarse con la codificación UTF8 y estar entrecomillados.

Para importar los datos a una base de datos en SQLite, el mejor programa que hallé es el Add-On para Firefox SQLite Manager.

Una vez instalado, lo ejecutamos desde Firefox -> Herramientas -> SQLite Manager (yo uso la versión 0.8.0) y cargamos nuestra base de datos, o la creamos.
Si la creamos no añadimos ninguna tabla, los datos importados crearán una automáticamente (mi base de datos se llama "Prueba01").



Luego vamos a la opción Base de Datos -> importar, o al ícono celeste con la flechita al costado del ícono de Abrir:



Elegimos la pestaña "CSV". Con el botón "Seleccionar Archivo" escogemos el archivo csv donde hemos exportado los datos desde xls. Las opciones a elegir son:
- Tipo de Codificación: UTF-8
- La primera fila contiene los nombres de las columnas
- Campos separados por coma
- Campos limitados por comillas dobles, siempre.
- Le cambié el nombre a la nueva tabla de "sample sales" a "sample_sales". Es mejor que las tablas no tengan nombres con espacios.

Presionamos OK. Aparecerá esta ventanita:



Oh! ¡Aquí hay algo qué resaltar!

En mi caso, como los datos de "CategoryID" se repiten, debo deseleccionar las opciones "Clave Primaria" "Auto Inc" y "única" si no botará error (y uno bastante feo). Estas opciones se seleccionan sólo si los datos correspondientes son únicos, no hay valores en blanco, y pueden convertirse a enteros.

En una bse de datos SQLIte es mejor no usar el formato DateTime. Lo mejor es guardar las fechas como texto, y recién realizar la conversión en nuestra aplicación. Así se evitan excepciones que se producen en el driver de SQLite y no en nuestro código (esta recomendación es de la misma web de SQLite, y la aprendí después de jugar un poco con el C# y aventar algunas hermosas excepciones de formato...).

Si todo sale bien, nuestros datos se verán así, ya dentro de la base de datos:


Si no se declara una clave primaria, el SQLite Manager nos creará una :D en este caso es "rowid". Y como se puede ver, los carácteres internacionales se conservan intactos.

Ya para trastear administrar la base de datos, prefiero usar el SQLite Studio.

jueves, 8 de agosto de 2013

Cómo ignorar los acentos al hacer una búsqueda en una base de datos en MS Access (mdb) con C#

Tengo el siguiente código:

string nombre = nombreABuscarenlaBD;

string query = String.Concat("Select * from Tabla1 where campoNombre like '", nombre, "'");

Este query funciona mientras no se desee buscar un nombre que incluya acentos como "María" ingresando "Maria" . Lo peor: puede que el usuario ni siquiera sepa si en la base de datos los nombres están guardados con acentos o no.

Para que la búsqueda devuelva todas las coincidencias con y sin acentos, se debe hacer el siguiente cambio a la variable tipo string que contiene el criterio de búsqueda (la idea es sacada de este foro):

nombre = nombre.Replace("a", "[aá]").Replace("e", "[eé]").Replace("i", "[ií]").Replace("o", "[oó]").Replace("u", "[uú]").Trim();

Si se desea ignorar también las diéresis, será:

nombre = nombre.Replace("a", "[aäá]").Replace("e", "[eëé]").Replace("i", "[iïí]").Replace("o", "[oöó]").Replace("u", "[uüú]").Trim();