Put your message here! Contact me for more information
 
 







 

Archive for the ‘Tutorials’ Category


 


At work, I had to run some updates on the Oracle Database so I took the chance to learn some PL/SQL. It turns out to be very handy. I didn’t have to write any .NET application just to be able to access Oracle, instead I can write a small Stored Procedure and run it to get the result I want.

My PL/SQL knowledge was 0 when I started yesterday, so I borrowed the Oracle 9i PL/SQL Programming book from a work buddy and started digging in. After half a day, I was able to get my little stored procedure running using cursors and reference cursors. And before I get a chance to forget the PL/SQL syntax, I am writing this summary about PL/SQL. It is not too detailed but enough to allow anybody who doesn’t know anything about Oracle PL/SQL get started in half an hour. So say if you know some sql from working with MySQL, you can use this guide to get started fairly quickly. Enjoy!

===== Getting started =====
* Each line in PL/SQL ends with semi-colon “;”
* PL/SQL is case-insensitive
* There are keywords like SELECT, CURSOR, TYPE, etc., so my convention is to CAPITALIZE those KEYWORDS. This way your eyes can pick out the keywords easier when you are debugging the code.
* Here are the naming convention, which is optional but will help you distinguish the variables better
* Local built-in type variables within a stored procedure are prefixed with v_. \\ e.g. v_inspectionId
* Cursors have prefix “c_”\\ e.g. c_Inspections
* Custom type variables have prefix “t_” \\ e.g. t_InspectionRecord
* A type for a dynamic cursor (REF CURSOR) has the Ref suffix \\ e.g. t_ViolationRef
* A record variable has the “Record” suffix \\ e.g. v_InspectionRecord
* Single-line comment follows a double-dash (- -), while the favorite C-style comment style is used for a block. Unfortunately, nested C-style commenting is not allowed.
-- This is a comment
SELECT * FROM someTable;
/*
This is a block comment
Hello! still in a comment
*/
SELECT * FROM someOtherTable;

===== Creating a stored procedure =====
First, let’s start with creating a new stored procedure. A procedure in PL/SQL has this overall structure:

CREATE OR REPLACE PROCEDURE procedure_name IS
... variable declarations
BEGIN
... your PL/SQL statements go here
END procedure_name;

===== Variables =====
==== Primitive-type Variables ====
Before we use any variable, we need to declare it first. We put the variable declarations after the CREATE OR REPLACE and before the BEGIN block. Variable name has to be less than 30 characters. We can declare the variables like this


v_number NUMBER;
v_description VARCHAR2;

In case we’d like the variable to describe a data row, we can declare


v_someVariable someTable.someColumn%ROWTYPE;

**%ROWTYPE** is the special property of the column to describe its data type.

==== CURSORS ====
Cursors can be used as a pointer to the result set returned by a SELECT. We can loop through a cursor and do calculations and so on. There are 2 types of cursor: Static Cursor and Dynamic (Ref) Cursor.

=== Static Cursors ===
Static cursor is declared in the declaration block with a specific SELECT statement. Something like this


-- declaration block
CURSOR c_Individuals IS
SELECT * FROM Individuals;

v_individualRecord c_Individuals%ROWTYPE;

-- begin block
BEGIN
-- .. some code

OPEN CURSOR c_Individuals;
LOOP
FETCH c_Individuals INTO v_individualRecord;
EXIT WHEN c_Individuals %NOTFOUND;

-- do some computations here

END LOOP;

-- be nice and close the cursor
CLOSE c_Individuals;

-- .... the rest of the procedure

What we just did is declare a new Cursor called “c_Individuals”, which is a pointer to the result set of the “SELECT * FROM Individuals” statement. Next, we declare a variable called v_individualRecord, whose type will be the return row of the c_Individuals cursor. Then later on in the actual body of the stored procedure, we open the CURSOR (e.g. execute the SELECT and have the Cursor pointed at the first returned row), then have a loop to fetch the Cursor into the v_individualRecord variable. However, if we don’t have no rows left in the result set, we will bail out from the Loop.

=== Reference (dynamic) Cursors ===
A Reference Cursor is a cursor that can be used to to fetch a SELECT statement within the body of the stored procedure. In contrast, for a static cursor, we can only specify which SELECT the static cursor is pointing to in the declaration area of the stored procedure.

