<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -24,6 +24,10 @@
 #define do_int64 signed long long int
 #endif
 
+#ifndef StringValueLen
+#define StringValueLen(v) (RSTRING(v)-&gt;len)
+#endif
+
 // To store rb_intern values
 static ID ID_NEW_DATE;
 static ID ID_LOGGER;
@@ -354,30 +358,52 @@ static VALUE cCommand_set_types(VALUE self, VALUE array) {
 	return array;
 }
 
-static VALUE build_query_from_args(VALUE klass, int count, VALUE *args[]) {
-	VALUE query = rb_iv_get(klass, &quot;@text&quot;);
-	if ( count &gt; 0 ) {
-		int i;
-		VALUE array = rb_ary_new();
-		for ( i = 0; i &lt; count; i++) {
-			rb_ary_push(array, (VALUE)args[i]);
+static PGresult *exec_query(int argc, VALUE argv[], VALUE self) {
+	PGconn *db = DATA_PTR(rb_iv_get(rb_iv_get(self, &quot;@connection&quot;), &quot;@connection&quot;));
+	VALUE ruby_command = rb_iv_get(self, &quot;@text&quot;);
+	char * orig_command = StringValueCStr(ruby_command);
+
+	if (argc &lt;= 0) {
+		DEBUG(ruby_command);
+		return PQexec(db, orig_command);
+	} else {
+		int maxplen = argc &lt; 100 ? 4 : argc &lt; 10000 ? 6 : 24;
+		int maxlen = strlen(orig_command) + argc * maxplen;
+		char command[maxlen + maxplen];
+		const char * paramValues[argc];
+
+		int i = 1;
+		char *ci, *co;
+		for (ci = orig_command, co = command; *ci; ci++) {
+			if (*ci == '?') {
+				co += sprintf(co, &quot;$%d&quot;, i++);
+			} else {
+				*co = *ci;
+				co++;
+			}
+		}
+		*co = '\0';
+
+		DEBUG(RUBY_STRING(command));
+
+		for (i = 0; i &lt; argc; i++) {
+			VALUE s = rb_funcall(argv[i], rb_intern(&quot;to_s&quot;), 0);
+			paramValues[i] = StringValueCStr(s);
 		}
-		query = rb_funcall(klass, ID_ESCAPE, 1, array);
+
+		return PQexecParams(db, command, argc, NULL, paramValues, NULL, NULL, 0);
 	}
-	return query;
 }
 
 static VALUE cCommand_quote_string(VALUE self, VALUE string) {
 	PGconn *db = DATA_PTR(rb_iv_get(rb_iv_get(self, &quot;@connection&quot;), &quot;@connection&quot;));
 
-	size_t length;
-	const char *source = StringValueCStr(string);
+	const char *source = StringValuePtr(string);
+	size_t length = StringValueLen(string);
 	char *escaped;
 	int quoted_length = 0;
 	VALUE result;
 
-	length = strlen(source);
-
 	// Allocate space for the escaped version of 'string'
 	// http://www.postgresql.org/docs/8.3/static/libpq-exec.html#LIBPQ-EXEC-ESCAPE-STRING
 	escaped = (char *)calloc(strlen(source) * 2 + 3, sizeof(char));
@@ -393,18 +419,13 @@ static VALUE cCommand_quote_string(VALUE self, VALUE string) {
 	return result;
 }
 
-static VALUE cCommand_execute_non_query(int argc, VALUE *argv[], VALUE self) {
-	PGconn *db = DATA_PTR(rb_iv_get(rb_iv_get(self, &quot;@connection&quot;), &quot;@connection&quot;));
-	PGresult *response;
+static VALUE cCommand_execute_non_query(int argc, VALUE argv[], VALUE self) {
 	int status;
 
 	int affected_rows;
 	int insert_id;
 
-	VALUE query = build_query_from_args(self, argc, argv);
-	data_objects_debug(query);
-
-	response = PQexec(db, StringValueCStr(query));
+	PGresult *response = exec_query(argc, argv, self);
 
 	status = PQresultStatus(response);
 
@@ -427,21 +448,15 @@ static VALUE cCommand_execute_non_query(int argc, VALUE *argv[], VALUE self) {
 	return rb_funcall(cResult, ID_NEW, 3, self, INT2NUM(affected_rows), INT2NUM(insert_id));
 }
 
-static VALUE cCommand_execute_reader(int argc, VALUE *argv[], VALUE self) {
-	VALUE reader, query;
+static VALUE cCommand_execute_reader(int argc, VALUE argv[], VALUE self) {
+	VALUE reader;
 	VALUE field_names, field_types;
 
 	int i;
 	int field_count;
 	int infer_types = 0;
 
-	PGconn *db = DATA_PTR(rb_iv_get(rb_iv_get(self, &quot;@connection&quot;), &quot;@connection&quot;));
-	PGresult *response;
-
-	query = build_query_from_args(self, argc, argv);
-	data_objects_debug(query);
-
-	response = PQexec(db, StringValueCStr(query));
+	PGresult *response = exec_query(argc, argv, self);
 
 	if ( PQresultStatus(response) != PGRES_TUPLES_OK ) {
 		char *message = PQresultErrorMessage(response);</diff>
      <filename>do_postgres/ext/do_postgres_ext.c</filename>
    </modified>
    <modified>
      <diff>@@ -31,7 +31,7 @@ describe DataObjects::Postgres::Command do
       command = @connection.create_command(&quot;INSERT INTO users (name) VALUES (?)&quot;)
       @mock_logger = mock('MockLogger', :level =&gt; 0)
       DataObjects::Postgres.should_receive(:logger).and_return(@mock_logger)
-      @mock_logger.should_receive(:debug).with(&quot;INSERT INTO users (name) VALUES ('Blah')&quot;)
+      @mock_logger.should_receive(:debug).with(&quot;INSERT INTO users (name) VALUES ($1)&quot;)
       command.execute_non_query('Blah')
     end
 </diff>
      <filename>do_postgres/spec/integration/logging_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>69937fcdf8b60372bbabca2edb0dfc24a965080f</id>
    </parent>
  </parents>
  <author>
    <name>Matthew Draper</name>
    <email>matthew@trebex.net</email>
  </author>
  <url>http://github.com/matthewd/sam-do/commit/0de9b238f01890dbbe4e08e5ea489eacec3e2ea1</url>
  <id>0de9b238f01890dbbe4e08e5ea489eacec3e2ea1</id>
  <committed-date>2008-08-03T06:45:59-07:00</committed-date>
  <authored-date>2008-08-03T06:45:59-07:00</authored-date>
  <message>Use PQexecParams() instead of building SQL ourselves.</message>
  <tree>5bde56512214e62bf9a8cca39e2462d8609c4026</tree>
  <committer>
    <name>Matthew Draper</name>
    <email>matthew@trebex.net</email>
  </committer>
</commit>
