Showing posts with label beta testing. Show all posts
Showing posts with label beta testing. Show all posts

Tuesday, March 24, 2009

Monday, January 26, 2009

I Made the Amazon EC2 Cloud Rain

Sometimes, elastic ain't so elastic.

I got (2) $50 AMEX Gift Cards for my Birthday, which are like feces that can only be exchanged for exactly ${FECES} worth of merchandise (not one dollar more!).

Sure enough, I decide to buy a couple games for my PS3, because it's lonely and nothing I want costs ~$50.00.

I have a credit on my Amazon account for $119.45 (two Christmas returns and three gift certs). After carefully reading Amazon's allowable methods of payment:

Which cards can you use on Amazon.com? We accept the following cards as payment for your orders:

* Visa (including the Amazon.com Visa Card)
* MasterCard/EuroCard
* Discover Network
* American Express
* Diner's Club (U.S. billing addresses only)
* JCB
* Visa or MasterCard check cards or ATM cards
* Visa, MasterCard, or American Express gift cards
* Amazon Credit Account

You can use debit, check, and gift cards issued by the companies above in addition to their standard credit cards. For example, if you're paying with a Visa Check Card please select Visa from the drop-down menu on the order form when indicating the card type. Similarly, if you're paying with a EuroCard or MasterMoney Card, select MasterCard.

If you are using a Visa, MasterCard, or American Express gift card, please note the following restrictions:

* Pre-paid gift cards can't be combined with credit cards on a single order.
* Pre-paid gift cards can't be used to sign up for Amazon Prime membership.
* Amex Gift Cards can't be used to purchase Amazon.com gift cards.


It says I can use an AMEX Gift Card (PayPal says no, but they lie), it says I cannot tender a second credit card with a pre-paid gift card, and I cannot use an AMEX Gift card to buy an Amazon.com gift card.

Knowing the rules, I try to buy a $59.99 game with a $50.00 gift card, assuming the $9.99 can come off the $119.45 Amazon owes me (!). Sure enough, it tries to put the whole amount on the card and closes out the transaction. Five minutes later, I get the "Your Order Has Blown Up" email. I try to explain to Customer Service three times by email (with my good friends Pranvi, Rhett, and Ooshmani) that I read and followed the rules and the payment system exploded. Frustrated, I used the "Call Me now" option, and Caucasian Brian from Seattle called me back.

Over the next 28 minutes, I discovered:
  • There is a bug in the system that Amazon's Customer Service Folk used, that does not show them the proper gift card balance (my $119.45 showed as $0)

  • My CS rep was very knowledgeable, but I taught him that you can't use Amex GCs to buy Amazon.com GCs (when he recommended that could fix this situation

  • Amazon employees cannot, in fact, fix this on their side. They have an extra option on their screen (gift cards), but that doesn't work either. I know this b/c I bought a $15.00 gc while we were on the phone, he tried to apply it, and it wouldn't work. I was able to add it to my account, bringing me up to $134.45

  • Though the pimply douche who makes $7.00/hr at Best Buy can tender two credit cards, the Internet(s) have no such capability. As I told Caucasian Brian: I've only been an Amazon customer since 1999, why should they enhance their checkout process? It's only been 10 years -- they'll catch up to cash registers eventually.

  • In the end, the only way to fix this was to reduce the price until it went through.

I think bug-finding and brow-beating a human-Amazon-employee were far more rewarding that the $10 off my video game. I did fill out a survey and gave him excellent marks, but only because he laughed at my jokes.

Friday, November 14, 2008

gforge hero

We use gforge for our software projects: tracking bugs and feature requests, storing documentation, and a bunch of other silly shit. Gforge is, in my opinion, somewhere between Jira (high end) and Bugzilla (low end) in the usability spectrum for this type of software. Likewise, beef bullion is somewhere between prime rib and feces in my choices for dinner tonight.

On November 6th, like a good project manager, I was cleaning up the enhancement tracker by removing choices from drop downs that aren't valid anymore (we renamed our 2.0.3 release 2.1, so 2.0.4 will now become 2.2), and accidentally deleted the entire enhancement request tracker. The error message doesn't tell you what you're doing (the cranky gforge admin didn't even blame me or say I fucked up), and I'm the fourth person to do this in as many years.

Our RFE tracker is 300+ items, collected over 4+ years, and includes notes, history, status, and all kinds of other information. This was a huge deal. Our system team, unwilling to restore a backup (which would punish everyone by obliterating their work for that day), restored a backup to our QA instance and told me to retype everything from there. I asked for access to the database and said I'd write the fix myself. I'm sure they were like 'whatever...project manager'.

My solution: archive tables and triggers on the 13 tables that hold tracker information (which I reverse engineered though my local backup/restore). Not only could I recover my shit this way, but the next fuckup won't be typing for days for a bad keystroke.

Unlike me -- who has used Oracle, SQL Server, Sybase, DB2, Informix, and MySQL -- gforge uses postgres. That meant I had to teach myself how to code for postgres (which, being based on Ingres, is 80% Oracle and 20% schizophrenic milk man). I could write 5 pages of the sillyness that is postgres (look: I'm Ada-like, but everything is a function, and triggers can't contain the trigger code, they must call a function that returns type trigger). Criminy.

I finally had a good backup and local copy of the db 11-NOV, had the archive table and trigger code written and debugged 12-NOV, and finished all the functions to restore and test by 13-NOV. I tested everything today, and all my codes without a single correction (and my test cases are tight as hell).

Now we just need to "delete" the data from QA, backup/restore the archive tables to production, and use my code to turn hamburger back into cow. I'm no expect, but I think I win.

-----------------------------------------------------------------
-- Table: 1.) deleted_artifact_history
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_history;
CREATE TABLE deleted_artifact_history(
like artifact_history
)
WITH OIDS;
ALTER TABLE deleted_artifact_history OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_history TO postgres;
ALTER TABLE deleted_artifact_history ADD PRIMARY KEY (id);