This is the general usage for Reference cursor.


-- declaration block
TYPE t_Individuals IS REF CURSOR RETURN Individuals%ROWTYPE;
c_Individuals t_Individuals;
c_IndividualRecord c_Individuals%ROWTYPE;

BEGIN
-- now open up the cursor dynamically.
OPEN c_Individuals FOR
SELECT * FROM Individuals WHERE department_id = 50;

LOOP
FETCH c_Individuals INTO c_IndividualRecord;
EXIT WHEN c_Individuals%NOTFOUND;

-- the rest of the calculation

END LOOP;

CLOSE c_Individuals;

-- the rest of the stored procedure

First, we need to “invent” a new data type for the reference cursor with the TYPE declaration. We indicate that this t_Individuals type is a Reference cursor and this particular reference cursor will return a row containing all columns from the Individuals table. Next, we declare a cursor using the new t_Individuals type. Now c_Individuals is officially a dynamic cursor. Later on in the body block, we can open the c_Individuals cursor using a SELECT * statement.

Many of you will ask already, “what if I only need a few columns, or the SELECT of the cursor is a complicated JOIN statement, then what is the return type of t_Individuals?” In this case, our declaration for the reference cursor is a little more involved.

Say we need the cursor to return the result of a JOIN between the Individuals and the Departments tables to find out what department an individual belongs to.


-- declaration block
/* t_IndividualRecord defines the data returned by the SELECT & JOIN between Individuals and Departments */
TYPE t_IndividualRecord IS RECORD (
name Individuals.Name%TYPE,
department_id Individuals.Department_id%TYPE,
department_name Departments.Department_Name%TYPE,
);
TYPE t_IndividualRef IS REF CURSOR RETURN t_IndividualRecord;
c_Individuals t_ViolationRef;
v_IndividualRecord c_Individuals%ROWTYPE;

BEGIN
-- now we open up the cursor and fetch it
OPEN c_Individuals FOR
SELECT i.Name, i.Department_id, d.Department_Name
FROM Individuals i, departments d
WHERE i.department_id = d.id;

LOOP
FETCH c_Individuals INTO v_IndividualRecord;
EXIT WHEN c_Individuals%NOTFOUND;

-- ...

END LOOP;

-- the rest of the stored procedure

So first, we declare a new type called “t_IndividualRecord”, which is a Record. A record is a data row with predefined columns. We only need 3 columns for this particular record. Next, we define a reference cursor t_IndividualRef which returns a t_IndividualRecord. Then c_Individuals is our cursor and v_IndividualRecord is the variable to hold our information. Yup, that’s it to use dynamic cursors!

First, make a new user-defined record, then declare a reference type cursor, then the cursor itself, and lastly the variable to hold the returned value of the cursor.

===== Control Structures & Loops =====
PL/SQL supports most basic control structures.
* IF-THEN-ELSE
IF boolean_expression1 THEN
-- ...
[ELSEIF boolean_expression2 THEN
-- ... ]
[ELSE
-- ... ]
END IF;

* CASE
CASE v_IndividualRecord.Department_id
WHEN 1 THEN
-- ...
WHEN 2 THEN
-- ...
WHEN 3 THEN
-- ...
[ELSE
-- ...]
END CASE;

* CASE with no default test expression
CASE
WHEN v_IndividualRecord.Department_id = 1 THEN
-- ...
WHEN v_IndividualRecord.Department_id = 2 THEN
-- ...
WHEN v_IndividualRecord.Department_id = 3 THEN
-- ...
[ELSE
-- ...]
END CASE;

* LOOP
LOOP
-- ...
EXIT [WHEN condition];
END LOOP;

* WHILE
WHILE condition LOOP
-- ...
END LOOP;

* FOR
FOR counter IN [REVERSE] start_index .. end_index LOOP
-- ...
END LOOP;
Example
FOR v_Counter IN 1..100 LOOP
-- ...
END LOOP;
The v_Counter index variable doesn’t have to be declared ahead of time. It’s implicitly declared as BINARY_INTEGER by PL/SQL. If the REVERSE keyword is used, our loop will run backward.

