1 var DATA_TYPES = require('../../constants/DataTypes'),
  2   Helpers = require('../../utils/Helpers'),
  3   CAS = require('../../constants/CASConstants'),
  4   ErrorMessages = require('../../constants/ErrorMessages'),
  5   ColumnMetaData = require('../../resultset/ColumnMetaData'),
  6   ResultInfo = require('../../resultset/ResultInfo');
  7 
  8 module.exports = ExecuteQueryPacket;
  9 
 10 /**
 11  * Constructor
 12  * @param options
 13  * @constructor
 14  */
 15 function ExecuteQueryPacket(options) {
 16   options = options || {};
 17 
 18   this.casInfo = options.casInfo;
 19   this.sql = options.sql;
 20   this.autoCommit = options.autoCommitMode;
 21   this.resultset = '';
 22   this.resultCacheLifetime = 0; //Cache lifetime
 23   this.statementType = null; //
 24   this.bindCount = 0; //Bind count
 25   this.isUpdatable = false; //Is updatable
 26   this.totalTupleCount = 0; //Total nomber of tuples
 27   this.cache_reusable = 0; //Cache reusable
 28   this.resultCount = 0; //Number of results
 29   this.columnCount = 0; //Number of columns
 30   this.infoArray = new ColumnMetaData(); //Column meta data
 31   this.resultInfos = new ResultInfo(); //Result info
 32   this.handle = 0; //Query handle
 33   this.currentTupleCount = 0; //Current number of returned tuples
 34   this.tupleCount = 0; //Number of tuples
 35   this.errorCode = 0; //Error code
 36   this.errorMsg = ''; //Error message
 37 }
 38 
 39 /**
 40  * Write data
 41  * @param writer
 42  */
 43 ExecuteQueryPacket.prototype.write = function (writer) {
 44   var bufferLength = DATA_TYPES.DATA_LENGTH_SIZEOF + DATA_TYPES.CAS_INFO_SIZE +
 45     DATA_TYPES.BYTE_SIZEOF + DATA_TYPES.INT_SIZEOF + DATA_TYPES.INT_SIZEOF + DATA_TYPES.INT_SIZEOF +
 46     Buffer.byteLength(this.sql) + 1 + DATA_TYPES.INT_SIZEOF + DATA_TYPES.BYTE_SIZEOF +
 47     DATA_TYPES.INT_SIZEOF + DATA_TYPES.BYTE_SIZEOF + DATA_TYPES.INT_SIZEOF + DATA_TYPES.BYTE_SIZEOF +
 48     DATA_TYPES.INT_SIZEOF + DATA_TYPES.INT_SIZEOF + DATA_TYPES.INT_SIZEOF + DATA_TYPES.INT_SIZEOF +
 49     DATA_TYPES.INT_SIZEOF + DATA_TYPES.INT_SIZEOF + DATA_TYPES.INT_SIZEOF + DATA_TYPES.INT_SIZEOF +
 50     DATA_TYPES.INT_SIZEOF + DATA_TYPES.INT_SIZEOF;
 51 
 52   //Prepare info
 53   writer._writeInt(bufferLength - DATA_TYPES.DATA_LENGTH_SIZEOF - DATA_TYPES.CAS_INFO_SIZE);
 54   writer._writeBytes(DATA_TYPES.CAS_INFO_SIZE, this.casInfo);
 55   writer._writeByte(CAS.CASFunctionCode.CAS_FC_PREPARE_AND_EXECUTE);
 56   writer._writeInt(DATA_TYPES.INT_SIZEOF);
 57   writer._writeInt(3);// number of CAS args
 58   writer._writeNullTerminatedString(this.sql);//sql string
 59   writer._writeInt(DATA_TYPES.BYTE_SIZEOF);
 60   writer._writeByte(CAS.CCIPrepareOption.CCI_PREPARE_NORMAL); //prepare flag
 61   writer._writeInt(DATA_TYPES.BYTE_SIZEOF);
 62   writer._writeByte(this.autoCommit ? 1 : 0); //autocommit mode
 63 
 64   //Execute info
 65   writer._writeInt(DATA_TYPES.BYTE_SIZEOF);
 66   writer._writeByte(CAS.CCIExecutionOption.CCI_EXEC_QUERY_ALL); //execute flag
 67   writer._writeInt(DATA_TYPES.INT_SIZEOF);
 68   writer._writeInt(0); //max col size;
 69   writer._writeInt(DATA_TYPES.INT_SIZEOF);
 70   writer._writeInt(0); //max row size;
 71   writer._writeInt(0);//NULL
 72   writer._writeInt(2 * DATA_TYPES.INT_SIZEOF); // write cache time
 73   writer._writeInt(0); //seconds
 74   writer._writeInt(0); //useconds
 75   writer._writeInt(DATA_TYPES.INT_SIZEOF);
 76   writer._writeInt(0);//query timeout
 77 
 78   return writer;
 79 };
 80 
 81 /**
 82  * Read data
 83  * @param parser
 84  */
 85 ExecuteQueryPacket.prototype.parse = function (parser) {
 86   var reponseLength = parser._parseInt();
 87   this.casInfo = parser._parseBytes(DATA_TYPES.CAS_INFO_SIZE);
 88 
 89   this.handle = parser._parseInt();
 90   if (this.handle < 0) {
 91     this.errorCode = parser._parseInt();
 92     this.errorMsg = parser._parseNullTerminatedString(reponseLength - 2 * DATA_TYPES.INT_SIZEOF);
 93     if (this.errorMsg.length == 0) {
 94       this.errorMsg = Helpers._resolveErrorCode(this.errorCode);
 95     }
 96   } else {
 97     this.resultCacheLifetime = parser._parseInt();
 98     this.statementType = parser._parseByte();
 99     this.bindCount = parser._parseInt();
100     this.isUpdatable = (parser._parseByte() === 0);
101     this.columnCount = parser._parseInt();
102     this.infoArray = new Array();
103     for (i = 0; i < this.columnCount; i++) {
104       var info = new ColumnMetaData();
105       info.ColumnType = parser._parseByte();
106       info.scale = parser._parseShort();
107       info.precision = parser._parseInt();
108       var len = parser._parseInt();
109       info.Name = parser._parseNullTerminatedString(len);
110       len = parser._parseInt();
111       info.RealName = parser._parseNullTerminatedString(len);
112       len = parser._parseInt();
113       info.TableName = parser._parseNullTerminatedString(len);
114       info.IsNullable = (parser._parseByte() === 1);
115       len = parser._parseInt();
116       info.DafaultValue = parser._parseNullTerminatedString(len);
117       info.IsAutoIncrement = (parser._parseByte() === 1);
118       info.IsUniqueKey = (parser._parseByte() === 1);
119       info.IsPrimaryKey = (parser._parseByte() === 1);
120       info.IsReverseIndex = (parser._parseByte() === 1);
121       info.IsReverseUnique = (parser._parseByte() === 1);
122       info.IsForeignKey = (parser._parseByte() === 1);
123       info.IsShared = (parser._parseByte() === 1);
124       this.infoArray[i] = info;
125     }
126 
127     this.totalTupleCount = parser._parseInt();
128     this.cache_reusable = parser._parseByte();
129     this.resultCount = parser._parseInt();
130     //read result info
131     for (i = 0; i < this.resultCount; i++) {
132       var resultInfo = new ResultInfo();
133       resultInfo.StmtType = parser._parseByte();
134       resultInfo.ResultCount = parser._parseInt();
135       resultInfo.Oid = parser._parseBytes(DATA_TYPES.OID_SIZEOF);
136       resultInfo.CacheTimeSec = parser._parseInt();
137       resultInfo.CacheTimeUsec = parser._parseInt();
138       this.resultInfos[i] = resultInfo;
139     }
140   }
141 
142   if (this.statementType === CAS.CUBRIDStatementType.CUBRID_STMT_SELECT) {
143     var fetchCode = parser._parseInt();
144     this.tupleCount = parser._parseInt();
145     var columnNames = new Array(this.columnCount);
146     var columnDataTypes = new Array(this.columnCount);
147     var columnValues = new Array(this.tupleCount);
148     for (var i = 0; i < this.columnCount; i++) {
149       columnNames[i] = this.infoArray[i].Name;
150       columnDataTypes[i] = CAS.getCUBRIDDataType(this.infoArray[i].ColumnType);
151     }
152 
153     columnValues = this._getData(parser, this.tupleCount);
154 
155     return JSON.stringify(
156       {
157         ColumnNames     : columnNames,
158         ColumnDataTypes : columnDataTypes,
159         RowsCount       : this.totalTupleCount,
160         ColumnValues    : columnValues
161       }
162     );
163   }
164 
165   return parser;
166 };
167 
168 /**
169  * Get records data from stream
170  * @param parser
171  * @param tupleCount
172  */
173 ExecuteQueryPacket.prototype._getData = function (parser, tupleCount) {
174   var columnValues = new Array(tupleCount);
175   for (var i = 0; i < tupleCount; i++) {
176     columnValues[i] = new Array(this.columnCount);
177     var index = parser._parseInt();
178     var Oid = parser._parseBytes(DATA_TYPES.OID_SIZEOF);
179     for (var j = 0; j < this.columnCount; j++) {
180       var size = parser._parseInt();
181       var val;
182       if (size <= 0) {
183         val = null;
184       } else {
185         var type = CAS.CUBRIDDataType.CCI_U_TYPE_NULL;
186 
187         if (this.statementType === CAS.CUBRIDStatementType.CUBRID_STMT_CALL ||
188           this.statementType === CAS.CUBRIDStatementType.CUBRID_STMT_EVALUATE ||
189           this.statementType === CAS.CUBRIDStatementType.CUBRID_STMT_CALL_SP ||
190           this.infoArray[j].ColumnType === CAS.CUBRIDDataType.CCI_U_TYPE_NULL) {
191           type = parser._parseByte();
192           size--;
193         } else {
194           type = this.infoArray[j].ColumnType;
195         }
196 
197         val = this._readValue(j, type, size, parser);
198         columnValues[i][j] = val;
199       }
200     }
201   }
202   this.currentTupleCount += tupleCount;
203 
204   return columnValues;
205 };
206 
207 /**
208  * Read column value from stream
209  * @param index
210  * @param type
211  * @param size
212  * @param parser
213  */
214 ExecuteQueryPacket.prototype._readValue = function (index, type, size, parser) {
215   switch (type) {
216     case CAS.CUBRIDDataType.CCI_U_TYPE_CHAR:
217     case CAS.CUBRIDDataType.CCI_U_TYPE_NCHAR:
218     case CAS.CUBRIDDataType.CCI_U_TYPE_STRING:
219     case CAS.CUBRIDDataType.CCI_U_TYPE_VARNCHAR:
220       return parser._parseNullTerminatedString(size);
221 
222     case CAS.CUBRIDDataType.CCI_U_TYPE_SHORT:
223       return parser._parseShort();
224 
225     case CAS.CUBRIDDataType.CCI_U_TYPE_INT:
226       return parser._parseInt();
227 
228     case CAS.CUBRIDDataType.CCI_U_TYPE_BIGINT:
229       return parser._parseLong();
230 
231     case CAS.CUBRIDDataType.CCI_U_TYPE_FLOAT:
232       return parser._parseFloat();
233 
234     case CAS.CUBRIDDataType.CCI_U_TYPE_DOUBLE:
235     case CAS.CUBRIDDataType.CCI_U_TYPE_MONETARY:
236       return parser._parseDouble();
237 
238     case CAS.CUBRIDDataType.CCI_U_TYPE_NUMERIC:
239       return parser._parseNumeric(size);
240 
241     case CAS.CUBRIDDataType.CCI_U_TYPE_DATE:
242       return parser._parseDate();
243 
244     case CAS.CUBRIDDataType.CCI_U_TYPE_TIME:
245       return parser._parseTime();
246 
247     case CAS.CUBRIDDataType.CCI_U_TYPE_DATETIME:
248       return parser._parseDateTime();
249 
250     case CAS.CUBRIDDataType.CCI_U_TYPE_TIMESTAMP:
251       return parser._parseTimeStamp();
252 
253     case CAS.CUBRIDDataType.CCI_U_TYPE_OBJECT:
254       return parser._parseObject();
255 
256     case CAS.CUBRIDDataType.CCI_U_TYPE_BIT:
257     case CAS.CUBRIDDataType.CCI_U_TYPE_VARBIT:
258       return parser._parseBytes(size);
259 
260     case CAS.CUBRIDDataType.CCI_U_TYPE_SET:
261     case CAS.CUBRIDDataType.CCI_U_TYPE_MULTISET:
262     case CAS.CUBRIDDataType.CCI_U_TYPE_SEQUENCE:
263       return parser._parseSequence();
264 
265     case CAS.CUBRIDDataType.CCI_U_TYPE_BLOB:
266       return parser._parseBlob(size);
267 
268     case CAS.CUBRIDDataType.CCI_U_TYPE_CLOB:
269       return parser._parseClob(size);
270 
271     case CAS.CUBRIDDataType.CCI_U_TYPE_RESULTSET:
272       return parser._parseResultSet();
273 
274     default:
275       return new Error(ErrorMessages.ERROR_INVALID_DATA_TYPE);
276   }
277 };
278