MeuMySQL Blog is now at http://blog.mdnsolutions.com/.

Tuesday, September 11, 2012

[OFF-TOPIC] Zend Framework - Uso de Barras (Slashes) na Url

Olá galera,

Como desenvolvedor todo dia matamos um leão. Hoje quero compartilhar uma situação que tivem com Zend Framework e os tipos de dados que tinha que trafegar na minha aplicação.


O problema

Quando tentei enviar uma variável pela url na minha aplicação em Zend Framework ela continha barras no em um parâmetro chamado grade "/BI/CV/PT". O que gerava uma url do tipo http://URL_PATH/MODULO/CONTROLLER/ACTION/id/289069/grade/BI/CV/PT. Quando eu tentava acessar essa URL recebia de retorno um bom NOT FOUND. 

Mesmo utilizando a função nativa do PHP stripslashes()  (resultando em http://URL_PATH/MODULO/CONTROLLER/ACTION/id/289069/grade/BI%2FCV%2FPT) continuava tendo o mesmo problema.


A solução

Ao pesquisar e com ajuda do @yourwebmarker descobri que se tratava de uma configuração do Apache para permitir o uso de barras codificadas. Você encontra sobre isso em http://httpd.apache.org/docs/2.2/mod/core.html#allowencodedslashes. O que fiz foi adicionar no meu arquivo de configuração do virtual host a linha AllowEncodedSlashes On e tudo funcionou perfeitamente. Exemplo:


<VirtualHost *:80>
    ServerName test.local
    DocumentRoot "/home/local/public"
    SetEnv APPLICATION_ENV "development"
    AllowEncodedSlashes On
    <Directory "/home/local/public">
        DirectoryIndex index.php
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>



Abraços!

Saturday, September 8, 2012

[OFF-TOPIC] APC/PHPIZE

Olá meus caros. Estava eu instalando o Symfony Framework em minha máquina de desenvolvimento e para tal tive que instalar o APC do PHP, que por tabela não me pediu para checar o 'phpize'. Bem, ao tentar rodar este último comando recebi a reposta:

medina@dev-env:~$ phpize
Cannot find config.m4. 
Make sure that you run '/usr/bin/phpize' in the top level source directory of the module

Bem, depois de algumas pesquisas descobrir que apenas precisava inserir o verbose:

medina@dev-env:~$ phpize -v
Configuring for:
PHP Api Version:         20100412
Zend Module Api No:      20100525
Zend Extension Api No:   220100525

Ridiculamente simples não?


O tal do APC

Ao tentar instalar o APC tive vários erros pulando na tela constantemente (encontrei vários artigos toscos) tais como "Error 324 (net::ERR_EMPTY_RESPONSE): The server closed the connection without sending any data." quando configurava o APC e entrava acessar a tela "web/app_dev.php". Isso ainda gerava no meu log do apache a linha "symfony[notice] child pid 3341 exit signal Segmentation fault (11)". Tudo por causa do maldito pecl.

Enfim, tudo isso desapareceu com um simples comando:

medina@dev-env: sudo apt-get install php-apc
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  php-apc
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 85.8 kB of archives.
After this operation, 246 kB of additional disk space will be used.
Get:1 http://ppa.launchpad.net/ondrej/php5/ubuntu/ precise/main php-apc i386 3.1.11-1~precise+1 [85.8 kB]
Fetched 85.8 kB in 2s (40.0 kB/s)  
Selecting previously unselected package php-apc.
(Reading database ... 269688 files and directories currently installed.)
Unpacking php-apc (from .../php-apc_3.1.11-1~precise+1_i386.deb) ...
Setting up php-apc (3.1.11-1~precise+1) ...

Caso você já tenha instalado o APC via PECL remova-o com o comando abaixo:

medina@dev-env: sudo pecl uninstall APC

Pronto, agora seu APC agora esta instalado.


Instalando no MAC OS Lion

Esse cara foi um pouco mais complicado, mas vamos la:

Instale o PEAR primeiramente:

sudo php /usr/lib/php/install-pear-nozlib.phar
pear config-set php_ini /private/etc/php.ini
pecl config-set php_ini /private/etc/php.ini
sudo pear upgrade-all

E em seguida o XCode (Via Apple Store)  eo autoconfig:

curl -OL http://ftpmirror.gnu.org/autoconf/autoconf-latest.tar.gz
tar xzf autoconf-latest.tar.gz
cd autoconf-*
./configure --prefix=/usr/local
make
sudo make install

E finalmente o APC:

curl -O http://freefr.dl.sourceforge.net/project/pcre/pcre/8.02/pcre-8.02.tar.gz
tar xvf pcre-8.02.tar.gz
sudo cp pcre-8.02/pcre*.h /usr/include
sudo cp pcre-8.02/pcre.h.generic /usr/include/pcre.h
rm -r pcre-8.02*

export MACOSX_DEPLOYMENT_TARGET=10.7
export CFLAGS="-arch x86_64"
export CXXFLAGS="-arch x86_64"

sudo pecl install apc

Referências:

Wednesday, August 29, 2012

[OFF-TOPIC][En] Zend_Form_Select with dynamic options


Hey Guys,

I'd like just to show off a really hand attribute to be used with select elements in Zend_Form.
It gives you the change of load options into your select fields without have that anoying message: "X  was not found in the haystack" (or in portuguese "X não faz parte dos valores esperados").

All you need to do is set the 'registerInArrayValidator' as false. Doing so Zend_Form is not validating the original set of values in your select element.



<?php
 ....
               $this->addElement('select', 'xptoId', array(
                    'label' => 'Xpto',
                    'multiOptions' => array(),
                    'registerInArrayValidator' => false,
                    'required' => true,
                ))

...
?>

Hope it is going to be hand for you mates!

Tuesday, July 17, 2012

[OFF-TOPIC] Creating a List of Timezones with PHP

Hey guys,

Below you can find how to create a list of timezones with PHP using the native object DateTimeZone. Enjoy!


<?php

class TimeZone
{

    static $regions = array(
        'Africa' => \DateTimeZone::AFRICA,
        'America' => \DateTimeZone::AMERICA,
        'Antarctica' => \DateTimeZone::ANTARCTICA,
        'Asia' => \DateTimeZone::ASIA,
        'Atlantic' => \DateTimeZone::ATLANTIC,
        'Europe' => \DateTimeZone::EUROPE,
        'Indian' => \DateTimeZone::INDIAN,
        'Pacific' => \DateTimeZone::PACIFIC,
    );

    /**
     * 
     * @return array List of locations
     */
    static public function getLocations()
    {
        foreach (self::$regions as $name => $mask) {
            $tzlist = \DateTimeZone::listIdentifiers($mask);
            foreach ($tzlist as $tz) {
                $locations[$name][$tz] = substr($tz, strrpos($tz, '/') + 1);
            }
        }
        
        return $locations;
    }

}

?/>

To use it just write in your code:

<?php
$locations = TimeZone::getLocations();
?>

Wednesday, June 6, 2012

[OFF-Topic] Customizando ZF BreadCrumb

Olá galera. Hoje trago um tópico que achei bacana para um problema que me confrontei hoje. E como  soluções surgem de necessidades aqui está um que me ajudou e que acredito que pode ajudar outra pessoa.


Breadcrumbs

O Zend Framework trabalha de forma elegante com navigation e breadcrumbs. Já vinha utilizando ambos há um bom tempo em meus sistemas, porém hoje precisei customizar um para um sistema especifico que possuo. Sem mais rodeios segue abaixo as intervenções que fiz no meu Layout e no meu breadcrumb.


No seu Layout.phtml adicione a linha:

<?php echo $this->navigation()->breadcrumbs()->setPartial('breadcrumb.phtml')->render(); ?>

E crie seu breadcrumb no diretório seuModulo/views/scripts/breadcrumb.phtml e escreva ele como desejar. Ex o meu:

<?php

if (null === $this->container) {
    $this->container = $this->breadcrumbs()->getContainer();
}

// find deepest active
if (!$active = $this->breadcrumbs()->findActive($this->container)) {
    return '';
}

$active = $active['page'];

// put the deepest active page last in breadcrumbs
if ($this->breadcrumbs()->getLinkLast()) {
    $html = $active;
} else {
    $html = $active->getLabel();
    if ($this->breadcrumbs()->getUseTranslator() && $t = $this->breadcrumbs()->getTranslator()) {
        $html = $t->translate($html);
    }
    $html = $this->escape($html);
}

// walk back to root
while (($parent = $active->getParent()) != null) {
    if ($parent instanceof Zend_Navigation_Page) {
        // prepend crumb to html
        $html = $parent->getLabel() . $this->breadcrumbs()->getSeparator() . $html;
    }

    if ($parent === $this->container) {
        // at the root of the given container
        break;
    }

    $active = $parent;
}
echo strlen($html) ? $this->breadcrumbs()->getIndent() . $html : '';

?>


Bem, é isso galera. Espero que tenham gostado da dica.

Tuesday, April 3, 2012

[OFF-TOPIC] O maravilhoso mundo GIT

Olá galera! Quanto tempo desde o último post. Mas isso não significa que eu estava de férias, muito pelo contrário. Venho trabalhando em grandes projetos pessoais e aperfeiçoando várias habilidades tecnicas e que agora quero compartilhar com vocês algumas delas.

Bem, hoje falarei sobre o GIT. Há muitos anos tenho trabalhado com o SUBVERSION e suas ferramentas administrativas tais como o Tortoise, mas desde que resolvi tratar de forma mais seria meu repositório, tal como, controle de branches, tags, manter o versionamento de meus softwares em dia, vi que o modelo CVS não me atenderia muito bem, tendo inclusive algumas decepções (Subversion com merge é terrivel).

Como um bom desenvolverdor, sempre que nos deparamos com um problema qual a primeira atitude a se tomar? Resolvê-lo. Em minhas pesquisas verifiquei que o Git (um sistema de controle de versão distribuído) já vinha sendo utilizado por várias pessoas e empresas e resolvi analisa-la um pouco mais de perto. Entre os vários artigos que li um que recomendo é o do Imasters que da uma ideia comparativa entre GIT e Subversion (leia aqui ou nas referências ao fim do texto).

Uma vez entendido o que é e como funciona sistemas distribuidos vamos ver com funciona na pratica. Você, antes de mais nada pode criar um projeto publico no github (eles possuem uma excelente documentação) ou mesmo em sua máquina local.

Nossa instalação será do git version 1.7 no Ubuntu 11.10. O acesso ao git será via WebDAV ou gitweb.

Instalação do Servidor Git

Estou considerando que você já tenha uma versão do apache instalada em sua máquina. Bem, temos que habilitar o módulo dav em nosso servidor. Para isso vamos criar um link simbólico para esses módulos:

ln -s /etc/apache2/mods-available/dav.load /etc/apache2/mods-enable/dav.load
ln -s /etc/apache2/mods-available/dav_fs.load /etc/apache2/mods-enable/dav_fs.load

Configuração do WebDAV

Criar e editar o arquivo de configuracao git:

touch /etc/apache2/conf.d/git
nano /etc/apache2/conf.d/git

Uma vez criado adicione as seguintes linhas:

<Directory "/var/www/git">
        DAV on
        Options +Indexes +FollowSymLinks
        AllowOverride None
        Order allow,deny
        Allow from all
        AuthType Basic
        AuthName "Private Git Access"
        AuthUserFile /etc/apache2/passwd.git
        Require valid-user
</Directory>

Agora temos que criar um arquivo de senhas para a autenticação do tipo Basic:

htpasswd -c /etc/apache2/passwd.git usuario

Feito isso, criaremos o diretório dos repositórios para testar a autenticação:

mkdir /var/www/git

Reiniciar o Apache e testar o endereço http://localhost/git:

service apache2 restart

Instalação e Configuração do GIT

Instale o git em sua máquina:

apt-get install git

Agora vamos criar um repositório de teste:

mkdir -p /var/www/git/meurepo
cd /var/www/git/meurepo
git --bare init
Initialized empty Git repository in /var/www/git/meurepo/

Teremos que habilitar o hook de post-update para garantir que o nosso recem criado repositório fique sempre atualizado:

cd /var/www/git/meurepo
cp hooks/post-update.sample hooks/post-update
chmod +x hooks/post-update

O conteúdo do hooks/post-update deve ser:

cat hooks/post-update
exec git update-server-info
Executaremos manualmente o hook na primeira vez:
./hooks/post-update

No Ubuntu o usuário Apache é www-data. Vamos dar permissão à ele em nosso diretório:

chown -R www-data:www-data  /var/www/git/meurepo

Reinicie o servidor apache:

service apache2 restart


Instalação e Configuração do gitweb

O Gitweb é a interface web padrão fornecido pelo git e é base para outros scripts tais como cgit, gitosis entre outros. Para instalarmos o gitweb no Server, podemos executar :

apt-get install gitweb

Criar e editar o arquivo gitweb.conf para o Apache:

touch /etc/apache2/conf.d/gitweb
nano /etc/apache2/conf.d/gitweb

Adicione o codigo no arquivo:

Alias /gitweb /var/www/git


<Directory /var/www/git>
  Options +ExecCGI
  AddHandler cgi-script .cgi
  DirectoryIndex gitweb.cgi
</Directory>

Criar arquivo de configuração do gitweb:

cat /etc/gitweb.conf
$projectroot = '/var/www/git/';
@git_base_url_list = ('http://localhost/git')

Reiniciar o Apache e testar o endereço http://localhost/gitweb:

/etc/init.d/httpd restart

Instalação do Cliente Git

No cliente, pode se a mesma máquina ou outra remota, temos que instalar novamente o git .

apt-get  install git

Configuracao mínima do nosso git:

git config --global user.name "My Name"
git config --global user.email "my@email.com"

Configuraremos um usuário e senha para acessar ao servidor git:

nano ~/.netrc

Adicione no arquivo:

machine localhost
login usuario
password senha


Nota para usuários windows


Neste caso é necessário abri seu iniciar > executar e rodar o cmd, dentro dele digite o seguinte comando:


setx HOME %USERPROFILE%


onde %USERPROFILE% é o diretório do seu usuário 'C:/Users/nomedousuario'. Uma vez feito isso, crie um arquivo neste diretório chamado _netrc (uma vez que o Windows não aceita .netrc) e a adicione o mesmo conteúdo usado acima.


Podemos testar o acesso ao servidor via curl:

curl --netrc --location -v http://localhost/git

Clonar o repositório remoto:

git clone http://localhost/git/meurepo
Cloning into meurepo...
warning: You appear to have cloned an empty repository.

Vamos agora adicionar alguma coisa ao nosso  repositório:

cd meurepo
echo hellow world! > teste.txt
git add teste.txt
git commit -m 'Adicionando meu primeiro arquivo'

Enviando os arquivos para o servidor que criamos:

git push origin master
Fetching remote heads...
  refs/
  refs/tags/
  refs/heads/
updating 'refs/heads/master'
  from 0000000000000000000000000000000000000000
  to   87366d467e2dfcc6057bf7d5e112b79ede984861
    sending 3 objects
    done


Bem, é isso galera, espero que esse post seja útil à todos. Assim que eu tiver mais novidades sobre essa maravilhosa ferramenta volto a publicar aqui. Grande abraço!

Referências:

  • http://pt.wikipedia.org/wiki/Git
  • http://pt.wikipedia.org/wiki/Controle_de_versão
  • http://progit.org/
  • http://imasters.com.br/artigo/23356/desenvolvimento/por-que-voce-deveria-mudar-do-subversion-para-git-parte-01


Wednesday, November 23, 2011

MySQL - Checando a segurança após instalação


Olá galera, hoje nosso tópico é curto mas muito importante, vamos falar sobre algumas medidas de segurança que devemos tomar uma vez que instalamos o MySQL em nosso servidor.

Estou usando o Ubuntu 11.04 e MySQL 5.1.54 e acabei de fazer a instalação do meu serviço aqui (você pode checar como fazer isso aqui). Bem, agora temos algumas medidas de segurança para tomar de forma a proteger nossa base de dados. Inicialmente o MySQL cadastra usuarios anônimos em suas tabelas de grant, mas ele também tem ferramentas que te auxiliam no processo de aperfeiçoamento da segurança do banco.


Usuários anônimos e segurança

Podemos checar que usuários possuimos em nossa base inicialmente com o comando abaixo:

  1. mysql> SELECT user, host,  password from mysql.user;
  2. +--------+-----------+-----------------------------------+
  3. | user   | host      | password                          |
  4. +--------+-----------+-----------------------------------+
  5. | root   | localhost | *57000000000000000000000000000001 |
  6. | root   | 127.0.0.1 | *57000000000000000000000000000001 |
  7. | root   | ::1       | *57000000000000000000000000000001 |
  8. |        | localhost |                                   |
  9. +--------+-----------+-----------------------------------+
  10. 7 rows in set (0.00 sec)


Note que temos 2 usuários anônimos em nossa base. Poderiamos simplesmente apagar este usuário usando um DELETE FROM mysql.user..., mas como manda a documentação temos commandos específicos e utilitários que já fazem essa tarefa de forma limpa e segura do ponto de vista do SGDB.

Em nosso caso aqui iremos trabalhar com o utilitário mysql_secure_installation. (Lembrando que esse comando é válido apenas para o linux). Veja abaixo:

  1. shell> mysql_secure_installation
  2. NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL       SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
  3. In order to log into MySQL to secure it, we'll need the current
  4. password for the root user.  If you've just installed MySQL, and you haven't set the root password yet, the password will be blank, so you should just press enter here.
  5. Enter current password for root (enter for none):


Uma vez digitado o password que você definiu para o seu root inicialmente (você ainda lembra né?) ele vai te guiar em um intuitivo passo a passo para tornar sua base mais segura. Entre eles te perguntar sobre a remoção dos usuário anônimos, desabilitar conexões remotas, remoção do banco de dados teste (uma vez que essa banco permite acessos por qualquer usuário) e finalmente recarregar todos os privilégios para que as alterações tenham efeito.


  1. OK, successfully used password, moving on...
  2. Setting the root password ensures that nobody can log into the MySQL
  3. root user without the proper authorisation.
  4. You already have a root password set, so you can safely answer 'n'.
  5. Change the root password? [Y/n] Y
  6. Password updated successfully!
  7. Reloading privilege tables..
  8.  ... Success!
  9. Remove anonymous users? [Y/n] Y
  10.  ... Success!
  11. Disallow root login remotely? [Y/n] Y
  12.  ... skipping.
  13. Remove test database and access to it? [Y/n] Y
  14.  ... skipping.
  15. Reload privilege tables now? [Y/n] Y
  16.  ... Success!
  17. Cleaning up...
  18. All done!  If you've completed all of the above steps, your MySQL
  19. installation should now be secure.
  20. Thanks for using MySQL!


Bem, após isto você ainda pode fazer algumas importantes verificações:

Tenha certeza que todas as suas contas tem senha, sua query abaixo tem que retornar vazia:

  1. mysql> SELECT Host, User FROM user WHERE Password = '';
  2. Empty set (0.00 sec)

Periodicamente procure por senhas duplicadas:

mysql> SELECT User from mysql.user GROUP BY password HAVING count(user) > 1;

Fique alerta quanto a hosts com curingas. Periodicamente faça o teste:

mysql> SELECT User, Host FROM mysql.user WHERE Host LIKE '%\%%';

Com esse passo a passo seu banco de dados já está mais seguro contra invasões e usuários não autorizados. Em breve trarei mais tópicos de como melhorar sua segurança.

Viva ao meu, seu, nosso MySQL! Até mais!



Tuesday, November 1, 2011

Identificadores no MySQL

Olá Pessoal. Vamos falar nesse artigo sobre Identificadores no MySQL, algo extremanente importante em nosso cotidiano com o banco de dados, mas que por vezes não entendemos bem o funcionamento.

Quando escrevemos requisições SQL,  usamos nomes para se referir a banco de dados e outros objetos contidos no mesmo, tais como tabelas, stored routines, triggers entre outros. Alguns destes objetos tem em seus componentes nomes próprios. Por exemplo, tabelas em suas colunas e índices. Ou ainda é possível criar 'apelidos' (Alias), pelo quais atuam como sinônimos para nomes de tabelas e colunas.

Sintaxe

Identificadores podem estar ou não entre acentos grave (`). Se não estiver deve seguir algumas regras:

  • Ele pode conter qualquer caracter alfanumerico, o (_) e o sinal de dolar $;
  • O identificador pode iniciar com qualquer caracter citado acima, inclusive números. Contudo, é melhor evitar identificadores que podem ser entendidos como constantes. Por exemplo 1e3 pode ser considerado um numero de notação cientifica ou 0x1 como uma contante hexadecimal. Portanto nenhum dos dois são bons candidatos à identificadores.
  • Um indentificador não pode ser apenas números.
Um identificador estando entre acentos agudos pode conter espaços, aspas simples ou duplas. Caso o SQL mode esteja habilitado em ANSI_QUOTES você também pode usar as aspas duplas ("). Usando desta forma há algumas regras para serem seguidas:
  • Em geral, qualquer caracter pode ser usado em um identificador entre aspas. Excessões neste caso são que um identificador não pode conter um byte com um valor numero 0 ou 255, e os nomes de banco de dados e tabelas não podem conter '.', '/' ou '\'.
  • Um identificador entre aspas pode conter apenas números.
  • Um identificador pode incluir qualquer palavra, mas caso esta seja uma palavra reservada (tais como SELECT ou DESC), conter caractes especiais, ou ser apenas números ele deve ser obrigatoriamente adicionado entre aspas ou acento grave.
Caso você não esteja certo se o seu identificador é ou não uma palavra reservada coloque ele entre acentos grave.


Case Sensitivity de Identificadores

Uma caracteristica que afeta como usamos identificadores é se eles são case sensitive. Alguns podem ser e outros não. As regras que determinam essas caracteristicas dependem que tipo de identificador estamos lidando:
  • Para banco de dados e tabelas o case sensitivity dependem do sistema operacional e do sistem de arquivos do servidor. Ou ainda da variável de sistema lower_case_table_names. Bancos de dados ou tabelas são representados por diretorios e arquivos, então se o sistema operacional não é case sensitive os identificadores também não são.
    O Windows não é case sensitive, porém a maioria dos sistemas Unix são. Contudo, se a a variável de sistema lower_case_table_names estiver setada para 1 ou 2, identificadores de banco de dados e tabelas são usados no estilo case-insensitive em declarações SQL. Caso deseje usar esssa variavel, você deve seta-la antes de começar a criar seus bancos de dados e tabelas.
    Independente das propriedades do seu sistema de arquivos, identificadores de bancos de dados e tabelas devem ser escritos de forma consistente com o mesmo padrão em toda declaração SQL.
  • Identificadores para colunas, índices, stored routines e triggers não sao case sensitive.
  • 'Alias' para colunas não sao case sensitive.

Utilizando 'Nomes Qualificados'

Identificadores de colunas e tabelas podem ser escritas de forma qualificada - isto quer dizer, junto com o identificador de um nivel superior utilizando o ponto '.' como separador. Algumas vezes estes qualificadores são necessários para resolver problemas de ambiguidade. Outras vezes você pode eleger seu uso para tornar uma declaração mais simples ou precisa.

Uma tabela pode ser qualificada com o nome do banco de dados que ela pertence. Ambos os casos trazem o mesmo resultado:

SELECT * FROM tb1;
SELECT * FROM db1.tb1;

Uma coluna também pode ser qualificada com o nome da tabela à que pertence. E como a tabela também pode ser qualificada podemos ter até 3 formas diferentes de escrever a mesma query:

SELECT coluna1 FROM tb1;
SELECT tb1.coluna1 FROM tb1;
SELECT db1.tb1.coluna1 FROM db1.tb1;

Store routines e triggers também podem  ser referenciados em uma forma qualificada. No primeiro caso a qualificação é pelo banco de dados à que pertence. Um trigger é associado com uma tabela, neste caso ele deve ser associado com a mesma (table_trigger.trigger_name).

Em identificadores entre aspas em nomes qualificados use eles separados. Por exemplo: db1.tb1 como `db1`.`tb1` e não `db1.tb1`.


Usando Palavras Reservadas como Identificadores

Palavras reservadas (Reserved Words) são especiais. Por exemplo, nome de funções não podem ser usadas como identificadores de tabelas ou colunas, e caso tente mensagens de erros podem ser emitidas. A declaração abaixo é um exemplo claro do uso errôneo:

mysql> CREATE TABLE t (order INT NOT NULL UNIQUE, d DATE NOT NULL);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order INT NOT NULL UNIQUE, d DATE NOT NULL)' at line 1

Igualmente, a outra query abaixo retornará a mesma situação:

mysql> SELECT 1 AS INTEGER;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTEGER' at line 1

A solução para estes problemas é colocar os identificadores entre aspas / acentos agudos. As regras desse encapsulamento do identificador dependem do seu tipo:
  •  Para utilizar uma palavra reservada como banco de dados, tabela, coluna ou indentificar um índice há um ou dois estilos para o encapsulamento, dependendo do SQL mode do servidor. Por padrão, palavras reservadas utilizando acento grave "`" podem ser usadas como identificadores:
mysql> CREATE TABLE t (`order` INT NOT NULL UNIQUE, d DATE NOT NULL);
Query OK, 0 rows affected (0.00 sec)

Se o ANSI_QUOTES no SQL mode estiver habilitado você pode escrever a declaração da usando aspas duplas:

mysql> CREATE TABLE t ("order" INT NOT NULL UNIQUE, d DATE NOT NULL);

Query OK, 0 rows affected (0.00 sec)
Se é necessário encapsular um identificador para sua criação, em todas as declarações envolvendo ele também será necessário executar o mesmo procedimento.
  • Pode-se usar uma palavra reservada como um 'Alias' usando aspas simples, duplas ou acento agudo. O SQL mode não faz diferença, uma vez que é legal utilizar qualquer uma das três formas. Portanto, para usar INTEGER como um 'alias' você pode escrever em todos os modos abaixo:

SELECT 1 AS 'INTEGER';SELECT 1 AS `INTEGER`;SELECT 1 AS "INTEGER";
É uma boa ideia evitar nomes de funções como identificadores. Normalmente, eles não são reservados, contudo há circunstancias pelo qual isto pode não ser verdade:
  • Algumas funções tem nomes que também são palavras chaves 'keywords' e portanto reservadas. CHAR() é um exemplo.
  • Por padrão, um nome de função seguido de um parenteses aberto deve ser escrito sem espaços entre eles. Isso permite ao statement parser do MySQL distinguir um nome em uma função do mesmo para outro propósito, tal como um identificador.
Contudo, se o IGNORE_SPACE SQL mode estiver habilitado, o servidor permite espaços entre o nome da função e seu parenteses de abertura "(". Rodando o servidor desse modo o nome de algumas funções passam a ser ambinguas em alguns contextos, uma vez que o statement parser não consegue mais distinguir seguramente se um nome representa uma função ou um identificador.
veja abaixo:

mysql> INSERT INTO COUNT (id) VALUES(43);

EM IGNORE_SPACE mode, esta declaração pode significar "criar uma nova linha na tabela COUNT, setando a coluna id com 43", ou pode significar uma falha de sintaxe na declaração INSERT que tem uma chamada da função COUNT onde o nome da tabela deveria estar. O parse não consegue distinguir.

Outra observação, palavras reservadas não são case sensitive. Elas pode ser escritas em maíusculo, minusculo ou ainda com ambos. Elas também não precisam ser escritas da mesma forma por toda a query. O mesmo também é verdadeiro para nome de funções.


Thursday, October 20, 2011

MTBF e MTTR em sua aplicação. Sua equipe de TI sabe do que estamos falando?


Olá galera, esta semana estou fazendo um curso de Alta Disponibilidade com MySQL Cluster e entre os vários tópicos abordados há uma forma de calcular o tempo de atividade Uptime "disponibilidade"das máquinas. E sendo esta umas das principais razões para usarmos o Cluster do MySQL o assunto realmente me interessou, o que me fez ler e procurar entender melhor o conceito e de quebra fiz este artigo baseado em um outro do site http://world-class-manufacturing.com uma vez que não encontrei muita documentação em português. Espero que apreciem.


MTBF e MTTR o que são?

MTBF, Mean Time Between Failures (Tempo médio entre falhas) e MTTR - Mean Time To Repair (Tempo médio de reparo) são dois importantes KPI's dentro do nível de desempenho de processos.

MTBF = (Total up time) / (número de breakdowns)
MTTR = (Total down time) / (número de breakdowns)


MTBF e MTTR - O que eles querem dizer?

"Tempo médio" significa, estatisticamente falando, o valor médio de tempo dentre a ocorrência de uma mesma situação.

“Mean Time Between Failures” (MTBF) é literalmente a média de tempo decorrida entre uma falha e a próxima vez em que ela irá ocorrer. Normalmente pessoas pensam nisto como uma média de tempo de alguma coisa funcionando até  falhar e precisar ser reparada (novamente).

“Mean Time To Repair” (MTTR)  é a média de tempo que se leva para reparar alguma coisa depois de uma falha.

Para algo que não pode ser reparado o termo correto é MTTF - “Mean Time To Failure” (Tempo médio para falhas). Alguns definiriam MTBF - para dispositivos reparáveis -  como a soma de MTTF mais MTTR.  (MTTF = MTTF + MTTR). Em outras palavras, o Meio Tempo entre falhas é o tempo entre uma falha e outra. Esta distinção é importante se o tempo de reparo (MTTR) é uma fração significante do MTTF.

Aqui está um exemplo: Uma lâmpada em um candelabro não é reparável, então MTTF é mais apropriado. A lâmpada deve ser trocada. O MTTF possivelmente é de 10.000 horas.

Por outro lado, sem trocas de óleos, um motor de carro pode falhar depois de 150 horas dirigindo em uma rodovia - neste caso é MTTF. Assumindo 6 horas para remover e substituir o motor (MTTR), MTBF é 150 + 6 = 156 horas.

Como automóveis, a maioria de equipamentos manufaturados serão reparados, ao invés de substituidos após uma falha. Logo MTBF é a mais apropriada forma de medir.


O que é uma falha?

""Falha" pode ter vários significados. Vamos rapidamente examinar uma falha em um dispositivo:

Uma Fonte de Energia Ininterrupta (UPS - Uninterruptible Power Source) pode ter cinco funções dentro de duas condições:
  • Enquanto a principal fonte de energia está disponível:
    • F1) Permite a energia circular da fonte principal para as máquinas protegidas;
    • F2)Condiciona a energia limitando saltos ou interrupções;
    • F3)Armazena energia em uma bateria até completá-la;
  • Quando a principal fonte de energia é interrompida:
    • F4)Fornece energia para as máquinas protegidas;
    • F5)Emite um sinal indicando que a forte de energia principal está inoperante;
