Support for DB2 databases?

Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 17:04

I found the problem with SessionTest.testSessionCookieHeaderAndPersistence... apparently it assumes that the ImageFrame and Migration modules are installed and activated.

I thought these tests were supposed to only run of their required modules were installed?

I'll install all modules and re-run the whole set of tests again.

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Sat, 2006-02-11 17:09

there are some minor dependencies... obviously we posted at the same time. see my last post.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 17:32

Yeah I saw your response after I posted mine. ;-)

Next problem... when installing *all* modules, I now get a database error. There's an "UPDATE g2_SessionMap" statement that is squawking, but it doesn't seem to be fatal... it doesn't cause the module install/activation to fail. I just happened to notice it at the bottom of the page.

Quote:
db2 error: [22001: [IBM][CLI Driver][DB2/NT] SQL0433N Value
"a:6:{s:13:"core.language";s:5:"en_US";s:15:"core.navigation"" is too long.
SQLSTATE=22001 SQLCODE=-433]

The statement is very long, but starts off with:

UPDATE g2_SessionMap SET
 g_userId=6,
 g_remoteIdentifier='a:2:i:0;s:11:"192.168.1.1";i:1;s:32:"2581833420733f29e9446ab1312d0ac0";}',
 g_creationTimestamp=1139677980,
 g_modificationTimestamp=1139678138,
 g_data='...'
 ...

It's the 'g_data' value that is apparently too long (the DB2 message is truncating it). That column is currently defined as VARCHAR(8000). What do you think a safe length for it should be?

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Sat, 2006-02-11 17:53

in mysql, we're using TEXT, a 65kbyte field.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 18:11

In DB2 the max VARCHAR is 32K, so I'll try using a CLOB(64K). Will let you know how it goes. Thanks.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 19:05

When I change it to CLOB(64K), the core module install fails, but there's no DB2 error in the log. It looks like there's a problem determining the type of locking used.

Quote:
Error (ERROR_BAD_PARAMETER)
in modules\core\classes\Gallery.class at line 393 (GalleryCoreApi::error)
in modules\core\classes\helpers\GalleryLockHelper_simple.class at line 198 (Gallery::getLockSystem)
in modules\core\classes\GalleryCoreApi.class at line 2319 (GalleryLockHelper_simple::isWriteLocked)
in modules\core\classes\GalleryEntity.class at line 286 (GalleryCoreApi::isWriteLocked)
in modules\core\CoreModuleExtras.inc at line 2341 (GalleryEntity::save)
in ??? at line 0 (CoreModuleExtras::_createAccessListCompacterLock)
in modules\core\CoreModuleExtras.inc at line 262
in modules\core\module.inc at line 486 (CoreModuleExtras::upgrade)
in modules\core\classes\GalleryModule.class at line 157 (CoreModule::upgrade)
in install\steps\InstallCoreModuleStep.class at line 131 (GalleryModule::installOrUpgrade)
in install\index.php at line 165 (InstallCoreModuleStep::processRequest)

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 19:41

In Gallery::getLockSystem(), I'm printing $which, and it is "database". I don't know why the switch() is failing. ???

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Sat, 2006-02-11 19:46

maybe you're not debugging correctly.
your print $which; exit; should be right after
default:

because the function could be called previously too and only a second or third call create an error.

alternatively, even better, change:
$ret = array(GalleryCoreApi::error(ERROR_BAD_PARAMETER, __FILE__, __LINE__), null);
to
$ret = array(GalleryCoreApi::error(ERROR_BAD_PARAMETER, __FILE__, __LINE__, "unknown locking system '$which'"), null);

then the error generated will include the name in quotes.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 20:03

I'm printing it immediately before the which(), so it is printed in all cases, success and failure.

I updated the error message, but don't see it in the output?

Ah, but when I var_dump() it (as opposed to just printf()), $which is a string(9). Why 9?

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Sat, 2006-02-11 20:39

