Support for DB2 databases?
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
@BIT_OR: i realized yesterday that the - (COUNT(*) - CONSTANT) is NOT necessary. your UDF BIT_OR() function will nevertheless have to be a UDF that outputs the intermediate result after each step and puts it also on the scratchpad. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
FYI, I'm making progress on the BIT_OR function. I figured that I should break this task down into smaller milestones, the first being to create a java UDF that uses the scratchpad to increment a counter and print out that counter for every row. Quote:
select myUdf(myColumn) from myTable Now I have to add the bitwise ANDing and printing of the intermediate results. I don't anticipate any problems with that. When I reach that point, then we can tackle whatever MAXing you want to do. I found that Knut's article is helpful after all, but only if you ignore the extraneous clutter, like the user-defined datatype (complex number) stuff. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
- just to be sure: you did this counter just to check if your UDF works (does something correctly for each row, and prints out the result) @MAX: $query = ' SELECT [GalleryAccessSubscriberMap::itemId], BIT_OR([GalleryAccessMap::permission]) FROM [GalleryAccessMap], [GalleryAccessSubscriberMap] WHERE [GalleryAccessSubscriberMap::itemId] IN (' . $itemIdMarkers . ') AND [GalleryAccessSubscriberMap::accessListId] = [GalleryAccessMap::accessListId] AND ([GalleryAccessMap::userId] = ? OR [GalleryAccessMap::groupId] IN (' . $groupIdMarkers . ')) GROUP BY [GalleryAccessSubscriberMap::itemId] '; with $storage =& $gallery->getStorage(); list ($ret, $bitor) = $storage->getFunctionSql( 'BIT_OR', array('[GalleryAccessMap::permission]')); if ($ret->isError()) { return array($ret->wrap(__FILE__, __LINE__), null); } $query = ' SELECT [GalleryAccessSubscriberMap::itemId], ' . $bitor . ' FROM [GalleryAccessMap], [GalleryAccessSubscriberMap] WHERE [GalleryAccessSubscriberMap::itemId] IN (' . $itemIdMarkers . ') AND [GalleryAccessSubscriberMap::accessListId] = [GalleryAccessMap::accessListId] AND ([GalleryAccessMap::userId] = ? OR [GalleryAccessMap::groupId] IN (' . $groupIdMarkers . ')) GROUP BY [GalleryAccessSubscriberMap::itemId] '; and in Db2DatabaseStorage.class we'll add: case 'BIT_OR': $sql = 'MAX(BIT_OR(' . $args[0] . '))' break; while other DBs will have: case 'BIT_OR': $sql = 'BIT_OR(' . $args[0] . ')' break;
your BIT_OR is different from other BIT_OR functions, since it returns COUNT(*) results, and not a single end result. thus we need MAX to select the end result. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Yes, that's correct, the UDF will ultimately not display a counter. I think this is exactly what I had in mind with the UDF prototype I described above... it would return only the last intermediate result for each GROUP BY, so again I say, why do we need a MAX? |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
how can you control to only output the last intermediate result? |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
I was thinking that the GROUP BY would handle that. Wouldn't it? |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Ah, on second thought, I guess not. I see your point. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
I've downloaded a new version of the code, and am unable to get past Step 5 of the installation. It says: Quote:
The database privileges test did not complete successfully. But as we've discussed before, that 'error' is not really an error... it is printed by ADOdb every time a DB2 connection is established, regardless whether or not the args are already in the right order. (Currently we force G2 to get the args in the right order by entering the dbname in the "Hostname" field of the installer form.) Any idea why it's failing? |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Sorry, never mind... I had forgotten to do the "gmake" in "modules/cor/classes/GalleryStorage/DatabaseStorage/schema". However, In Step 8 I get error: Quote:
Fatal error: Call to undefined method Db2DatabaseStorage::_executeSqlFile() in C:\My Server\gallery2\modules\core\classes\GalleryStorage\DatabaseStorage\Db2DatabaseStorage.class on line 117 |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
@only outputting the intermediate result: @gmake: @executeSqlFile: Meanwhile, for testing, please replace in Db2DatabaseStorage.class: /* Install our custom aggregate function */ $ret = $this->_executeSqlFile(dirname(__FILE__) . '/CreateDb2Udfs.sql'); if ($ret->isError()) { return $ret->wrap(__FILE__, __LINE__); } with global $gallery; $platform = $gallery->getPlatform(); $sqlFile = dirname(__FILE__) . '/CreateDb2Udfs.sql'; if (!$platform->file_exists($sqlFile)) { if ($ret->isError()) { return $ret->wrap(__FILE__, __LINE__); } } if (($sqlData = $platform->file_get_contents($sqlFile)) === false) { if ($ret->isError()) { return $ret->wrap(__FILE__, __LINE__); } } $extras =& $this->_getExtras(); $ret = $extras->_executeSql($sqlData ); if ($ret->isError()) { return $ret->wrap(__FILE__, __LINE__); } you might then have to remove all blank lines after a ; within CreateDb2Udfs.sql (i just did that in cvs) |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Thanks, Valiant. > did gmake change anything for you? Yes, it got me past step 5 all the way to Step 8, where I hit the _executeSqlFile() problem. > remove all blank lines after a ; within CreateDb2Udfs.sql Not sure what you mean by that. Remember that I created that SQL on Windows, so there might be an extra LF in it when you look at it in a unix editor... it looks fine to me. I've replaced the code in db2DatabaseStorage as you described (you're missing a ';') and I'm now getting a different error, still in Step 8. Quote:
Unable to install the core module Thanks. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
@blank lines after ; the updated file: @missing ; @installer step 5: |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Also, I don't know if this is related, but I now get another warning in Step 2: Quote:
Translation support: Warning I enabled gettext in my 'php.ini', restarted my web server, and closed all browsers, and still get the warning. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
this warning shows up when your php doesn't have gettext support (loaded). it doesn't really matter and is 100% irrelevant for db2. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
> blank lines after ';' I see. Thanks. > missing ';' Quote:
$extras =& $this->_getExtras() // <--- missing ';' > installer Step 5 I presume you mean the "use dsn as arg 1" message. It seems to only show up when there's another more serious error. I'm not sure how to suppress it completely. Fixing my copy of CreateDb2Udfs.sql, and it didn't help with the current error. I stuck a var_dump($query) in the error block of DatabaseStorage.class at line 305: if ($recordSet) { return array(GalleryStatus::success(), new DatabaseSearchResults($recordSet)); } else { var_dump ($query); return array(GalleryStatus::error(ERROR_STORAGE_FAILURE, __FILE__, __LINE__), null); } and it says: Quote:
string(314) " SELECT g2_PluginParameterMap.g_parameterName, g2_PluginParameterMap.g_parameterValue FROM g2_PluginParameterMap WHERE g2_PluginParameterMap.g_pluginType = ? AND g2_PluginParameterMap.g_pluginId = ? AND g2_PluginParameterMap.g_itemId = ? " I'm not sure why it's printing two different statements. I presume the 2nd is the fatal one. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
can you please post the complete install.log as attachement (or link to it)? thanks. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Attached here. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
ok, the 2 errors before the system information in the install log can be ignored. that's normal. but we see that our CreateDb2Udf2.sql file is the problem: 2005-11-21 12:16:30 [] db2 error: [42617: [IBM][CLI Driver][DB2/NT] SQL0198N The statement string of the PREPARE or EXECUTE IMMEDIATE statement is blank or empty. SQLSTATE=42617 ] in EXECUTE("-- Author: Larry Menard, 11/2005 -- AND two bits DROP FUNCTION BIT_AND(SMALLINT, SMALLINT)") so execute can't deal with comments it seems. can you remove all comments from CreateDb2Udfs.sql please. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
I got Step 9 to work. There are two problems: 1) Comments are allowed but only inside the PL/SQL blocks (between the BEGIN ATOMIC and END, where DB2 recognizes them). 2) The DROP FUNCTION statements were returning errors because the functions to not exist in a newly-created database. Attached is the CreateDb2Udfs.sql file that works. Now the install completes successfully. When I run gallery2/main.php, I get a new error: Quote:
Notice: Undefined variable: arg in C:\My Server\gallery2\modules\core\classes\GalleryStorage\DatabaseStorage\Db2DatabaseStorage.class on line 181 Details: Quote:
db2 error: [0: ] in EXECUTE(" SELECT DISTINCT g2_AccessMap.g_accessListId FROM g2_AccessMap WHERE (g2_AccessMap.g_userId = ? OR g2_AccessMap.g_groupId IN (?)) AND BITAND(g2_AccessMap.g_permission, ) = ? ") Looks like a problem with the 3rd arg I'm passing to the G2_LIKE code. I'll look into it. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
great! i had a typo in db2 storage class: instead of: that was your arg error. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Ah, of course. Thanks. I've fixed it, but am now getting error: Quote:
db2 error: [0: ] in EXECUTE(" SELECT DISTINCT g2_AccessMap.g_accessListId FROM g2_AccessMap WHERE (g2_AccessMap.g_userId = ? OR g2_AccessMap.g_groupId IN (?)) AND BITAND(g2_AccessMap.g_permission, ?) = ? ") I'll look into that. Hope it's not as bad as it sounds. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
arg, another artifact, sorry. db2 sotrage class: with |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Ah, that's it. I was just about to post an observation that that this was working fine on the previous build with the updated files that I sent you. Now I'm getting an error in G2_LIKE: db2 error: [0: ] in EXECUTE(" SELECT iam0.g_itemId, COUNT(iam1.g_itemId) FROM g2_ItemAttributesMap AS iam0, g2_ItemAttributesMap AS iam1, g2_AccessSubscriberMap WHERE iam0.g_itemId IN (?) AND G2_LIKE(iam1.g_parentSequence, char(iam0.g_parentSequence) || char(iam0.g_itemId) || char('/%')) AND iam1.g_itemId = g2_AccessSubscriberMap.g_itemId AND g2_AccessSubscriberMap.g_accessListId IN (?,?) GROUP BY iam0.g_itemId ") -------------------------------------------------------------------------------- (db2): SELECT iam0.g_itemId, COUNT(iam1.g_itemId) FROM g2_ItemAttributesMap AS iam0, g2_ItemAttributesMap AS iam1, g2_AccessSubscriberMap WHERE iam0.g_itemId IN (?) AND G2_LIKE(iam1.g_parentSequence, char(iam0.g_parentSequence) || char(iam0.g_itemId) || char('/%')) AND iam1.g_itemId = g2_AccessSubscriberMap.g_itemId AND g2_AccessSubscriberMap.g_accessListId IN (?,?) GROUP BY iam0.g_itemId [ (0=>'7') (1=>'8') (2=>'9') ] -------------------------------------------------------------------------------- Warning: odbc_prepare() [function.odbc-prepare]: SQL error: [IBM][CLI Driver][DB2/NT] SQL0104N An unexpected token "AND" was found following "emId) || char('/%'))". Expected tokens may include: "<interval_qualifier>". SQLSTATE=42601 , SQL state 42601 in SQLPrepare in C:\My Server\gallery2\lib\adodb\drivers\adodb-odbc.inc.php on line 502 I don't see anything wrong with this SQL. ?? |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
I think I see the problem. We're not testing for a returned value from G2_LIKE. ( "= 1"). |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Yeah, that was it. I added " = 1" to the end of the clause in the G2_LIKE code, and it works. I'm now at the BIT_OR error, as expected. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
sorry, i removed that = 1 my bad, sorry. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
No prob. Thanks. ;-) |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Need some java help. I've written a test java program to simplify the BIT_OR processing, and it has a compile error that I can't shake. C:\temp>javac test.java test.java:34: byte cannot be dereferenced if (scratchPad[ctr].intValue() == 1) // If scratchpad bit is already 1, ^ test.java:40: byte cannot be dereferenced if (columnValueArray[ctr].intValue() == 1) // check the current value bit. If it's 1, ^ 2 errors I'm attaching the source here. Any ideas what I'm doing wrong? |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
haven't coded java in a while, maybe try (scratchPad[ctr]).intValue() or just (integer)(scratchPad[ctr]) @code: it's almost the same as you already have, just less == operations. but why not use boolean operators of hava? you've got an input string x "00100010011"; |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
OK, I'm game to try your suggestion, but how do I convert a byte[] into an integer? That's basically the same problem I originally askred about. That's what I can't find in the javadoc. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
with my suggested code, you receveive a String in your function, and you convert it to integer and back to a string. what do you need byte for? for storing it in the scratchpad? an int = 4 bytes hacky code (maybe there are simple methods): maybe you can use the same methods as Kurt... |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
OK, I have it working using my original plan plus your suggested optimization. Remember, I'm not a hard-core developer. I kept running into more problems with the boolean solution, and it was getting out of hand. I'd rather go with something I wrote because I understand it. I'll attach the source here. Let me know if you have any violent objections. Remember, the fancier you want me to make it, the less likely I am to understand it (or do it). |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
i'm sure this could done easier... but i myself haven't coded too much in java and it's also been a few years ago since i last coded in java. but your string -> byte[] -> Byte conversion could at least be made one step shorter. just use |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
C:\temp>javac test.java test.java:60: not a statement scratchPad[ctr] == 49; ^ 1 error This is why I hate java. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
sorry, should have been: basic programing SQL is different of course, but SQL is SQL. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
I should have spotted that too. Must be getting tired. BUT!!! There's good news. I've finally got the "gallery2/main.php" tp run to completion! I'm attaching here the latest files I updated. Since you actually diagnosed some of them, you might have already updated them in CVS. Quote:
modules/core/classes/GalleryStorage/DatabaseStorage/db2DatabaseStorage.class (Fix creation of UDFs (Valiant's fix), fix '$arg' typo, remove accidental line from G2_BIT_AND, add " = 1" to G2_LIKE, case 'BITOR') Important notes: 1) Creation of the java UDF requires DBADM permissions. Users/installers of G2 should be informed of that. 2a) The java class "modules/core/classes/GalleryStorage/DatabaseStorage/g2_bit_or.java" needs to be compiled at some point. I presume we would not expect the user to do that, so it should be added to the makefile. Should I go ahead and do that? 2b) The compiled "g2_bit_or.class" needs to be copied to the "sqllib/function" directory of DB2 (which no doubt has its own permissions issues, but let's ignore that for now). I'm not sure how to determine where the "sqllib" is on the given system. In the worst case, would we be able to ask the User during the Installer? And while we're on the subject of Installer changes, remember that I'm still using a hack in which I enter the database name in the "hostname" field to get around that ODBC funkiness. Let me know when I can get a new build and confirm these changes. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
Ah, excellent but before, you need to be able to login i will commit your changes tomorrow, it's already night here. I'm curious about the performance since we've got here quite slow implementations of BIT operation (using varchar in SQL instead of int, and the UDF calls...i don't know. i'm just curious @installing: @hostname / db name field: |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Ah, I wondered if you had a formal test suite anywhere. I'll look at that soon. I presume it requires me to have some photos in my gallery? You didn't answer my question about the makefile, but I presume the answer is yes, so I'll work on adding that in and send you the update. Thanks for your help with all of this. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
no, you don't need to add anything to your g2. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Oh yeah that reminds me. At Step 9 I don't actually install any of the optional modules. Does that make any difference at this point? |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
no, it doesn't. you can add items, it just doesn't generate thumbnails. if the first steps seem to be a success, you can try to run the unit steps. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
> you can activate other modules in site admin -> modules, if you want. I was more concerned about whether those optional modules required anything else to be installed. Sounds like they don't. > building & installing the java .class file I started looking at the makefile, then I thought that since the java UDF file is only required for DB2, you might have some opinions about how to implement the building and delivery of this class file? |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
other modules don't need any special SQL, no. some of the modules have external dependencies, e.g. imagemagick binaries etc. @makefiles: |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
I didn't realize there already were other java .class files in G2. The UDF .class file needs to be in a place that DB2 knows where to look for it. By default, that place is ".../sqllib/function". If the .class file is not put there, then we have to specify that location in the SQL statement that creates the UDF. Specifically, the line: Quote:
EXTERNAL NAME 'g2_bit_or!g2_bit_or' The first "g2_bit_or" is the name of the .class file, the second "g2_bit_or" is the name of the method in that class file. If the class file is in a jar file then it's much more complicated again... a whole additional SQL statement is required. call sqlj.install_jar(file://<path>/g2_bit_or.jar, myJarId); create function g2_bit_and ... external name 'myJarId:g2_bit_or!g2_bit_or' ... ; |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
there's no need to put it in a jar, absolutely not. the jar makes just things easier for the multi class files applets. so you say we can install the udf with g2, no need to move the file elsewhere? excellent!! i'll be back in a few hours. |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
That's the theory anyway... I don't remember ever successfully doing so... it's usually simpler to just drop it into sqllib/function. I'll give it a test and let you know how it goes. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
that would be awesome. installation would be as simple as for every other DBMS. i hope it works |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Sure enough, I'm having difficulty with specifying the absolute path. I suspect the colon in the drive specification is being misinterpreted as a jar file separator. I've posted a question to comp.databases.ibm-db2, am waiting for a response. In the meantime, I've run a bunch of the tests and many of them are failing with: Quote:
PHP ERROR: odbc_prepare() [function.odbc-prepare]: SQL error: [IBM][CLI Driver] CLI0005W Option value changed. SQLSTATE=01S02, SQL state 01S02 in SQLPreparein C:\My Server\gallery2\lib\adodb\drivers\adodb-odbc.inc.php at line 502 We discussed this back on 2005-11-04 16:50 (page 3 of this forum)... it's just a warning that DB2's CLI driver is doing extra work to handle a JOIN that Microsoft's ODBC driver doesn't handle at all. I tried putting an "@" in front of the "odbc-prepare()" call in "adodb-odbc.inc.php", but it didn't seem to help. |
|
valiant
Joined: 2003-01-04
Posts: 32509 |
![]() |
what's the exact DB2 SQL you want to execute? i can help you with the absolute path stuff etc. e.g. in Db2DatabaseStorage.class we could do: $path = dirname(__FILE__) . $platform->getDirectorySeparator() . 'g2_bit_or.jar'; on windows, $path could be: |
|
Larry Menard
![]()
Joined: 2005-10-01
Posts: 757 |
![]() |
Yeah, that would probably work, but to keep things as simple as possible, I thought we would prefer to avoid having to use the "sqlj.install_jar" function. First of all, it's another SQL statement that has to be executed, and second, the class file would then need to be in a jar file. The DB2 docs clearly say that an absolute file name can be used in the CREATE FUNCTION ... EXTERNAL NAME '<class>!<method>' clause, but they give examples only for Unix/Linux (where the path contains no colons). |
|