- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Only with real databases. This is probably MySQL. It's such a toy.
You see? Robert was right!
Admin
Since there will exists either a count of 0 or a count of 1 the expression is always true.
Anyway, PL/SQL is worse.
select count(*)
into li_count
from dual
where exists ( select * from sessions where session_id = id );
if count(*) = then ...
Admin
Man, the wear and tear on that database engine has to be nasty. I bet they have to change oil at least once a month not to mention replacing broken tables.
Admin
are you sure it's not:
select count(*)
into li_count
from sessions
where session_id = id;
;-))
Admin
The real WTF are :
Why does he use database stored session ? does he never try $_SESSION[], session_start() and stuff like that. it's made for session management, you can setup time out without any need to garbage collector in case user forgot to "disconnect"... to use a database for that is a waste of time to develop, risk (sql injection), a wast of performance, and an imcomplete user made implementation of session. that's stupid !
Admin
Uhm, no. There is an implied transaction if you don't explicitly start one. You can change this by setting autocommit to off (It defaults to being on, as per SQL specification).
http://www.postgresql.org/docs/8.1/static/populate.html
http://www.postgresql.org/docs/8.1/static/tutorial-transactions.html
From the second link
Admin
Err.. what use are WTF code snippets that don't resemble original code anymore? If there wasn't an infinite loop originally, why make one?
Admin
IT
Admin
Maybe the Exec ends up executing the database command asyncronously, and returns without having blocked on the database execution? The delay before the database callback or thread execution may be enough to warrant his 5000 retries.
Then again he'd have to be an idiot to realise the error if that were the case. Surely he's not an idiot...
Admin
With PHP and Postgres, if the table is locked, PHP will wait (atleast until it timesout).
Admin
It also means that Robert was (at least this one time) the reasonable one.
Personally, I feel the correct approach would have been to debug the network/apache/php/postgres/linux stack since this "bug" might affect the operations of other critical queries in the system. Only once the cause was explained or time ran out do we put in a documented hack explaining why we do the seemingly stupid thing. I found a kernel driver error in a SCSI controller that only failed under a certain specific set of conditions. I was able to get a patch made and it is now redistributed by several major software vendors... all from finding a random 'bug' in a single web page.
However, I've worked with other developers who would not have spent a week carefully isolating software and hardware systems running through all possible permutations and documenting their behaviors to determine the bug was not in the SCSI controller but in the driver for the controller itself. Those folks would have just done something like what Robert had done. Does that make them idiots? I don't think so. I think it makes them pragmatic. They simply aren't going to blow-off a deadline, tell the customer go whistle, take over the jobs of three system administrators and DBA's, kick them out of their own server rooms and co-opt all the hardware from three projects to isolate a SCSI driver bug.
Yeah. Stupid.
Admin
That's a good guess, but I think I figured it out...
The user id was "bob; insert into sessions (session_id) values ('bob');"
He started the loop with no matching rows and ended with 10,000 (or is that 9998?)
Admin
Hey look... a WTF on a WTF.
Admin
Hint: Ceausescu = Romania
Admin
Wow, I can't believe I didn't find this comment yet. Or maybe Firefox is just a crappy toy with bad search... but:
Don't you know what he's doing? He's following the first rule that we learned... "If at first you don't succeed, try, try again... 5000 times if you need to!
Just don't ever try to learn what went wrong...
Admin
The "" at the end is probably some kind of leftover from when the ID was a string, which would require a closing quote.
He doesn't set $bDeleted to true on successful query execution because he doesn't believe the database actually deleted the row. That's why he has the SELECT query. He wants to verify that it actually was deleted. An earlier comment from the WTF's donator indicated that Robert, by chance, found a session in the database that shortly before had been deleted. Apparently it didn't dawn on him that it was a new session with the same user ID, which prompted this abomination.
Couple notes:
1) This forum software doesn't accept the CUA standard keyboard shortcuts for copy and past (CTRL-INS and SHIFT-INS, respectively). It only recognizes the absurd Windows-specific CTRL-C and CTRL-V combo. Horrible.
2) An atomic delete never needs to be part of a transaction. Either it succeeds or it doesn't. There's nothing to roll back on failure.
Admin
Admin
I'm not familiar with the mechanics of PHP database objects or exception handling, but shouldn't a table lock cause an exception, telling the coders why the logout is failing?
We're obviously not being shown the whole function. $user_id may well have been validated (and $iTimes initialized) earlier in the function.
These confuse me as well. I can only think that they may be for code consistency... If you consistently code SQL statement lines to end in strings, then perhaps you'll be less likely to forget a trailing "'" or ")" or " " after a variable concatenation. It's only a little inefficient.
It makes sense only if the delete silently fails for some reason. Assuming that to be the case, he needs to do the select to check to make sure the record is deleted and, if not, repeat the query. It would be marginally more efficient to do the delete and then the check, but it works both ways.
It sounds like this is what happened:
If this is the case, the real problems are the coder's diagnostic skills, documentation, and attitude.
Admin
I expected a reply like that... but devdas was faster to refute it. Anyway, psql != PostgreSQL, and just because you don't see the transaction doesn't mean it isn't there.
I noticed there are some PostgreSQL commands that do not involve transactions, though, for example VACUUM. However, none of standard DML commands work without a transaction.
Well, Hungary, Romania... that's all outside the US. And everything that's not in the US is kinda like the same anyway, isn't it?
Admin
I prefer using exists for stuff like this
SELECT 1 WHERE EXISTS
(SELECT * FROM sessions WHERE s_user_id = input_id )
Admin
I've been told taht if you live in New York, everything east of the Hudson River is kinda like the same way.
Admin
If you want to check for existence of a single row, then you don't need to do a full-table scan.
Oracle:
SELECT s_user_id from sessions WHERE s_user_id = :input_id AND rownum<2;
MySQL:
SELECT s_user_id from sessions WHERE s_user_id = :input_id LIMIT 1;
Admin
And that is supposed to mean what? While PHP is slightly more dangerous than MS-Access in the hands of an inexperienced user - like most things - you can write incredibly scaleable apps using PHP/PG/Apache. Some companies who have used this stack (at least the PG/Linux parts) include:
-Whitepages.com
-ADP Dealer Services
-BASF
But, alas, I guess if you don't desire to offer your customers the best value, you don't need to consider using these apps... :)
Cheers,
-J
Admin
As someone who has done more than my share of PHP/PostgreSQL work, there is no way that code works as intended.
- If PHP cannot connect to the database server, you would have to re-try the connection inside the loop, so that has nothing to do with it.
- If a table is locked, PHP will wait on the lock as long as it can (usually 30 seconds) before terminating the script (thus no loop)
There are only two conditions I can think of that would apply to this code: 1) either there is a race condition, where another process is also in a loop trying to INSERT sessions:
Or, 2) the database abstraction library being used (there are many available for PHP) is so bad that it occasionally returns the wrong value for success or failure of a query.
Both of these, are of course highly unlikely, and the first could be checked simply by placing the SELECT and the DELETE inside the same transaction.
Methinks more likely our brave Sir Robert was covering for some other equally bad application design elsewhere.
Admin
If you are not changing the parameters I don't think numbered retries are ever a good idea. If you are waiting for some scarce resource to be freed make your code check for that resource before making it's single attempt, and put in some kind of timeout code so your loop will give up if the resource won't be available in time. The only time multiple retries are acceptable is when whatever your code is supposed to do also happens to be the only way to verify that it can do it.
Admin
A missed precondition for determining "sameness".
Admin
This is fun. People, have you ever looked at the execution plan some query is mapped to before claiming "full table scan" or other scary stuff?
"SELECT COUNT(s_user_id) from sessions WHERE s_user_id = input_id;" is perfectly fine. It's not as clear as "SELECT 1 WHERE EXISTS(...)", but it does NOT perform a full table scan, at least not is there is *any* index that's got s_user_id as it's first column. And there bloody well better be.
Also the "SELECT TOP..." (or "SELECT ... LIMIT 1" or whatever) versions are unnecessary since we're probably limiting stuff to one session per user anyway (think "unique index"). If not, well, ok, but then the WHERE clause would be wrong ("delete all sessions of user X if he quits any one session" is surely not what's intended).
There is really really a whole lot of misinformation regarding databases out there. "IS NULL means full table-/index-scan" -> nonsense. "OR means full table-/index-scan" -> nonsense. "NOT IN (...) is slow as hell" -> nonsense. Go, get MSSQL 2005 Express and see for yourselfs - the included "SQL Server Management Studio Express" can display the estimated and actual execution plan and some nice statistics.
CAPTCHA: bedtime. not really...
Admin
Oh, MSSQL Server is such a toy... shamelessly optimizing queries without me asking.
Real databases don't do things behind my back like making my queries more efficient.
Admin
Most of the Roberts of the world don't comment their code nearly this well (i.e. at all).
Admin
Nice education.
But why do most commentors use an existence check anyway? Either the record is there and the delete will nuke it or it isn't and nothing will happen. Without a transaction you can only shoot into your own foot, if something deletes the record in between and you don't notice and your error handling does funny things.
CAPTCHA: Pizza
Admin
Looks like he's trying to wait for an asynchronous operation using that loop. Normally such a loop would be infinite until some condition is met; allowing it to "fail" with a finite number of iterations will get such a client into trouble on faster processors...
Admin
captcha: random well, ok. it might be called random too. didn't think of that.
Admin
What everyone seems to have missed is that s_user_id is more than likely not the primary key. There shouldn't need to be an index on user ID either, except for some obscure 'see if this user is logged in' feature.
And the real WTF is that he's deleting by user ID, not session ID.
Admin
The back page of the Sept 4 Information Week has a full-page ad for Oracle. There's a feature matrix comparing Oracle Business Intelligence to Business Objects and Cognos.
One of the "features" that's checked for Oracle B.I. and not for the others is called "Real-time Predictive Decisioning".
What does that even mean?
Admin
Oops, I posted this in the wrong thread. Oh well.
Admin
You guys forgot hardware issues. ;)
Admin
TRWTF : he didn't use the build in session-handling code but instead wrote this huge pile of stinking crap ... Sessions in Database . true worse than failure