Não há dúvida sque o UPS falhou se ele interromper o fluxo de energia provido pela fonte principal para as máquinas protegidas (F1). Falhas para F2, F3 ou F5 podem não ser óbvias porque as "máquinas protegidas" estão ainda rodando pela fonte principal ou pela bateria. Ainda que notado, estas falhas pode não acionar medidas corretivas porque as "máquinas protegidas" estão ainda rodando e pode ser mais importante mantê-las rodando do que corrigir ou substituir o UPS.


O que é Disponibilidade? 

A "disponibilidade" de um equipamento é, matematicamente, MTBF / (MTBF + MTTR) para tempo de trabalho programado.

O automóvel do exemplo anterior está disponível para 150/156 = 96,2% do tempo. O reparo é tempo de inatividade não programada.

Com meia hora de não programada troca de óleo a cada 50 horas dirigidas - acontece quando um indicador no painel do carro alerta o motorista -  o tempo de disponibilidade sobre para 50 / 50.5 = 99%.

Se trocas de óleo fossem agendadas corretamente como atividade de manutenção a disponibilidade do veículo seria de 100%.


Porque tudo isso é importante?

"Disponibilidade" é um indicador de performance para processos e fábricas. É parte da medida da eficácia geral do equipamento ou “Overall Equipment Effectiveness” (OEE).

