Python Java Including Special Characters and NULL Values in Queries

I f youre using PHP 4, you have som e addit ional opt ions for handling NULL values and special charact ers. First , PHP 4 has a special value NULL t hat is like an unset value, so you could use t hat in place of null in t he preceding code t hat generat ed t he INSERT st at em ent . However, t o writ e code t hat works for bot h PHP 3 and PHP 4, use an unset variable such as null . Second, as of PHP 4.0.3, an alt ernat ive t o addslashes is t o use mysql_escape_string , which is based on t he funct ion of t he sam e nam e in t he MySQL C API . For exam ple, you could rewrit e sql_quote t o use mysql_escape_string like t his: function sql_quote str { return isset str ? . mysql_escape_string str . : NULL; } I f you want a version t hat uses mysql_escape_string if it s present and falls back t o addslashes ot herwise, writ e sql_quote like t his: function sql_quote str { if isset str return NULL; func = function_exists mysql_escape_string ? mysql_escape_string : addslashes; return . func str . ; } Whichever version of sql_quote you use, it s t he kind of rout ine t hat is a good candidat e for inclusion in a library file. I ll assum e it s availabilit y for PHP script s in t he rest of t his book. You can find it as part of t he Cookbook_Ut ils.php file in t he lib direct ory of t he recipes dist ribut ion. To use t he file, inst all it in t he sam e locat ion where you put Cookbook.php and reference it from script s like t his: include Cookbook_Utils.php;

2.8.6 Python

Pyt hon provides a placeholder m echanism t hat you can use for handling special charact ers in dat a values, as described in Recipe 2.7 . To add t he profile t able record for DeMont , t he code looks like t his: try: cursor = conn.cursor cursor.execute INSERT INTO profile name,birth,color,foods,cats VALUESs,s,s,s,s , DeMont, 1973-01-12, None, eggroll, 4 print d row was inserted cursor.rowcount except: print Oops, the query failed The param et er binding m echanism adds quot es around dat a values where necessary. DB- API t reat s None as logically equivalent t o t he SQL NULL value, so you can bind None t o a placeholder t o produce a NULL in t he query st ring. The query t hat is sent t o t he server by t he preceding execute call looks like t his: INSERT INTO profile name,birth,color,foods,cats VALUESDe\Mont,1973-01-12,NULL,eggroll,4 Wit h MySQLdb 0.9.1 or newer, an alt ernat ive m et hod of quot ing dat a values is t o use t he literal m et hod. To produce t he INSERT st at em ent for DeMont by using literal , do t his: try: cursor = conn.cursor str = INSERT INTO profile name,birth,color,foods,cats VALUESs,s,s,s,s \ conn.literal DeMont, \ conn.literal 1973-01-12, \ conn.literal None, \ conn.literal eggroll, \ conn.literal 4 cursor.execute str print d row was inserted cursor.rowcount except: print Oops, the query failed

2.8.7 Java

Java provides a placeholder m echanism t hat you can use t o handle special charact ers in dat a values, as described in Recipe 2.7 . To add t he profile t able record for DeMont , creat e a prepared st at em ent , bind t he dat a values t o it , t hen execut e t he st at em ent : PreparedStatement s; int count; s = conn.prepareStatement INSERT INTO profile name,birth,color,foods,cats + VALUES?,?,?,?,?; s.setString 1, DeMont; s.setString 2, 1973-01-12; s.setNull 3, java.sql.Types.CHAR; s.setString 4, eggroll; s.setInt 5, 4; count = s.executeUpdate ; s.close ; close statement Each value-binding call here is chosen t o m at ch t he dat a t ype of t he colum n t o which t he value is bound: setString t o bind a st ring t o t he name colum n, setInt t o bind an int eger t o t he cats colum n, and so fort h. Act ually, I cheat ed a bit by using setString t o t reat t he dat e value for birth as a st ring. The set XXX calls add quot es around dat a values if necessary, so no quot es are needed around t he ? placeholder charact ers in t he query st ring. One difference bet ween JDBC and t he ot her API s is t hat you dont specify a special value t o bind a NULL t o a placeholder by specifying som e special value such as undef in Perl or None in Pyt hon . I nst ead, you invoke a special m et hod setNull , where t he second argum ent indicat es t he t ype of t he colum n java.sql.Types.CHAR for a st ring, java.sql.Types.INTEGER for an int eger, et c. . To achieve som e uniform it y in t he value- binding calls, a helper funct ion bindParam can be defined t hat t akes a Statement obj ect , a placeholder posit ion, and a dat a value. This allows t he sam e funct ion t o be used t o bind any dat a value. We can even use t he convent ion t hat passing t he Java null value binds a SQL NULL t o t he query. Aft er rewrit ing t he previous exam ple t o use bindParam , it looks like t his: PreparedStatement s; int count; s = conn.prepareStatement INSERT INTO profile name,birth,color,foods,cats + VALUES?,?,?,?,?; bindParam s, 1, DeMont; bindParam s, 2, 1973-01-12; bindParam s, 3, null; bindParam s, 4, eggroll; bindParam s, 5, 4; count = s.executeUpdate ; s.close ; close statement The im plem ent at ion of bindParam requires m ult iple funct ions, because t he t hird argum ent can be of different t ypes, so we need one funct ion for each t ype. The following code shows versions t hat handle int eger and st ring dat a values t he st ring version handles null and binds it t o NULL : public static void bindParam PreparedStatement s, int pos, int val { try { s.setInt pos, val; } catch Exception e { catch and ignore } } public static void bindParam PreparedStatement s, int pos, String val { try { if val == null s.setNull pos, java.sql.Types.CHAR; else s.setString pos, val; } catch Exception e { catch and ignore } } To handle addit ional dat a t ypes, youd writ e ot her versions of bindParam t hat accept argum ent s of t he appropriat e t ype. Special Characters in Database, Table, and Column Names I n MySQL versions 3.23.6 and lat er, you can quot e dat abase, t able, and colum n nam es by surrounding t hem wit h backquot es. This allows you t o include charact ers in such nam es t hat norm ally would be illegal. For exam ple, spaces in nam es are not allowed by default : mysql CREATE TABLE my table i INT; ERROR 1064 at line 1: You have an error in your SQL syntax near table i INT at line 1 To include t he space, prot ect t he nam e wit h backquot es: mysql CREATE TABLE `my table` i INT; Query OK, 0 rows affected 0.04 sec The backquot e m echanism gives you wider lat it ude in choosing nam es, but m akes it m ore difficult t o writ e program s correct ly. When you act ually use a backquot ed nam e, you m ust rem em ber t o include t he backquot es every t im e you refer t o it . Because of t his addit ional bit of com plexit y, I prefer t o avoid using such nam es, and I recom m end t hat you dont use t hem , eit her. I f you want t o ignore t hat advice, a st rat egy you m ay find helpful in t his sit uat ion is t o define a variable t hat holds t he nam e including backquot es and t hen use t he variable whenever you need t o refer t o t he nam e. For exam ple, in Perl, you can do t his: tbl_name = `my table`; dbh-do DELETE FROM tbl_name;

2.9 Handling NULL Values in Result Sets