• BillyBob (unregistered)

    Now seriously, if you were going through code and saw someone appending a 1=1 out of nowhere, you'd scratch your head and pull that face sitting at the top left hand corner of this website.

  • Tom_fan_DK (unregistered) in reply to StressBomb
    StressBomb:
    "Uh huh, and what if the query actually IS complex, with multiple places (possibly different functions, objects etc) where 'where' clauses can be added? I guess we could... search the query string for the substr 'where'?"

    I can't believe that you just said this b.s., and want to seriously make it seem as if I'm the one overcomplicating the situation.

    FYI, in my code, since every part of the query is dynamic, I usually collect valid expression which are valid on their own, means, I could wrap them in parens: (..) or join them with OR, AND or XOR, or whatever I see fit.

    At any point the expressions are valid since this is the basic guiding principle I build them upon. I don't have extraneous operators or commands on left or right which "assume" to be added to the correct filler junk in the query.

    In the end, I just add the expressions in the query skeleton:

    query = 'SELECT '+selectExpr+' FROM '+tableName; if (whereExpr) query+= ' WHERE '+whereExpr; if (orderExpr) query+= ' ORDER BY '+orderExpr; if (limitExpr) query+= ' LIMIT '+limitExpr;

    I've used this query build process as a basis for driver-independent abstraction for generic queries in a MVC framework. I have YET to ever have a query gone wrong by using it, if even because the methods will validate all parameters for me before the query is built and executed.

    I see you're great writing SQL injection prone code (and killing at the same time the database...).

    W T F ? ? ?

  • Grammarian (unregistered) in reply to Tom_fan_DK
    Tom_fan_DK:
    I see you're great writing SQL injection prone code (and killing at the same time the database...).

    W T F ? ? ?

    Is it injection-prone? Or have the lists of parameters been sanitized prior to this point in the code? You don't know.

  • StressBomb (unregistered) in reply to Tom_fan_DK

    "I see you're great writing SQL injection prone code (and killing at the same time the database...)."

    Would you care to explain yourself? And while you're explaining yourself, make sure:

    1. you've a basic idea what the database provided API's "quoting" function does, and how it helps prevent injections on any external data.

    2. prepared statements will add overhead, versus reduce it, for PHP/ASP/CGI applications, as no data is shared and thus the statement is prepared every time.

    I hate repeating myself, but obviously I'm not in a smart company (actually, I'm truly disappointed by the comments on this article, let's say it makes me think lower of this entire site...).

  • StressBomb (unregistered) in reply to Grammarian

    Grammarian: "Is it injection-prone? Or have the lists of parameters been sanitized prior to this point in the code? You don't know."

    Hehe, shhh! Let's wipe years and years of successfully implementing safely applications running non-prepared queries, and claim anyone who doesn't prepare his statements, while using parameter wildcards is having injection prone SQL!

    Because preparing is so cool, mon.

  • (cs) in reply to StressBomb
    StressBomb:
    prepared statements will *add* overhead, versus reduce it, for PHP/ASP/CGI applications, as no data is shared and thus the statement is prepared every time.

    That statement is misleading. Prepared Statements (at least in the toy I use, MySQL) are prepared once per connection. That means that if I use a shared, persistent connection, I can cache a reference to the statement once per connection. It also means that if I have a kind of statement (e.g. getUser(id) -> "SELECT * FROM Users WHERE id=?") I can use it multiple times in a single request with different data without invoking the query parser every time.

    But what do I know? I still think FastCGI is awesome.

  • StressBomb (unregistered) in reply to Derrick Pallas

    "That statement is misleading. Prepared Statements (at least in the toy I use, MySQL) are prepared once per connection. That means that if I use a shared, persistent connection, I can cache a reference to the statement once per connection. It also means that if I have a kind of statement (e.g. getUser(id) -> "SELECT * FROM Users WHERE id=?") I can use it multiple times in a single request with different data without invoking the query parser every time."

    Derrick, I guess noone is protected from being wrong, even the editors of WorseThanFailure.com

    Sharing the connection AND sharing a previously prepared statement are two completely different things. It's not the first time I hear people confuse both.

    Sure you can "reuse" the prepared statement in the same REQUEST, just how often do you do this in real applications? I've probably almost never done it. I'm doing web sites after all, and I don't have time retrieving my data piece by piece in multiple identical queries each request, now do I?

    In the end, you end up preparing it, then running it once, and that's about all use of this prepared statement before the request is done.

    To reuse a prepared statement, you need to be able to share the handle somehow between multiple requests which ALSO share the same connection. Java/C# (aka "real languages") have the benefit of being able to do this. PHP/old ASP/CGI on the other hand, can't do it, PHP doesn't even have a support for spawning or accessing the other requests threads, let alone passing resource handles among them.

  • StressBomb (unregistered) in reply to StressBomb

    "Prepared Statements (at least in the toy I use, MySQL) are prepared once per connection."

    Oh also, Derrick: MySQL can't use the query cache when you use prepared statements. Did you know this?

    Means if each request performs the same SELECT(s) (ex. retrieving the same articles and/or navigation for the page), without prepared statements you use the query cache, with them, the SELECT runs every time.

    Now, sure, you could cache those yourself your business logic layer, but then the point of the superior performance of prepared statements becomes totally moot.

    That's more of a flaw with MySQL than the concept of prepared statements (Postgres will apply caching to prepped statements), but it pays to research what's your DB actually doing while advocating those.

  • jethro tull (unregistered) in reply to PJH

    yeah, c is cool as it requires checking the buffer length. The lack of fake "true" condition in the "where" clause is a lightwieght. The real WTF is people still using C.

  • (cs) in reply to jethro tull
    jethro tull:
    yeah, c is cool as it requires checking the buffer length. The lack of fake "true" condition in the "where" clause is a lightwieght. The real WTF is people still using C.

    C isn't bad. I'm more shocked of people still using Pascal, or god forbid, Visual Basic.

    C for dynamic web sites however ... that's a real WTF.

    (Of course, it will run faster maybe, but that only means it will crash faster!!!! muhahahahahaa)

  • (cs) in reply to sjs
    sjs:
    Real C programmers don't use stdlib! ;) Kidding, of course, but implode is easy to write.

    I bet this code sucks, but it's a shot:

    char *implode(char *separator, char **quoted_statements) { if (!separator || !quoted_statements) return NULL;

    char *query = NULL, *statement = NULL;
    int separator_len = strlen(separator);
    int query_len = 1, i = 0, append_separator = 0;
    
    for (statement = quoted_statements[i]; statement != NULL; statement = quoted_statements[++i])
    {
        query_len += strlen(statement);
        if (quoted_statements[i+1] != NULL)
        {
            query_len += separator_len;
            append_separator = 1;
        }
        else
            append_separator = 0;
    
        if ( !(query = (char *)realloc(query, query_len)) )
            return NULL;
    
        strcat(query, statement);
        if (append_separator == 1) strcat(query, separator);
    }
    
    return query;
    

    }

    captcha: poindexter! and how...

    Main criciticms:

    1. Not const-correct
    2. Keeps reallocating your buffer.

    Also functions that return newly allocated buffers should be avoided, unless they begin with the word "create", which this one doesn't.

    Better to have 2 functions, one to return the length and another that takes a pre-allocated buffer to write into. Let the caller manage the buffer.

    Also not a good way to iterate through. Better to just use pointer arithmetic.

    So how about this as a function to start to get the total length of all the strings.

    typedef struct tagSizePair
    {
      size_t first;
      size_t second;
    } SizePair;
    
    /* returns pair of size_t, 
     * first is number of strings
     * second is total length of all the strings
     */
    
    SizePair getStringArrayStats( const char * const * strings )
    {
       SizePair stats = { 0, 0 };
       for ( const char * s = strings; s != NULL; ++s )
       {
          ++stats.first;
          stats.second += strlen( s );
       }
       return stats;
    }
    
    /* now a cpy_returnend function */
    
    char * cpy_returnend( char * target, const char * src, size_t len )
    {
      memcpy( target, src, len );
      return target + len;
    }
    
    /* Now build our string. Again no bounds checking */
    
    void implode( char * target, const char * sep, const char * const * strings )
    {
      int first = 1;
      size_t sepLen = strlen( sep );
      for ( char * s = strings; s != NULL; ++s )
      {
         if ( !first )
         {
            target = cpy_returnend( target, sep, sepLen );
         }
         else
         {
            first = 0;
         }
    
         target = cpy_returnend( target, s, strlen( s ) );
      }
    }
    
    char * create_implode( const char * sep, const char * const * strings )
    {
       SizePair stats = getStringArrayStats( strings );
       char * target = (char *) malloc( strlen( sep ) * stats.first + stats.second + 1 );
       if ( target != NULL )
       {
          implode( target, sep, strings );
       }
       return target;
    }
    

    Of course, easier with C++ where you can use ostringstream. Or Java, of course.

  • (cs)

    In C++ by the way, if we use "end" to mark the pointer to the null-terminating string, we can then do the copy in just one line:

    std::string implode( const char * sep, const char * const * strings )
    {
      const char * const * end = strings;
      while ( *end ) ++end;
    
      std::ostringstream oss;
      std::copy( strings, end, std::ostream_iterator( oss, sep ) );
      return oss.str();
    }
    

    If we input std::vector< std::string > in the first place then:

    std::string implode( const std::string & sep, const std::vector< std::string > & strings )
    {
      std::ostringstream oss;
      std::copy( strings.begin(), strings.end(), std::ostream_iterator( oss, sep.c_str() );
      return oss.str();
    }
    

    Oh how nice and simple.

  • Thr Crafty Sod (unregistered) in reply to Red5

    One of the benefits of using C is that you can do both!

    I am not a slashdot, but I play one on TV

  • Me (unregistered)

    I can't believe no one has used this cheap joke:

    "and then?" "no and then" "and then?" "NO and then" "and then?" "NO AND THEN!"

  • (cs) in reply to StressBomb
    StressBomb:
    " Sharing the connection AND sharing a previously prepared statement are two completely different things. It's not the first time I hear people confuse both.

    Sure you can "reuse" the prepared statement in the same REQUEST, just how often do you do this in real applications? I've probably almost never done it. I'm doing web sites after all, and I don't have time retrieving my data piece by piece in multiple identical queries each request, now do I?

    I'm not confusing them. Last time I checked: in MySQL, prepared statements exist only in relation to a single connection. (Maybe that was just a limitation of PHP.) If you want to reuse a prepared statement across invocations, you have to keep the connection open and share it. Hence the mention of FastCGI: it makes it really easy to share resources like this; I've done it in both C++ and PHP.

    StressBomb:
    In the end, you end up preparing it, then running it once, and that's about all use of this prepared statement before the request is done.

    cough Sorry, I'm choking on the bad habit you put in my mouth. There are use cases (which I also mentioned) where you do want to prepare a statement that is used multiple times with different data.

    StressBomb:
    Oh also, Derrick: MySQL can't use the query cache when you use prepared statements. Did you know this?

    ...

    Now, sure, you could cache those yourself your business logic layer, but then the point of the superior performance of prepared statements becomes totally moot.

    Yes, I realize this used to be true; it was because the Query Cache happens before the Query Compiler. There is a patch that was added last month that fixes this, however, by substituting the values into the prepared statement early. Unfortunately, it doesn't work very well with PREPARE...FROM statements; that's because of user variables, which the Query Cache can't handle, either.

    On a similar note, the right place to do this kind of caching is usually not in the database, especially when the database lives on a different machine than the application. If you think the Query Cache is fast, try saving oft used, seldom writ results in something like memcache on the local host.

  • Paul (unregistered) in reply to cklam
    cklam:
    (1) there is is only one code file and it is only 40 KB in size. 40 KB is not so big - in my experience that will typically equal between 50 and 100 A4 pages of printout. That is not a tome, at least.

    Not 40kb. 40kb would be easy. It was 40K LINES of code, weighing in significantly higher.

    The copy and paste was always the starting point - very large portions which were then minorly tweaked for the specific situation, then copied and tweaked again. I'll call this process "inbreeding."

    Yes - almost ALL the variables (at least the ones that didn't leak) were global. Arguments to functions were almost unheard of - if a function was called by an app, it was simply assumed that the variables it needed to access at the time had already been set.

  • Coyne (unregistered) in reply to StressBomb

    So I take it I broke something somewhere (not surprising; it's been a while since I did C)?

    The theory is that "termword" is a pointer that either contains the address of "whereword" or "andword". It is initially set to "whereword", but gets changed to "andword" if any term is received from the server.

    That was the theory anyway.

    So the last if should have been true iff none of the preceding if statements were true; i.e., none of the GetField() calls returned a value.

    This would indicate that someone tried to bypass the security by sending a page with no fields. For the article example, if this were to happen, the SQL returns all rows in the database. For my intended design, it returns none, because the user that sent no fields is clearly a cheater who was trying to bypass security.

    (This was supposed to address a potential problem I didn't like the other code because "WHERE 1=1" returns all the rows in the database if none of the GetField() calls returned a value, which seemed unsafe.)

    Of course, my example doesn't address SQL injection at all (any more than the original article did). There needs to be something else to handle that.

  • Nero (unregistered)

    Have you ever seen AWStats source code? No? Than you've never seen a Monolith.

  • Joseph Newton (unregistered)

    I think I see some tool blame here.

    The evil does not inhere in C. I've written object-oriented work in ANSI C. No arrows pointing to functions, true, but object oriented conceptually. Not a single function too long to be read and comprehended in a single screen. Any given file contained only functions specific to the object represented.

    C is in fact ideally designed for good programming structure--put definitions in the header file, implemetation code in the related source.

    So if the code in this app sprawled out to eternity in a single page, the fault lay with a brain-dead programmer, not with the language.

    Captcha: yeah, there's got to be a twist.

  • ahhh? is that a quote from me? (unregistered) in reply to sol
    sol:
    PERL hold the everything in this universe togethor like crazy glue ;)

    PHP is PERL's less sticky cousin and ColdFusion is according to Jim Carlow the most powerful tool known to man... what do I know though I get paid to write vb code all day...

Leave a comment on “The Counter of And”

Log In or post as a guest

Replying to comment #:

« Return to Article