Uma produção programada que inclui tempos de paradas para manutenção preventiva pode precisamente prever o total de uma produção. Agendamentos que ignoram MTBF e MTTR são simplesmente um desastres (programados ou não, desculpe o trocadilho) aguardando para acontecer.


Como calcular o atual MTBF

Atual ou histórico MTBF é calculado usando observações no mundo real. (Há uma disciplina para designers de equipamentos preverem MTBF, baseado nos componentes e cargas de trabalho previstas).

Calculando o atual MTBF requer um conjunto de observações, onde cada uma seria:
  • Tempo de Funcionamento (Uptime_moment): o momento no qual a máquina começa a operar (inicialmente ou após um reparo);
  • Tempo de Parada (Downtime_moment): o momento no qual a máquina parou após iniciado suas operações.
Cada tempo entre falhas (Time Between Failure TBF) é a diferença entre um tempo de funcionamento (Uptime_moment) e seu tempo de parada (Downtime_moment) subsequente.

Três quantidades são requeridas:

n = Numero de observações
ui = Este é o ith Uptime_moment 
di = Este é o ith Downtime_moment seguido de um ith Uptime_moment


Então temos MTBF = Sum (di - ui) / n, para todos i = 1 entre n observações. Mais simplesmente, este é o tempo de trabalho total dividido pelo número de falhas.


