Archive for the ‘howto’ Category

TaskFreak! v0.6.2 – Alter Search Plugin

Июль 15th, 2010

Background Knowledge


The Search Plugin for TaskFreak! created by DaDaemon and xdu v0.0.1 (March 26, 2007) was designed to create a simple, quick search capability of the tasks title and description. As well it only searched through he current task view (tasks visible at the time) and tasks that are not completed. For some this was not what was desired and would rather have the Search Plugin search through all tasks weather completed or not and as well search through the comments of tasks along with the title and description. I’ll show you how this is done using Searcher, bchristie and davidlmansfield instructions posted on the TaskFreak! Forums.

Solution – Add the Ability to Search All Tasks


Edit the “index.php” located in the root of TaskFreak! as follows. We will be working in the “Load Tasks” section to just above the “Task Order” section. This solution was posted by Searcher at Re: Quick ‘n’ Dirty Search Plugin.

Code Before
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
$arrFilters = array();
 
// --- filter: project ---
if ($pProject) {
    // load tasks for specific project
	$sqlFilter = 'ii.projectId = \''.$pProject.'\'';
    $pLink=Tzn::concatUrl($pLink,'sProject='.$pProject);
} else if (!$objUser->checkLevel(6)) {
    // user can only access his own projects
    if ($objUserProjectList->rMore()) {
        $arrProject = array();
        while($objTmp = $objUserProjectList->rNext()) {
            $arrProject[] = $objTmp->id;
        }
        if ($objUser->checkLevel(13)) {
        	$arrProject[] = '0';
        }
        $sqlFilter = 'ii.projectId IN ('.implode(',',$arrProject).')';
 
        unset($arrProject);
        $objUserProjectList->rReset();
    }
}
 
$objItemList->addWhere($sqlFilter);
 
// --- filter: user ---
$pUser = intval($_REQUEST['sUser']);
if (!isset($_REQUEST['sUser']) && @constant('FRK_DEFAULT_VIEW_OWN_TASKS')) {
	// default view is own tasks only
	$pUser = $objUser->id;
}
 
if($_REQUEST['sUser'] == 'myprojects' && $_SESSION['selUser']){
   $objItemList->addWhere('ii.authorId='.$_SESSION['selUser']);
}
elseif ($pUser) {
	$objItemList->addWhere('ii.memberId = \''.$pUser.'\'');
    $_SESSION['selUser'] = $pUser;
    $pDefaultUserId = $pUser;
} else {
    unset($_SESSION['selUser']);
    session_unregister('selUser');
    $pDefaultUserId = $objUser->id;
    // by default, show own tasks
    /*
    if (!$objUser->checkLevel(1)) { // admin can see all
	    $objItemList->addWhere('(ii.memberId='.$objUser->id
    		.' OR ii.authorId='.$objUser->id.')');
    }
    */
}
 
$pLink=Tzn::concatUrl($pLink,'sUser='.$pUser);
 
// --- private tasks --------------------------------------------------------
 
$arrFilter[] = 'showPrivate=0';
 
if ($objUser->checkLevel(12)) {
	// show internal tasks
	$arrFilter[] = 'showPrivate=1';
}
 
$arrFilter[] = '(showPrivate=2 AND (ii.memberId='.$objUser->id
	.' OR ii.authorId='.$objUser->id.'))';
 
$objItemList->addWhere('('.implode(' OR ',$arrFilter).')');
 
// --- filter: context ---
 
if ($_REQUEST['sContext']) {
	$pContext = Tzn::getHttp($_REQUEST['sContext'],true);
	$objItemList->addWhere('context = \''.$pContext.'\'');
    $pLink=Tzn::concatUrl($pLink,'sContext='.$pContext);
}
 
$sqlFilter = '';
$pShow = ($_REQUEST['show'])?$_REQUEST['show']:'today';
$pLink=Tzn::concatUrl($pLink,'show='.$pShow);
 
$pKeepNoDead = intval(@constant('FRK_NO_DEADLINE_KEEP') -1) * 86400;
 
// --- Filter per date -----------------------------------------------------
 