-- Function: fn_deleted_artifact_history
CREATE OR REPLACE FUNCTION fn_deleted_artifact_history()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_history SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_history on artifact_history
--DROP TRIGGER deleted_artifact_history ON artifact_history;
CREATE TRIGGER deleted_artifact_history
BEFORE DELETE
ON artifact_history
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_history();
-----------------------------------------------------------------
-- Table: 2.) deleted_artifact_file
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_file;
CREATE TABLE deleted_artifact_file(
like artifact_file
)
WITH OIDS;
ALTER TABLE deleted_artifact_file OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_file TO postgres;
ALTER TABLE deleted_artifact_file ADD PRIMARY KEY (id);

-- Function: fn_deleted_artifact_file
CREATE OR REPLACE FUNCTION fn_deleted_artifact_file()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_file SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_file on artifact_file
--DROP TRIGGER deleted_artifact_file ON artifact_file;
CREATE TRIGGER deleted_artifact_file
BEFORE DELETE
ON artifact_file
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_file();
-----------------------------------------------------------------
-- Table: 3.) deleted_artifact_group_list
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_group_list;
CREATE TABLE deleted_artifact_group_list(
like artifact_group_list
)
WITH OIDS;
ALTER TABLE deleted_artifact_group_list OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_group_list TO postgres;
ALTER TABLE deleted_artifact_group_list ADD PRIMARY KEY (group_artifact_id);

-- Function: fn_deleted_artifact_group_list
CREATE OR REPLACE FUNCTION fn_deleted_artifact_group_list()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_group_list SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_group_list on artifact_group_list
--DROP TRIGGER deleted_artifact_group_list ON artifact_group_list;
CREATE TRIGGER deleted_artifact_group_list
BEFORE DELETE
ON artifact_group_list
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_group_list();
-----------------------------------------------------------------
-- Table: 4.) deleted_artifact_extra_field_data
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_extra_field_data;
CREATE TABLE deleted_artifact_extra_field_data(
like artifact_extra_field_data
)
WITH OIDS;
ALTER TABLE deleted_artifact_extra_field_data OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_extra_field_data TO postgres;
ALTER TABLE deleted_artifact_extra_field_data ADD PRIMARY KEY (data_id);

-- Function: fn_deleted_artifact_extra_field_data
CREATE OR REPLACE FUNCTION fn_deleted_artifact_extra_field_data()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_extra_field_data SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_extra_field_data on artifact_extra_field_data
--DROP TRIGGER deleted_artifact_extra_field_data ON artifact_extra_field_data;
CREATE TRIGGER deleted_artifact_extra_field_data
BEFORE DELETE
ON artifact_extra_field_data
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_extra_field_data();
-----------------------------------------------------------------
-- Table: 5.) deleted_artifact_extra_field_list
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_extra_field_list;
CREATE TABLE deleted_artifact_extra_field_list(
like artifact_extra_field_list
)
WITH OIDS;
ALTER TABLE deleted_artifact_extra_field_list OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_extra_field_list TO postgres;
ALTER TABLE deleted_artifact_extra_field_list ADD PRIMARY KEY (extra_field_id);

-- Function: fn_deleted_artifact_extra_field_list
CREATE OR REPLACE FUNCTION fn_deleted_artifact_extra_field_list()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_extra_field_list SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_extra_field_list on artifact_extra_field_list
--DROP TRIGGER deleted_artifact_extra_field_list ON artifact_extra_field_list;
CREATE TRIGGER deleted_artifact_extra_field_list
BEFORE DELETE
ON artifact_extra_field_list
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_extra_field_list();
-----------------------------------------------------------------
-- Table: 6.) deleted_artifact_perm
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_perm;
CREATE TABLE deleted_artifact_perm(
like artifact_perm
)
WITH OIDS;
ALTER TABLE deleted_artifact_perm OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_perm TO postgres;
ALTER TABLE deleted_artifact_perm ADD PRIMARY KEY (id);

-- Function: fn_deleted_artifact_perm
CREATE OR REPLACE FUNCTION fn_deleted_artifact_perm()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_perm SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_perm on artifact_perm
--DROP TRIGGER deleted_artifact_perm ON artifact_perm;
CREATE TRIGGER deleted_artifact_perm
BEFORE DELETE
ON artifact_perm
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_perm();
-----------------------------------------------------------------
-- Table: 7.) deleted_artifact_type_monitor
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_type_monitor;
CREATE TABLE deleted_artifact_type_monitor(
like artifact_type_monitor
)
WITH OIDS;
ALTER TABLE deleted_artifact_type_monitor OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_type_monitor TO postgres;
ALTER TABLE deleted_artifact_type_monitor ADD PRIMARY KEY (group_artifact_id,user_id);

-- Function: fn_deleted_artifact
CREATE OR REPLACE FUNCTION fn_deleted_artifact_type_monitor()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_type_monitor SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_type_monitor on artifact_type_monitor
--DROP TRIGGER deleted_artifact_type_monitor ON artifact_type_monitor;
CREATE TRIGGER deleted_artifact_type_monitor
BEFORE DELETE
ON artifact_type_monitor
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_type_monitor();
-----------------------------------------------------------------
-- Table: 8.) deleted_artifact_query
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_query;
CREATE TABLE deleted_artifact_query(
like artifact_query
)
WITH OIDS;
ALTER TABLE deleted_artifact_query OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_query TO postgres;
ALTER TABLE deleted_artifact_query ADD PRIMARY KEY (artifact_query_id);

-- Function: fn_deleted_artifact_query
CREATE OR REPLACE FUNCTION fn_deleted_artifact_query()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_query SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_query on artifact_query
--DROP TRIGGER deleted_artifact_query ON artifact_query;
CREATE TRIGGER deleted_artifact_query
BEFORE DELETE
ON artifact_query
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_query();
-----------------------------------------------------------------
-- Table: 9.) deleted_artifact_query_fields
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_query_fields;
CREATE TABLE deleted_artifact_query_fields(
like artifact_query_fields
)
WITH OIDS;
ALTER TABLE deleted_artifact_query_fields OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_query_fields TO postgres;
ALTER TABLE deleted_artifact_query_fields ADD PRIMARY KEY (artifact_query_id, query_field_type, query_field_id);