- in php, there's usually no need to use printf. we just do "print $which;"
- i guess you mean "immediately before the switch()" and not which()
- var_dump() outputs the variable type and the value. type is in your case string(9), that is a string of length 9. but you didn't specify what value it outputted.
and you should output not before the switch, but in the default block.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 20:39

Even when I dump it in the default:, it is 9. By d displaying the ascii value of each byte in the string, the last character is a null (x'0').

Quote:
In Gallery::getLockSystem(), default: $which =
string(9) "database"

substr($which, 0, 1) = "d", or ASCII "100".
substr($which, 1, 1) = "a", or ASCII "97".
substr($which, 2, 1) = "t", or ASCII "116".
substr($which, 3, 1) = "a", or ASCII "97".
substr($which, 4, 1) = "b", or ASCII "98".
substr($which, 5, 1) = "a", or ASCII "97".
substr($which, 6, 1) = "s", or ASCII "115".
substr($which, 7, 1) = "e", or ASCII "101".
substr($which, 8, 1) = "", or ASCII "0".
Error (ERROR_BAD_PARAMETER)
in modules\core\classes\Gallery.class at line 405 (GalleryCoreApi::error)
in modules\core\classes\helpers\GalleryLockHelper_simple.class at line 198 (Gallery::getLockSystem)
in modules\core\classes\GalleryCoreApi.class at line 2319 (GalleryLockHelper_simple::isWriteLocked)
in modules\core\classes\GalleryEntity.class at line 286 (GalleryCoreApi::isWriteLocked)
in modules\core\CoreModuleExtras.inc at line 2341 (GalleryEntity::save)
in ??? at line 0 (CoreModuleExtras::_createAccessListCompacterLock)
in modules\core\CoreModuleExtras.inc at line 262
in modules\core\module.inc at line 486 (CoreModuleExtras::upgrade)
in modules\core\classes\GalleryModule.class at line 157 (CoreModule::upgrade)
in install\steps\InstallCoreModuleStep.class at line 131 (GalleryModule::installOrUpgrade)
in install\index.php at line 165 (InstallCoreModuleStep::processRequest)

How would that be caused by the TEXT-MEDIUM changing to CLOB(64K)?

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 21:18

I can verify that the data in the database if OK:

C:\MyServer>db2 select substr(G_PARAMETERVALUE, 1, 10) as G_PARAMETERVALUE, length(G_PARAMETERVALUE) as length from g2_pluginparametermap where g_parametername = 'lock.system'

G_PARAMETERVALUE LENGTH
---------------- -----------
database                   8

  1 record(s) selected.

I also see that g2_PluginParameterMap.g_ParameterValue is one of the columns that is now a CLOB.

C:\MyServer>db2 describe table g2_pluginparametermap

Column                         Type      Type
name                           schema    name               Length   Scale Nulls

------------------------------ --------- ------------------ -------- ----- -----
-
G_PLUGINTYPE                   SYSIBM    VARCHAR                  32     0 No

G_PLUGINID                     SYSIBM    VARCHAR                  32     0 No

G_ITEMID                       SYSIBM    INTEGER                   4     0 No

G_PARAMETERNAME                SYSIBM    VARCHAR                 128     0 No

G_PARAMETERVALUE               SYSIBM    CLOB                  65536     0 No


  5 record(s) selected.

I'll keep plugging through the code to see if I can spot where that null is coming from.

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Sat, 2006-02-11 21:20

no idea what that change in db2 implies for the returned data etc. can't help you there.
there sure shouldn't be added a terminating ascii 0 character. at least not as part of the string.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 23:00

I think this is another 'ibm_db2' bug. I'm able to reproduce it completely outside of Gallery in a very simple script. When doing SELECT from a CLOB column, the result is fine using ODBC, but has an extra x'0' using ibm_db2'.

C:\MyServer>php testLob.php odbc

API in use = 'odbc'.

Statement = "SELECT col1, col2 FROM mytable".

"database" from VARCHAR is 8 bytes long, "database" from CLOB is 8 bytes long.