switch ($pShow) {
	case 'all':
		break;
	case 'future':
		// show coming tasks and late tasks (undone only)
		$sqlFilter = '((deadlineDate >= \''
			.strftime(TZN_DATE_SQL,PRJ_DTE_NOW).'\' AND statusKey < '
			.FRK_STATUS_LEVELS.')'.' OR statusKey < '.FRK_STATUS_LEVELS.')';
        // show uncompleted tasks with no deadline
		$sqlFilter .= ' OR (deadlineDate = \'9999-00-00\' AND statusKey < '
			.FRK_STATUS_LEVELS.')';
		break;
	case 'past':
		// show past tasks and already done
		$sqlFilter = '(deadlineDate < \''
			.strftime(TZN_DATE_SQL,PRJ_DTE_NOW).'\' OR statusKey = '
			.FRK_STATUS_LEVELS.')';
		break;
	case 'today':
		// show all future tasks (done + undone) and late tasks
		$pKeepNoDead = intval(@constant('FRK_NO_DEADLINE_KEEP') -1) * 86400;
		$sqlFilter = '(statusKey = '.FRK_STATUS_LEVELS.' AND statusDate > \''
			.gmdate('Y-m-d 00:00:00',time()-$pKeepNoDead).'\') ';
 
		// hide far future tasks ?
		$tmpFilter = '';
		if (@constant('FRK_DEFAULT_FAR_FUTURE_HIDE')) {
			$tmp = intval(FRK_DEFAULT_FAR_FUTURE_HIDE) * 86400;
			$tmpFilter .= 'deadlineDate < \''
				.gmdate('Y-m-d 00:00:00',time()+$tmp).'\'';
		}
 
		// show tasks with no deadline ?
		if (@constant('FRK_NO_DEADLINE_TOO')) {
			// yes
			if ($tmpFilter) {
				$sqlFilter .= 'OR ('.$tmpFilter
					.' OR deadlineDate = \'9999-00-00\')'
					. ' AND statusKey < '.FRK_STATUS_LEVELS;
			} else {
				$sqlFilter .= ' OR statusKey < '.FRK_STATUS_LEVELS;
			}
		} else {
			// don't show uncompleted non planned tasks
			if ($tmpFilter) {
				$sqlFilter .= ' OR ('.$tmpFilter.' AND statusKey < '
    	        	.FRK_STATUS_LEVELS.')';
			} else {
	            $sqlFilter .= ' OR (deadlineDate <> \'9999-00-00\' AND statusKey < '
    	        	.FRK_STATUS_LEVELS.')';
			}
		}
 
        if (@constant('FRK_DEFAULT_CURRENT_TASKS')) {
            $objItemList->setPagination(FRK_DEFAULT_CURRENT_TASKS);
        }
		break;
	default:
		break;
}
 
// -TODO- Add filter current project only (no completed, no cancelled)
 
// echo '<p>&</p><p>-</p><p>-</p>'.$sqlFilter;
 
if ($sqlFilter) {
	$objItemList->addDateFilter($sqlFilter);
}
 
// search filter
	$pSearch = ($_REQUEST['search']);
	if ($pSearch) {
		$sqlFilter = '(ii.title LIKE \'%'.$pSearch.'%\' OR ii.description LIKE \'%'.$pSearch.'%\')';
		$objItemList->addWhere($sqlFilter);
	}