-- Function: fn_deleted_artifact_query_fields
CREATE OR REPLACE FUNCTION fn_deleted_artifact_query_fields()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_query_fields SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_query_fields on artifact_query_fields
--DROP TRIGGER deleted_artifact_query_fields ON artifact_query_fields;
CREATE TRIGGER deleted_artifact_query_fields
BEFORE DELETE
ON artifact_query_fields
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_query_fields();
-----------------------------------------------------------------
-- Table: 10.) deleted_artifact_monitor
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_monitor;
CREATE TABLE deleted_artifact_monitor(
like artifact_monitor
)
WITH OIDS;
ALTER TABLE deleted_artifact_monitor OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_monitor TO postgres;
ALTER TABLE deleted_artifact_monitor ADD PRIMARY KEY (artifact_id, user_id);

-- Function: fn_deleted_artifact_monitor
CREATE OR REPLACE FUNCTION fn_deleted_artifact_monitor()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_monitor SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_monitor on artifact_monitor
--DROP TRIGGER deleted_artifact_monitor ON artifact_monitor;
CREATE TRIGGER deleted_artifact_monitor
BEFORE DELETE
ON artifact_monitor
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_monitor();
-----------------------------------------------------------------
-- Table: 11.) deleted_artifact_message
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_message;
CREATE TABLE deleted_artifact_message(
like artifact_message
)
WITH OIDS;
ALTER TABLE deleted_artifact_message OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_message TO postgres;
ALTER TABLE deleted_artifact_message ADD PRIMARY KEY (id);

-- Function: fn_deleted_artifact_message
CREATE OR REPLACE FUNCTION fn_deleted_artifact_message()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_message SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_message on artifact_message
--DROP TRIGGER deleted_artifact_message ON artifact_message;
CREATE TRIGGER deleted_artifact_message
BEFORE DELETE
ON artifact_message
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_message();
-----------------------------------------------------------------
-- Table: 12.) deleted_artifact_counts_agg
-----------------------------------------------------------------
--DROP TABLE deleted_artifact_counts_agg;
CREATE TABLE deleted_artifact_counts_agg(
like artifact_counts_agg
)
WITH OIDS;
ALTER TABLE deleted_artifact_counts_agg OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact_counts_agg TO postgres;
ALTER TABLE deleted_artifact_counts_agg ADD PRIMARY KEY (group_artifact_id);

-- Function: fn_deleted_artifact_counts_agg
CREATE OR REPLACE FUNCTION fn_deleted_artifact_counts_agg()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact_counts_agg SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact_counts_agg on artifact_counts_agg
--DROP TRIGGER deleted_artifact_counts_agg ON artifact_counts_agg;
CREATE TRIGGER deleted_artifact_counts_agg
BEFORE DELETE
ON artifact_counts_agg
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact_counts_agg();
-----------------------------------------------------------------
-- Table: 13.) deleted_artifact
-----------------------------------------------------------------
--DROP TABLE deleted_artifact;
CREATE TABLE deleted_artifact(
like artifact
)
WITH OIDS;
ALTER TABLE deleted_artifact OWNER TO postgres;
GRANT ALL ON TABLE deleted_artifact TO postgres;
ALTER TABLE deleted_artifact ADD PRIMARY KEY (artifact_id);

-- Trigger: deleted_artifact_update_last_modified_date on deleted_artifact
--DROP TRIGGER deleted_artifact_update_last_modified_date ON deleted_artifact;
CREATE TRIGGER deleted_artifact_update_last_modified_date
BEFORE INSERT OR UPDATE
ON deleted_artifact
FOR EACH ROW
EXECUTE PROCEDURE update_last_modified_date();

-- Function: fn_deleted_artifact
CREATE OR REPLACE FUNCTION fn_deleted_artifact()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_artifact SELECT OLD.*;
RETURN OLD;
END;
$BODY$
LANGUAGE 'plpgsql';

-- Trigger: deleted_artifact on artifact
--DROP TRIGGER deleted_artifact ON artifact;
CREATE TRIGGER deleted_artifact
BEFORE DELETE
ON artifact
FOR EACH ROW
EXECUTE PROCEDURE fn_deleted_artifact();

and..
-----------------------------------------------------------------
-- Test Case: I. Archive Deleted Records
-- Precondition 1) Deleted tables have 0 records
-- 2) Artifact tables have N records
-- Postcondition 1) Deleted tables have N records
-- 2) Artifact tables reduced by N records
-- Execution 1) In isolation (from SQL prompt)
-- 2) Through gforge GUI
-----------------------------------------------------------------
-----------------------------------------------------------------
-- Test Case: II. Restore Deleted Records
-- Precondition: 1) Deleted tables have X records
-- 2) Artifact tables have Y records
-- Postcondition 1) Deleted tables have 0 records
-- 2) Artifact tables = X + Y records
-- Execution 1) In isolation (from SQL prompt)
-- 2) Through gforge GUI
-----------------------------------------------------------------
CREATE TABLE testRecordCount (
run_type varchar,
artifact integer NOT NULL,
d_artifact integer NOT NULL,
a_history integer NOT NULL,
d_a_history integer NOT NULL,
a_file integer NOT NULL,
d_a_file integer NOT NULL,
a_extra_field_data integer NOT NULL,
d_a_extra_field_data integer NOT NULL,
a_group_list integer NOT NULL,
d_a_group_list integer NOT NULL,
a_perm integer NOT NULL,
d_a_perm integer NOT NULL,
a_type_monitor integer NOT NULL,
d_a_type_monitor integer NOT NULL,
a_query integer NOT NULL,
d_a_query integer NOT NULL,
a_query_fields integer NOT NULL,
d_a_query_fields integer NOT NULL,
a_monitor integer NOT NULL,
d_a_monitor integer NOT NULL,
a_message integer NOT NULL,
d_a_message integer NOT NULL,
a_counts_agg integer NOT NULL,
d_a_counts_agg integer NOT NULL,
run_date date NOT NULL DEFAULT now()
);