* GOTO \\ I haven’t heard any good things about Goto. The overall opinions on GOTO is that using GOTO extensively is bad practice. Nonetheless, GOTO can be used for error-handling.

===== Debugging and Outputting to log =====
Sometimes we need to debug the stored-procedure to see what’s going on. PL/SQL has very nice line debugging capabilities. I am using the PL/SQL Developer version 7.0.3 by AllaroundAutomations and find that it’s pretty easy to use. However, I wish that the shortcuts for the line debugging are customizable, or made consistent with VisualStudio, so that I don’t have to mentally switch between 2 sets of shortcuts.

To write out to the DBMS output log, you will have to add DBMS_OUTPUT.ENABLE(1000000); before writing out the first log entry, otherwise Oracle will throw you an error. After setting DMBS_OUTPU.ENABLE(1000000), you can write an entry by using DBMS_OUTPUT.PUT_LINE( 'Hello World!' );. A variable can also be used inside the .PUT_LINE() like thisDBMS_OUTPUT.PUT_LINE('Individual: ' || v_IndividualRecord.Name || ' is in department ' || v_IndividualRecord.Department_Name);

However, if you are in a debugging session in PL/SQL Developer, you won’t see the entry in the DBMS Output window until after you are done with the debugging session. Maybe I haven’t found a “flush” method for DBMS_Output yet. Nonetheless, the Watch window always comes handy during debugging.

===== Views =====
Views are named queries, e.g. a view represents a derived table from a SELECT statement. End users can consider a view as a table. As views are treated like tables, we can also run query against the view such as SELECT and UPDATE, making our life a bit easier on complex queries. In comparison with an actual table, a view doesn’t contain data thus we cannot create index on a such view.

To create a view, we use

CREATE VIEW view_name AS
SELECT sub-query

[WITH CHECK OPTION];

The With CHECK OPTION means we cannot update the view if the select sub-query doesn’t retrieve the updated rows.

And to drop a view, we just do

DROP VIEW view_name;

Later on within our query, stored procedure body, or function body, we can refer the view directly by calling out its name.

===== Some “post-it-notes” for SQL syntax in Oracle =====
Here are some tips for SQL syntax in Oracle.
* Select a first few rows
SELECT * FROM Individuals WHERE ROWNUM <= 50;
ROWNUM is the special keyword to limit how many rows to be returned, similar to the TOP keyword in SQL Server.
* Columns with space between words can be put in double quote like “COLUMN NAME”. The equivalent in SQL Server is the square brackets.
* Keyword for Column alias is “**AS**”: \\ e.g. SELECT (1+1) AS one_and_one;
* For table aliasing, it’s “TableName New_Alias” \\ e.g. SELECT new_alias_for_this_table.* FROM this_table new_alias_for_this_table
* SELECT with conditional logic: In case you’d like to select a column value and do some logic with it, here is the sample syntax SELECT (CASE WHEN t.name = 'Alex' THEN 'Alex Le' ELSE t.name END ) AS name from table t
* to be continued

===== Final Remarks =====
I hope that you’ll find this quick primer guide helpful. Sometimes it’s the syntax that bogs you down when you start to work in a new environment, and this is where the guide comes in. I put this together so that everyone who has to work in PL/SQL can quickly pick up the syntax and get started right away in a minimal amount of time.

Comments, suggestions, and corrections are very welcome.