Code After
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
$pSearch = ($_REQUEST['search']);
if ($pSearch) {
	$sqlFilter = '(ii.title LIKE \'%'.$pSearch.'%\' OR ii.description LIKE \'%'.$pSearch.'%\')';
	$objItemList->addWhere($sqlFilter);
}
else
{
	$arrFilters = array();
 
	// --- filter: project ---
	if ($pProject) {
	    // load tasks for specific project
		$sqlFilter = 'ii.projectId = \''.$pProject.'\'';
	    $pLink=Tzn::concatUrl($pLink,'sProject='.$pProject);
	} else if (!$objUser->checkLevel(6)) {
	    // user can only access his own projects
	    if ($objUserProjectList->rMore()) {
	        $arrProject = array();
	        while($objTmp = $objUserProjectList->rNext()) {
	            $arrProject[] = $objTmp->id;
	        }
	        if ($objUser->checkLevel(13)) {
	        	$arrProject[] = '0';
	        }
	        $sqlFilter = 'ii.projectId IN ('.implode(',',$arrProject).')';
 
	        unset($arrProject);
	        $objUserProjectList->rReset();
	    }
	}
 
	$objItemList->addWhere($sqlFilter);
 
	// --- filter: user ---
	$pUser = intval($_REQUEST['sUser']);
	if (!isset($_REQUEST['sUser']) && @constant('FRK_DEFAULT_VIEW_OWN_TASKS')) {
		// default view is own tasks only
		$pUser = $objUser->id;
	}
 
	if($_REQUEST['sUser'] == 'myprojects' && $_SESSION['selUser']){
	   $objItemList->addWhere('ii.authorId='.$_SESSION['selUser']);
	}
	elseif ($pUser) {
		$objItemList->addWhere('ii.memberId = \''.$pUser.'\'');
	    $_SESSION['selUser'] = $pUser;
	    $pDefaultUserId = $pUser;
	} else {
	    unset($_SESSION['selUser']);
	    session_unregister('selUser');
	    $pDefaultUserId = $objUser->id;
	    // by default, show own tasks
	    /*
	    if (!$objUser->checkLevel(1)) { // admin can see all
		    $objItemList->addWhere('(ii.memberId='.$objUser->id
	    		.' OR ii.authorId='.$objUser->id.')');
	    }
	    */
	}
 
	$pLink=Tzn::concatUrl($pLink,'sUser='.$pUser);
 
	// --- private tasks --------------------------------------------------------
 
	$arrFilter[] = 'showPrivate=0';
 
	if ($objUser->checkLevel(12)) {
		// show internal tasks
		$arrFilter[] = 'showPrivate=1';
	}
 
	$arrFilter[] = '(showPrivate=2 AND (ii.memberId='.$objUser->id
		.' OR ii.authorId='.$objUser->id.'))';
 
	$objItemList->addWhere('('.implode(' OR ',$arrFilter).')');
 
	// --- filter: context ---
 
	if ($_REQUEST['sContext']) {
		$pContext = Tzn::getHttp($_REQUEST['sContext'],true);
		$objItemList->addWhere('context = \''.$pContext.'\'');
	    $pLink=Tzn::concatUrl($pLink,'sContext='.$pContext);
	}
 
	$sqlFilter = '';
	$pShow = ($_REQUEST['show'])?$_REQUEST['show']:'today';
	$pLink=Tzn::concatUrl($pLink,'show='.$pShow);
 
	$pKeepNoDead = intval(@constant('FRK_NO_DEADLINE_KEEP') -1) * 86400;
 
	// --- Filter per date -----------------------------------------------------
 
	switch ($pShow) {
		case 'all':
			break;
		case 'future':
			// show coming tasks and late tasks (undone only)
			$sqlFilter = '((deadlineDate >= \''
				.strftime(TZN_DATE_SQL,PRJ_DTE_NOW).'\' AND statusKey < '
				.FRK_STATUS_LEVELS.')'.' OR statusKey < '.FRK_STATUS_LEVELS.')';
	        // show uncompleted tasks with no deadline
			$sqlFilter .= ' OR (deadlineDate = \'9999-00-00\' AND statusKey < '
				.FRK_STATUS_LEVELS.')';
			break;
		case 'past':
			// show past tasks and already done
			$sqlFilter = '(deadlineDate < \''
				.strftime(TZN_DATE_SQL,PRJ_DTE_NOW).'\' OR statusKey = '
				.FRK_STATUS_LEVELS.')';
			break;
		case 'today':
			// show all future tasks (done + undone) and late tasks
			$pKeepNoDead = intval(@constant('FRK_NO_DEADLINE_KEEP') -1) * 86400;
			$sqlFilter = '(statusKey = '.FRK_STATUS_LEVELS.' AND statusDate > \''
				.gmdate('Y-m-d 00:00:00',time()-$pKeepNoDead).'\') ';
 
			// hide far future tasks ?
			$tmpFilter = '';
			if (@constant('FRK_DEFAULT_FAR_FUTURE_HIDE')) {
				$tmp = intval(FRK_DEFAULT_FAR_FUTURE_HIDE) * 86400;
				$tmpFilter .= 'deadlineDate < \''
					.gmdate('Y-m-d 00:00:00',time()+$tmp).'\'';
			}
 
			// show tasks with no deadline ?
			if (@constant('FRK_NO_DEADLINE_TOO')) {
				// yes
				if ($tmpFilter) {
					$sqlFilter .= 'OR ('.$tmpFilter
						.' OR deadlineDate = \'9999-00-00\')'
						. ' AND statusKey < '.FRK_STATUS_LEVELS;
				} else {
					$sqlFilter .= ' OR statusKey < '.FRK_STATUS_LEVELS;
				}
			} else {
				// don't show uncompleted non planned tasks
				if ($tmpFilter) {
					$sqlFilter .= ' OR ('.$tmpFilter.' AND statusKey < '
	    	        	.FRK_STATUS_LEVELS.')';
				} else {
		            $sqlFilter .= ' OR (deadlineDate <> \'9999-00-00\' AND statusKey < '
	    	        	.FRK_STATUS_LEVELS.')';
				}
			}
 
	        if (@constant('FRK_DEFAULT_CURRENT_TASKS')) {
	            $objItemList->setPagination(FRK_DEFAULT_CURRENT_TASKS);
	        }
			break;
		default:
			break;
	}
 
	// -TODO- Add filter current project only (no completed, no cancelled)
 
	// echo '<p>&</p><p>-</p><p>-</p>'.$sqlFilter;
 
	if ($sqlFilter) {
		$objItemList->addDateFilter($sqlFilter);
	}
}