CREATE OR REPLACE FUNCTION populateTestRecordCount (notes varchar, tracker_id int)
RETURNS VOID AS $$
DECLARE
v_artifact int;
v_d_artifact int;
v_a_history int;
v_d_a_history int;
v_a_file int;
v_d_a_file int;
v_a_extra_field_data int;
v_d_a_extra_field_data int;
v_a_group_list int;
v_d_a_group_list int;
v_a_perm int;
v_d_a_perm int;
v_a_type_monitor int;
v_d_a_type_monitor int;
v_a_query int;
v_d_a_query int;
v_a_query_fields int;
v_d_a_query_fields int;
v_a_monitor int;
v_d_a_monitor int;
v_a_message int;
v_d_a_message int;
v_a_counts_agg int;
v_d_a_counts_agg int;
BEGIN
-----------------------------------------------------------------
-- Artifact Tables
-----------------------------------------------------------------
select into v_artifact count(*) from artifact; --where group_artifact_id=tracker_id;
select into v_a_history count(*) from artifact_history;
--where artifact_id in (select artifact_id from artifact where group_artifact_id=tracker_id);
select into v_a_file count(*) from artifact_file;
--where artifact_id in (select artifact_id from artifact where group_artifact_id=tracker_id);
select into v_a_extra_field_data count(*) from artifact_extra_field_data;
--where artifact_id in (select artifact_id from artifact where group_artifact_id=tracker_id);
select into v_a_group_list count(*) from artifact_group_list; --where group_artifact_id=tracker_id;
select into v_a_perm count(*) from artifact_perm; --where group_artifact_id=tracker_id;
select into v_a_type_monitor count(*) from artifact_type_monitor; --where group_artifact_id=tracker_id;
select into v_a_query count(*) from artifact_query; --where group_artifact_id=tracker_id;
select into v_a_query_fields count(*) from artifact_query_fields;
--where artifact_query_id in (select artifact_query_id from artifact_query where group_artifact_id=tracker_id);
select into v_a_monitor count (*) from artifact_monitor;
select into v_a_message count (*) from artifact_message;
select into v_a_counts_agg count (*) from artifact_counts_agg;
-----------------------------------------------------------------
-- Deleted Tables
-----------------------------------------------------------------
select into v_d_artifact count(*) from deleted_artifact where group_artifact_id=tracker_id;
select into v_d_a_history count(*) from deleted_artifact_history where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
select into v_d_a_file count(*) from deleted_artifact_file where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
select into v_d_a_extra_field_data count(*) from deleted_artifact_extra_field_data where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
select into v_d_a_group_list count(*) from deleted_artifact_group_list where group_artifact_id=tracker_id;
select into v_d_a_perm count(*) from deleted_artifact_perm where group_artifact_id=tracker_id;
select into v_d_a_type_monitor count(*) from deleted_artifact_type_monitor where group_artifact_id=tracker_id;
select into v_d_a_query count(*) from deleted_artifact_query where group_artifact_id=tracker_id;
select into v_d_a_query_fields count(*) from deleted_artifact_query_fields where artifact_query_id in (
select artifact_query_id from deleted_artifact_query where group_artifact_id=tracker_id
);
select into v_d_a_monitor count (*) from deleted_artifact_monitor;
select into v_d_a_message count (*) from deleted_artifact_message;
select into v_d_a_counts_agg count (*) from deleted_artifact_counts_agg;
-----------------------------------------------------------------
-- Populate Test Table with Counts
-----------------------------------------------------------------
INSERT INTO testRecordCount (
run_type, artifact, d_artifact, a_history, d_a_history,
a_file, d_a_file, a_extra_field_data, d_a_extra_field_data,
a_group_list, d_a_group_list, a_perm, d_a_perm,
a_type_monitor, d_a_type_monitor, a_query, d_a_query,
a_query_fields, d_a_query_fields, a_monitor, d_a_monitor,
a_message, d_a_message, a_counts_agg, d_a_counts_agg
) VALUES (
notes, v_artifact, v_d_artifact, v_a_history, v_d_a_history,
v_a_file, v_d_a_file, v_a_extra_field_data, v_d_a_extra_field_data,
v_a_group_list, v_d_a_group_list, v_a_perm, v_d_a_perm,
v_a_type_monitor, v_d_a_type_monitor, v_a_query, v_d_a_query,
v_a_query_fields, v_d_a_query_fields, v_a_monitor, v_d_a_monitor,
v_a_message, v_d_a_message, v_a_counts_agg, v_d_a_counts_agg
);
END;
$$ LANGUAGE 'plpgsql';

-----------------------------------------------------------------
-- Test Deleting Records
-----------------------------------------------------------------
CREATE OR REPLACE FUNCTION testRecordDelete (tracker_id int)
RETURNS VOID AS $$
BEGIN
-----------------------------------------------------------------
-- artifact_history, file, and extra_field_data have fk's to artifact
-----------------------------------------------------------------
delete from artifact_history where artifact_id in (
select artifact_id from artifact where group_artifact_id=tracker_id
);
delete from artifact_file where artifact_id in (
select artifact_id from artifact where group_artifact_id=tracker_id
);
delete from artifact_extra_field_data where artifact_id in (
select artifact_id from artifact where group_artifact_id=tracker_id
);
delete from artifact_monitor where artifact_id in (
select artifact_id from artifact where group_artifact_id=tracker_id
);
delete from artifact_message where artifact_id in (
select artifact_id from artifact where group_artifact_id=tracker_id
);
delete from artifact where group_artifact_id=tracker_id;
-----------------------------------------------------------------
-- group_list, perm, type_monitor, counts_agg are straight forward
-----------------------------------------------------------------
delete from artifact_perm where group_artifact_id=tracker_id;
delete from artifact_group_list where group_artifact_id=tracker_id;
delete from artifact_type_monitor where group_artifact_id=tracker_id;
delete from artifact_counts_agg where group_artifact_id=tracker_id;
-----------------------------------------------------------------
-- query_history needs query to turn hamburger back into cow
-----------------------------------------------------------------
delete from artifact_query_fields where artifact_query_id in (
select artifact_query_id from artifact_query where group_artifact_id=tracker_id
);
delete from artifact_query where group_artifact_id=tracker_id;
END;
$$ LANGUAGE 'plpgsql';

