|
|
@ -6,6 +6,14 @@ |
|
|
|
var util = require('util'); |
|
|
|
var assert = require('assert'); |
|
|
|
|
|
|
|
/** |
|
|
|
* Config can contain: |
|
|
|
* |
|
|
|
* questionMarkParameterPlaceholder:true which will use a "?" for the parameter placeholder instead of the @index. |
|
|
|
* |
|
|
|
* @param config |
|
|
|
* @constructor |
|
|
|
*/ |
|
|
|
var Mssql = function(config) { |
|
|
|
this.output = []; |
|
|
|
this.params = []; |
|
|
@ -23,6 +31,7 @@ Mssql.prototype._quoteCharacter = '['; |
|
|
|
Mssql.prototype._arrayAggFunctionName = ''; |
|
|
|
|
|
|
|
Mssql.prototype._getParameterPlaceholder = function(index, value) { |
|
|
|
if (this.config.questionMarkParameterPlaceholder) return '?'; |
|
|
|
return '@' + index; |
|
|
|
}; |
|
|
|
|
|
|
@ -95,7 +104,7 @@ Mssql.prototype.visitAlter = function(alter) { |
|
|
|
var table = self._queryNode.table; |
|
|
|
var result = ['EXEC sp_rename '+self.visit(table.toNode())+', '+self.visit(alter.nodes[0].nodes[0])]; |
|
|
|
self._visitingAlter = false; |
|
|
|
return result |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
// Implement our own rename column:
|
|
|
@ -110,7 +119,7 @@ Mssql.prototype.visitAlter = function(alter) { |
|
|
|
"'COLUMN'" |
|
|
|
]; |
|
|
|
self._visitingAlter = false; |
|
|
|
return result |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
if (isAlterAddColumn(alter)) return _addColumn(); |
|
|
@ -124,13 +133,13 @@ Mssql.prototype.visitAlter = function(alter) { |
|
|
|
// CASE WHEN true THEN xxx END
|
|
|
|
// the "true" has to be a boolean expression like 1=1
|
|
|
|
Mssql.prototype.visitCase = function(caseExp) { |
|
|
|
var _this=this |
|
|
|
var _this=this; |
|
|
|
|
|
|
|
function _whenValue(node){ |
|
|
|
if (node.type!='PARAMETER') return _this.visit(node); |
|
|
|
// dealing with a true/false value
|
|
|
|
var val=node.value(); |
|
|
|
if (val==true) return '1=1'; else return '0=1'; |
|
|
|
if (val===true) return '1=1'; else return '0=1'; |
|
|
|
} |
|
|
|
|
|
|
|
assert(caseExp.whenList.length == caseExp.thenList.length); |
|
|
@ -146,7 +155,7 @@ Mssql.prototype.visitCase = function(caseExp) { |
|
|
|
text += whenExp + thenExp; |
|
|
|
} |
|
|
|
|
|
|
|
if (null != caseExp.else && undefined != caseExp.else) { |
|
|
|
if (null !== caseExp.else && undefined !== caseExp.else) { |
|
|
|
text += ' ELSE ' + this.visit(caseExp.else); |
|
|
|
} |
|
|
|
|
|
|
@ -154,7 +163,7 @@ Mssql.prototype.visitCase = function(caseExp) { |
|
|
|
|
|
|
|
text += ' END)'; |
|
|
|
return [text]; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
Mssql.prototype.visitColumn = function(columnNode) { |
|
|
|
var self=this; |
|
|
@ -162,12 +171,12 @@ Mssql.prototype.visitColumn = function(columnNode) { |
|
|
|
var inSelectClause; |
|
|
|
|
|
|
|
function _arrayAgg(){ |
|
|
|
throw new Error("SQL Server does not support array_agg.") |
|
|
|
throw new Error("SQL Server does not support array_agg."); |
|
|
|
} |
|
|
|
|
|
|
|
function _countStar(){ |
|
|
|
// Implement our own since count(table.*) is invalid in Mssql
|
|
|
|
var result='COUNT(*)' |
|
|
|
var result='COUNT(*)'; |
|
|
|
if(inSelectClause && columnNode.alias) { |
|
|
|
result += ' AS ' + self.quote(columnNode.alias); |
|
|
|
} |
|
|
@ -184,8 +193,8 @@ Mssql.prototype.visitColumn = function(columnNode) { |
|
|
|
|
|
|
|
|
|
|
|
Mssql.prototype.visitCreate = function(create) { |
|
|
|
var isNotExists=isCreateIfNotExists(create) |
|
|
|
var isTemporary=isCreateTemporary(create) |
|
|
|
var isNotExists=isCreateIfNotExists(create); |
|
|
|
var isTemporary=isCreateTemporary(create); |
|
|
|
if (!isNotExists && !isTemporary) { |
|
|
|
return Mssql.super_.prototype.visitCreate.call(this, create); |
|
|
|
} |
|
|
@ -210,7 +219,7 @@ Mssql.prototype.visitCreate = function(create) { |
|
|
|
// if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')}
|
|
|
|
// Add some tests for this as well
|
|
|
|
|
|
|
|
if (!isNotExists) return createResult |
|
|
|
if (!isNotExists) return createResult; |
|
|
|
return ['IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+createResult.join(' ')+' END']; |
|
|
|
}; |
|
|
|
|
|
|
@ -237,9 +246,9 @@ Mssql.prototype.visitDrop = function(drop) { |
|
|
|
|
|
|
|
Mssql.prototype.visitFunctionCall = function(functionCall) { |
|
|
|
this._visitingFunctionCall = true; |
|
|
|
var name=functionCall.name |
|
|
|
var name=functionCall.name; |
|
|
|
// override the LENGTH function since mssql calls it LEN
|
|
|
|
if (name=="LENGTH") name="LEN" |
|
|
|
if (name=="LENGTH") name="LEN"; |
|
|
|
var txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; |
|
|
|
this._visitingFunctionCall = false; |
|
|
|
return [txt]; |
|
|
@ -273,9 +282,9 @@ Mssql.prototype.visitOrderBy = function(orderBy) { |
|
|
|
*/ |
|
|
|
Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ |
|
|
|
function _handleLimitAndOffset(){ |
|
|
|
var limitInfo=Mssql.super_.prototype.findNode.call(this, filters, "LIMIT"); |
|
|
|
var offsetInfo=Mssql.super_.prototype.findNode.call(this, filters, "OFFSET"); |
|
|
|
var orderByInfo=Mssql.super_.prototype.findNode.call(this, filters, "ORDER BY"); |
|
|
|
var limitInfo=Mssql.super_.prototype.findNode.call(this, filters, "LIMIT"); // jshint ignore:line
|
|
|
|
var offsetInfo=Mssql.super_.prototype.findNode.call(this, filters, "OFFSET"); // jshint ignore:line
|
|
|
|
var orderByInfo=Mssql.super_.prototype.findNode.call(this, filters, "ORDER BY"); // jshint ignore:line
|
|
|
|
|
|
|
|
// no OFFSET or LIMIT then there's nothing special to do
|
|
|
|
if (!offsetInfo && !limitInfo) return; |
|
|
@ -292,8 +301,8 @@ Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ |
|
|
|
* @private |
|
|
|
*/ |
|
|
|
function _processLimit(limitInfo){ |
|
|
|
var selectInfo=Mssql.super_.prototype.findNode.call(this, actions, "SELECT"); |
|
|
|
assert(selectInfo!=undefined,"MS SQL Server requires a SELECT clause when using LIMIT"); |
|
|
|
var selectInfo=Mssql.super_.prototype.findNode.call(this, actions, "SELECT"); // jshint ignore:line
|
|
|
|
assert(selectInfo!==undefined,"MS SQL Server requires a SELECT clause when using LIMIT"); |
|
|
|
// save the LIMIT node with the SELECT node
|
|
|
|
selectInfo.node.msSQLLimitNode=limitInfo.node; |
|
|
|
// remove the LIMIT node from the filters so it doesn't get processed later.
|
|
|
@ -376,59 +385,59 @@ Mssql.prototype.visitSelect = function(select) { |
|
|
|
|
|
|
|
// Node is either an OFFSET or LIMIT node
|
|
|
|
function getModifierValue(dialect,node){ |
|
|
|
return node.count.type ? dialect.visit(node.count) : node.count |
|
|
|
return node.count.type ? dialect.visit(node.count) : node.count; |
|
|
|
} |
|
|
|
|
|
|
|
function isAlterAddColumn(alter){ |
|
|
|
if (alter.nodes.length==0) return false; |
|
|
|
if (alter.nodes.length===0) return false; |
|
|
|
if (alter.nodes[0].type!='ADD COLUMN') return false; |
|
|
|
return true; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
function isAlterDropColumn(alter){ |
|
|
|
if (alter.nodes.length==0) return false; |
|
|
|
if (alter.nodes.length===0) return false; |
|
|
|
if (alter.nodes[0].type!='DROP COLUMN') return false; |
|
|
|
return true; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
function isAlterRename(alter){ |
|
|
|
if (alter.nodes.length==0) return false; |
|
|
|
if (alter.nodes.length===0) return false; |
|
|
|
if (alter.nodes[0].type!='RENAME') return false; |
|
|
|
return true; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
function isAlterRenameColumn(alter){ |
|
|
|
if (alter.nodes.length==0) return false; |
|
|
|
if (alter.nodes.length===0) return false; |
|
|
|
if (alter.nodes[0].type!='RENAME COLUMN') return false; |
|
|
|
return true; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
function isCountStarExpression(columnNode){ |
|
|
|
if (!columnNode.aggregator) return false; |
|
|
|
if (columnNode.aggregator.toLowerCase()!='count') return false; |
|
|
|
if (!columnNode.star) return false; |
|
|
|
return true; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
function isCreateIfNotExists(create){ |
|
|
|
if (create.nodes.length==0) return false; |
|
|
|
if (create.nodes.length===0) return false; |
|
|
|
if (create.nodes[0].type!='IF NOT EXISTS') return false; |
|
|
|
return true; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
function isCreateTemporary(create){ |
|
|
|
return create.options.isTemporary |
|
|
|
}; |
|
|
|
return create.options.isTemporary; |
|
|
|
} |
|
|
|
|
|
|
|
function isDropIfExists(drop){ |
|
|
|
if (drop.nodes.length==0) return false; |
|
|
|
if (drop.nodes.length===0) return false; |
|
|
|
if (drop.nodes[0].type!='IF EXISTS') return false; |
|
|
|
return true; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// SQL Server does not support array expressions except in the IN clause.
|
|
|
|
function isRightSideArray(binary){ |
|
|
|
return Array.isArray(binary.right); |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
module.exports = Mssql; |
|
|
|