Solution – Add Ability to Also Search within Task Comments


Edit the “index.php” located in the root of TaskFreak! as follows. We will be working in just below the heading section of the “Load Tasks”. This solution was posted by davidlmansfield at [PATCH] [Search Plugin] include tasks matching in comment fields.

Code Before
39
40
41
42
43
44
// search filter
$pSearch = ($_REQUEST['search']);
if ($pSearch) {
	$sqlFilter = '(ii.title LIKE \'%'.$pSearch.'%\' OR ii.description LIKE \'%'.$pSearch.'%\')';
	$objItemList->addWhere($sqlFilter);
}
Code After
39
40
41
42
43
44
// search filter
$pSearch = ($_REQUEST['search']);
if ($pSearch) {
	$sqlFilter = '(ii.title LIKE \'%'.$pSearch.'%\' OR ii.description LIKE \'%'.$pSearch.'%\' OR ii.itemId in (select itemId from '.$objItemList->gTable('itemComment').' where body LIKE \'%'.$pSearch.'%\'))';
	$objItemList->addWhere($sqlFilter);
}

Solution – Stop SQL Injections


Edit the “index.php” located in the root of TaskFreak! as follows. We will be working in just below the heading section of the “Load Tasks”. This solution was posted by bchristie at Re: Quick ‘n’ Dirty Search Plugin.

Code Before
39
40
// search filter
$pSearch = ($_REQUEST['search']);
Code After
39
40
// search filter
$pSearch = isset($_REQUEST['search'])?mysql_real_escape_string($_REQUEST['search']):false;

PlanetMySQL Voting: Vote UP / Vote DOWN

Running MySQL Cluster without Arbitrator: don’t, but if you have to..

Июнь 16th, 2010

This post explains how to disable Arbitration when using MySQL Cluster. It gives a case where this could be useful.

First, a piece of advice: you do not want to run MySQL Cluster with arbitration disabled. But if you must, e.g. because of an oversight in your implementation, you can.
Arbitration is very important in MySQL Cluster. It makes sure you don't end up with a Split Brain situation: 2 halves working independently, continuing changing data, making it impossible for them to work together later on.

However, Arbitration comes with a price: you need an extra machine. "Sure, what's the big deal?". It's not that easy when you lack the money, or more problematic, when you lack the real-estate in your rack.

Everyone running MySQL Cluster should know that you should not run the ndb_mgmd on the same machines on which the data node processes, ndbd or ndbmtd, are running. The Management Nodes need to be on a separate machine so it can act as an Arbitrator.

Here's an example why: If you have two hosts A and B and both are running a management and data node process. Host A's ndb_mgmd is currently the Arbitrator. Now unplug host A *BANG*: one data node and the arbitrator down. The other data node on Host B notices this, and tries to figure out if it can continue. So it checks if it can reach the Arbitrator: but it's gone as well! So, the data node on host B goes faithfully down. This all happens in a few seconds, there is no time to elect a new Arbitrator. "Cluster's dead, Jim".