Texto extraído e traduzido de http://world-class-manufacturing.com/KPI/maintenance.html.

Outras referências sobre o assunto:
http://pt.wikipedia.org/wiki/Indicador-chave_de_desempenho

Thursday, October 13, 2011

Quiz de MySQL - Por que não testar o que sabe?

Olá à todos. Neste post teremos um pequeno quiz para checar o quanto sabemos sobre MySQL. Estas questões não são oficiais ou fazem parte de nenhuma certificação, mas nos dão uma dica de como anda nosso conhecimento sobre esse banco de dados. Ao final das questões vocês podem encontrar as respostas e caso desejem comentem sobre seu score. Abraços e espero que se divirtam.
                       
1) MySQL roda em que sistemas operacionais?
a) Linux e Mac OS-X apenas
b) Qualquer um
c) Unix, Linux, Windows e outros
d) Unix e Linux apenas

2) Para remover registros duplicados de um result set de um SELECT use a palavra-chave abaixo:
a) NO DUPLICATE
b) UNIQUE
c) DISTINCT
d) Nenhuma das respostas anteriores

3) Qual das respostas abaixo podem adicionar uma linha na tabela?
a) Add
b) Insert
c) Update
d) Alter

4) Para usar MySQL no seu computador você precisará?
a) FTP e Telnet
b) Algum tipo de client programa para acessar os banco de dados
c) Um Browser
d) Perl, PHP ou Java