C:\MyServer>php testLob.php ibm_db2

API in use = 'db2'.

Statement = "SELECT col1, col2 FROM mytable".

"database" from VARCHAR is 8 bytes long, "database " from CLOB is 9 bytes long.

I'll open a PECL bug for this and keep you posted.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Sat, 2006-02-11 23:14
 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Mon, 2006-02-13 01:24

committed adodb-db2 change (removed that stuff that was from odbc days).
committed sessiontest changes (added $expected3 to error handler).

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 01:41

Thanks. Did you check in the CLOB(64000) change too, or are you waiting for resolution to the 'ibm_db2' bug for that?

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 01:43

Actually, it's CLOB(64K), not CLOB(64000).

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Mon, 2006-02-13 01:46

i guess it's a good idea to wait for the db fix / notice before we use CLOB for the session data. else sessions won't work at all.
please add everything i missed to commit on the codex page.
thanks!

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 02:13

Only thing not yet committed is the CLOB(64K). The way it is now (VARCHAR(8000)) I suspect it should work for most casual users.

I've updated codex accordingly.

Thanks. I'll let you know as soon as I hear anything about the 'ibm_db2' bug.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 17:23

Dan has acknowledged the bug. Hoping for a fix today.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 18:22

CLOB fix has been committed to CVS, just waiting now for the next build snapshot.

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Mon, 2006-02-13 18:38

ok, let me know if the session stuff etc works with CLOB(64K) and if so, i'll commit the change to g2.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 20:04

I got the fixed DLL, and I reinstalled G2, all modules. No error. So far so good.

But the Unit Tests are a complete disaster. After only 80 tests (and 14 new failures), the entire run abruptly stopped.

I'll grab a new build, rebuild the CLOB(64K) change, and look into these.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 21:03

Brand new build, same problem.

I've chosen AdminCoreControllerTest.testChangeCookiePath to debug. I see that it loops around an array of 6 different ['path'] keys.

When I run each of those 6 paths in isolation (comment out the rest), each one of them runs clean.

When I uncomment the first 2 paths, the test reports "Success", but it does generate STORAGE_ERROR_FAILUREs (no DB2 errors).

http://cpe0013102da23b-cm0f0079804905.cpe.net.cable.rogers.com/misc/Gallery2/Gallery%20Unit%20Tests%20-%20testChangeCookiePath%20-%202.htm

When I uncomment the first 3 paths, the test now reports "Failure", I get the same STORAGE_ERROR_FAILUREs, and it now has some DB2 errors (db2_fetch_array()).

http://cpe0013102da23b-cm0f0079804905.cpe.net.cable.rogers.com/misc/Gallery2/Gallery%20Unit%20Tests%20-%20testChangeCookiePath%20-%203.htm

Any words of wisdom as to how to tackle this?

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Mon, 2006-02-13 21:36

@testChangeCookiePath

as you can see, the error comes from

$this->_gs->_traceStart();
	$recordSet = $this->_gs->_db->Execute($query, $data);
	$this->_gs->_traceStop();
	if ($recordSet === false) {
	    return GalleryCoreApi::error(ERROR_STORAGE_FAILURE, __FILE__, __LINE__);
	}

in GalleryStorageExtras::addMapEntry().

so adodb returns false and not a proper result-set / success on the INSERT query.

these look all like pluginParameterMap issues and the parameterValue column is a TEXT column. do you use now CLOB(64K) there too? that could explain things.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 22:06

Yes, it is also CLOB(64K):

C:\MyServer>db2 describe table g2_pluginparametermap

Column                         Type      Type
name                           schema    name               Length   Scale Nulls

------------------------------ --------- ------------------ -------- ----- -----
-
G_PLUGINTYPE                   SYSIBM    VARCHAR                  32     0 No

G_PLUGINID                     SYSIBM    VARCHAR                  32     0 No

G_ITEMID                       SYSIBM    INTEGER                   4     0 No

