1

Task

After extracting SQL statements from a log file I'm doing simple string concatenation to append a ; at the end:

var query = line[i] + ";"

Problem

What it should look like: insert into [...];

What it does look like: ;nsert into [...]

Approaches

I tried different concatenation mechanisms, seeing that only appended concatenation fails.

for (i in lines) {
  var txt = lines[i];
  console.log(txt);                 // "insert into"
  console.log(txt.concat(";"));     // ";nsert into"
  console.log(txt + ";");           // ";nsert into"
  console.log(txt+=";");            // ";nsert into"
  console.log(";" + txt);           // ";insert into"
}

Extraction script

var fs = require('fs');
var array = fs.readFileSync('file').toString().split("\n");
var result = [];

var currentRow;
var line;
var value;

// loop through all lines of the file
for(i in array) {
    line = array[i];
    // if there is an insert statement, push it on the array
    if (line.lastIndexOf("insert into", 0) === 0) {
      result.push(line);
    // if there is a binding param, interpolate that into the recent insert statement
    } else if (line.lastIndexOf("binding param", 0) === 0){
      value = line.split(" - ")[1].replace("\n", "").replace("\r", "");
      // hibernate represents null as <null> while oracle needs ""
      if (value === "<null>") {
        value = '""';
      // if there is a string, put "" around
      } else if (isNaN(value)) {
        value = '"' + value + '"';
      }
      currentRow = result[result.length-1];
      // interpolate
      currentRow = currentRow.replace("?", value);
      result[result.length-1] = currentRow;
    }
}

Data sneak peek

insert into <user>.<table> (<col1>, <col2>, <col3>) values (?, ?, ?)
binding parameter [1] as [<type>] - <value>
binding parameter [2] as [<type>] - <value>
binding parameter [3] as [<type>] - <value>

System

  • Windows 7
  • Node.js v4.2.1

Question

Why is the ; not appended but replaces the first character?

michaelbahr
  • 4,837
  • 2
  • 39
  • 75
  • 1
    That is not how string concatenation works in JavaScript, so the *apparent* behavior is misleading. Perhaps there is a terminating carriage return character (ASCII 13 decimal) in the string. Appending a semicolon to a string ending in a carriage return *might* end up looking like the appended character overwrote the first character, because that's kind-of what a carriage return does (at least back in the wooden computer days). – Pointy Oct 22 '15 at 14:00
  • You have something very odd going on there. I can assure you that string concatenation in javascript does work. Also note your line `console.log(txt+=";"); ` is mutating `txt` so the claimed output of your last line makes no sense whatsoever (you've not only added `;` but you've somehow managed to put the `i` back). – Matt Burland Oct 22 '15 at 14:00
  • You can use `console.log((txt + ";").charCodeAt(0))` to log the character code at the beginning of the resulting string. The semicolon character is decimal 59, and lower-case "i" is 105. Or, `console.log(txt.charCodeAt(txt.length - 1))` will log the code of the last character in the original string. – Pointy Oct 22 '15 at 14:04
  • @MattBurland note that the OP is working in Node. The output of `console.log()` is rendered via the (fairly dumb and certainly archaic) command prompt UI on Windows. I would not be surprised if a simple carriage return *not* followed by a line feed would have exactly that effect. – Pointy Oct 22 '15 at 14:11
  • @Pointy thanks for pointing out the ASCII 13 character. Replacing that one did the trick. Will post an answer. – michaelbahr Oct 22 '15 at 14:12

1 Answers1

1

As Pointy indicated, there was a terminating carriage return character (ASCII 13 decimal) in the string.

Extending the extraction script to trim the last character if there is one did the trick.

if (line.lastIndexOf("insert into", 0) === 0) {
   if (line.charCodeAt(line.length - 1) == 13) {
     line = line.substring(0, line.length - 1);
   }
   result.push(line);
   console.log(line); // "insert into [...];"
}

Note: There are prettier solutions using regex.

Community
  • 1
  • 1
michaelbahr
  • 4,837
  • 2
  • 39
  • 75