-----------------------------------------------------------------
-- Restore Records
-----------------------------------------------------------------
CREATE OR REPLACE FUNCTION RecordRestore (tracker_id int)
RETURNS VOID AS $$
BEGIN
-----------------------------------------------------------------
-- artifact_group_list (disable trigger before restore)
-----------------------------------------------------------------
alter table artifact_group_list disable trigger artifactgrouplist_insert_trig;
insert into artifact_group_list select * from deleted_artifact_group_list where group_artifact_id=tracker_id;
alter table artifact_group_list enable trigger artifactgrouplist_insert_trig;
delete from deleted_artifact_group_list where group_artifact_id=tracker_id;
-----------------------------------------------------------------
-- artifact_query & artifact_query_fields
-----------------------------------------------------------------
insert into artifact_query select * from deleted_artifact_query where group_artifact_id=tracker_id;
insert into artifact_query_fields select * from deleted_artifact_query_fields where artifact_query_id in (
select artifact_query_id from deleted_artifact_query where group_artifact_id=tracker_id
);
delete from deleted_artifact_query_fields where artifact_query_id in (
select artifact_query_id from deleted_artifact_query where group_artifact_id=tracker_id
);
delete from deleted_artifact_query where group_artifact_id=tracker_id;
-----------------------------------------------------------------
-- artifact_perm & artifact_type_monitor
-----------------------------------------------------------------
insert into artifact_counts_agg select * from deleted_artifact_counts_agg where group_artifact_id=tracker_id;
insert into artifact_perm select * from deleted_artifact_perm where group_artifact_id=tracker_id;
insert into artifact_type_monitor select * from deleted_artifact_type_monitor where group_artifact_id=tracker_id;
delete from deleted_artifact_counts_agg where group_artifact_id=tracker_id;
delete from deleted_artifact_perm where group_artifact_id=tracker_id;
delete from deleted_artifact_type_monitor where group_artifact_id=tracker_id;
-----------------------------------------------------------------
-- fish desired records out of deleted_artifact, restore, clean up
-----------------------------------------------------------------
insert into artifact select * from deleted_artifact where group_artifact_id=tracker_id;
insert into artifact_history select * from deleted_artifact_history where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
insert into artifact_file select * from deleted_artifact_file where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
insert into artifact_extra_field_data select * from deleted_artifact_extra_field_data where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
insert into artifact_monitor select * from deleted_artifact_monitor where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
insert into artifact_message select * from deleted_artifact_message where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
delete from deleted_artifact_message where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
delete from deleted_artifact_monitor where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
delete from deleted_artifact_extra_field_data where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
delete from deleted_artifact_file where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
delete from deleted_artifact_history where artifact_id in (
select artifact_id from deleted_artifact where group_artifact_id=tracker_id
);
delete from deleted_artifact where group_artifact_id=tracker_id;
END;
$$ LANGUAGE 'plpgsql';

Wednesday, November 12, 2008

iPhone App: Kitten Escape


It is a game that moves the block, and goes out of the kitten that has been confined. Kitten Escape is said "Daughter in the Box" of classical slide puzzle game.


Kitten reminds me of my old friend, CATS...



You have no chance to survive. Make your time. Haha!

Friday, October 24, 2008

Google News, Finance need to stop ignoring each other

I found yet another bug in Google News. To give some content, the stock market is down a shit-ton right now. I head over to GNews and see:



That the DJ closed UP 172 points? But it's the middle of the trading day, and doom is everywhere. Let's ask Google Finance:



Oh nevermind, it's DOWN 373 points!

Honest mistake for 3 year old betaware.

Thursday, October 02, 2008

Found a Bug in HSBC Online Banking