What if you can't get a 3rd machine? There's an option for that.. Data nodes can before configured setting Arbitration to WaitExternal. This means you will have to develop your own arbitration application or script. How cool is that? Well, it might be cool, but it's a pain in the butt.

[ndbd default]
Arbitration = WaitExternal
ArbitrationTimeout = 3

What happens with our 2 host setup with above changes: When Host A, which has the Arbitrator, goes down, the data node on Host B will wait for 3 seconds, i.e. ArbitrationTimeout. It will block all incoming transactions, refusing changes. An application, the External Arbitrator, running on Host B (actually on all hosts running MySQL Cluster proceses) has 3 seconds to figure out whether Host B can continue running it's ndbd process(es), or not. In this case, it should find out that Host A is down and that Host B should continue keeping the data available.

"Ah, easy! Problem solved!", you might joyfully exclaim. No, it isn't. It's more complicated than that. What happens when Host A doesn't go down, but both hosts can't see each other due to a network issue between them? Both External Arbitrators would figure out that they need to continue: you end up again with a split brain. So you still need someway to handle that.

At this point, I would like to say: "Goodluck!". Every situation is going to be different. Everyone will have his own External Arbitrator requirements or ways to check if a host or blade chassis is up or not. It's a great option, and it puts you more in control of your MySQL Cluster, but it adds a lot of complexity.

So, my advice: revise and correct your MySQL Cluster setup when you think you need to disable Arbitration.


PlanetMySQL Voting: Vote UP / Vote DOWN

Insert data into a VARCHAR field using NDB API: a solution

Апрель 2nd, 2010

You are using MySQL Cluster and crazy enough to digest NDB API? Sick of SQL? Here's a treat: a function to make C/C++ strings ready for inserting into a VARCHAR field. The special thing about them is that the length is prefixed in the first 2 bytes.

void make_ndb_varchar(char *buffer, char *str)
{
  int len = strlen(str);
  int hlen = (len > 255) ? 2 : 1;
  buffer[0] = len & 0xff;
  if( len > 255 )
    buffer[1] = (len / 256);
  strcpy(buffer+hlen, str);
}

Yes, you can use memcpy. Whatever floats your boat.

Lets use this function for a table t1, defined as follows (note: latin1!):

CREATE TABLE t1 (
  id INT UNSIGNED NOT NULL,
  vc VARCHAR(128),
  vclong VARCHAR(1280),
  PRIMARY KEY (id)
  ) ENGINE=NDB DEFAULT CHARSET=latin1

Here is part of the code, simplified for this post:

char vc[128+1]; // Size of 'vc', +1 for length info
 char vclong[1280+2]; // Size of 'vclong', +2 for length info
 ..
 make_ndb_varchar(vc, "NDB API kicks ass");
 operation->setValue("vc", vc);
 ..

The above example uses latin1. You could use Unicode, but that would probably mean converting from one encoding to the other using iconv. That's another story.

This post complements Johan Andersson's blog entry. Thanks to my colleagues Mats and Roger who helped me with a silly problem today regarding this function.


PlanetMySQL Voting: Vote UP / Vote DOWN

Python, oursql and MacOS X 10.6 (Snow Leopard)

Февраль 8th, 2010

This post explains how to compile oursql and install it on MacOS 10.6. oursql is a Python database interface for MySQL, an alternative to MySQL for Python (i.e. MySQLdb) and MySQL Connector/Python.

First, find out which MySQL you installed. This can be either the 32-bit or the 64-bit version. To make sure, find the mysqld (e.g. in /usr/local/mysql/bin) and do the following in a Terminal window:


shell> file /usr/local/mysql/bin/mysqld
.../mysqld: Mach-O 64-bit executable x86_64

If you see x86_64, you got 64-bit, otherwise 32-bit. If you see both, then you have a universal build. This is important for specifying the ARGSFLAG when building.

Download oursql from Launchpad and unpack it into some directory. Using the information from above, you'll have to do following for 64-bit platform (or universal build) in a Terminal window:


shell> ARCHFLAGS="-arch x86_64" python setup.py build
shell> sudo python setup.py install

For 32-bit, you'll have to do:


shell> ARCHFLAGS="-arch i386" python setup.py build
shell> sudo python setup.py install

Following error will be reported when you don't specify the correct ARCHFLAGS:


ld: warning: in .../lib/libmysqlclient.dylib,
file is not of required architecture

Tips:

  • When building failed, it is good to remove oursql, unpack it and try again.
  • If you don't want to compile anything, or run into more troubles, give MySQL Connector/Python a try (alpha releases). It's a pure Python implementation of the MySQL Client/Server protocol and doesn't need compiling or a MySQL installation.
  • You can download MySQL from either www.mysql.com or dev.mysql.com.

PlanetMySQL Voting: Vote UP / Vote DOWN

Building MySQL universal binaries using MacOS X 10.6 (Snow Leopard)

Декабрь 31st, 2009

On the eve of 2010.. and your boss wants to stick to these MacOS X 10.5 machines, too stubborn or chicken to upgrade. Some developers still have their old PowerBook laptops and they need MySQL flying on PowerPC machines. To top it all, one guy said he wanted to have 32 and 64-bit in one bite. *Sigh* .. But there is an easy way out! A universal binary!

This post shows you a way to create MySQL universal binaries using MacOS X 10.6 so you can run them on MacOS X 10.5/10.6 whether it is PowerPC or Intel, or 32bit or 64bit.

However, if you need libmysqld (Embedded MySQL), this post will not work for you.

Requirements:

  • You have MacOS X 10.6 with latest Xcode (fully) installed.
  • The MySQL source unpacked somewhere. Get it on the MySQL download website under Source Downloads, package named Compressed GNU TAR archive (tar.gz).
  • And some nerves for when the build process fails.

Most complete Universal Binary

First, here is away to build MySQL so it runs on MacOS X 10.5 Intel/PowerPC and 10.6 32 or 64-bit.

Here is the source of the build script names build.sh. Executed it while located inside the source directory of MySQL.


#!/bin/bash

SDK="-isysroot /Developer/SDKs/MacOSX10.5.sdk"
SDKLIB="-Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk"
export MACOSX_DEPLOYMENT_TARGET="10.5"
PREFIX=/opt/mysql/mysql-5.1.42-universal-macosx-10.5

ARCH="-arch i386 -arch x86_64 -arch ppc"

export CFLAGS="-O2 -fPIC $ARCH $SDK"
export CXXFLAGS="-O2 -fPIC $ARCH $SDK"
export LDFLAGS="$ARCH $SDKLIB"

CC="/usr/bin/gcc-4.2"
CXX="/usr/bin/g++-4.2"
OBJC="/usr/bin/gcc-4.2"

INSTALL="/usr/bin/install -c"


./configure --prefix=$PREFIX \
--disable-dependency-tracking \
--mandir=$PREFIX/share/man --infodir=$PREFIX/share/info \
--localstatedir=$PREFIX/var/ --libdir=$PREFIX/lib \
--bindir=$PREFIX/bin --libexecdir=$PREFIX/bin \
--includedir=$PREFIX/include \
--datadir=$PREFIX/share/ --sysconfdir=$PREFIX/etc \
--with-extra-charsets=complex \
--with-mysqld-user=mysql \
--without-docs \
--with-plugins=all \
--enable-thread-safe-client --without-embedded-server \
--with-pic --with-libedit

if [ $? -eq 0 ]; then
make clean
time make -j 2
fi

Here is what file shows for the mysqld binary:


Black:mysql-5.1.42 geert$ file sql/mysqld
sql/mysqld: Mach-O universal binary with 3 architectures
sql/mysqld (for architecture i386): Mach-O executable i386
sql/mysqld (for architecture x86_64): Mach-O 64-bit executable x86_64
sql/mysqld (for architecture ppc7400): Mach-O executable ppc

These binaries were tested and work on MacOS X 10.6 Intel and MacOS X 10.5 PowerPC.

32/64-bit Universal binaries for MacOS X 10.6

Same as above, but with the following changes:


SDK="-isysroot /Developer/SDKs/MacOSX10.6.sdk"
SDKLIB="-Wl,-syslibroot,/Developer/SDKs/MacOSX10.6.sdk"
export MACOSX_DEPLOYMENT_TARGET="10.6"
PREFIX=/opt/mysql/mysql-5.1.42-universal-macosx-10.6

Setting the above is probably not needed when you are already on a Mac running 10.6, but it doesn't hurt to be explicit.

Need it for MacOS X 10.4?

I gave this a spin:


SDK="-isysroot /Developer/SDKs/MacOSX10.4u.sdk"
SDKLIB="-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk"
export MACOSX_DEPLOYMENT_TARGET="10.4"
ARCH="-arch i386 -arch ppc"

But it failed with


/Developer/SDKs/MacOSX10.4u.sdk/usr/include/stdarg.h:4:25:
error: stdarg.h: No such file or directory

.. but I lack intrest making stuff for MacOS X 10.4 (Tiger). Consider this your homework!


PlanetMySQL Voting: Vote UP / Vote DOWN

How to install MySQL Connector/Python

Сентябрь 24th, 2009

Currently, MySQL Connector/Python is only available through Launchpad. Here's a small how-to for installing it using the Bazaar bzr client tool. All you need is a machine with Python installed (v2.3 or higher, but not v3.x), and.. well, that's it!


shell> bzr checkout lp:~mysql/myconnpy/main myconnpy
shell> cd myconnpy
shell> python setup.py install

Please check it out. It's not feature complete yet, and probably can use some code optimizations here and there. I'm looking forward to bug reports! Also, only works with MySQL 4.1 and above.

Here is a little script that shows how it works, save it in file test_myconn.py:


import mysql.connector

if __name__ == "__main__":
db = mysql.connector.Connect(host="localhost",
user="root",password="",database="test")
cursor = db.cursor()
cursor.execute("SHOW ENGINES")

for row in cursor.fetchall():
print row

cursor.close()
db.close()

Execute it like this and you should see the available storage engines:

shell> python test_myconn.py
[u'InnoDB', u'YES', u'Supports transactions, row-level locking, and foreign keys', u'YES', u'YES', u'YES']
[u'MRG_MYISAM', u'YES', u'Collection of identical MyISAM tables', u'NO', u'NO', u'NO']
[u'BLACKHOLE', u'YES', u'/dev/null storage engine (anything you write to it disappears)', u'NO', u'NO', u'NO']
[u'CSV', u'YES', u'CSV storage engine', u'NO', u'NO', u'NO']
[u'MEMORY', u'YES', u'Hash based, stored in memory, useful for temporary tables', u'NO', u'NO', u'NO']
[u'FEDERATED', u'NO', u'Federated MySQL storage engine', None, None, None]
[u'ARCHIVE', u'YES', u'Archive storage engine', u'NO', u'NO', u'NO']
[u'MyISAM', u'DEFAULT', u'Default engine as of MySQL 3.23 with great performance', u'NO', u'NO', u'NO']

PlanetMySQL Voting: Vote UP / Vote DOWN

MySQL, Python and MacOS X 10.6 (Snow Leopard)

Сентябрь 23rd, 2009
This has been already mentioned in on a few blogs, but I thought it would be good to post here too. Note: this is not using MacPorts!

To get MySQL and Python going on MacOS X 10.6 you need the following:

Install MySQL using the tar ball and make sure you get it up and running.

Compile MySQL-python (leave out setting the $PATH when it's already done):

shell> PATH="/usr/local/mysql/bin:$PATH"
shell> tar xzf MySQL-python-1.2.3c1.tar.gz
shell> cd MySQL-python-1.2.3c1
shell> ARCHFLAGS="-arch x86_64" /usr/bin/python setup.py build
shell> /usr/bin/python setup.py install

I'm giving the full path for python to make sure it does not use the MacPorts one.

Here a test script test_mysql.py:

import MySQLdb

if __name__ == "__main__":
db = MySQLdb.connect(host="localhost",
user="root",db="test")
cursor = db.cursor()
cursor.execute("SHOW ENGINES")

for row in cursor.fetchall():
print row

cursor.close()
db.close()


Run the above script like:

shell> /usr/bin/python test_mysql.py

It should output the available storage engines.

PlanetMySQL Voting: Vote UP / Vote DOWN