Posts Tagged bluehost

Triggers on mySQL 5 without SUPER privilege

As people should know, MySQL 5.0 introduced several new features, with triggers among them. However, creating triggers require a user with SUPER privilege, which is not something the database administrator is willing to spread easily.

The full story of how I came to this solution and how it works can be found in my blog (off site). The gist of it is that a normal user can request a trigger creation or removal by filling a table record, and this program, running as a cron job, will check if the request is appropriate and if so it will comply with the user’s request.

The source code follows.


#!/usr/bin/perl

# addtriggers
#
# Device to add triggers on demand in databases assigned
# to users without SUPER privilege.
#
# It is intended to be run as a cron job from a user with
# SUPER privileges and full access to all the concerned databases.
#
# Set username and password for this user in a ~/.my.cnf file
# under the label [trigger_creator]
#
# See the docs at http://datacharmer.blogspot.com/

package main;
use strict;
use warnings;
use English qw( -no_match_vars );
use Data::Dumper;
use DBI;
use Carp;

our $VERSION    = '0.2';
our $DEBUG      = $ENV{DEBUG};

my $dbh=DBI->connect('dbi:mysql:stardata1;host=localhost'
            . ";mysql_read_default_file=$ENV{HOME}/.my.cnf"
            . ';mysql_read_default_group=trigger_creator',
                undef,
                undef,
                {RaiseError => 1, PrintError=> 0})
         or die "Can't connect: $DBI::errstr\n";

my $database_list_query = qq{
    SELECT DISTINCT
        table_schema
    FROM
        information_schema.tables
    WHERE
        table_name ='trigger_request'};

my $databases = safe_selectcol_arrayref($dbh, $database_list_query,und
+ef);