I bank with Bank of America, but my savings is with Citibank because (1) better interest rate, and (2) there is a branch close to my house. With my savings, I prefer to swing by the branch and make my deposits (it's like putting money in a piggy bank...oink). With the exception of savings and my safe deposit box, I do everything else online.

In August, I opened up an HSBC credit card to pay for the deck: it's 0% interest for 12 months, so I figured I'd passively do some credit card arbitrage and make interest for a year on the balance.

Since a brand new HSBC branch opened about a mile from house this summer, and their savings rate is about a point higher than Citibank, I decided on 26-September to open an online savings account and a CD.

I actually have three (3) checking accounts at BofA, with the so-called primary account just trafficking my mortgage (money in, payments out). I indicated on the application for HSBC to fund the initial deposit from my 2nd BofA account, and to verify online (instead of a trial deposit). This lets you enter your online banking credentials so it can make sure you're who you say you are (much like Quicken or MS Money, both of which suck).

I clickity-click in my bank information, and it fails twice, then tells me it's going to go ahead and do trial deposits. Yesterday, I receive an email that my trial deposits are there, and to verify them so it can fund my new accounts.

I log in to BofA, and the trial deposits aren't in account #2, they're in account #1. It failed b/c the account I request to use in the online verification is not the primary for my online banking account.

I sent an email to HSBC this morning, but I have not received a response. I called their 800-number (which sounds to be in Bangalore), and was told I entered the wrong account number. I described what happened in exacting detail, but the rep kept arguing that I put in that account number (yes, you're right, I typed in an account number I don't know, instead of the one I use all the time). My options were to mail in a check, or have my application deleted and start over.

As you can imagine, I had the application deleted, but I won't be starting over (with them).

Wednesday, June 18, 2008

Firefox 3

The new version of Firefox was released today, and I already found a bug. Please take a moment to login to Mozilla's Bugzilla (or create an account) and vote for it to be fixed.

My three-day streak of technology destruction continues.

Monday, June 16, 2008

Your call cannot be completed as dialed

35 days ago, my Sony w810i jumped in a puddle. In the smoothest insurance claim in the history of cell phones, I received a new Sony w580i as a replacement just two days later.

The phone worked flawlessly for 33 days, then froze today while I was writing a text message.

So I will be leaving work early today to go to the mysterious AT&T depot, where it will either be replaced by a working w580i, or Foldger's crystals.

Wednesday, May 28, 2008

Software Update



I downloaded the new Mac OS update today. Let's see how my MBP feels about it.

General

* Fixes a font issue that could result in Helvetica Narrow being used in applications instead of Helvetica.
* Addresses an issue with stuttering video and audio playback in certain USB devices.
* Resolves stability issues with Word of the Day, iTunes Artwork, and Slideshow screen savers.
* Fixes an issue in which certain attached hard drives may not show up in the Finder.
* Addresses an issue with .Mac syncing of Dashboard widgets over multiple Macs that use different screen resolutions.
* Includes additional RAW image support for several cameras.
* Improves the accuracy of the Software Update progress bar indicator.
* Addresses an issue in which Finder may not be available if the computer name is blank in Sharing preferences.
* Improves Active Directory binding and login.
* Eliminates a delay when logging in as an Active Directory user in a .local domain.
* Improves Spotlight searches on a AFP file server volumes.
* Clients can now change their password at the login window when bound to a Mac OS X 10.4 Open Directory server.
* Improves Safari reliability when connecting to the Internet through a Microsoft ISA proxy.

AirPort

* Improves 802.1X behavior and reliability.
* Improves reliability when using Time Capsule.

Spaces

* Resolves an issue in which switching to a different space and returning back to the original space may reorder the application windows with a different active window.
* Resolves an issue in which activating an application from the Dock switches to a different space, even if there is a window for that application in the current space.
* Fixes an issue in which Command-Tab may incorrectly switch to a new space.
* Addresses reliability issues with Spaces when syncing preferences over .Mac.

Time Machine

* Includes fixes for Time Machine compatibility with Time Capsule.
* Resolves certain issues when backing up a portable Mac that is on battery power.
* Addresses compatibility issues with Aperture 2.
* Addresses reliability issues when performing a full restore from a Time Machine backup.
* Fixes an issue in which certain function keys may be disabled after using Time Machine.
* Fixes a possible alert message that incorrectly states a backup volume does not have enough space.
* Updates Time Machine to reliably restore attachments and messages in Mail.


Thank the Baby Jeebus that the Software Update Progress Bar is now more accurate!

Thursday, January 03, 2008

Me thinks its a Bug

An email that I was CC'ed on today:

We measured caCTUS-Lite performance in a Dev server by loading protocols incrementally. For each protocol we add we insert a protection element in CSM table.

Here is the login duration results:


Here is the code snippet which we reviewed during our last meeting. This getProtectionElementPrivilegeContextForUser is invoked during the login process.

UserProvisioningManager upManager = SecurityServiceProvider.getUserProvisioningManager(Constant.APPLICATION_NAME);

User user = upManager.getUser(userId);

Collection pepcCollection = upManager.getProtectionElementPrivilegeContextForUser(user.getUserId().toString());

Saturday, October 20, 2007

Monday, October 15, 2007

Happy Monday!

My Powerbook just made this cranky face:



and now it won't boot.

I have a burning bag of dog shit project I inherited three weeks ago that goes live this Sunday, along with two midterms and two group projects this week. A dead laptop is the last thing I need.

It's time for lunch: Maybe if I'm lucky, a Metro Bus will run me over on an empty stomach.

Thursday, October 04, 2007

Useless Trivia


Yes, I am in fact browsing with a Mac.

Saturday, September 29, 2007

I hx0r3d my DVR

The DVR first entered my house on December 28, 2002 when I purchased a ReplayTV 5040. I think I've watched less than 15 commercials in the past five years.

I have DirecTV, but the ReplayTV doesn't know how to change the channels on the new D10 receivers they use. In April 2006, when I had a PC in the house, I followed the 87-step process the Internet(s) outline to load new IR codes to change channels on the D10.

My parents purchased their own ReplayTV in 2004, but abandoned it after some problems it in favor of a DVR from their cable company. I took their unit home last September, and after replacing the hard drive it was as good as new EXCEPT it did not have the update to change the channels.

Finally fed up, I decided two days ago to find the magic process on the Internet(s) to update the ReplayTV in my bedroom so it can change the channels on the box (otherwise, it can't record anything unless I've changed the channel on the box beforehand).

Without boring you (further) with the details, it was unbelievably complex. The only PC I have in the house that I could put a hard drive into is my server. My laptop is a Mac, but all the fucking software to do the updates is PC-based.

Solution?

You guessed it fool: mother fucking Virtual PC:



!!!

Fucking ridiculous.

Nerdier than when When I hx0r3d my cell phone to enable bluetooth.

Tuesday, September 25, 2007

Chivalry?


Unless the rules of English changed, that is not the correct sort-order.

Monday, September 17, 2007

Fuck you, iPhone; I know this is your fault!


It appears that Apple changed the sort order in iTunes for version 7.3 and above:

iTunes 7.3: Changes in music sort order

Starting with iTunes version 7.3, the following sort order is implemented:
General ordering

* Letters & Unicode characters (except for digits)
* Digits
* Other

Ignore leading definite and indefinite articles

* "The Beatles" sorts as "Beatles"
* "A Night in Tunisia" sorts as "Night in Tunisia"

Note: In English these are "A ", "An ", and "The " and includes the localized or international equivalents.
Ignore leading symbols and punctuation

* "#41"sorts as "41"
* " ' Til I Collapse " sorts as "Til I Collapse"

Sort digits numerically

The songs "1 foo", "2 foo", "10 foo" will sort as
"1 foo", "2 foo", "10 foo" and not as
"1 foo", "10 foo", "2 foo"
Ignore leading white space when sorting

Any spaces entered at the beginning of the title will be ignored when sorting.
Sort ignoring case

For example with iTunes 7.2 and older versions, the song playlist sorts in the following order:

* .38 Special
* 'Til Tuesday
* "Weird Al" Yankovic
* 4 Non Blondes
* The 5th Dimension
* 311
* Oingo Boingo
* ZZ Top
* つしまみれ

With iTunes 7.3 and newer versions, the song playlist sorts in the following order:

* Oingo Boingo
* 'Til Tuesday
* "Weird Al" Yankovic
* ZZ Top
* 4 Non Blondes
* The 5th Dimension
* .38 Special
* 311
* つしまみれ

Note: If you sort a playlist and sync it to an iPod, the sort order from iTunes will be retained.

If you want to override the default sort rules for a given artist or song, follow these steps:

1. Get Info on a song and click the Sorting tab.
2. Enter the text in the appropriate sorting field. If you want "The Beatles" to sort by "The Beatles" instead of "Beatles" you would enter "The Beatles" in the Sort Artist Field.
3. Click OK.
4. To apply that change to all of the songs by "The Beatles", right-click (or Control-click) the song that you just changed and choose Apply Sort Field > [relevant field] (using the example above, Same Artist).


I'm glad somebody asked me if I wanted to change the fucking sort order. I've only been using iTunes since 2003 -- it's not like I'm used to a certain behavior.

Fucking savages.

Monday, June 25, 2007

I don't find bugs, bugs find me

I found two bugs today, the first was in our own Patriotweb, and the second was in Bank of America's website.

I got a notice from my MKTG301 professor that grades were posted. When I checked in Patriotweb, no grade:



but then I ran a detailed degree requirements analysis, and there's my grade:



Hi, I'm referential integrity. Have we met??

Next, fucking BofA's shitface website redesign is driving me insane. I receive my statements electronically, but the account I need to see my electronic statements for shows nothing online (the account I could care less about, however, has eStatements). Dandy. So I email my premier banking droid and ask if that can be regenerated.

What I need to see are my ending balances for the past 6-12 months. Then I realize that the last transaction each month is my Interest Earned, so I search for that:



no God damned balances. Look again in the transaction listings:



and there's the balance. It's the same fucking transaction, and there's even a balance column in the quick search results (it's just empty).