===== Reference =====
* Urman, Scott. “**Oracle9i PL/SQL Programming**”. McGraw-Hill/Osborne, Oracle Press. 2002.
* Upadhye, Suhas. “**Oracle Views: What can they do for you?**”. October 1999. Retrieved from [[http://www.cdoug.org/docs/views-1099.pdf]] on Feb 13, 2007

view comments
 


I was working on some javascript stuff for a project and ran into this problem with setInterval(): for IE 6, calling setInterval() to an object’s method results in the wrong scope. In the object’s method, the alfamous **this** keyword now refers to **window**, instead of the conventional “this” as in “**this object**”. So let me give you some more details on this and a free, amazingly simple solution to this head-ache.

**SPOILER:**\\ the solution uses eval(). if you are allergic to eval(), don’t take my advice.\\ **END SPOILER**

===== The code =====
Let’s look at some code and we’ll have a little discusssion. Here’s the psuedo-code for a fictional TimeTicker object, which is supposed to automatically update a “clock” on the screen every second.


/* A. Constructor */
function TimeTicker()
{
/* A.1 - populate internal variable here, like hour, minute, second, etc. */
...

/* A.2 - now we set the timer to periodically update the time value every 999 miliseconds */
this.timer = setInterval( this.updateTime, 999 );
}

/* B. This function is to update the time value somewhere on the screen */
TimeTicker.prototype.updateTime = function ()
{
/* B.1 - compute new value */
...
this.hour = new_hour_value;
this.minute = new_minute_value;
this.second = new_second_value;
...

/* B.2 - now update the screen */
...
}

===== The problem =====
The above psuedo code will sadly **FAIL** in both IE and FF (not because it’s only psuedo-code!), as the ‘’setInterval()” invocation has **totally changed the scope** of the polled function. First of all, let’s look at ”**A.2**” from above. Calling ”this” within the ‘’setInterval()” will change the reference of ”this” to some other object (which I think is ”this” now refers to ”window”.) Hence calling ‘’setInterval( this.updateTime, 999 )” fails in both Firefox and IE 6, as it means that the ‘’setInterval()” will poll the ”window.updateTime()” function every 999 ms. That’s not what we want, and ”window” object could care less about our ”updateTime()” since we suddenly found ourselves in the wrong scope.

===== The Firefox’s Solution =====
For firefox, the fix is a small rewrite of how we would call the polled-function, updateTime(). The setInterval() function in Firefox is improved and we can now pass an extra parameter to it, and that’s exactly what we will do. We pass in the current object’s reference as ”this” to the a proxy function, which in turn makes a call to the updateTime(). I found this solution through [[http://www.klevo.sk/javascript/javascripts-settimeout-and-how-to-use-it-with-your-methods/|Klevo’s blog]], a web developer from Slovakia.

We will have to rewrite ”**A.2**” as follows:


/* A.2 */
this.timer = setInterval ( function( that ) { that.updateTime(); }, 999, this );

What we just did is we create a proxy function, whose only parameter is ”that”, a pointer to another object. Within this proxy function, we can make invoke all of “that”’s methods! Basically we migrate the scope of ”this” as a reference to the current ”TimerTicker” object into the polled proxy function via a pass-by-reference ”that” parameter. Notice the extra 3rd parameter of ‘’setInterval()”: we are passing ”this”, in this case, a reference to the current ”TimeTicker” object, as the only parameter of the newly created proxy function. Since now ”that” is equivalent to ”this”, we can call all methods of TimeTicker object! Beautiful!

===== The Internet Explorer’s Problem =====
While setInterval() in Firefox provide us a way to pass in extra parameters, IE’s version of ‘’setInterval()” is less flexible (and it also did drive me nuts!) Anyway, let’s talk about the mechanism of IE’s ‘’setInterval()”. According to [[http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/setinterval.asp|MSDN’s manual on setInterval()]], the syntax of setInterval() is

”iTimerID” = ”window”.**setInterval(** ”vCode”, ”iMilliSeconds” [, sLanguage])

with ”vCode” is either a reference pointer or a “string that indicates the code to be executed when the specified interval has elapsed”. Since there’s no way we can pass an extra parameter to the polled-function, we cannot pass ”this” as a 3rd parameter of setInterval() as what we just did for Firefox.

If we rewrite the code as this.timer = setInterval ( this.updateTime(), 999);then 2 things are gonna happen: first,” this.updateTime()” is executed right away. It’s equivalent to a direct call to the ”updateTime()” function of the current object, ”TimeTicker”. As we are still in the scope of the current function, hence, ”this” refers to the current ”TimeTicker” object. Secondly, after the 999ms has elapsed, ‘’setInterval()”" will invoke ”this.updateTime()”, and now ”this” refers to ”window” as we are now out of the scope of the ”TimeTicker” object. And of course, ”window.updateTime()” is wrong. So what you see is that your script will work the first time (when this.updateTime() is executed in the correct scope), and then everything fails (when this.updateTime() is excuted by setInterval() in the wrong scope).

And If we write this.timer = setInterval ( this.updateTime, 999);(Notice the missing parenthesis). This will also fails as when this.updateTime is invoked, we are already in the wrong scope, the scope of ”window” object!

On the other hand, if we writethis.timer = setInterval ("this.updateTime()", 999);we are still in the wrong scope when setInterval() invoke the updateTime() method. ”this” still refers to ”window” when the updateTime() function is executed. Notice that we can include the parenthesis “( )” (and potentially other pass-by-value parameters since the method is refered to as a string and it’s not executed right away, but only when being invoiked by ‘’setInterval()”). However, we can’t pass a pointer to the current object in a string!

We’d like to pass a pass-by-reference pointer object to point to the current ”TimeTicker” object but no matter what we do, we cannot seem to do so. But be hold! Our salvation comes from the use of a glorifying global variable, and of course, a dash of ”eval()”, just enough to tame Internet Explorer.

===== The Internet Explorer’s Solution =====
I’d like to include the code for IE here, just read over and we will discuss later.


/* C. global scope object */
var globalScope = new Array();

/* A. Constructor */
function TimeTicker()
{
/* A.0 - An extra unique identifier for the current object */
this.uniqueId = some_text_or_numers;

/* A.1 - populate internal variable here, like hour, minute, second, etc. */
...

/* A.3 - setInterval Fix */
/* A.3.1 - for IE */
if( document.all )
{
/* A.3.1.1 - make a reference to the current object and saved in the global scope array
* to use later to correct the scope.
*/
globalScope[ this.uniqueId ] = this;
setInterval( 'ieIntervalHandler("' + this.uniqueId + '","updateTime")', 999 );
}
else
{
/* A.3.2 - Mozilla */
this.timer = setInterval ( function( that ) { that.updateTime(); }, 999, this );
}
}

And we add an extra function, ”ieIntervalHandler( **id**, **strFunc** )” to the script.

/* D. - Special IE setInterval handler function with scope corrected */
function ieIntervalHandler( id, strFunc )
{
/* D.1 - correct the scope then make the call */
var scope = globalScope[id];
eval( "scope." + strFunc + "()" );
}

All set? Here comes the explanations: First of all, we added a global associative array named globalScope (”**C**”). This associative array is used to store reference to a particle object based on that object’s unique identifier. Confused? Not a problem, just keep on reading.

Let’s read A.0, this is where we set the unique identifier for this ”TimeTicker” object. For this technique to work, each object **must** have a **unique identifier** since the unique identifier is used as the **key** of the global associative array.

Look at ”**A.3.1**”. Here we do a little browser-intelligence. If the browser doesn’t know ”document.all”, which is IE-specific, we use the improved version of ‘’setInterval()” as mentioned in the above Firefox’s solution section. If the browser is indeed IE, at ”**A.3.1.1**”, we store the reference to this ”TimeTicker” object as an element in the globalScope associative array. Then we cheerfully and confidently ‘’setInterval()” the ”ieIntervalHandler()” function (see ”**D.1**”). We do a pass-by-value the unique ID of the current ”TimeTicker” object as the first parameter of ”ieIntervalHandler()”, and ”updateTime” as the name of the method of the same ”TimeTicker” object.

Look at ”**D.1**”. Here we have a 2-line function. First, we get the reference to the particular TimeTicker object, which we already stored in the globalScope associative array back in ”**A.3.1.1**”. Since we are now in the scope of ieIntervalHandler(), our ‘’scope” variable is pointing to the ”TimeTicker” object. With the correct reference to the correct object, now we can make the call to the correct method with a quick, painless ”eval()”eval( "scope." + strFunc + "()" );

What did we just do? We use a global array to store the references so that later on we can get to the right object, even when ieIntervalHandler is invoked by ‘’setInterval()” and the scope now is all over the place — we could care less! Hence we now can solve the wrong scope issue within IE. And guess what, now we can have any object to poll a method of itself! How awesome is that?

===== Memory Issue =====
Since we need to keep polling a function, we need to be careful of not creating more and more objects or functions that the garbage collect will never be able to purge because of a hidden reference somewhere. If you do create a lot of objects that do self-polling using this global associative array technique, when destroying the object, you will probably have to set the element of the globalScope to ”**null**” also, so that there is no further reference to the destroyed object. Also, in ”**A.3.2**”, we do create a new function everytime we’d like to run the timer, this may be a potential memory leaking point on Firefox.

I’d like to leave the quest of battling memory-leak monster to somebody else, but just remeber to watch out for potential weak point where memory leak can happen, especially when your page will be opened for a prolonged preriod of time.

===== Keywords spam =====
This setInterval() and the scope problem is a pretty abstract and hard to describe problem. I just include some potential search keywords here so that other people can by chance find this page. Call it keyword spam, call it shameless-self advertising, I could care less, but if somebody find this helpful, then I call it success :)

setInterval scope loosing, setTimeout, this setInterval wrong scope, javascript setInterval scope, global associative array scope correction, object oriented setInterval, self polling, this polling scope error, internet explorer setInterval fail, firefox setInterval fail, setInterval object.

===== Final remarks =====
Thank you for reading! I hope this helps. And I’d like to wish you a …

Merry Christmas and Happy New Year!

4:13AM, Dec 23, 2006.

view comments
 

Last nite, I was surfing around and found this page at the ThePlanet.com forum. Someone has configured a subdomain to proxy to the Plesk admin page. This way, in stead of accessing Plesk admin page via port 8443 (which I forget half of the time), I can access the page via https//plesk.mydomain.com (still encrypted with SSL for your privacy and security). In case I am behind a firewall that blocks most incoming/ outgoing ports, I still can access my plesk control panel page via the standard SSL port of 443.

From the forum thread (see the link above), the setup is pretty straightforward, but for some reasons, a few people could not configure the subdomain to act as a proxy to the Plesk control panel. The reason is there is a bug in how Plesk 8.0 writes the domain/ subdomain configuration files for Apache. And as there were a few people asking for a more detailed step-by-step tutorial, here is my take on it.

Let’s first go over the setup and configuration, then we can talk about the bug in Plesk. I assume that you have root access to your box because the Plesk manual explicitly states that you have to be root to create the vhost_ssl.conf file, which is the file we need to create to turn the subdomain into the proxy to the Plesk control panel.

The setup

  • Create a subdomain in Plesk. Remeber to enable SSL support, PHP support, and CGI support. By checking these 2 options, we are forcing Plesk to add an “include” directive to the configuration file of the domain. We discuss more on this later. I created a subdomain called “plesk” so that I can use it like https://plesk.alexle.net/ to access to the Plesk CP. From now on, let’s use “plesk” as our subdomain and alexle.net as our main domain.
  • Next, SSH to your box as root, then cd to the configurations folder of the newly created subdomain:
    #cd /var/www/vhosts/alexle.net/subdomains/plesk/conf/
  • Create a vhost_ssl.conf file ins this conf folder using your favorite text editor. The content of this file should be

    SSLProxyEngine on
    ProxyRequests off
    ProxyPass / https://www.alexle.net:8443/
    ProxyPassReverse / https://www.alexle.net:8443/

    What we are doing is to turn on the SSLProxyEngine for this particular subdomain. In order for this to work, we have to turn the ProxyRequests off. Next, we tell Apache to pass all traffics (or requests) from the root / access of the subdomain to the destination URL (which means all future requests from https://plesk.alexle.net/ will be “ProxyPass“ed to https://www.alexle.net:8443/) . Then with ProxyPassReverse, we tell Apache to redirect the response from https://www.alexle.net:8443/ back to /, our “https://plesk.alexle.net”. (By the way, you will have to use your own domain/ subdomain instead www.alexle.net in the above configuration)

  • Finally, for Apache to pickup the the new configuration file, we need to restart the httpd service
    #/etc/init.d/httpd restart
  • Surf to htps://plesk.alexle.net/. Humh, it doesn’t work yet? Here is the Plesk bug.

The Bug

Plesk BugThe way Plesk generates and stores configurration files are covered in the Plesk Manual Page. Basically there’s a master Apache config file at /etc/httpd/conf. This master Apache configuration file will include a whole bunch of other specific configuration files for each domains (located in /var/www/vhosts/domain_name/conf/httpd.include) and subdomains (/var/www/vhosts/domain_name/subdomains/your_subdomains/conf/vhost.conf or vhost_ssl.conf). Phew.

Remeber when we created the subdomain, we have selected PHP support and CGI support. By doing this, we have forced Plesk to write an “include” directive in the configuration file of the main domain to include the configuration file of the subdomain. To clarify, if you now open up the file httpd.include (in my case, at /var/www/vhosts/alexle.net/conf/httpd.include), find the VirtualHost section for your newly created subdomain, you will find a line similar to this

#file: /var/www/vhosts/alexle.net/conf/httpd.include
Include /var/www/vhosts/alexle.net/subdomains/plesk/conf/vhost.conf

However, there are 2 VirtualHost sections for the plesk subdomain: one is for port 80, and the other is for port 443, SSL. Moreover, both sections include the same vhost.conf file. This is wrong. Based on the Plesk’s Manual, the VirtualHost section for the SSL at port 443 should include the vhost_ssl.conf instead of the vhost.conf. So that’s the Plesk 8.0 bug. I’ve tried a couple times and was able to reproduce the Include bug.

The fix

Now we know why our configuration file for SSL access via the subdomain is not picked up. We need to change the Include directive of the VirtualHost SSL section for the subdomain to use the vhost_ssl.conf file instead. Then restart apache (#/etc/init.d/httpd restart) and everything should works fine.

The catch

We are modifying the main domain’s httpd.include file, which Plesk will overwrite everytime we make changes to this particular domain. Once that happens, you will have to re-modify the httpd.include file so that the correct vhost_ssl.conf file is used.

I hope that this short article helps you work and understand Plesk better. Thanks for the thread from ThePlanet.com forum to inspire me for this article. Comments are welcome as always.

view comments
 

I was trying to setup a MySQL cluster with CentOS 4.4 and VMWare and I was initially successful at getting the NDB storage engine to work. However, I could not start the MySQL API (or MySQL client, whatever you call it) because I ran into the infamous MySQL error of “ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)“. Googling didn’t help much either because people were just asking and very few got the answer.

After a while, I was desparate. My cluster was up and I had no way to connect to it and test out the exciting cluster’s replicate feature. I went to bed at 4:00am last night and kept thinking what could go wrong? Setting up the ndb engine for the nodes was pretty straightforward but why just getting mysql client to run is so problematic? Well, here’s my solution to the puzzle:

My Setup

  • CentOS 4.4 installed from DVD with most packages unchecked, especially MySQL
  • The newest MySQL 5.0.27-max was used. See, I’m on the bleeding-side of technology.
  • MySQL is locaed in the default location at /usr/local/mysql/
  • When I installed MySQL, the mysql.server script was cp from /usr/local/mysql/support-files/mysql.server to /etc/init.d/
  • The my.cnf file is very simple like this

#file: /etc/my.cnf
ndbcluster
ndb-connectstring=’host=192.168.2.100′
[mysql_cluster]
ndb-connectring=’host=192.168.2.100′

Cause:

When the MySQL server (mysqld) starts, it created a sock file. Since I overwrote the original /etc/my.cnf without the socket parameter under [mysqld], the MySQL server (mysqld) created the socket file under /tmp/mysql.sock instead. Furthermore, I was also missing the socket parameter under [client] section in the my.cnf - I didn’t even have the [client] section.

What happens when I tried to start the mysql client (#mysql -u root) was that the mysql client was looking for the mysql.sock file but coudln’t find the path to the file. It then looked into the default path /usr/lib/mysql/ to find the mysql.sock file. Of course this doesn’t work because when mysqld was started, the socket file was created in /tmp instead. The client gave up, spit out the connect error prompt.

In brief, the cause of the infamous error is because the mysql client cannot find the socket file at run time.

Solutions

First of all, you should verify that mysqld is running by typing #ps aux | grep [m]ysqld. Then there are 2 ways to solve this: one is to fix the socket path in the /etc/my.cnf under [mysqld] and [client] like this

# file: /etc/my.cnf
[mysqld]
… # someother settings
socket=/var/lib/mysql/mysql.sock
[client]
… # some other settings
socket=/var/lib/mysql/mysql.sock

then restart the mysqld server so that the mysql.sock file is generated. The next time you start the client with #mysql -u root, you will magically get it. This fix is permanently but the catch is you will have to shutdown mysqld, the MySQL server itself.
The other way when you want to just login really fast to the mysql server, try this (actually I used this method to obtain the overall solution to the infamous error)

  • #find / | grep mysql.sock
    this will do a look up on the entire disk and look for the mysql.sock file. You will get back something like /tmp/mysql.sock. This is the socket file we will need to use.
  • #mysql -u root –socket=/tmp/mysql.sock
    this will tell the mysql client to login as root user and use the socket file located in /tmp/mysql.sock

Boom, you should get into the suddenly-loved mysql> prompt. I was so excited when I was able to fix the client and was able to access to the mysql prompt.

I hope this help you all. With this success in installing the MySQL 5.0.27 cluster, I am planning to do a screencast of setting the whole thing up (VMWare is just awesome. It allows me to have 3 CentOS 4.4 servers at the same time, making this installation a breeze)

view comments
 


I’ve just made a comments on php.net’s manual page under imagecopyresized() about resizing transparent PNGs with GD. Here is the post again, hopefully it can help someone. Comments are welcome.

Belows is the code snipet that allows you to resize a transparent PNG and composite it into another image. The code is tested to work with PHP5.1.2, GD2, but I think it can also work with other versions of PHP and GD.

The code has been commented to help you read through it. The idea of resizing the transparent PNG image is to create a new destination image which is completely transparent then turn off the imageAlphaBlending of this new image so that when the PNG source file is copied, its alpha channel is still retained.

===Code:===


/**
* Compose a PNG file over a src file.
* If new width/ height are defined, then resize the PNG (and keep all the transparency info)
* Author: Alex Le - http://www.alexle.net
*/
function imageComposeAlpha( &$src, &$ovr, $ovr_x, $ovr_y, $ovr_w = false, $ovr_h = false)
{
if( $ovr_w && $ovr_h )
$ovr = imageResizeAlpha( $ovr, $ovr_w, $ovr_h );

/* Noew compose the 2 images */
imagecopy($src, $ovr, $ovr_x, $ovr_y, 0, 0, imagesx($ovr), imagesy($ovr) );
}

/**
* Resize a PNG file with transparency to given dimensions
* and still retain the alpha channel information
* Author: Alex Le - http://www.alexle.net
*/
function imageResizeAlpha(&$src, $w, $h)
{
/* create a new image with the new width and height */
$temp = imagecreatetruecolor($w, $h);

/* making the new image transparent */
$background = imagecolorallocate($temp, 0, 0, 0);
ImageColorTransparent($temp, $background); // make the new temp image all transparent
imagealphablending($temp, false); // turn off the alpha blending to keep the alpha channel

/* Resize the PNG file */
/* use imagecopyresized to gain some performance but loose some quality */
imagecopyresized($temp, $src, 0, 0, 0, 0, $w, $h, imagesx($src), imagesy($src));
/* use imagecopyresampled if you concern more about the quality */
//imagecopyresampled($temp, $src, 0, 0, 0, 0, $w, $h, imagesx($src), imagesy($src));
return $temp;
}
?>

===Example usage:===


header('Content-type: image/png');

/* Open the photo and the overlay image */
$photoImage = ImageCreateFromJPEG('images/MiuMiu.jpg');
$overlay = ImageCreateFromPNG('images/hair-trans.png');

$percent = 0.8;
$newW = ceil(imagesx($overlay) * $percent);
$newH = ceil(imagesy($overlay) * $percent);

/* Compose the overlay photo over the target image */
imageComposeAlpha( $photoImage, $overlay, 86, 15, $newW, $newH );

/* Open another PNG file, then resize and compose it */
$watermark = imagecreatefrompng('images/watermark.png');
imageComposeAlpha( $photoImage, $watermark, 10, 20, imagesx($watermark)/2, imagesy($watermark)/2 );

/**
* Open the same PNG file then compose without resizing
* As the original $watermark is passed by reference, it was resized already.
* So we have to reopen it.
*/
$watermark = imagecreatefrompng('images/watermark.png');
imageComposeAlpha( $photoImage, $watermark, 80, 350);
Imagepng($photoImage); // output to browser

ImageDestroy($photoImage);
ImageDestroy($overlay);
ImageDestroy($watermark);
?>

view comments