G_PARAMETERNAME                SYSIBM    VARCHAR                 128     0 No

G_PARAMETERVALUE               SYSIBM    CLOB                  65536     0 No


  5 record(s) selected.


C:\MyServer>db2 describe table g2_sessionmap

Column                         Type      Type
name                           schema    name               Length   Scale Nulls

------------------------------ --------- ------------------ -------- ----- -----
-
G_ID                           SYSIBM    VARCHAR                  32     0 No

G_USERID                       SYSIBM    INTEGER                   4     0 No

G_REMOTEIDENTIFIER             SYSIBM    VARCHAR                 128     0 No

G_CREATIONTIMESTAMP            SYSIBM    INTEGER                   4     0 No

G_MODIFICATIONTIMESTAMP        SYSIBM    INTEGER                   4     0 No

G_DATA                         SYSIBM    CLOB                  65536     0 Yes


  6 record(s) selected.

But if an INSERT is failing, why do I not see an SQL error message to that effect?

And even if I put a debug print() in the Execute() function, I do not see it in the output of the "2 path" scenario. In fact, when I run the "2 path" scenario, I don't see any database activity at all in the trace. All I see are the STORAGE_ERROR_FAILUREs. I see it in the "3 path" scenario, but not the "2 path" scenario.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 22:39

Perhaps this is relevant:

When I take one of the INSERT statements from the trace and try to run it from the command line, I get more constraint violations.