Too bad there's no way to send useful feedback to the useless web designers who clearly forgot to do any requirements analysis before they rushed this shit out the door.

Friday, March 23, 2007

All I really need to know about ColdFusion I had to fucking teach myself

Let's start with what we know:
  • The content management system that we purchased is written in ColdFusion. CMS runs on Windows, Linux, and Solaris and it can use Oracle, SQL Server, or mySQL for its database.

  • ColdFusion was a Macromedia product until they were purchased by Adobe. While there is a free developer/trail edition you can download, ColdFusion needs to be licensed for use, and that only covers installation support. You need to buy a support plan for any further assistance.

  • ColdFusion has its own built-in web server that is unsupported for production deployments.

  • ColdFusion is now a J2EE server application, and needs to run inside a full J2EE server (it's deployed as either an EAR or a WAR.

  • SunOne is a full J2EE server, but is only supported as a web server and not an application server (which makes no sense). To deploy ColdFusion with SunOne, it needs to be run inside Adobe's JRun.

  • The latest and greatest version of JRun uses Java 1.4.2_09, which is not compliant with the Energy Policy Act of 2005.

  • ColdFusion connects to the database via JDBC. ColdFusion and JRun use Data Direct's JDBC Drivers to provide that connectivity.

  • The latest and greatest version of ColdFusion, version 7.02, ships with version 3.3 of the Data Direct Drivers, which do not support Oracle 10gR2 (the latest and greatest version of Oracle). We had to update to Data Direct 3.5 to get ColdFusion working with Oracle 10gR2.

So far, not worth its own blog post, is it? Update the drivers and move on.

My last three weeks of problems have centered around this Adobe technote about updating the JDBC drivers.

To install the new DataDirect database drivers, follow the instructions in the appropriate section below.

[...]

JRun 4

1. Stop JRun 4.
2. Backup your existing macromedia_drivers.jar file.
3. Unzip macromedia_drivers.zip into the same directory, overwriting the previous macromedia_drivers.jar.
A new file, DDJDBCAuth03.dll, which is required for Windows Authentication, is also included in the zip file replacing the older DDJDBCAuth.DLL.

Note: java.library.path must be modified (either in the jvm.config file or through the JMC) to include {application.home}/lib so that DDJDBCAuth03.DLL loads correctly.
4. Restart JRun 4.

JRun uses the JDBC drivers in macromedia_drivers.jar in /jrun4/lib. For example, with JRun 4 on Windows installed on drive C:, this would be C:\JRun4\lib\macromedia_drivers.jar.

This looks pretty straight forward, and only took me five minutes to complete. I toiled with the same performance problem I was having for another week or so until the CMS vendor provided a piece of test code that showed we were still running Data Direct 3.3.

::scratches head::

Remember up above where I said that ColdFusion is deployed as either an EAR or a WAR file? It turns out that the driver is actually in two places:

cmsadmin@zetes2$ find . -name macromedia_drivers.jar -print
./lib/macromedia_drivers.jar
./servers/cfusion/cfusion-ear/cfusion-war/WEB-INF/cfusion/lib/macromedia_drivers.jar

To really update the drivers, and not just hope the Java class loader picks the right one, I had to:
  • Start JRun and ColdFusion, which explodes the archive and deploys the application.

  • Find the compiled driver file inside the archive and replace it with the updated version.

  • Shutdown and restart JRun and CF.

Lo and behold, suddenly my test code shows my data sources are running Data Direct 3.5; good start.

The actual problem that started this was installing the CMS demo site. Since this product is repository-independent (like every other chicken-shit vendors), the demo site is created by a bunch of CFQUERY tags inside the page you install from: You browse to page, point it to the database, push a button, and it makes with the CREATE TABLE...INSERT INTO TABLE...BEEP BEEP...BLINK BLINK...for a couple minutes until viola!

Only when I tried, it blew up. I reset and tried again, and it blew up. I turned on debugging, reset, tried again, and it blew up. The first day I had this problem, my install abended eleven times. Over the course of several weeks, no less than forty times: setup, go, explode.

The problem? After inserting about 1800 records, the database server would run to a point and then stop to wait for the web server to say "ready for more? let's go". While the database server waited for an ack from the web server, the web server sat there waiting for the database server to tell it "I finished inserting those records, what now?". Which, if you care, looks something like this:


He's watching football, she's doing Sudoku; neither one is really listening to the other.

The CMS vendor has no idea what the problem is, and in fairness they probably shouldn't. The problem is three layers of middleware down in the JDBC drivers that Macromedia (who is now owned by Adobe) licensed from Data Direct to bundle with JRun and ColdFusion.

Does your head hurt yet?

To further troubleshoot this, I had our DBAs do SQL traces on their side (which is where that screen shot came from) while I did JDBC traces on the web server side. Here's where the second problem in that technote bites me in the ass:

JDBCSpy built into the driver

Spy passes calls issued by a running application to an underlying DataDirect Connect for JDBC driver and logs detailed information about those calls, information you can use for troubleshooting problems. Configuration requires addingSpyAttributes to the JDBC URL through the "Connection String" field. [My emphasis] Unfortunately, due to bug 60098, the "Connection String" field doesn't work for Oracle, SQL Server, Sybase or Informix built-in drivers.

Yes, how unfortunate for me and everyone else in the world. What the fuck database isn't on that list? Access?

Now I need to fist the enchanted goat in order to get any useful debugging information. Here's where it gets better:

For these drivers, users need to create an "Other" type data source and fill in all the data source parameters manually.

For ODBC Socket and DB2 (7.0.1):

Add the following parameters to the data source Connection String field: [...]

Seems helpful enough, until you realize that the parameters they've laid out for you aren't actually all the parameters that you need to fill in. I had to play trial-and-error for 25 minutes to guess what the correct parameters were. It gets even better because here is their example of an Oracle connect string:

For Oracle, SQL Server, Sybase and Informix:
JDBCSpy URL for "other" type data sources:

jdbc:macromedia:oracle://Server1:1521;serviceName=ORCL;SpyAttributes=(log=(file)C:\\temp\\spy.log;logTName=yes;timestamp=yes)


Wait for it...

The fucking syntax is wrong!

Barry found Data Direct's Manual for their JDBC drivers on March 8th, so I dug through that to find that the parameter is NOT serviceName=[] it's SID=[].


How hard would it be to add a screen shot so you know NOT to fill in the "Driver Name" with "Oracle"? If you do, it's no longer type "OTHER" and JDBCSpy won't log your transactions.

The log files it generated were as worthless as they were voluminous, except to show it stopped at exactly the same insert statement every single time:

spy(jrpp-3)(2007/03/21 17:48:10.004)>> Statement[1435].execute(String sql)
spy(jrpp-3)(2007/03/21 17:48:10.004)>> sql = INSERT INTO ControlInstance
(CONTROLID,CONTROLTYPE,CREATIONDATE,INHERITED,OWNERID,PAGEID,PARENTCONTROLID,PARENTCONTROLTYPE)
VALUES
(1541,26,'2004-06-15 10:43:34',0,1000002,857,1185,1)

spy(Finalizer)(2007/03/21 17:49:54.043)>> Connection[3].setAutoCommit(boolean autoCommit)
spy(Finalizer)(2007/03/21 17:49:54.043)>> autoCommit = true
spy(Finalizer)(2007/03/21 17:49:54.043)>> java.sql.SQLException: [Macromedia][Oracle JDBC Driver]Object has been closed. ErrorCode=0 SQLState=HY000
java.sql.SQLException: [Macromedia][Oracle JDBC Driver]Object has been closed.
at macromedia.jdbc.base.BaseExceptions.createException(Unknown Source)
at macromedia.jdbc.base.BaseExceptions.getException(Unknown Source)
at macromedia.jdbc.base.BaseConnection.setAutoCommit(Unknown Source)
at macromedia.jdbcspy.SpyConnection.setAutoCommit(Unknown Source)
at coldfusion.server.j2ee.sql.JRunConnection.setAutoCommit(JRunConnection.java:394)
at coldfusion.server.j2ee.sql.JRunConnection.clean(JRunConnection.java:223)
at coldfusion.server.j2ee.sql.JRunConnection.close(JRunConnection.java:433)
at coldfusion.server.j2ee.sql.pool.JDBCPool.expire(JDBCPool.java:695)
at coldfusion.server.j2ee.pool.ObjectPool.closeAllResources(ObjectPool.java:292)
at coldfusion.server.j2ee.sql.pool.JDBCPool.closeAllResources(JDBCPool.java:884)
at coldfusion.server.j2ee.pool.ObjectPool.finalize(ObjectPool.java:312)
at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:83)
at java.lang.ref.Finalizer.access$100(Finalizer.java:14)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:160)