for my $db (@$databases) {
    use_db($dbh,$db);
    #
    # no need to check anymore: the initial query ensures that
    # only databases with a trigger_request tables are inspected
    #
    # my ($trigger_request) = $dbh->selectrow_array(
    #    qq{SHOW TABLES LIKE 'trigger_request'});
    # next unless $trigger_request;

    #
    # create the trigger_answer table
    #
    safe_do(
            $dbh,
            qq{create table if not exists trigger_answer
                (trigger_name varchar(50) not null primary key,
                TS timestamp, result text) }
            );

    #
    # collects the list of triggers to be created
    #
    my $triggers = safe_selectall_arrayref(
            $dbh,
            qq{select trigger_name, coalesce(trigger_body, '') as trig
+ger_body
                from trigger_request where done = 0},
            {Slice => {}}
            );

    #
    # collects the list of existing triggers, so we know which
    # ones we need to drop before creation
    #

    my $existing_triggers_list = safe_selectcol_arrayref(
            $dbh,
            qq{select trigger_name
               from information_schema.triggers
               where trigger_schema = ?},
            undef, $db);

    my %existing_triggers = map { $_, 1 } @$existing_triggers_list;

    #
    # trigger creation loop
    #
    TRIGGERS:
    for my $trig (@$triggers)
    {
        if ($DEBUG) {
            print "DB: $db\n", Data::Dumper->Dump([$trig],['trig']);
        }
        last TRIGGERS unless exists $trig->{trigger_name};
        last TRIGGERS unless exists $trig->{trigger_body};
        my $result = undef;
        #
        # removing trailing spaces from trigger definition
        #
        $trig->{trigger_body} =~ s/^\s+//x;
        $trig->{trigger_body} =~ s/\s+$//x;
        #
        # sanitizing check. We are going to execute only queries that
+are
        # trigger creations, without any database specification
        #
        if ( ( $trig->{trigger_body} eq q{} ) # = only drop trigger re
+quest
                                              # Notice that the query
+will convert
                                              # any NULL trigger body
+to ''
              or
              ($trig->{trigger_body} =~ /^\s* create \s+ trigger \s+ $
+trig->{trigger_name}/xi) )
        {

            #
            # more sanitizing checks
            #

            if (my ($tdb,$ttable) = $trig->{trigger_body} =~ /(\w+|`[^
+`]+`)\.(\w+|`[^`]+`)/xi)
            {
                if ($tdb ne $db)
                {
                    set_result(
                        $dbh,
                        $trig->{trigger_name},
                        "REJECTED: Attempt at using database $tdb from
+ database $db");
                    next TRIGGERS;
                }
            }

            #
            # The requested trigger will be dropped first, if exists.
            #
            if (exists $existing_triggers{$trig->{trigger_name}}) {
                eval {
                    $dbh->do(qq[drop trigger $trig->{trigger_name}] )
+;
                } ;
                if ($EVAL_ERROR) {
                    set_result(
                        $dbh,
                        $trig->{trigger_name},
                        $EVAL_ERROR);
                    next TRIGGERS;
                }
                else {
                    $result = 'OK';
                }
            }
            if ( $trig->{trigger_body} ne q{} )  { # if the body is em
+pty, skip the creation
                #
                # for future versions of MySQL. Starting 5.0.17 a DEFI
+NER clause
                # can be used.
                #
                $trig->{trigger_body} =~ s{^\s* create}{CREATE /*!5001
+7 DEFINER=CURRENT_USER*/ }xi;

                #
                # This is the main point. The trigger is created here
                #
                eval {
                    $dbh->do($trig->{trigger_body});
                };
                if ($EVAL_ERROR) {
                    $result = $EVAL_ERROR;
                }
                else {
                    $result = 'OK';
                }
            }
        }
        #
        # if the initial check failed, we report that such query was
        # not accepted
        #
        else {
            $result = 'SQL command not recognized as a CREATE TRIGGER'
+;
        }
        #
        # finally, we report the results
        # to the trigger_answer table
        set_result( $dbh, $trig->{trigger_name}, $result);
    }
}

sub set_result {
    my ($dbh,$trigger_name, $result) = @_;
    $result =~ s/^ .* do failed: \s* //x;
    $result =~ s/at \s+ line \s+ \d+ \s+ at \s+ \S+ \s+ line \s+ \d+ \
+W*$//x;
    safe_do(
        $dbh,
        qq{insert into trigger_answer (trigger_name, result) values (?
+, ?)
           on duplicate key update result = ?},
        undef,
        $trigger_name, $result, $result);

    safe_do(
        $dbh,
        qq{update trigger_request set done = 1 where trigger_name = ?}
+,
        undef ,
        $trigger_name);
    if ($DEBUG) {
        print "RESULT: $result\n";
    }
}

sub use_db {
    my ($dbh,$db) = @_;
    # prepared statements do not support "use database_name"
    my $save_prepare_option = $dbh->{mysql_emulated_prepare};
    $dbh->{mysql_emulated_prepare}=1;
    eval { $dbh->do(qq{use $db}) };
    if ($EVAL_ERROR) {
        croak "unable to change to database $db\n";
    }
    $dbh->{mysql_emulated_prepare}= $save_prepare_option;
}

sub safe_selectcol_arrayref {
    my ($dbh, $query, $options, @params) = @_;
    my $result;
    # This should be the normal call
    # my $result = $dbh->selectcol_arrayref($query);
    #
    # the following ugly hack is a workaround for a bug in
    # DBD::mysql 3.0002_4 (http://bugs.mysql.com/bug.php?id=15546)
    #
    eval {
        if (@params) {
            $result = $dbh->selectall_arrayref($query, $options, @para
+ms);
        }
        else {
            $result = $dbh->selectall_arrayref($query, $options);
        }
    };
    if ($EVAL_ERROR) {
        croak "error executing query: $query\n$EVAL_ERROR\n";
    }
    return [ map {$_->[0] } @$result ];
}

sub safe_do {
    my ($dbh, $query, $options, @params) = @_;
    my $result;
    eval {
        if (@params) {
            $result = $dbh->do($query,$options,@params);
        }
        else {
            $result = $dbh->do($query,$options);
        }
        if ($EVAL_ERROR) {
            croak "error executing query: $query\n$EVAL_ERROR\n";
        }
    };
    return $result;
}

sub safe_selectall_arrayref {
    my ($dbh, $query, $options, @params) = @_;
    my $result;
    eval {
        if (@params) {
            $result = $dbh->selectall_arrayref($query,$options,@params
+);
        }
        else {
            $result = $dbh->selectall_arrayref($query,$options);
        }
        if ($EVAL_ERROR) {
            croak "error executing query: $query\n$EVAL_ERROR\n";
        }
    };
    return $result;
}

via http://www.perlmonks.org/?node_id=515527

Tags: , , ,

Installing GIT on bluehost

Background

It seems that Bluehost by default does not support nor tell you how to install Git. I also tried posting a query on Bluehost’s forums to see if anybody has done it before but with no luck.  So I decided to just go ahead and try this out myself.  Also note that you will need to enable the SSH access on your bluehost account to do this. You can easily enable SSH on your account by sending a request to Bluehost Tech support.

Here are my specs from the bluehost account:

myuser@koolwal.net [~]# cat /proc/version

Output:
Linux version 2.6.28-9.16.intel.BHsmp (kernel@bluehost.com) (gcc version 3.4.6 20060404 (Red Hat 3.4.6-10)) #1 SMP Sat Apr 18 11:41:59 MDT 2009
myuser@koolwal.net [~]#

Basically it is a Red Hat Linux system with 2.6.28 Linux kernel running. So now we have all the information that we need let’s get started…

Step 1: Download git tarball

Log into your Bluehost account and give the following command:

# wget http://kernel.org/pub/software/scm/git/git-1.6.3.3.tar.bz2

Note: The latest stable release version might have changed since this posting, so you need to substitute in the above command the latest git version that you would like to install or else you can continue with the git version that I ended up installing. You can checkout the latest stable release version of git here.

Step 2: Extract the tarball

Now just extract the tarball installation file in your home directory

# tar -xjvf git-1.6.3.3.tar.bz2

Step 3: Compile the git program

# cd git-1.6.3.3
# make

Now mostly after a while you will get the following error message and your make command will fail:

make[2]: true: Command not found
make[2]: *** [blibdirs] Error 127
make[1]: *** [all] Error 2
make: *** [all] Error 2

It seems that the true command is not installed on the bluehost servers but you type in the command true it seems that it exits:

myuser@koolwal.net [~]# true
myuser@koolwal.net [~]#

This probably means that the git make command is not able to locate the directory in which the true command sits.

Step 4: Fix “true”: Command not found error

The simplest way to fix this error is to create an empty script file called true with just the following line:

#!/bin/sh

Save and exit the file and copy it in your local bin directory after making it executable:

# cd;
# chmod 755 true
# mkdir bin (if the directory does not exits)
# cp true bin/true

and now you can re-issue the make command:

# cd git-1.6.3.3
# make clean
# make

and now after a while you should see the the “make” command finishes without any error.

Step 5: Install the git program

Finally you can install the git software by issuing the following command:

# make install

and you should be able to execute the “git” command on your Bluehost account.

Step 6: Test git

Now it is time to test if the “git” program installed successfully or not.

# mkdir test_project
# cd test_project
# git

Output:

Initialized empty Git repository in /home1/myuser/test_project/.git/

Congratulations the above output means that your “git” is working just fine and now you can use it for your project that you have been planning.

via http://blogs.koolwal.net/2009/07/20/howto-installing-git-on-bluehost-domain-hosted-websites/

Tags:

Bad Behavior has blocked 272 access attempts in the last 7 days.

Better Tag Cloud