C:\MyServer>db2 INSERT INTO g2_PluginParameterMap (g_pluginType, g_pluginId, g_i
temId, g_parameterName, g_parameterValue) VALUES ('module', 'core', 0, 'reposito
ry.updateTime', '0')
DB21034E  The command was processed as an SQL statement because it was not a
valid Command Line Processor command.  During SQL processing it returned:
SQL0803N  One or more values in the INSERT statement, UPDATE statement, or
foreign key update caused by a DELETE statement are not valid because the
primary key, unique constraint or unique index identified by "1" constrains
table "G2USER.G2_PLUGINPARAMETERMAP" from having duplicate rows for those
columns.  SQLSTATE=23505

I'd like to be able to get that kind of info from the actual test run, but I don't know how.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Mon, 2006-02-13 22:49

Ah-HAA! When I remove the "$this->_gs->_traceStart();" and "$this->_gs->_traceStop();" calls, I can finally see the information I need.

And yes, the problem we're getting *is* constraint violations. I've updated the URLs with the latest trace info:

http://cpe0013102da23b-cm0f0079804905.cpe.net.cable.rogers.com/misc/Gallery2/Gallery%20Unit%20Tests%20-%20testChangeCookiePath%20-%202.htm
http://cpe0013102da23b-cm0f0079804905.cpe.net.cable.rogers.com/misc/Gallery2/Gallery%20Unit%20Tests%20-%20testChangeCookiePath%20-%203.htm

So why are we getting constraint violations? Is there perhaps a DELETE from g2_PluginParameterMap that is not working (and that is not being caught/reported)?

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Tue, 2006-02-14 02:29

I think I might know what's happening.

According to the error message, the unique index being violated is G2_PLUGIA2_26955, consisting of columns G_PLUGINTYPE, G_PLUGINID, G_ITEMID and G_PARAMETERNAME.

Here are the current contents of those columns (where g_parametervalue = '0'):

C:\MyServer>db2 select substr(g_plugintype, 1, 10) as g_plugintype, substr(g_plu
ginid, 1, 10) as g_pluginid, g_itemid, substr(g_parametername, 1, 30) as g_param
etername from g2_pluginparametermap where g_parametervalue like '0'

G_PLUGINTYPE G_PLUGINID G_ITEMID    G_PARAMETERNAME
------------ ---------- ----------- ------------------------------
module       core                 0 exec.beNice
module       core                 0 repository.updateTime
theme        matrix               0 showImageOwner
theme        matrix               0 showMicroThumbs
module       ffmpeg               0 useWatermark

  5 record(s) selected.

That would explain why the "INSERT" I tried above is failing. (The 2nd row would be duplicated.) I've verified that this is also the case for every one of the failing INSERTs.

So, now I'm going to assume that those rows should not already be in the table (please confirm or correct me on that). So why are they there?

Apparently CLOBs cannot be specified in "=" or "IN" or some other literal comparisons (I think we discussed that a while ago too). They can however be used in 'LIKE' comparisons.

For example:

C:\MyServer>db2 select count(*) from g2_pluginparametermap where g_parametervalue = '0'
SQL0401N  The data types of the operands for the operation "=" are not
compatible.  SQLSTATE=42818

C:\MyServer>db2 select count(*) from g2_pluginparametermap where g_parametervalue in '0'
SQL0401N  The data types of the operands for the operation "IN" are not
compatible.  SQLSTATE=42818

C:\MyServer>db2 select count(*) from g2_pluginparametermap where g_parametervalue like '0'

1
-----------
          5

  1 record(s) selected.

So, I suspect there's a "DELETE from G2_PLUGINPARAMETERMAP ..." somewhere that is failing but is not being reported.

Does that sound likely to you? If so, where might that be happening? And if so, would you object to using LIKE?

(Note that we don't have to use wildcards in the LIKE value, we can specify absolute values. But, even so, there is a snag. Certain characters in the G_PARAMETERVALUE values will need to be escaped. In my testing I found that to be true of double-quotes ("), but I presume the same would be true for wildcard characters percent(%) and underscore(_).)

So what do you say? Do you think I'm even close to being on the right track?

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Tue, 2006-02-14 14:32

@ traceStart / traceStop:
enable immediate debug mode to see the output anyway

@duplicate rows:
if we had duplicate OK / UK it would of course be a problem for other DBMS too. we'd get the same error from mysql, pg etc too. but we don't get errors there. maybe you need to do a fresh install.

@ using LIKE instead of = for PluginParameterMap.parameterValue
1. where do we compare its value to something else?
2. generally: replacing = with LIKE "just for DB2" is not an option. maybe we can make an exception somewhere, but there should be very good reasons
3. if we use IN somewhere, replacing it with x times LIKE a OR LIKE b OR ... is obviously also not an option.

oh, i see. we use = and IN in GalleryCoreApi::removeParameterByValue(). darn.
so this means we can't use CLOB for TEXT at least not for PluginParameterMap.

an alternative would be to override GalleryStorage::removeMapEntry in Db2Storage. but duplicating all the logic seems a little expensive and theoretically, there could also be function calls of updateMapEntry() where parameterValue is set. darn.

@bharat:
the curent problem:
In G2 we need a few TEXT columns, that is, columns with up to 64kbyte size, e.g. for the session data and for plugin parameters.
DB2's varchar() type can't be that large. DB2's CLOB(64K) could fill the void but you cannot use a CLOB column in a = or IN(,,,,) comparison. you can use LIKE with CLOB though.
we need the IN and = comparison for PluginParameterMap.parameterValue e.g. for removePluginParameterByValue() but generally it could be used in any update / removeMapEntry call.
we don't need to compare the session data at any time.

so what should we do?
options:
1. in GalleryStorage::removeMapEntry, use LIKE instead of = and LIKE OR LIKE OR LIKE ... instead of IN. i'm -1 for that option. it's slower, and we'd do that just 'cause of DB2 and it affects all DBMS.
2. use DB2's VARCHAR(8000) (or max varchar size) for pluginParameterMap.parameterValue and use CLOB(64K) for SessionMap.data (8000 chars is too short for serialized session data). that would require that we change e.g. the memberType of GallerySession->data to something else than TEXT. or that we introduce other generate-sql changes. also, we'd assume that the PluginParameterMap.parameterValue is always shorter than 8000 characters.
3. duplicate / override removeMapEntry and updateMapEntry in Db2Storage.
4. add a few switches in updateMapEntry / removeMapEntry to give the Db2Storage a chance to replace LIKE with = and IN with a LIKE .. OR LIKE ..OR .. construct

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Tue, 2006-02-14 15:00

Just to add some info to Valiant's option #2... the max length of VARCHAR is 32,672. I don't know if that's long enough for the serialized session data... you'd know better than I would.

Oh and one more thing about that... the total row length cannot exceed the page size of the database (we are currently using the max pagesize: 32k). So the VARCHAR we can use will actually be even less than 32,672 (depending on other columns in the table).

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Tue, 2006-02-14 17:20

After some trial-and-error, I found that I was able install core and all modules with TEST-MEDIUM of VARCHAR(32001). Unit Testing started off pretty well but eventually it blew up too.

I really hope that last schema change of yours was worth it for the product as a whole, because it has really screwed DB2 support. There's no way a change of that magnitude should be done so close to the scheduled ship date. I was soooo close, but now I'm set waaaay back.

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Tue, 2006-02-14 17:39
Quote:
There's no way a change of that magnitude should be done so close to the scheduled ship date.

- scheduled release date is March 1st or 1st week
- sessions change was on January 31st
- we've got a lot of unit tests and a respectable number of nightly snapshots / CVS users, so this should be fine.

of course i'm sorry that this caused delays for the DB2 support, but it is like it is. using the DB for sessions was on our roadmap for a long time and it had a pretty high priority.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Tue, 2006-02-14 18:29

I don't want to debate project management with you, but suffice it to say that I disagree.

While waiting for Bharat's input, I've started investigating the latest unit test failures errors (with VARCHAR(32001)).

First of all, the only way I can get the SQL error is if I remove the $this->_gs->trace*() calls and use setDebug('buffered').

The actual error is:

db2 error: [22001: [IBM][CLI Driver][DB2/NT] SQL0433N Value "Western European (ISO) Hello World Norwegian Norsk Hallo" is too long. SQLSTATE=22001 SQLCODE=-433] in 
EXECUTE("INSERT INTO g2_Item (g_canContainChildren, g_description, g_ownerId, g_summary, g_title, g_viewedSinceTimestamp, g_originationTimestamp, g_id)
VALUES (0,NULL,6,NULL,'Western European (ISO) Hello World Norwegian Norsk Hallo Verden Gallery er så utrolig bra at jeg har satt det opp til flere',1139938452,1139938452,1171)") 

But the length of that string is only 123 bytes, so it should work (the g_title column is VARCHAR(128)).

I can't reproduce this error outside of G2.

C:\MyServer>php testDb2Api.php ibm_db2

API in use = 'db2'.

Processing statement "CREATE TABLE mytable (g_id INTEGER NOT NULL,
                                                     g_cancontainchildren SMALLINT NOT NULL,
                                                     g_description VARCHAR(32001),
                                                     g_keywords VARCHAR(255),
                                                     g_ownerid INTEGER NOT NULL,
                                                     g_summary VARCHAR(255),
                                                     g_title VARCHAR(128),
                                                     g_viewedsincetimestamp INTEGER NOT NULL,
                                                     g_originationtimestamp INTEGER NOT NULL
                                                    )".

Processing statement "INSERT INTO mytable (g_canContainChildren, g_description,
g_ownerId, g_summary, g_title, g_viewedSinceTimestamp, g_originationTimestamp, g_id)
                               VALUES (0,NULL,6,NULL,'Western European (ISO) Hello World Norwegian Norsk Hallo Verden Gallery er så utrolig bra at jeg har sattdet opp til flere',1139938452,1139938452,1171)".

No errors.

Is Gallery modifying the string somehow?

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Tue, 2006-02-14 20:02

I've also added ADOdb support to my test script. The troublesome INSERT statement works even using ADOdb, so that's not the problem either.

C:\MyServer>php testDb2Api.php ADOdb

API in use = 'ADOdb'.

-----
(db2): DROP TABLE mytable
-----
-----
(db2): CREATE TABLE mytable (g_id INTEGER NOT NULL,
                                                     g_cancontainchildren SMALLINT NOT NULL,
                                                     g_description VARCHAR(32001),
                                                     g_keywords VARCHAR(255),
                                                     g_ownerid INTEGER NOT NULL,

                                                     g_summary VARCHAR(255),
                                                     g_title VARCHAR(128),
                                                     g_viewedsincetimestamp INTEGER NOT NULL,
                                                     g_originationtimestamp INTEGER NOT NULL
                                                    )
-----
-----
(db2): INSERT INTO mytable (g_canContainChildren, g_description, g_ownerId, g_summary, g_title, g_viewedSinceTimestamp, g_originationTimestamp, g_id)
                               VALUES (0,NULL,6,NULL,'Western European (ISO) Hello World Norwegian Norsk Hallo Verden Gallery er så utrolig bra at jeg har sattdet opp til flere',1139938452,1139938452,1171)
-----

C:\MyServer>
 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Tue, 2006-02-14 20:04

the string is 123 utf8 multi-byte characters long.
are you sure
- your db is utf8,
- the connection is utf8 (i don't know if the db2 connection needs to be configured) and
- that db2 can store 128 multybyte characters in a varchar(128) field?

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Tue, 2006-02-14 20:29

Yes the database is definitely utf-8, and no there's nothing to do differently at connection time.

As for storing multi-byte characters, I would think that it should work. I haven't seen any doc to the contrary. Plus, like I said, it works fine outside of G2, in my test PHP script.

http://cpe0013102da23b-cm0f0079804905.cpe.net.cable.rogers.com/misc/Gallery2/testDb2Api.php.txt

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Tue, 2006-02-14 20:46

as test string, you should use:

$string =                         "Western European (ISO)\r\n" .
				  "Hello World \r\n" .
				  "Norwegian Norsk\r\n" .
				  "Hallo Verden\r\n" .
				  "Gallery er s\xc3\xa5 utrolig bra at jeg " .
				  "har satt det opp til flere"

that's the string from the unit test.

 
bharat
bharat's picture

Joined: 2002-05-21
Posts: 7994
Posted: Tue, 2006-02-14 21:17

Larry, I screwed you on this one. I pushed valiant to get this change in because session files access is killing performance on larger installs. I didn't realize that it would have such an affect on DB2 -- but in general we do push really hard to have a consistent database abstraction layer specifically so that we can make schema changes like this with little or no pain (or at least find out early if there's going to be pain).

The concept of a "TEXT" column is abstract in G2, but concrete the database. Perhaps we could provide a hint to the database to tell it what type of column to use? Ie we could add a new searchable XML entity, eg:

  <map>
    <map-name>GalleryPluginParameterMap</map-name>
    <schema>
      <schema-major>1</schema-major>
      <schema-minor>3</schema-minor>
    </schema>
    ...
    <member>
      <member-name>parameterValue</member-name>
      <member-type>TEXT</member-type>
      <required empty="allowed"/>
      <searchable/>
    </member>
  </map>

Knowing that GalleryPluginParameterMap::parameterValue is searchable would let us determine that we need to use a VARCHAR(32000) and we could use a CLOB(64K) for the other columns (eg GallerySessionMap::data). Would that work?

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Tue, 2006-02-14 21:20

Ah, OK, that reproduces the problem. (Lesson learned: read the code, not the output.)

Next I doubled the size of g_item (and decreased g_description accordingly), and it worked successfully. Then I queried the length of the string in the database:

C:\MyServer>db2 select length(g_title) from mytable

1
-----------
        131

  1 record(s) selected.

Does that look reasonable to you? If so, then are we looking at simply making g_item larger? If so, how large? (Remember, whatever we add to g_item has to come off g_description because of the 32k row length limit).

Thanks.

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Tue, 2006-02-14 21:24

yep, that could work.
alternatively we could just use varchar(32000) for TEXT columns since i don't think session data will need 64kbyte. well maybe it does. we found out that 8000 chars is not enough. but if 32000 is not enough 64000 is not far away, so we could just try it for db2 with varchar(32000).

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Tue, 2006-02-14 21:33

Hi, Bharat.

I understand that you have requirements, and I know the Gallery code is very nicely modular. But I would think that the database schema would be one of the first things stabilized in a release. That's just based on my own experience in IBM... there were very strict rules regarding when 'database-breaking' changes could be made. Maybe in the 'real' world we just have to take our lumps for the team. ;-)

Sorry but I'm afraid I don't quite follow your suggestion. (I'm not very familiar with XML in general, never mind how G2 uses it.)

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Tue, 2006-02-14 21:41

Isn't that coming at it kind of backwards? The problem is now the length of g_title, not g_description. We need to determine what is a reasonable length for g_title, then adjust g_description to accommodate it.

For example, g_title is currently VARCHAR(128). Should we just double it to VARCHAR(256)? That would mean the max g_description would be VARCHAR(31873).

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Tue, 2006-02-14 21:54

@Norwegian utf8 string:
yes, these are 131 characters.
no, we should not increase the size of the column since the test passes for MySQL and pg and both give a warning when the string that you insert / update is too long (MySQL since version 5 in strict mode).
and our GalleryStorage.class _truncateString function which is called in GalleryStorage::_normalizeValue() should truncate the 131 characters to 128. which works fine, else we'd get errors for pg / mysql 5 too.

so the problem lies somewhere else. maybe you can do a strlen() before and after the truncation in GalleryStorage.class function _normalizeValue(). note that you have to remove traceStart / traceStop in the query to see output generated in normalizeValue.

hmm, maybe better copy the truncate code from GalleryStorge and GalleryUtilities.class to your test script.

@XML changes:
why not try it for now with varchar(3200) for all TEXT columns, ok? i'll gladly change the xml if it is required.

@project management etc:
i agree that we changed a little too much too close before the release this time. we did a much better job at stabilizing before the first release (2.0). but you should not underestimate a) the level of test coverage we get from our unit tests (we require all tests to pass or at least not introduce further failures when committing new code, tested on multiple platforms), and b) the feedback we get during development from our users.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Wed, 2006-02-15 01:23