Somewhere, somehow, some resource on the database server is being exhausted by a fairly small number of inserts and we don't know what resource or why because both servers eventually stare off into space waiting for the other to make the next move.

In the end, I gave up and had the vendor walk me through cloning the demo site from our production system and hand-jamming it into test.

Oh, did I forget to mention that this ran flawlessly on our production system? That's right, I didn't because I found another bug in CMS. We installed the demo site into /opt/SUNWwbsvr/docs but when the installer ran (and blew up) it had created /opt/sunwwbsvr/docs. Solaris is case sensitive, and a developer had jammed in an lcase() function that non-narcissistic applications like Apache forgive. Sun has to make their name CAPS in all their products.

What a fucking waste of time. Adobe's documentation staff need to bathe in napalm.

Wednesday, March 07, 2007

iTunes 7.1 includes new Cover Flow

A handful of point releases ago, Apple added the ability for iTunes to retrieve your album artwork from their servers if it wasn't already embedded in your MP3 (which, chances were, it wasn't). It would seem the point of this is to make a feature like Cover Flow, which is how you actually look for CDs in real life, much more valuable:




For these screen shots, I used my purchased music because most of the music I ripped from my own CDs look like this in Cover Flow:




Cool new feature? Yes.

Life altering experience? Not so much.

I suspect the next generation of iPods will probably have a Cover Flow interface though.

Thursday, March 01, 2007

Aww...my first CMS Bug

How adorable!



Something tells me if their Q/A didn't test subsite creation, that this won't be my last bug report and bug fix.