@@ -11,17 +11,85 @@ function Execute(id, parameters, charsetNumber) {
11
11
this . encoding = CharsetToEncoding [ charsetNumber ] ;
12
12
}
13
13
14
- var pad = '000000000000' ;
15
- function leftPad ( num , value ) {
16
- var s = value . toString ( ) ;
17
- // if we don't need to pad
18
- if ( s . length >= num ) {
19
- return s ;
14
+ function isJSON ( value ) {
15
+ return Array . isArray ( value ) ||
16
+ value . constructor === Object ||
17
+ ( typeof value . toJSON === 'function' && ! Buffer . isBuffer ( value ) ) ;
18
+ }
19
+
20
+ function toMysqlDateBuffer ( value ) {
21
+ var bufferValue = Buffer . allocUnsafe ( 12 ) ;
22
+ bufferValue . writeUInt8 ( 11 , 0 ) ;
23
+ bufferValue . writeUInt16LE ( value . getFullYear ( ) , 1 ) ;
24
+ bufferValue . writeUInt8 ( value . getMonth ( ) + 1 , 3 ) ;
25
+ bufferValue . writeUInt8 ( value . getDate ( ) , 4 ) ;
26
+ bufferValue . writeUInt8 ( value . getHours ( ) , 5 ) ;
27
+ bufferValue . writeUInt8 ( value . getMinutes ( ) , 6 ) ;
28
+ bufferValue . writeUInt8 ( value . getSeconds ( ) , 7 ) ;
29
+ bufferValue . writeUInt32LE ( value . getMilliseconds ( ) * 1000 , 8 ) ;
30
+ return bufferValue ;
31
+ }
32
+
33
+ /**
34
+ * Converts a value to an object describing type, String/Buffer representation and length
35
+ * @param {* } value
36
+ */
37
+ function toParameter ( value , encoding ) {
38
+ var type = Types . VAR_STRING ;
39
+ var length ;
40
+ var fixed = false ;
41
+ if ( value !== null ) {
42
+ switch ( typeof value ) {
43
+ case 'undefined' :
44
+ throw new TypeError ( 'Bind parameters must not contain undefined' ) ;
45
+
46
+ case 'number' :
47
+ type = Types . DOUBLE ;
48
+ fixed = true ;
49
+ var bufferValue = Buffer . allocUnsafe ( 8 ) ;
50
+ bufferValue . writeDoubleLE ( value , 0 ) ;
51
+ value = bufferValue ;
52
+ break ;
53
+
54
+ case 'boolean' :
55
+ type = Types . TINY ;
56
+ fixed = true ;
57
+ var bufferValue = Buffer . allocUnsafe ( 1 ) ;
58
+ bufferValue . writeInt8 ( value | 0 , 0 ) ;
59
+ value = bufferValue ;
60
+ break ;
61
+
62
+ case 'object' :
63
+ if ( Object . prototype . toString . call ( value ) == '[object Date]' ) {
64
+ type = Types . DATETIME ;
65
+ fixed = true ;
66
+ value = toMysqlDateBuffer ( value ) ;
67
+ } else if ( isJSON ( value ) ) {
68
+ type = Types . JSON ;
69
+ value = JSON . stringify ( value ) ;
70
+ }
71
+ break ;
20
72
}
21
- return ( pad + s ) . slice ( - num ) ;
73
+ } else {
74
+ type = Types . NULL ;
75
+ value = '' ;
76
+ }
77
+ if ( fixed ) {
78
+ length = value . length ;
79
+ } else {
80
+ if ( Buffer . isBuffer ( value ) ) {
81
+ length = Packet . lengthCodedNumberLength ( value . length ) + value . length ;
82
+ } else {
83
+ value = value . toString ( ) ;
84
+ length = Packet . lengthCodedStringLength ( value , encoding ) ;
85
+ }
86
+ }
87
+ return { type, value, length, fixed } ;
22
88
}
23
89
24
90
Execute . prototype . toPacket = function ( ) {
91
+ var self = this ;
92
+
25
93
// TODO: don't try to calculate packet length in advance, allocate some big buffer in advance (header + 256 bytes?)
26
94
// and copy + reallocate if not enough
27
95
@@ -32,33 +100,17 @@ Execute.prototype.toPacket = function() {
32
100
// 9 + 1 - flags
33
101
// 10 + 4 - iteration-count (always 1)
34
102
var length = 14 ;
103
+ var parameters ;
35
104
if ( this . parameters && this . parameters . length > 0 ) {
36
105
length += Math . floor ( ( this . parameters . length + 7 ) / 8 ) ;
37
106
length += 1 ; // new-params-bound-flag
38
107
length += 2 * this . parameters . length ; // type byte for each parameter if new-params-bound-flag is set
39
- for ( i = 0 ; i < this . parameters . length ; i ++ ) {
40
- if ( this . parameters [ i ] !== null ) {
41
- if (
42
- Object . prototype . toString . call ( this . parameters [ i ] ) == '[object Date]'
43
- ) {
44
- var d = this . parameters [ i ] ;
45
- // TODO: move to asMysqlDateTime()
46
- this . parameters [ i ] =
47
- [ d . getFullYear ( ) , d . getMonth ( ) + 1 , d . getDate ( ) ] . join ( '-' ) +
48
- ' ' +
49
- [ d . getHours ( ) , d . getMinutes ( ) , d . getSeconds ( ) ] . join ( ':' ) +
50
- '.' + leftPad ( 3 , d . getMilliseconds ( ) )
51
- ;
52
- }
53
- if ( Buffer . isBuffer ( this . parameters [ i ] ) ) {
54
- length += Packet . lengthCodedNumberLength ( this . parameters [ i ] . length ) ;
55
- length += this . parameters [ i ] . length ;
56
- } else {
57
- var str = this . parameters [ i ] . toString ( ) ;
58
- length += Packet . lengthCodedStringLength ( str , this . encoding ) ;
59
- }
60
- }
61
- }
108
+ parameters = this . parameters . map ( function ( value ) {
109
+ return toParameter ( value , self . encoding ) ;
110
+ } ) ;
111
+ length += parameters . reduce ( function ( accumulator , parameter ) {
112
+ return accumulator + parameter . length ;
113
+ } , 0 ) ;
62
114
}
63
115
64
116
var buffer = Buffer . allocUnsafe ( length ) ;
@@ -68,11 +120,11 @@ Execute.prototype.toPacket = function() {
68
120
packet . writeInt32 ( this . id ) ;
69
121
packet . writeInt8 ( CursorType . NO_CURSOR ) ; // flags
70
122
packet . writeInt32 ( 1 ) ; // iteration-count, always 1
71
- if ( this . parameters && this . parameters . length > 0 ) {
123
+ if ( parameters ) {
72
124
var bitmap = 0 ;
73
125
var bitValue = 1 ;
74
- for ( i = 0 ; i < this . parameters . length ; i ++ ) {
75
- if ( this . parameters [ i ] === null ) {
126
+ parameters . forEach ( function ( parameter ) {
127
+ if ( parameter . type === Types . NULL ) {
76
128
bitmap += bitValue ;
77
129
}
78
130
bitValue *= 2 ;
@@ -81,7 +133,7 @@ Execute.prototype.toPacket = function() {
81
133
bitmap = 0 ;
82
134
bitValue = 1 ;
83
135
}
84
- }
136
+ } ) ;
85
137
if ( bitValue != 1 ) {
86
138
packet . writeInt8 ( bitmap ) ;
87
139
}
@@ -91,27 +143,24 @@ Execute.prototype.toPacket = function() {
91
143
// if not, previous execution types are used (TODO prooflink)
92
144
packet . writeInt8 ( 1 ) ; // new-params-bound-flag
93
145
94
- // TODO: don't typecast always to sting, use parameters type
95
- for ( i = 0 ; i < this . parameters . length ; i ++ ) {
96
- if ( this . parameters [ i ] !== null ) {
97
- packet . writeInt16 ( Types . VAR_STRING ) ;
98
- } else {
99
- packet . writeInt16 ( Types . NULL ) ;
100
- }
101
- }
146
+ // Write parameter types
147
+ parameters . forEach ( function ( parameter ) {
148
+ packet . writeInt8 ( parameter . type ) ; // field type
149
+ packet . writeInt8 ( 0 ) ; // parameter flag
150
+ } ) ;
102
151
103
- for ( i = 0 ; i < this . parameters . length ; i ++ ) {
104
- if ( this . parameters [ i ] !== null ) {
105
- if ( Buffer . isBuffer ( this . parameters [ i ] ) ) {
106
- packet . writeLengthCodedBuffer ( this . parameters [ i ] ) ;
152
+ // Write parameter values
153
+ parameters . forEach ( function ( parameter ) {
154
+ if ( parameter . type !== Types . NULL ) {
155
+ if ( parameter . fixed ) {
156
+ packet . writeBuffer ( parameter . value ) ;
157
+ } else if ( Buffer . isBuffer ( parameter . value ) ) {
158
+ packet . writeLengthCodedBuffer ( parameter . value ) ;
107
159
} else {
108
- packet . writeLengthCodedString (
109
- this . parameters [ i ] . toString ( ) ,
110
- this . encoding
111
- ) ;
160
+ packet . writeLengthCodedString ( parameter . value , self . encoding ) ;
112
161
}
113
162
}
114
- }
163
+ } ) ;
115
164
}
116
165
return packet ;
117
166
} ;
0 commit comments