I've added debug code to GalleryStorage::_normalizeValue() and commented out the traceStart/Stop in the query. I can see quite a few occurrences of output from my debug code, but none of them have anything to do with the Norwegian INSERT failure.

http://cpe0013102da23b-cm0f0079804905.cpe.net.cable.rogers.com/misc/Gallery2/Gallery%20Unit%20Tests%20-%20testImportno_NO.htm

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Wed, 2006-02-15 07:54

yeah, maybe there's another output cache or so.
what about copying the normalize / truncate functions to your test script where you have everything under control?

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Wed, 2006-02-15 17:16

Yeah, will try to do so today.

 
Larry Menard
Larry Menard's picture

Joined: 2005-10-01
Posts: 757
Posted: Wed, 2006-02-15 22:35

OK, I have a script that does not use any database (basically just calls the truncate code from G2). So you can run it too to see if you get different output than I do.

http://cpe0013102da23b-cm0f0079804905.cpe.net.cable.rogers.com/misc/Gallery2/test_utf8Substr.php.txt

I don't really understand some of the truncation though, so I don't know what to expect at any given point in the process.

For example, basically I'm dumping the value of $string after every step of the truncation. I can see how it is changed after calling utf8ToUnicodeEntities(), but after calling the entitySubstr() function, $string is still the same. Does that mean this is where the problem is?

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Wed, 2006-02-15 23:15

first, i gotta correct myself. i counted it with strlen and by hand and the string is indeed just 129 characters long. 1 character too long.
so the truncation is supposed to cut off the last character.

here's my own debug script:
http://gallery.pastebin.com/556797

and it shows that something's odd with that Norwegian string. it seems our truncate function doesn't truncate it correctly.
but i really wonder if that's also what's happening in the unit tests since the tests pass on pg / mysql.