i realized yesterday that the - (COUNT(*) - CONSTANT) is NOT necessary.
since BIT_OR will only increase the value of a sequence of 0s and 1s, MAX(BIT_OR(column)) is already fine.
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
Posted: Sun, 2005-11-20 18:26
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.
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
Posted: Sun, 2005-11-20 21:10
- 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)
- cool that this works
- but we don't need a counter (as explained in my last post). so now you can replace the counter with the AND operation... (i guess you had this in mind anyway, just wanted to make sure that we're going into the same direction)
@MAX:
we'll replace
$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.
as explained, MAX() will work for a BIT_ORed intermediate result list, since OR only adds something, so the intermediate result with the max value is the last intermediate result anyway. lucky us.
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Sun, 2005-11-20 22:11
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
Posted: Sun, 2005-11-20 22:18
how can you control to only output the last intermediate result?
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Mon, 2005-11-21 02:56
I was thinking that the GROUP BY would handle that. Wouldn't it?
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Mon, 2005-11-21 03:04
Ah, on second thought, I guess not. I see your point.
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Mon, 2005-11-21 03:57
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.
Missing SQL statements
We received the following database related errors:
For odbc Connect(), gallery2 is not used. Place dsn in 1st parameter.
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
Posted: Mon, 2005-11-21 04:06
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
Posted: Mon, 2005-11-21 09:56
@only outputting the intermediate result:
yep, you can't control that (says Knut, and it makes sense), that's why we need the MAX around your function.
@gmake:
hmm, sorry. i didn't run gmake before committing. but since there were no generate-sql changes, i thought it wasn't necessary. did gmake change anything for you?
@executeSqlFile:
arg. sorry for that. I copied from the oracle class which still uses this function although it was removed / changed = oracle doesn't work right now either.
I've notified Bharat and mindless and we'll solve it soon.
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
Posted: Mon, 2005-11-21 15:54
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
Unable to activate the core module
Error installing Gallery Core
Stack Trace:
Error (ERROR_STORAGE_FAILURE)
in modules\core\classes\GalleryStorage\DatabaseStorage.class at line 305 (GalleryStatus::error)
in modules\core\classes\GalleryStorage.class at line 248 (DatabaseStorage::search)
in modules\core\classes\Gallery.class at line 223 (GalleryStorage::search)
in modules\core\classes\helpers\GalleryPluginHelper_simple.class at line 484 (Gallery::search)
in modules\core\classes\helpers\GalleryPluginHelper_simple.class at line 347 (GalleryPluginHelper_simple::fetchPluginList)
in modules\core\classes\GalleryCoreApi.class at line 276 (GalleryPluginHelper_simple::fetchPluginStatus)
in modules\core\classes\GalleryPlugin.class at line 179 (GalleryCoreApi::fetchPluginStatus)
in modules\core\classes\GalleryModule.class at line 381 (GalleryPlugin::activate)
in install\steps\InstallCoreModuleStep.class at line 131 (GalleryModule::activate)
in install\index.php at line 167 (InstallCoreModuleStep::loadTemplateData)
Thanks.
valiant
Joined: 2003-01-04
Posts: 32509
Posted: Mon, 2005-11-21 16:07
@blank lines after ;
that has to do with our parser of SQL files. if there's a blank line after a semicolon, we interpret it as 2 different statements -> 2 executes
if there's no blank line after a semicolon, it's interpreted as a single (PL/SQL) block.
@installer step 5:
can we change anything in db2 storage class to suppress the warning?
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Mon, 2005-11-21 16:09
Also, I don't know if this is related, but I now get another warning in Step 2:
Quote:
Translation support: Warning
Your webserver does not support localization. To enable support for additional languages please instruct your system administrator to reconfigure PHP with the gettext option enabled.
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
Posted: Mon, 2005-11-21 16:13
this warning shows up when your php doesn't have gettext support (loaded).
on windows, you sometimes just can uncomment the extension= ..gettext...dll line in php.ini and restart apache/iis. but only if you already got that dll.
it doesn't really matter and is 100% irrelevant for db2.
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 = ? "
string(165) " SELECT g2_PluginMap.g_pluginId, g2_PluginMap.g_active FROM g2_PluginMap WHERE g2_PluginMap.g_pluginType = ? "
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
Posted: Mon, 2005-11-21 17:00
can you please post the complete install.log as attachement (or link to it)? thanks.
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Mon, 2005-11-21 17:13
Attached here.
valiant
Joined: 2003-01-04
Posts: 32509
Posted: Mon, 2005-11-21 17:25
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.
and make sure there are no blank new lines after ; unless between the create / drop / create statements.
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Mon, 2005-11-21 18:14
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, ) = ? ")
--------------------------------------------------------------------------------
(db2): 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, ) = ? [ (0=>'5') (1=>'4') (2=>'00000000000000000000000000000001') (3=>'00000000000000000000000000000001') ]
--------------------------------------------------------------------------------
Warning: odbc_prepare() [function.odbc-prepare]: SQL error: [IBM][CLI Driver][DB2/NT] SQL0104N An unexpected token ")" was found following "essMap.g_permission,". Expected tokens may include: "<value_expr_or_stub>". SQLSTATE=42601 , SQL state 42601 in SQLPrepare in C:\My Server\gallery2\lib\adodb\drivers\adodb-odbc.inc.php on line 502
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
Posted: Mon, 2005-11-21 18:22
great!
i had a typo in db2 storage class:
$sql = 'BITAND(' . $args[0] . ', ' . $arg[1] . ')';
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, ?) = ? ")
--------------------------------------------------------------------------------
(db2): 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, ?) = ? [ (0=>'5') (1=>'4') (2=>'00000000000000000000000000000001') (3=>'00000000000000000000000000000001') ]
--------------------------------------------------------------------------------
Warning: odbc_prepare() [function.odbc-prepare]: SQL error: [IBM][CLI Driver][DB2/NT] SQL0418N A statement contains a use of a parameter marker that is not valid. SQLSTATE=42610 , SQL state 42610 in SQLPrepare in C:\My Server\gallery2\lib\adodb\drivers\adodb-odbc.inc.php on line 502
I'll look into that. Hope it's not as bad as it sounds.
with
$sql = 'G2_BIT_AND (CAST(' . $args[0] . ' AS CHAR(32)), ' .
'CAST(' . $args[1] . ' AS CHAR(32)))';
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Mon, 2005-11-21 19:53
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
Posted: Mon, 2005-11-21 20:00
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
Posted: Mon, 2005-11-21 20:04
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
Posted: Mon, 2005-11-21 20:18
sorry, i removed that = 1
since i thought SQL was smart enough, e.g.
AND 1
reads for me
AND true
but obviously you need a comparator there.
my bad, sorry.
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Mon, 2005-11-21 20:22
No prob. Thanks. ;-)
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Tue, 2005-11-22 17:27
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
Posted: Tue, 2005-11-22 17:54
haven't coded java in a while, maybe try (scratchPad[ctr]).intValue() or just (integer)(scratchPad[ctr])
@code:
- you have to to do a == 1 compare operation per bit anyway, but not more
i'd do (pseudo code):
1. scratchPad = data loaded from scratch
2. input = data from current column row
3. iterate over each bit
foreach bitposition i
if (input[i] == 1) {
scratchPad[i] = 1;
}
print scratchPad[i];
}
4. store scratchPad in scratch again for next row
it's almost the same as you already have, just less == operations.
but why not use boolean operators of hava?
load the data from scratchpad into an integer
convert the input row data into an integer
result = input & scratchPad;
and then print out the result as string again...
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
Posted: Tue, 2005-11-22 18:53
with my suggested code, you receveive a String in your function, and you convert it to integer and back to a string.
hacky code (maybe there are simple methods):
int fromScratch = 0;
for (int i = scratchPadByteArray.length - 1; i >= 0; i--) {
fromScratch |= scratchPadByteArray[i] & 0xFF;
if (i != 0) {
fromScratch <<= 8; // leftshirt by 8 bits
}
}
maybe you can use the same methods as Kurt...
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Tue, 2005-11-22 20:42
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
Posted: Tue, 2005-11-22 22:44
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
1. no result array is needed since we can write the new result into the scratchpad variable.
2.
in for { use:
if (columnValueArray[ctr] == 49) { // 49 is the ascii value for "1" see www.asciitable.com
scratchPad[ctr] == 49;
}
System.out.println(scratchPad[ctr]); // cast byte to string or so to get 1 and 0 instead of 49 and 48
} // end for
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Tue, 2005-11-22 23:03
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
Posted: Tue, 2005-11-22 23:18
sorry, should have been:
scratchPad[ctr] = 49;
basic programing doh!
== is for comparison
= for assignment
SQL is different of course, but SQL is SQL.
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Wed, 2005-11-23 01:50
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! Now I'm looking at an empty gallery. I'm sure there's still a lot of work to do though.
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')
modules/core/classes/GalleryStorage/DatabaseStorage/g2_bit_or.java (source for G2_BIT_OR UDF. After compilation, class file needs to be copied to sqllib/function.)
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
Posted: Wed, 2005-11-23 02:01
Ah, excellent
Btw: We can test whether DB2/G2 works correctly with the 1500+ unit tests of G2, which should trigger all code of G2 at least once.
you can start them with yourgallery/lib/tools/phpunit/index.php
but before, you need to be able to login
and you should put your php memory_limit to 64M.
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:
we'll certainly have to at least create installation notes for DB2. thanks for already thinking about that and writing
i guess we should show these instructions in the db step when the user selects DB2.
of course we could ask the user to enter the path to sqllib (if we can't get it from the path ENV or from db2) and make it writable, but asking the user to copy a file is fine i guess.
@hostname / db name field:
right, will need to change the installer for that. do you only need the hostname field for DB2? should i only show a single field for hostname/db name and tag it "Database Name"?
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Wed, 2005-11-23 02:26
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
Posted: Wed, 2005-11-23 02:48
no, you don't need to add anything to your g2.
but it only tests active modules.
but testing core only is already a huge thing
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Wed, 2005-11-23 02:52
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
Posted: Wed, 2005-11-23 03:02
no, it doesn't. you can add items, it just doesn't generate thumbnails.
you can activate other modules in site admin -> modules, if you want.
if the first steps seem to be a success, you can try to run the unit steps.
i'm sure there will be errors. they don't even have to be related to your DB2 stuff, G2 is in development right now and sometimes a few tests fail. then we have to fix things.. _
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Wed, 2005-11-23 03:23
> 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
Posted: Wed, 2005-11-23 03:34
other modules don't need any special SQL, no. some of the modules have external dependencies, e.g. imagemagick binaries etc.
@makefiles:
the the db2 java file won't be part of our make scripts.
we'll deal with it exactly like we deal with the other java binary files we have in g2 (slideshow, upload applet, crop applet). they are just in a data/ directory in the specific module as .jar file.
you don't have to build a jar file.
once we're finished, we'll have to make sure that we have the source code etc. just in case someone wants the source or if we need to recompile the java class because we need to change something.
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Wed, 2005-11-23 04:05
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
Posted: Wed, 2005-11-23 04:29
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!!
then we just put the class file in the DatabaseStorage/ dir
i'll be back in a few hours.
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Wed, 2005-11-23 04:38
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
Posted: Wed, 2005-11-23 04:44
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
Posted: Wed, 2005-11-23 15:07
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
Posted: Wed, 2005-11-23 15:19
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';
you could then use $path in your SQL query:
execute("call sqlj.install_jar(file://$path, myJarId);
on windows, $path could be:
c:\www\gallery2\modules\core\classes\GalleryStorage\DatabaeStorage\g2_bit_or.jar
on linux/unix:
/var/www/gallery2/modules/core/classes/GalleryStorage/DatabaeStorage/g2_bit_or.jar
Larry Menard
Joined: 2005-10-01
Posts: 757
Posted: Wed, 2005-11-23 15:30
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).
Posts: 32509
@BIT_OR:
i realized yesterday that the - (COUNT(*) - CONSTANT) is NOT necessary.
since BIT_OR will only increase the value of a sequence of 0s and 1s, MAX(BIT_OR(column)) is already fine.
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.
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.
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.
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)
- cool that this works
- but we don't need a counter (as explained in my last post). so now you can replace the counter with the AND operation... (i guess you had this in mind anyway, just wanted to make sure that we're going into the same direction)
@MAX:
we'll replace
with
and in Db2DatabaseStorage.class we'll add:
while other DBs will have:
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.
as explained, MAX() will work for a BIT_ORed intermediate result list, since OR only adds something, so the intermediate result with the max value is the last intermediate result anyway. lucky us.
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?
Posts: 32509
how can you control to only output the last intermediate result?
Posts: 757
I was thinking that the GROUP BY would handle that. Wouldn't it?
Posts: 757
Ah, on second thought, I guess not. I see your point.
Posts: 757
I've downloaded a new version of the code, and am unable to get past Step 5 of the installation. It says:
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?
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:
Posts: 32509
@only outputting the intermediate result:
yep, you can't control that (says Knut, and it makes sense), that's why we need the MAX around your function.
@gmake:
hmm, sorry. i didn't run gmake before committing. but since there were no generate-sql changes, i thought it wasn't necessary. did gmake change anything for you?
@executeSqlFile:
arg. sorry for that. I copied from the oracle class which still uses this function although it was removed / changed = oracle doesn't work right now either.
I've notified Bharat and mindless and we'll solve it soon.
Meanwhile, for testing, please replace in Db2DatabaseStorage.class:
with
you might then have to remove all blank lines after a ; within CreateDb2Udfs.sql (i just did that in cvs)
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.
Thanks.
Posts: 32509
@blank lines after ;
that has to do with our parser of SQL files. if there's a blank line after a semicolon, we interpret it as 2 different statements -> 2 executes
if there's no blank line after a semicolon, it's interpreted as a single (PL/SQL) block.
the updated file:
http://cvs.sourceforge.net/viewcvs.py/gallery/gallery2/modules/core/classes/GalleryStorage/DatabaseStorage/CreateDb2Udfs.sql?rev=1.2&view=markup
@missing ;
where am i missing a semicolon?
@installer step 5:
can we change anything in db2 storage class to suppress the warning?
Posts: 757
Also, I don't know if this is related, but I now get another warning in Step 2:
I enabled gettext in my 'php.ini', restarted my web server, and closed all browsers, and still get the warning.
Posts: 32509
this warning shows up when your php doesn't have gettext support (loaded).
on windows, you sometimes just can uncomment the extension= ..gettext...dll line in php.ini and restart apache/iis. but only if you already got that dll.
it doesn't really matter and is 100% irrelevant for db2.
Posts: 757
> blank lines after ';'
I see. Thanks.
> 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:
and it says:
I'm not sure why it's printing two different statements. I presume the 2nd is the fatal one.
Posts: 32509
can you please post the complete install.log as attachement (or link to it)? thanks.
Posts: 757
Attached here.
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:
so execute can't deal with comments it seems.
can you remove all comments from CreateDb2Udfs.sql please.
and make sure there are no blank new lines after ; unless between the create / drop / create statements.
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:
Details:
Looks like a problem with the 3rd arg I'm passing to the G2_LIKE code. I'll look into it.
Posts: 32509
great!
i had a typo in db2 storage class:
$sql = 'BITAND(' . $args[0] . ', ' . $arg[1] . ')';
instead of:
$sql = 'BITAND(' . $args[0] . ', ' . $args[1] . ')';
that was your arg error.
Posts: 757
Ah, of course. Thanks.
I've fixed it, but am now getting error:
I'll look into that. Hope it's not as bad as it sounds.
Posts: 32509
arg, another artifact, sorry.
db2 sotrage class:
replace:
$sql = 'G2_BIT_AND (CAST(' . $args[0] . ' AS CHAR(32)), ' .
'CAST(' . $args[1] . ' AS CHAR(32)))';
$sql = 'BITAND(' . $args[0] . ', ' . $args[1] . ')';
with
$sql = 'G2_BIT_AND (CAST(' . $args[0] . ' AS CHAR(32)), ' .
'CAST(' . $args[1] . ' AS CHAR(32)))';
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:
I don't see anything wrong with this SQL. ??
Posts: 757
I think I see the problem. We're not testing for a returned value from G2_LIKE. ( "= 1").
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.
Posts: 32509
sorry, i removed that = 1
since i thought SQL was smart enough, e.g.
AND 1
reads for me
AND true
but obviously you need a comparator there.
my bad, sorry.
Posts: 757
No prob. Thanks. ;-)
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.
I'm attaching the source here. Any ideas what I'm doing wrong?
Posts: 32509
haven't coded java in a while, maybe try (scratchPad[ctr]).intValue() or just (integer)(scratchPad[ctr])
@code:
- you have to to do a == 1 compare operation per bit anyway, but not more
i'd do (pseudo code):
1. scratchPad = data loaded from scratch
2. input = data from current column row
3. iterate over each bit
foreach bitposition i
if (input[i] == 1) {
scratchPad[i] = 1;
}
print scratchPad[i];
}
4. store scratchPad in scratch again for next row
it's almost the same as you already have, just less == operations.
but why not use boolean operators of hava?
load the data from scratchpad into an integer
convert the input row data into an integer
result = input & scratchPad;
and then print out the result as string again...
you've got an input string x "00100010011";
use integer input = Integer.parseInt(x, 2);
do the same for scratchPad, then you can simply call integer result = input & scratchPad;
and you can print Integer.toString(result, 2);
see:
http://javaalmanac.com/egs/java.lang/ConvertNum2.html
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Integer.html
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.
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?
ok, i see getScratchPad returns a byte[] array:
http://publib.boulder.ibm.com/infocenter/db2help/index.jsp?topic=/com.ibm.db2.udb.doc/ad/r0008987.htm
an int = 4 bytes
hacky code (maybe there are simple methods):
int fromScratch = 0;
for (int i = scratchPadByteArray.length - 1; i >= 0; i--) {
fromScratch |= scratchPadByteArray[i] & 0xFF;
if (i != 0) {
fromScratch <<= 8; // leftshirt by 8 bits
}
}
maybe you can use the same methods as Kurt...
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).
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
1. no result array is needed since we can write the new result into the scratchpad variable.
2.
in for { use:
if (columnValueArray[ctr] == 49) { // 49 is the ascii value for "1" see www.asciitable.com
scratchPad[ctr] == 49;
}
System.out.println(scratchPad[ctr]); // cast byte to string or so to get 1 and 0 instead of 49 and 48
} // end for
Posts: 757
This is why I hate java.
Posts: 32509
sorry, should have been:
scratchPad[ctr] = 49;
basic programing doh!
== is for comparison
= for assignment
SQL is different of course, but SQL is SQL.
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! Now I'm looking at an empty gallery. I'm sure there's still a lot of work to do though.
I'm attaching here the latest files I updated. Since you actually diagnosed some of them, you might have already updated them in CVS.
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.
Posts: 32509
Ah, excellent
Btw: We can test whether DB2/G2 works correctly with the 1500+ unit tests of G2, which should trigger all code of G2 at least once.
you can start them with yourgallery/lib/tools/phpunit/index.php
but before, you need to be able to login
and you should put your php memory_limit to 64M.
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:
we'll certainly have to at least create installation notes for DB2. thanks for already thinking about that and writing
i guess we should show these instructions in the db step when the user selects DB2.
of course we could ask the user to enter the path to sqllib (if we can't get it from the path ENV or from db2) and make it writable, but asking the user to copy a file is fine i guess.
@hostname / db name field:
right, will need to change the installer for that. do you only need the hostname field for DB2? should i only show a single field for hostname/db name and tag it "Database Name"?
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.
Posts: 32509
no, you don't need to add anything to your g2.
but it only tests active modules.
but testing core only is already a huge thing
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?
Posts: 32509
no, it doesn't. you can add items, it just doesn't generate thumbnails.
you can activate other modules in site admin -> modules, if you want.
if the first steps seem to be a success, you can try to run the unit steps.
i'm sure there will be errors. they don't even have to be related to your DB2 stuff, G2 is in development right now and sometimes a few tests fail. then we have to fix things.. _
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?
Posts: 32509
other modules don't need any special SQL, no. some of the modules have external dependencies, e.g. imagemagick binaries etc.
@makefiles:
the the db2 java file won't be part of our make scripts.
we'll deal with it exactly like we deal with the other java binary files we have in g2 (slideshow, upload applet, crop applet). they are just in a data/ directory in the specific module as .jar file.
you don't have to build a jar file.
once we're finished, we'll have to make sure that we have the source code etc. just in case someone wants the source or if we need to recompile the java class because we need to change something.
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:
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.
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!!
then we just put the class file in the DatabaseStorage/ dir
i'll be back in a few hours.
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.
Posts: 32509
that would be awesome. installation would be as simple as for every other DBMS. i hope it works
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:
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.
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';
you could then use $path in your SQL query:
execute("call sqlj.install_jar(file://$path, myJarId);
on windows, $path could be:
c:\www\gallery2\modules\core\classes\GalleryStorage\DatabaeStorage\g2_bit_or.jar
on linux/unix:
/var/www/gallery2/modules/core/classes/GalleryStorage/DatabaeStorage/g2_bit_or.jar
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).