5) Qual declaração SQL é usada para inserir um novo dado no banco de dados?
a) INSERT INTO
b) UPDATE
c) ADD
d) INSERT NEW

6) Em uma cláusula LIKE você poderia pedir por qualquer valur terminado em 'qpt' escrevendo:
a) LIKE %qpt
b) LIKE *ton
c) LIKE ton$
d) LIKE ^.*ton$

7) Um valor NULL é tratado como blank ou 0.
a) Verdadeiro
b) Falso
c) Nenhuma das respostas acima

8) MySQL é
a) Uma linguagem de Programação
b) Uma tecnica para escrever programs confiáveis
c) Um Sistema de Gerenciamento de Banco de dados Relacionais

9) Em uma cláusula LIKE você pode solicitar por qualquer valor de 6 digitos digitando?
a) LIKE ??????
b) LIKE .{6} Answer 5: LIKE ^.{6}$
c) LIKE ...... (6 pontos)
d) LIKE ______ (6 underscore characters)

10) O resultado de um SELECT pode comter linhas duplicadas.
a) Falso
b) Verdadeiro
c) Nenhuma das respostas acima

11) Qual função é usada para pegar o tempo corrente no MySQL?
a) getTime()
b) Time()
c) NOW()

12) Uma tabela pode fazer um JOIN nela mesma.
a) Verdadeiro
b) false
c) Nenhuma das respostas acima

