- 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
Aaah, now this is why I come here. Good old-fashioned painful WTF. No random stories here, just ugly code. Well done.
Admin
Admin
Admin
Admin
Using "INSERT INTO ... VALUES (...) SELECT @@IDENTITY" does the trick just fine, in just one query. Run it with ExecuteScalar (at least that's what it's called in .NET) and you'll get the ID as the result.
np: Fink - This Is The Thing (Distance And Time)
Admin
Admin
The true WTF isn't using random ids; the TWTF is picking the id from a very narrow range of values, thus having a crazy number of collisions. In fact, when you have heavy concurrency, sequential numbers can be a source of contention in indexes, since every one is trying to insert more or less at the same place in the index (contention is often more severe in indexes than in tables). There was no primary key, but there might have been (let's be optimistic) an index, possibly unique (optimism will kill me) on the column. But it's likely that this is a case where they was no concurrency at all ... It's very typical of ideas that are not totally insane by themselves, which in some cases are quite suitable, but were poorly understood and consequently misused.
Admin
I worked with someone I originally thought was a talented developer. He did almost the exact same thing. Upon insert, he would randomly generate a number and try the insert. If it failed he would change the number (there was at least a unique index on the column!).
He didn't want to use the "new fangled" identity column that was just made available (in SQL Server 6.0). Much worse than this WTF, was the fact that this was a distributed database (used by the USPS no less). So the key he generated was always prepended by another number indicating the "location". That way when the data was brought together (with our custom replication solution - SQL Server didn't have that yet) - the data would not collide. There was no opportunity for expanding the range of numbers because whatever was done could collide with another location's initial numbers. He didn't want to use a CHAR or VARCHAR for the primary key. He had read an article from MS that they were slower than a numeric column. (If he had relented on this, at least locations could have been text either pre- or post- pended to the ID).
I still have palm marks on my forehead from doing the code review.
Admin
That is not an exponential-time function. As the table fills up, execution time grows asymptotically towards infinity.
Probably faster, if the random number generator is not strong.
Admin
WTF? That's the first time I've encountered that - thanks a lot for giving me a new pet peeve to watch out for! Still doesn't top "could of", "prolly" and "PIN number" though. (Yes I do need to get out more!)
As a side-WTF, Merriam-Webster actually returns results for 'eachother'. Good old Oxford English restores sanity though by returning no results.
Admin
Admin
May be a security issue. If the numbers are sequential, then if you have X, then you know X+/-N are likely valid as well. If they are random, then it's harder to guess them.
I once worked at a place where a developer did a sequential numbering scheme, and lo and behold, someone could increment/decrement the ID in the URL and see other client's data. I had to patch in a random number validation code to hack a fix for that.
Admin
Or until you get a Hash collision...but those never happen, right?
Admin
Admin
Admin
Admin
Admin
Better solution would have been to just increment the invoice ID by a value other than 1, pick like a prime number or something. That way, invoice numbers still have an order to them but it looks like more are being generated than there really are. And if you're incrementing by some oddball value, chances are nobody that sees the invoices will ever notice.
Any customer that does pay attention to the Invoice Numbers will likely thing something is weird when they one week get invoice #104545 and then a week later #50
Admin
1 and 23456 12 and 3456 123 and 456 1234 and 56 12345 and 6 etc.
Admin
"1" + "21" = "12" + "1" = "121"
Admin
This is how language evolves. If 'eachother' isn't aword itwill besoon.
Admin
Oi vey.
Solution to the "we don't want to reveal our low volume to our customers" problem: CYYMMDDHHNNSS - yeah its a 13 digit invoice id, but what non programmer customer is going to pick up on the sequence?
Admin
oracle: INSERT INTO ........ RETURNING
Avoid it, use a sequence manually, and two statements instead.
Admin
Admin
Actually, your average runtime is going to be solved as the limit of the series (n/N) + 2*(n/N)^2 + ... k*(n/N)^k. This makes the calculation decidedly non-linear.
F(n/N)(to 15 terms) 0.1 = 0.12 0.2 = 0.31 0.5 = 2.00 0.7 = 7.57 0.75 = 11.24 0.76 = 12.21 0.9 = 43.67
So it grows exponentially from 0 at 0% load to infinity at 100% load; the performance would fall off sharply once it passed a particular threshold and it went exponential.
Admin
If your application says "Enterprise" anywhere in the title then you use random numbers to determine the number of zeros to append to the cost.
Admin
Also, Oracle Sequencers are very handy. I use them quite frequently to populate key values. An in-line SELECT SEQUENCE_NAME.NEXTVAL FROM dual, and you're good to go.
A single statement, outside of the database? Ugh. Don't do it. Stored procs are the way to go if you're using Oracle. Well, they are IMHO.
Admin
Admin
Admin
Admin
Given that the original poster was the one that realized that they have less randomness than they originally thought, I think it's fair to say they hadn't thought of padding the string with zeros. Otherwise they wouldn't have a problem.
Admin
What I want to know is this: what was the random-number generator seeded with? Please, oh please, tell me they use the same seed every time -- it would make this WTF so much more ... err ... WTFier.
Admin
It's thinking like that that will see you go far in management, my son.
Admin
Admin
If it's PHP 4.2 or higher than the seeding is done automatically according to the documentation. However, I suspect that it's only by accident that this is saving the code from that particular WTF.
Admin
Oh, I get it... they're missing the definition!
Admin
Nope, didn't pad it. So I got somewhat more than 127 bits of randomness... every combination in which the second number was negative was unique, since the second number in string form then began with a "-".
I should have used a stored procedure. Or a real GUID type. Or both. Or just fired off two SQL statements, perhaps bundled in one request. There was much room for improvement all around. At least I won't make those particular mistakes again. I'm sure I'll find exciting new ones...
Admin
Admin
Admin
Also, in principle, it was the wrong thing to do in practice.
Doing the completely wrong thing, no matter how flawless your implementation, is never correct. Not even in principle. Especially not in practice.
Admin
I unfortunately have encountered this exact solution before also.
Admin
Admin
Also, that's kinda lame. You have to squint and pretend not to have noticed that there already is a statement assigning a value to $code and that it doesn't need any extra definitions and you're just proposing to throw that existing value away. Any joke that relies on you being dumber than the guy who coded the original WTF in order to be able to see it is headed for fail.
Admin
Can't be bothered to do the maths right now, but it can't be growing exponentially to infinity; exponential functions don't go to infinity.
Admin
And really, can any of us ask for anything more than the continuous opportunity to make exciting new mistakes?
Admin
This reminds me of a sorting algorithm that a friend invented (in jest). He called it a "bumble sort".
The code randomly looked at an array location and compared it's contents to the location immediately after. If it was lower than the first, it swapped the location's contents and repeated the process on another randomly selected array location.
Admin
My exponential functions all go to 11.
Admin
I've seen this where clients want to share their read-only access to their data with other other people who do not have credentials for the server. Think photo sharing: People post photos and then send the link to their friends or customers. The server has to provide the image to anyone with the right URL, because that is its purpose. However, users may start to complain if they figure out that their image URLs can be guessed by random strangers.
The folks at SmugMug went through this a year or two ago. The guessability of URLs was obvious to anyone who thought about it, and users had the option of requiring authentication. Then one day it erupted as a "scandle" and SmugMug fixed it by adding random numbers to make it harder to brute force the URLs.
Admin
WayneCollins:
Since you've identified Oracle and MSSQL as your target databases, the single request should be accomplished with a stored procedure call.
In Oracle, use a sequence to reserve the number, and then insert it as the unique ID.
In MSSQL, us an Identity column, and SCOPE_IDENTITY() (not @@IDENTITY) to retrieve the newly inserted ID from the current scope (@@IDENTITY ignores scope).
That solves the multi-threaded conflict issue and the "single statement" is a sproc.
Admin