Using SQL parameters without using SQL parameters


  • Considered Harmful

    So, I'm dealing with a fairly moderately sized outsourced codebase. It has every antipattern you've heard of and a few you haven't. Par for the course, I've come to expect this.

    Earlier this afternoon, one of their processes start to break, so I dove down the rabbit hole. In the past two hours I've fixed eight logic errors, five memory leaks, fixed a couple crashes and excised ~200 lines of dead code from this class. I'm far from done, but I just uncovered a gem:

    See, there's this statement, that's concatenated together over 72 lines in a string builder despite being a single insert into a single table - that's still not the TRWTF!

    At first glance this query appears to be using parameters. On closer inspection, the parameters are expanded with stringBuilder.Replace( "PARAMETER_NAME", "'" + input_value + "'" ); Yes, it's vulnerable to SQL injection! And this bug could probably be exploited to pwn quite a few systems as the database is extremely large.

    They were so close to doing it right.



  • @joe.edwards said:

    In the past two hours I've fixed eight logic errors, five memory leaks, fixed a couple crashes and excised ~200 lines of dead code from this class.

    I hereby formally accuse you of making up numbers (aka "Michael Mooring" or "Climategating"). You could vastly improve the credibility of this post by not using those fake numbers. Also please refrain to use "pwn" unless Chumlee is involved.


  • Considered Harmful

    Actually, those are the real numbers. Most of them were easy because they were compiler warnings already, and Resharper highlighted the dead code blocks, unused variable assignments, and some of the logic errors like "expression always evaluates to true"; the crashes came from the line numbers in the exception logs.

    No, these weren't at all hard to catch. The outsourcers just gave zero fucks.



  • @joe.edwards said:

    Resharper highlighted the dead code blocks, unused variable assignments, and some of the logic errors like "expression always evaluates to true".

    That's not a logic error. See this example:


    if(Ronald == awesome)
      applause();
    
    

    The condition is always true but the IF shows the rationale behind the method call and provides a visual hook to maintainers allowing them to see where business logic could be later updated (as an example by replacing "Ronald" with "joe.edwards").



  • @joe.edwards said:

    On closer inspection, the parameters are expanded with stringBuilder.Replace( "PARAMETER_NAME", "'" + input_value + "'" );

    Let me introduce you to this block of code, straight from the file, not even anonymized (since I don't really see anything in here other than rather generic lead capture stuff):

    _sql = string.Format(@"EXEC [dbo].[upProspectSave] @ProspectIDY = {0}, @SkilledProspectIDY = {1}, @ProspectPeopleIDY = {2},
    	@ProspectFirstName = {3}, @ProspectMiddleName = {4}, @ProspectLastName = {5}, @ProspectPrefix = {6},
    	@Gender = {7}, @MaritalStatus = {8}, @EthnicityFK = {9}, @ProspectivePayorFK = {10}, @SSN = {11},
    	@BirthDate = {12}, @MarketArea = {13}, @ProspectAddressFK = {14}, @ProspectAddress1 = {15}, 
    	@ProspectAddress2={16}, @ProspectCity = {17}, @ProspectState = {18}, @ProspectZipCode = {19}, 
    	@ProspectCounty = {20}, @ProspectCountry = {21}, @ProspectEmail = {22}, @ProspectPhone1FK = {23},
    	@ProspectPhone1Number = {24}, @ProspectPhone1Extension = {25}, @ProspectPhone1TypePL = {26}, 
    	@ProspectPhone2FK = {27}, @ProspectPhone2Number = {28}, @ProspectPhone2Extension = {29}, @ProspectPhone2TypePL = {30},
    	@ProspectPhone3FK = {31}, @ProspectPhone3Number = {32}, @ProspectPhone3Extension = {33}, @ProspectPhone3TypePL = {34},
    	@ProspectPhone4FK = {35}, @ProspectPhone4Number = {36}, @ProspectPhone4Extension = {37}, @ProspectPhone4TypePL = {38}, 
    	@ReferralSourceFK = {39}, @ReferralOrganizationFK = {40}, @InitialContactFK = {41}, @PrimaryIsSameAsProspect = {42}, 
    	@PrimaryContactPeopleIDY = {43}, @PrimaryContactRelationshipTypeIDY = {44}, @PrimaryContactFirstName = {45},
    	@PrimaryContactMiddleName = {46}, @PrimaryContactLastName = {47}, @PrimaryContactPrefix = {48}, @PrimaryContactAddressFK = {49},
    	@PrimaryContactAddress1 = {50}, @PrimaryContactAddress2={51}, @PrimaryContactCity = {52}, @PrimaryContactState = {53}, 
    	@PrimaryContactZipCode = {54}, @PrimaryContactCounty = {55}, @PrimaryContactCountry = {56}, @PrimaryContactEmail = {57}, 
    	@PrimaryContactPhone1FK = {58}, @PrimaryContactPhone1Number = {59}, @PrimaryContactPhone1Extension = {60}, 
    	@PrimaryContactPhone1TypePL = {61}, @PrimaryContactPhone2FK = {62}, @PrimaryContactPhone2Number = {63}, 
    	@PrimaryContactPhone2Extension = {64}, @PrimaryContactPhone2TypePL = {65}, @PrimaryContactPhone3FK = {66}, 
    	@PrimaryContactPhone3Number = {67}, @PrimaryContactPhone3Extension = {68}, @PrimaryContactPhone3TypePL = {69}, 
    	@PrimaryContactPhone4FK = {70}, @PrimaryContactPhone4Number = {71}, @PrimaryContactPhone4Extension = {72}, 
    	@PrimaryContactPhone4TypePL = {73}, @FinancialIsSameAs = {74}, @FinancialContactPeopleIDY = {75}, 
    	@FinancialContactFirstName = {76}, @FinancialContactMiddleName = {77}, @FinancialContactLastName = {78}, 
    	@FinancialContactPrefix = {79}, @FinancialContactAddressFK = {80}, @FinancialContactAddress1 = {81}, 
    	@FinancialContactAddress2={82}, @FinancialContactCity = {83}, @FinancialContactState = {84}, @FinancialContactZipCode = {85}, 
    	@FinancialContactCounty = {86}, @FinancialContactCountry = {87}, @FinancialContactEmail = {88}, @FinancialContactPhone1FK = {89}, 
    	@FinancialContactPhone1Number = {90}, @FinancialContactPhone1Extension = {91}, @FinancialContactPhone1TypePL = {92}, 
    	@FinancialContactPhone2FK = {93}, @FinancialContactPhone2Number = {94}, @FinancialContactPhone2Extension = {95}, 
    	@FinancialContactPhone2TypePL = {96}, @FinancialContactPhone3FK = {97}, @FinancialContactPhone3Number = {98}, 
    	@FinancialContactPhone3Extension = {99}, @FinancialContactPhone3TypePL = {100}, @FinancialContactPhone4FK = {101}, 
    	@FinancialContactPhone4Number = {102}, @FinancialContactPhone4Extension = {103}, @FinancialContactPhone4TypePL = {104}, 
    	@DateUpdated = {105}, @UserFK = {106}, @CommunityIDY = {107}",
    	new object[] { 
    		// Prospect Information
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectIDY), SQLMethods.ToSQL(_ProspectDemographicRec.SkilledProspectIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PeopleIDY), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectFirstName),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectMiddle), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectLastName), 
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPrefix), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectGender), 
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectMaritalStatus), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectRace), 
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectivePayorIDY), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectSSN), 
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectDateOfBirth), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectMarketAreaIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectAddress.AddressIDY), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectAddress.Address1),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectAddress.Address2), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectAddress.City),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectAddress.State), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectAddress.ZipCode),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectAddress.County), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectAddress.Country),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectEmail), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber1.PhoneIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber1.PhoneNumber), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber1.Extension),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber1.PhoneTypePL), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber2.PhoneIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber2.PhoneNumber), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber2.Extension), 
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber2.PhoneTypePL), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber3.PhoneIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber3.PhoneNumber), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber3.Extension),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber3.PhoneTypePL), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber4.PhoneIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber4.PhoneNumber), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber4.Extension), 
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectPhoneNumber4.PhoneTypePL), SQLMethods.ToSQL(_ProspectDemographicRec.ReferralSourceIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.OrganizationIDY), SQLMethods.ToSQL(_ProspectDemographicRec.InitialContactIDY),
    		// Primary Contact Information
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.SameAsProspect), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPeopleIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactRelationshipIDY), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactFirstName),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactMiddle), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactLastName),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPrefix), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactAddress.AddressIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactAddress.Address1), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactAddress.Address2), 
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactAddress.City), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactAddress.State), 
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactAddress.ZipCode), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactAddress.County), 
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactAddress.Country), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactEmail),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone1.PhoneIDY), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone1.PhoneNumber),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone1.Extension), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone1.PhoneTypePL),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone2.PhoneIDY), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone2.PhoneNumber),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone2.Extension), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone2.PhoneTypePL),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone3.PhoneIDY), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone3.PhoneNumber),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone3.Extension), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone3.PhoneTypePL),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone4.PhoneIDY), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone4.PhoneNumber),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone4.Extension), SQLMethods.ToSQL(_ProspectDemographicRec.PrimaryContact.ContactPhone4.PhoneTypePL),
    		// Financial Contact Information
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.RadioSameAsProspect), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPeopleIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactFirstName), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactMiddle),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactLastName), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPrefix),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactAddress.AddressIDY), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactAddress.Address1),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactAddress.Address2), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactAddress.City),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactAddress.State), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactAddress.ZipCode),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactAddress.County), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactAddress.Country),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactEmail), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone1.PhoneIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone1.PhoneNumber), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone1.Extension),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone1.PhoneTypePL), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone2.PhoneIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone2.PhoneNumber), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone2.Extension),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone2.PhoneTypePL), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone3.PhoneIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone3.PhoneNumber), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone3.Extension),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone3.PhoneTypePL), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone4.PhoneIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone4.PhoneNumber), SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone4.Extension),
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone4.PhoneTypePL), SQLMethods.ToSQL(_ProspectDemographicRec.DateUpdated), _UserIDY, _CommunityIDY });
    

    All the repeated fields in this proc are actually stored normalized in the database. So the proc that loads the data has to do this denormalization, then this proc has to make it normalized again. If you were curious, that SQLMethods.ToSQL method looks like this

    static public string ToSQL(int? _Int)
    {
    	if (_Int.HasValue)
    	{
    		return Convert.ToString(_Int.Value);
    	}
    	else
    	{
    		return "NULL";
    	}
    }
    

    With various permutations for different data types. And the execution plan for the proc I mentioned that does the denormalization:

    What a wonderful code base.



  • @Ronald said:

    if(Ronald == awesome)
    applause();

    Use braces, you bastard.



  • @bardofspoons42 said:

    @ProspectPhone1Number = {24}, @ProspectPhone1Extension = {25}, @ProspectPhone1TypePL = {26}, 
    	@ProspectPhone2FK = {27}, @ProspectPhone2Number = {28}, @ProspectPhone2Extension = {29}, @ProspectPhone2TypePL = {30},
    	@ProspectPhone3FK = {31}, @ProspectPhone3Number = {32}, @ProspectPhone3Extension = {33}, @ProspectPhone3TypePL = {34},
    	@ProspectPhone4FK = {35}, @ProspectPhone4Number = {36}, @ProspectPhone4Extension = {37}, @ProspectPhone4TypePL = {38}, 

    I once worked with a schema like that.  It becomes readily obvious that questions like "How can we be sure that phone numbers are valid and aren't duplicated within or across prospects?" or "How can I get a distinct list of all phone numbers?" were not important design considerations.  We confronted the original designer of the system (the CEO) about this and his response was that he initially had a nice normalized design, but the client was so used to carbon-paper forms that the idea of "adding" a phone number instead of having field(s) you fill in was unteachable.

    @bardofspoons42 said:

    int? _Int

     

    This only underscores the importance of good variable naming conventions.



  • @bardofspoons42 said:

    With various permutations for different data types. And the execution plan for the proc I mentioned that does the denormalization:

    What a wonderful code base.

    What a scam. I clicked on the picture, hoping to see the details, then it opens that awful image website with an even smaller version, then it opens the same fucking shit image. You AND imgur are now at the top of my transient shitlist.



  • @morbiuswilters said:

    @Ronald said:
    if(Ronald == awesome)
    applause();

    Use braces, you bastard.

    Braces are so 1998.

    
    using(var ronald = new messiah())
        while(ronald is messiah)
           if(ronald.awesomeNess > 0)
               do
                  applauseSomeMore();
               while (!tired);
    
    


  • @Ronald said:

    @morbiuswilters said:
    @Ronald said:
    if(Ronald == awesome)
    applause();

    Use braces, you bastard.

    Braces are required in Go.

    {
    	var ronald moron
    	for {
    		if ronald.randDomCapItALization > 0 {
    			fartSounds()
    			for !tired {
    				fartSounds()
    			}
    		}
    	}
    }

    FTFY



  • @Ben L. said:

    @Ronald said:
    @morbiuswilters said:
    @Ronald said:
    if(Ronald == awesome)
    applause();

    Use braces, you bastard.

    Braces are required in Go.

    {
    	var ronald moron
    	for {
    		if ronald.randDomCapItALization > 0 {
    			fartSounds()
    			for !tired {
    				fartSounds()
    			}
    		}
    	}
    }

    FTFY

    With this post you demonstrated two things:


    1. Go is an inferior language
    2. You are not funny


  • @Ben L. said:

    @Ronald said:
    @morbiuswilters said:
    @Ronald said:
    if(Ronald == awesome)
    applause();

    Use braces, you bastard.

    Braces are required in Go.

    {
    	var ronald moron
    	for {
    		if ronald.randDomCapItALization > 0 {
    			fartSounds()
    			for !tired {
    				fartSounds()
    			}
    		}
    	}
    }

    FTFY

    Lack of braces is fine, so long as you require consistent indentation (ala Python.) I do like that Go makes them mandatory (how is it that most languages still don't do this??) but it's like pretty eyes on a fat chick--kind of useless, unless you're really, really into eyes.



  • @Ronald said:

    I clicked on the picture, hoping to see the details

    That's about as big as I actually have it. Partly for anonymization, but also because that's about as big as I could actually get it without messing around with stretching SQL Management Studio across multiple screens, doing screenshot stitching or whatever.

    @Groaner said:
    I once worked with a schema like that. 

    The most annoying bit, to me, is the schema itself is rather sane (Outside of all primary keys ending with IDY, and columns that reference those PK's via foreign keys end with FK, sometimes). Actually the worst part with dealing with the database is the program we use to do schema updates is different than what happens in the build file during development, so we have to check in all SQL scripts into two different directories. Which is "what we've always done". Never mind that the dev build script makes an instance of osql for every script to be run, against every database, so that takes a bit. Or that since we use source safe, we don't easily know what SQL scripts have been changed. Or that sometimes updates get made in production, and not source control, causing data corruption after the next release we do.



  • @bardofspoons42 said:

    Let me introduce you to this block of code, straight from the file, not even anonymized (since I don't really see anything in here other than rather generic lead capture stuff):

    _sql = string.Format(@"EXEC [dbo].[upProspectSave] @ProspectIDY = {0}, @SkilledProspectIDY = {1}, @ProspectPeopleIDY = {2},
    	@ProspectFirstName = {3}, @ProspectMiddleName = {4}, @ProspectLastName = {5}, @ProspectPrefix = {6},
    	<snip>
    	@DateUpdated = {105}, @UserFK = {106}, @CommunityIDY = {107}",
    	new object[ { 
    		// Prospect Information
    		SQLMethods.ToSQL(_ProspectDemographicRec.ProspectIDY), SQLMethods.ToSQL(_ProspectDemographicRec.SkilledProspectIDY),
    		SQLMethods.ToSQL(_ProspectDemographicRec.PeopleIDY), SQLMethods.ToSQL(_ProspectDemographicRec.ProspectFirstName),
    		<snip>
    		SQLMethods.ToSQL(_ProspectDemographicRec.FinancialContact.ContactPhone4.PhoneTypePL), SQLMethods.ToSQL(_ProspectDemographicRec.DateUpdated), _UserIDY, _CommunityIDY });
    

    Whoever wrote that could at least have written an IFormatter to do the ToSQL bit.



  • You've got to be kidding me. If I ever came across something like this I'll simply shutdown my computer and run to cry in some corner.



  • @Groaner said:

    ...but the client was so used to carbon-paper forms that the idea of "adding" a phone number instead of having field(s) you fill in was unteachable.

    I assure you (and your idiot CEO) that it wasn't the idea that was unteachable...



  • @pjt33 said:

    Whoever wrote that could at least have written an IFormatter to do the ToSQL bit.

    They were writing non-parameterized SQL on a web site in 2009, do you think they were competent enough to read on how to implement an interface?



  • @Ronald said:

    That's not a logic error. See this example:


    if(Ronald == awesome)
      applause();
    

    Whoah... I always thought that Batman was awesome, and now I find out he's you?

    Starts applauding



  • @morbiuswilters said:

    @Ronald said:

    if(Ronald == awesome)
      applause();
    

    Use braces, you bastard.

     


  • Trolleybus Mechanic

    @morbiuswilters said:

    @Ronald said:

    if(Ronald == awesome)
      applause();
    

    Use braces, you bastard.

     

    Or use a bastard language like VB that doesn't use braces because weird characters are scary and will confuse the programmers.

     



  • @El_Heffe said:

    @morbiuswilters said:

    @Ronald said:

    if(Ronald == awesome)
    applause();

    Use braces, you bastard.

     

    Is that some kind of glitter on those braces? does she change the color depending on what she wears?


Log in to reply