13) Qual valor abaixo não é uma função de agregação?
a) COUNT
b) MIN
c) MAX
d) COMPUTE

14) mysql_pconnect() é usada para fazer a persistência com o banco de dados, o que significa um link SQL que não fecha quando a execução do seu script acaba. 
a) Verdadeiro
b) Falso

15) O que uma cláusula SQL usa para restringir o numero de linhas retornadas?
a) AND
b) WHERE
c) HAVING
d) FROM

16) Qual valor abaixo é usado para remover um banco de dados MySQL?
a) mysql_drop_database
b) mysql_drop_entiredb
c) mysql_drop_db
d) mysql_drop_dbase

17) MySQL suporta o padrao SQL99
a) Falso
b) Verdadeiro

18) Primary Key permite valores NULL, e UNIQUE KEY não aceita valores NULL.
a) Falso
b) Verdadeiro

19) Quantos caracteres são permitidos no nome de um banco de dados?
a) 55
b) 72
c) 64
d) 40

20) Qual comando abaixo deveria ser usado para criar um banco de dados chamado “student”?
a) CREATE ?I student
b) CREATE DATABASE student
c) DATABASE /student
d) DATABSE student

21) Qual comando irá deletar a estrutura da tabela e seus dados?
a) TRUNCATE
b) DROP

22) O que faz o comando USE?
a) É usado para carregar código de outro arquivo
b) tornou-se obsoleta e deve ser evitado por razões de segurança
c) É um pseudônimo para o comando SELECT
d) No caso de ser utilizado para escolher o banco de dados que deseja usar, uma vez que você tenha conectado ao MySQL

23) Data a tabela employees abaixo:  

emp_idemp_name
1Brush
2Jerrin

Que valor vai retornar com a query SELECT COUNT(*) FROM employees?
a) 3
b) 2
c) 1
d) Nenhuma das respostas acima

24) O principal programa MySQL que faz todo o tratamento dos dados é chamado?
a) mysql.exe
b) mysql
c) mysqld
d) httpd

25) Um comando SELECT sem uma cláusula WHERE retorna?
a) Todos os registros de uma tabela que correspondem à anterior cláusula WHERE
b) Todos os registros de uma tabela ou de informações sobre todos os registros
c) SELECT é inválido sem uma cláusula WHERE
d) Nada


26) O acesso de segurança do MySQL é controlado através de?
a) O ID que o usuário conectado ao servidor através e privilégios criados para essa conta
b) As contas de login MySQL e privilégios estabelecidos para cada conta
c) A segurança login normal é suficiente para MySQL, e ele não tem qualquer controle extra de seu próprio.
d) Uma tabela de endereços IP válidos, e os privilégios criados para cada endereço IP

27) Em um SELECT com uma cláusula GROUP BY, a cláusula WHERE e uma cláusula HAVING, as condições WHERE são aplicados antes que as condições HAVING.
a) Verdadeiro
b) Falso
c) Ambos Verdadeiro ou Falso
d) Nenhuma das respostas acima



Respostas:


(1) c(2) c(3) b(4) b(5) a
(6) a(7) b(8) c(9) d(10) b
(11) c(12) a(13) d(14) a(15) b
(16) c(17) a(18) a(19) c(20) b
(21) b(22) d(23) b(24) c(25) b
(26) b(27) a