1 | /* |
2 | |
3 | Derby - Class org.apache.derby.client.net.NetStatementRequest |
4 | |
5 | Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | package org.apache.derby.client.net; |
21 | |
22 | import org.apache.derby.iapi.reference.DRDAConstants; |
23 | import org.apache.derby.client.am.Blob; |
24 | import org.apache.derby.client.am.Clob; |
25 | import org.apache.derby.client.am.ColumnMetaData; |
26 | import org.apache.derby.client.am.ResultSet; |
27 | import org.apache.derby.client.am.Section; |
28 | import org.apache.derby.client.am.SqlException; |
29 | import org.apache.derby.client.am.Types; |
30 | import org.apache.derby.client.am.ClientMessageId; |
31 | import org.apache.derby.shared.common.reference.SQLState; |
32 | |
33 | // For performance, should we worry about the ordering of our DDM command parameters |
34 | |
35 | public class NetStatementRequest extends NetPackageRequest implements StatementRequestInterface { |
36 | java.util.ArrayList extdtaPositions_ = null; // Integers: build EXTDTA for column i |
37 | int overrideLid_ = FdocaConstants.FIRST_OVERRIDE_LID; |
38 | |
39 | // promototed parameters hold parameters that are promotoed to a different |
40 | // data type because they are too large to represent in PROTOCOL otherwise. |
41 | // This currently only applies for promotion of (VAR)CHAR -> CLOB and (VAR)BINARY -> BLOB |
42 | // The key for this structure is the parameter index. Note that having this |
43 | // collection does not eliminate the need for extdtaPositions_ because that |
44 | // is still needed for non-promototed LOBs |
45 | java.util.HashMap promototedParameters_ = new java.util.HashMap(); |
46 | |
47 | NetStatementRequest(NetAgent netAgent, CcsidManager ccsidManager, int bufferSize) { |
48 | super(netAgent, ccsidManager, bufferSize); |
49 | } |
50 | |
51 | //----------------------------- entry points --------------------------------- |
52 | |
53 | // Write the message to perform an execute immediate. |
54 | // The SQL statement sent as command data cannot contain references |
55 | // to either input variables or output variables. |
56 | // |
57 | // preconditions: |
58 | public void writeExecuteImmediate(NetStatement materialStatement, |
59 | String sql, |
60 | Section section) throws SqlException { |
61 | buildEXCSQLIMM(section, |
62 | false, //sendQryinsid |
63 | 0); //qryinsid |
64 | buildSQLSTTcommandData(sql); // statement follows in sqlstt command data object |
65 | } |
66 | |
67 | // Write the message to preform a prepare into. |
68 | // Once the SQL statement has been prepared, it is executed until the unit of work, in |
69 | // which the PRPSQLSTT command was issued, ends. An exception to this is if |
70 | // Keep Dynamic is being used. |
71 | // |
72 | // preconditions: |
73 | public void writePrepareDescribeOutput(NetStatement materialStatement, |
74 | String sql, |
75 | Section section) throws SqlException { |
76 | buildPRPSQLSTT(section, |
77 | sql, |
78 | true, //sendRtnsqlda |
79 | true, //sendTypsqlda |
80 | CodePoint.TYPSQLDA_X_OUTPUT); //typsqlda |
81 | |
82 | if (((NetStatement) materialStatement).statement_.cursorAttributesToSendOnPrepare_ != null) { |
83 | buildSQLATTRcommandData(((NetStatement) materialStatement).statement_.cursorAttributesToSendOnPrepare_); |
84 | } |
85 | |
86 | buildSQLSTTcommandData(sql); // statement follows in sqlstt command data object |
87 | } |
88 | |
89 | // Write the message to perform a reprepare. |
90 | // |
91 | // preconditions: |
92 | public void writePrepare(NetStatement materialStatement, |
93 | String sql, |
94 | Section section) throws SqlException { |
95 | buildPRPSQLSTT(section, |
96 | sql, |
97 | false, //sendRtnsqlda |
98 | false, //sendTypsqlda |
99 | 0); //typsqlda |
100 | |
101 | if (((NetStatement) materialStatement).statement_.cursorAttributesToSendOnPrepare_ != null) { |
102 | buildSQLATTRcommandData(((NetStatement) materialStatement).statement_.cursorAttributesToSendOnPrepare_); |
103 | } |
104 | |
105 | buildSQLSTTcommandData(sql); // statement follows in sqlstt command data object |
106 | } |
107 | |
108 | // Write the message to execute prepared sql statement. |
109 | // |
110 | // preconditions: |
111 | public void writeExecute(NetPreparedStatement materialPreparedStatement, |
112 | Section section, |
113 | ColumnMetaData parameterMetaData, |
114 | Object[] inputs, |
115 | int numInputColumns, |
116 | boolean outputExpected, |
117 | boolean chained) throws SqlException // chained flag for blobs only //dupqry |
118 | { |
119 | buildEXCSQLSTT(section, |
120 | true, // sendOutexp |
121 | outputExpected, // outexp |
122 | false, // sendPrcnam |
123 | null, // prcnam |
124 | false, // sendQryblksz |
125 | false, // sendMaxrslcnt, |
126 | 0, // maxrslcnt, |
127 | false, // sendMaxblkext |
128 | 0, // maxblkext |
129 | false, // sendRslsetflg |
130 | 0, // resultSetFlag |
131 | false, // sendQryrowset |
132 | 0); // qryrowset |
133 | |
134 | if (numInputColumns > 0) { |
135 | if ((extdtaPositions_ != null) && (!extdtaPositions_.isEmpty())) { |
136 | extdtaPositions_.clear(); // reset extdta column position markers |
137 | } |
138 | |
139 | boolean overrideExists = buildSQLDTAcommandData(numInputColumns, |
140 | parameterMetaData, |
141 | inputs); |
142 | |
143 | // can we eleminate the chain argument needed for lobs |
144 | buildEXTDTA(parameterMetaData, inputs, chained); |
145 | } |
146 | } |
147 | |
148 | |
149 | // Write the message to open a bound or prepared query with input parameters. |
150 | // Check this -> For open query with input parameters |
151 | // |
152 | // preconditions: |
153 | public void writeOpenQuery(NetPreparedStatement materialPreparedStatement, |
154 | Section section, |
155 | int fetchSize, |
156 | int resultSetType, |
157 | int numInputColumns, |
158 | org.apache.derby.client.am.ColumnMetaData parameterMetaData, |
159 | Object[] inputs) throws SqlException { |
160 | boolean sendQryrowset = checkSendQryrowset(fetchSize, resultSetType); |
161 | fetchSize = checkFetchsize(fetchSize, resultSetType); |
162 | // think about if there is a way we can call build ddm just passing ddm parameters and not passing the material ps object |
163 | // maybe not, if sometimes we need to set the caches hanging off the ps object during the ddm build |
164 | // maybe we can extricate conditionals in the build ddm logic outside |
165 | |
166 | buildOPNQRY(section, |
167 | sendQryrowset, |
168 | fetchSize); |
169 | |
170 | |
171 | // may be able to merge this with firstContinueQuery_ and push above conditional to common |
172 | ((NetStatement) materialPreparedStatement).qryrowsetSentOnOpnqry_ = sendQryrowset; |
173 | |
174 | if (numInputColumns > 0) { |
175 | if ((extdtaPositions_ != null) && (!extdtaPositions_.isEmpty())) { |
176 | extdtaPositions_.clear(); // reset extdta column position markers |
177 | } |
178 | // is this the best place for this |
179 | // EXCSQSTT needs this too |
180 | |
181 | // think about having this method return a boolean to |
182 | // indicate the extdta should be built |
183 | boolean overrideExists = buildSQLDTAcommandData(numInputColumns, |
184 | parameterMetaData, |
185 | inputs); |
186 | |
187 | // can we eleminate the chain argument needed for lobs |
188 | // do we chain after Extdta's on open, verify this |
189 | buildEXTDTA(parameterMetaData, |
190 | inputs, |
191 | false); //chained, do we chain after Extdta's on open |
192 | } |
193 | } |
194 | |
195 | // Write the message to open a bound or prepared query without input parameters. |
196 | // Check this-> For open query without input parameters |
197 | public void writeOpenQuery(NetStatement materialStatement, |
198 | Section section, |
199 | int fetchSize, |
200 | int resultSetType) throws SqlException { |
201 | boolean sendQryrowset = checkSendQryrowset(fetchSize, resultSetType); |
202 | fetchSize = checkFetchsize(fetchSize, resultSetType); |
203 | |
204 | // think about if there is a way we can call build ddm just passing ddm parameters and not passing the material ps object |
205 | // maybe not, if sometimes we need to set the caches hanging off the ps object during the ddm build |
206 | // maybe we can extricate conditionals in the build ddm logic outside |
207 | buildOPNQRY(section, |
208 | sendQryrowset, |
209 | fetchSize); |
210 | |
211 | |
212 | // may be able to merge this with firstContinueQuery_ and push above conditional to common |
213 | ((NetStatement) materialStatement).qryrowsetSentOnOpnqry_ = sendQryrowset; // net-specific event |
214 | |
215 | |
216 | } |
217 | |
218 | // Write the message to peform a describe input. |
219 | // |
220 | |
221 | public void writeDescribeInput(NetPreparedStatement materialPreparedStatement, |
222 | Section section) throws SqlException { |
223 | int typsqlda = CodePoint.TYPSQLDA_X_INPUT; |
224 | |
225 | buildDSCSQLSTT(section, |
226 | true, //sendTypsqlda |
227 | typsqlda); |
228 | } |
229 | |
230 | // Write the message to peform a describe output. |
231 | // |
232 | // preconditions: |
233 | public void writeDescribeOutput(NetPreparedStatement materialPreparedStatement, |
234 | Section section) throws SqlException { |
235 | // pick standard, light, extended sqlda. possibly push this up even more |
236 | // right now use SQLAM level as determining factor and go for the most data. |
237 | // if standard is the only suported option, don't send the typsqlda |
238 | // and let server default to standard. This prevents accidentally sending |
239 | // a typsqlda to a downlevel server. typsqlda is only supported at sqlam 6. |
240 | //KATHEY CHECK |
241 | buildDSCSQLSTT(section, |
242 | true, //sendTypsqlda |
243 | CodePoint.TYPSQLDA_X_OUTPUT); //typsqlda |
244 | } |
245 | |
246 | // Write the message to execute a stored procedure. |
247 | // |
248 | // preconditions: |
249 | public void writeExecuteCall(NetStatement materialStatement, |
250 | boolean outputExpected, |
251 | String procedureName, |
252 | Section section, |
253 | int fetchSize, |
254 | boolean suppressResultSets, // for batch updates == true |
255 | int resultSetType, |
256 | ColumnMetaData parameterMetaData, |
257 | Object[] inputs) throws SqlException // chain is for blobs |
258 | { |
259 | // always send QRYROWSET on EXCSQLSTT |
260 | boolean sendQryrowset = true; |
261 | fetchSize = (fetchSize == 0) ? org.apache.derby.client.am.Configuration.defaultFetchSize : fetchSize; |
262 | |
263 | boolean sendPrcnam = (procedureName != null) ? true : false; |
264 | int numParameters = (parameterMetaData != null) ? parameterMetaData.columns_ : 0; |
265 | outputExpected = numParameters > 0; |
266 | |
267 | // is it right here to send maxblkext (-1) |
268 | buildEXCSQLSTT(section, |
269 | true, // sendOutexp |
270 | outputExpected, // outexp |
271 | sendPrcnam, // sendPrcnam |
272 | procedureName, // prcnam |
273 | true, // sendQryblksz |
274 | !suppressResultSets, // sendMaxrslcnt, |
275 | CodePoint.MAXRSLCNT_NOLIMIT, // maxrslcnt, |
276 | true, // sendMaxblkext |
277 | -1, // maxblkext (-1 for AR capable of receiving entire result set) |
278 | true, // sendRslsetflg |
279 | calculateResultSetFlags(), // resultSetFlag |
280 | sendQryrowset, // sendQryrowset |
281 | fetchSize); // qryrowset |
282 | |
283 | if (numParameters > 0) { |
284 | if ((extdtaPositions_ != null) && (!extdtaPositions_.isEmpty())) { |
285 | extdtaPositions_.clear(); // reset extdta column position markers |
286 | } |
287 | // is this the best place for this (OPNQRY needs this too) |
288 | |
289 | // think about having this method return a boolean to |
290 | // indicate the extdta should be built |
291 | boolean overrideExists = buildSQLDTAcommandData(numParameters, |
292 | parameterMetaData, |
293 | inputs); |
294 | |
295 | buildEXTDTA(parameterMetaData, inputs, false); // no chained autocommit for CALLs |
296 | } |
297 | |
298 | ((NetStatement) materialStatement).qryrowsetSentOnOpnqry_ = sendQryrowset; |
299 | } |
300 | |
301 | // Write the message to execute an SQL Set Statement. |
302 | /* |
303 | public void writeSetGenericSQLSetInfo (org.apache.derby.client.am.SetGenericSQLSetPiggybackCommand setGenericSQLSetPiggybackCommand, |
304 | org.apache.derby.client.am.JDBCSection section) throws SqlException |
305 | { |
306 | buildEXCSQLSET (section); |
307 | |
308 | java.util.List sqlsttList = setGenericSQLSetPiggybackCommand.getList(); |
309 | for (int i = 0; i < sqlsttList.size(); i++) { |
310 | String sql = (String)sqlsttList.get(i); |
311 | // Build SQLSTT only for the SET statement that coming from the server after RLSCONV |
312 | buildSQLSTTcommandData (sql); |
313 | } |
314 | } |
315 | |
316 | */ |
317 | //----------------------helper methods---------------------------------------- |
318 | // These methods are "private protected", which is not a recognized java privilege, |
319 | // but means that these methods are private to this class and to subclasses, |
320 | // and should not be used as package-wide friendly methods. |
321 | |
322 | // Build the Open Query Command to open a query to a relational database. |
323 | // At SQLAM >= 7 we can request the return of a DA, are there |
324 | // scenarios where this should currently be done (it is not supported now) |
325 | // |
326 | // preconditions: |
327 | // the sqlam and/or prdid must support command and parameters passed to this method, |
328 | // method will not validate against the connection's level of support |
329 | // |
330 | void buildOPNQRY(Section section, |
331 | boolean sendQueryRowSet, |
332 | int fetchSize) throws SqlException { |
333 | createCommand(); |
334 | markLengthBytes(CodePoint.OPNQRY); |
335 | |
336 | buildPKGNAMCSN(section); |
337 | buildQRYBLKSZ(); // specify a hard coded query block size |
338 | |
339 | if (sendQueryRowSet) { |
340 | buildMAXBLKEXT(-1); |
341 | buildQRYROWSET(fetchSize); |
342 | } |
343 | |
344 | // Tell the server to close forward-only result sets |
345 | // implicitly when they are exhausted. The server will ignore |
346 | // this parameter if the result set is scrollable. |
347 | if (netAgent_.netConnection_.serverSupportsQryclsimp()) { |
348 | buildQRYCLSIMP(); |
349 | } |
350 | |
351 | updateLengthBytes(); // opnqry is complete |
352 | } |
353 | |
354 | // Build the Execute Immediate SQL Statement Command to |
355 | // execute a non-cursor SQL statement sent as command data. |
356 | // |
357 | // precondtions: |
358 | void buildEXCSQLIMM(Section section, |
359 | boolean sendQryinsid, |
360 | long qryinsid) throws SqlException { |
361 | createCommand(); |
362 | markLengthBytes(CodePoint.EXCSQLIMM); |
363 | |
364 | buildPKGNAMCSN(section); |
365 | buildRDBCMTOK(); |
366 | if (sendQryinsid) { |
367 | buildQRYINSID(qryinsid); |
368 | } |
369 | |
370 | updateLengthBytes(); |
371 | } |
372 | |
373 | // Build the Prepare SQL Statement Command to dynamically binds an |
374 | // SQL statement to a section in an existing relational database (RDB) package. |
375 | // |
376 | // preconditions: |
377 | // the sqlam and/or prdid must support command and parameters passed to this method, |
378 | // method will not validate against the connection's level of support |
379 | void buildPRPSQLSTT(Section section, |
380 | String sql, |
381 | boolean sendRtnsqlda, |
382 | boolean sendTypsqlda, |
383 | int typsqlda) throws SqlException { |
384 | createCommand(); |
385 | markLengthBytes(CodePoint.PRPSQLSTT); |
386 | |
387 | buildPKGNAMCSN(section); |
388 | if (sendRtnsqlda) { |
389 | buildRTNSQLDA(); |
390 | } |
391 | if (sendTypsqlda) { |
392 | buildTYPSQLDA(typsqlda); |
393 | } |
394 | |
395 | updateLengthBytes(); |
396 | } |
397 | |
398 | // Build the command to execute an SQL SET Statement. |
399 | // Called by NETSetClientPiggybackCommand.write() |
400 | // |
401 | // preconditions: |
402 | // the sqlam and/or prdid must support command and parameters passed to this method, |
403 | // method will not validate against the connection's level of support |
404 | void buildEXCSQLSET(Section section) |
405 | throws SqlException { |
406 | createCommand(); |
407 | markLengthBytes(CodePoint.EXCSQLSET); |
408 | buildPKGNAMCSN(section); // is this PKGNAMCSN or PKGNAMCT |
409 | updateLengthBytes(); |
410 | } |
411 | |
412 | // Build the Execute SQL Statement (EXCSQLSTT) Command |
413 | // to execute a non-cursor SQL statement previously bound into a named package |
414 | // of a relational database (RDB). The SQL statement can optionally include |
415 | // references to input variables, output variables, or both. |
416 | // |
417 | // At SQLAM >= 7 we can get a DA back on this, are there times that we want to request it |
418 | // If so, we probably want to pass a parameter indicating the sqldaLevel requested. |
419 | // |
420 | // preconditions: |
421 | // the sqlam and/or prdid must support command and parameters passed to this method, |
422 | // method will not validate against the connection's level of support |
423 | // Here is the preferred codepoint ordering: |
424 | // PKGNAMCSN |
425 | // RDBCMTOK |
426 | // OUTEXP |
427 | // QRYBLKSZ |
428 | // MAXBLKEXT |
429 | // MAXRSLCNT |
430 | // RSLSETFLG |
431 | // QRYROWSET |
432 | // RTNSQLDA |
433 | // TYPSQLDA |
434 | // NBRROW |
435 | // ATMIND |
436 | // PRCNAM |
437 | // OUTOVROPT |
438 | // RDBNAM |
439 | void buildEXCSQLSTT(Section section, |
440 | boolean sendOutexp, |
441 | boolean outexp, |
442 | boolean sendPrcnam, |
443 | String prcnam, |
444 | boolean sendQryblksz, |
445 | boolean sendMaxrslcnt, |
446 | int maxrslcnt, |
447 | boolean sendMaxblkext, |
448 | int maxblkext, |
449 | boolean sendRslsetflg, |
450 | int resultSetFlag, |
451 | boolean sendQryrowset, |
452 | int qryrowset) throws SqlException { |
453 | createCommand(); |
454 | markLengthBytes(CodePoint.EXCSQLSTT); |
455 | |
456 | buildPKGNAMCSN(section); |
457 | buildRDBCMTOK(); |
458 | if (sendOutexp) { |
459 | buildOUTEXP(outexp); |
460 | } |
461 | if (sendQryblksz) { |
462 | buildQRYBLKSZ(); |
463 | } |
464 | if (sendQryrowset && sendMaxblkext) { |
465 | buildMAXBLKEXT(maxblkext); |
466 | } |
467 | if (sendMaxrslcnt) { |
468 | buildMAXRSLCNT(maxrslcnt); |
469 | } |
470 | if (sendRslsetflg) { |
471 | buildRSLSETFLG(resultSetFlag); |
472 | } |
473 | if (sendQryrowset) { |
474 | buildQRYROWSET(qryrowset); |
475 | } |
476 | if (sendPrcnam) { |
477 | buildPRCNAM(prcnam); |
478 | } |
479 | |
480 | updateLengthBytes(); // command is complete, update the length bytes |
481 | } |
482 | |
483 | // Build the Describe SQL Statement command. |
484 | // |
485 | // preconditions: |
486 | // the sqlam and/or prdid must support command and parameters passed to this method, |
487 | // method will not validate against the connection's level of support |
488 | void buildDSCSQLSTT(Section section, |
489 | boolean sendTypsqlda, |
490 | int typsqlda) throws SqlException { |
491 | createCommand(); |
492 | markLengthBytes(CodePoint.DSCSQLSTT); |
493 | |
494 | buildPKGNAMCSN(section); |
495 | if (sendTypsqlda) { |
496 | buildTYPSQLDA(typsqlda); |
497 | } |
498 | |
499 | updateLengthBytes(); |
500 | } |
501 | |
502 | // Build the SQL Program Variable Data Command Data Object. |
503 | // This object contains the input data to an SQL statement |
504 | // that an RDB is executing. |
505 | // |
506 | // preconditions: |
507 | boolean buildSQLDTAcommandData(int numInputColumns, |
508 | ColumnMetaData parameterMetaData, |
509 | Object[] inputRow) throws SqlException { |
510 | createEncryptedCommandData(); |
511 | |
512 | int loc = offset_; |
513 | |
514 | markLengthBytes(CodePoint.SQLDTA); |
515 | |
516 | int[][] protocolTypesAndLengths = allocateLidAndLengthsArray(parameterMetaData); |
517 | |
518 | java.util.Hashtable protocolTypeToOverrideLidMapping = null; |
519 | java.util.ArrayList mddOverrideArray = null; |
520 | protocolTypeToOverrideLidMapping = |
521 | computeProtocolTypesAndLengths(inputRow, parameterMetaData, protocolTypesAndLengths, |
522 | protocolTypeToOverrideLidMapping); |
523 | |
524 | boolean overrideExists = false; |
525 | |
526 | buildFDODSC(numInputColumns, |
527 | protocolTypesAndLengths, |
528 | overrideExists, |
529 | protocolTypeToOverrideLidMapping, |
530 | mddOverrideArray); |
531 | |
532 | buildFDODTA(numInputColumns, |
533 | protocolTypesAndLengths, |
534 | inputRow); |
535 | |
536 | updateLengthBytes(); // for sqldta |
537 | if (netAgent_.netConnection_.getSecurityMechanism() == |
538 | NetConfiguration.SECMEC_EUSRIDDTA || |
539 | netAgent_.netConnection_.getSecurityMechanism() == |
540 | NetConfiguration.SECMEC_EUSRPWDDTA) { |
541 | encryptDataStream(loc); |
542 | } |
543 | |
544 | return overrideExists; |
545 | } |
546 | |
547 | // Build the FDOCA Data Descriptor Scalar whose value is a FDOCA |
548 | // Descriptor or a segment of an FDOCA Descriptor. |
549 | // |
550 | // preconditions: |
551 | private void buildFDODSC(int numColumns, |
552 | int[][] protocolTypesAndLengths, |
553 | boolean overrideExists, |
554 | java.util.Hashtable overrideMap, |
555 | java.util.ArrayList overrideArray) throws SqlException { |
556 | markLengthBytes(CodePoint.FDODSC); |
557 | buildSQLDTA(numColumns, protocolTypesAndLengths, overrideExists, overrideMap, overrideArray); |
558 | updateLengthBytes(); |
559 | } |
560 | |
561 | // Build the FDOCA SQLDTA Late Row Descriptor. |
562 | // |
563 | // preconditions: |
564 | protected void buildSQLDTA(int numColumns, |
565 | int[][] lidAndLengthOverrides, |
566 | boolean overrideExists, |
567 | java.util.Hashtable overrideMap, |
568 | java.util.ArrayList overrideArray) throws SqlException { |
569 | // mdd overrides need to be built first if any before the descriptors are built. |
570 | if (overrideExists) { |
571 | buildMddOverrides(overrideArray); |
572 | writeBytes(FdocaConstants.MDD_SQLDTAGRP_TOSEND); |
573 | } |
574 | |
575 | buildSQLDTAGRP(numColumns, lidAndLengthOverrides, overrideExists, overrideMap); |
576 | |
577 | if (overrideExists) { |
578 | writeBytes(FdocaConstants.MDD_SQLDTA_TOSEND); |
579 | } |
580 | writeBytes(FdocaConstants.SQLDTA_RLO_TOSEND); |
581 | } |
582 | |
583 | // Build the FDOCA SQLDTAGRP Late Group Descriptor. |
584 | // preconditions: |
585 | protected void buildSQLDTAGRP(int numVars, |
586 | int[][] lidAndLengthOverrides, |
587 | boolean mddRequired, |
588 | java.util.Hashtable overrideMap) throws SqlException { |
589 | int n = 0; |
590 | int offset = 0; |
591 | |
592 | n = calculateColumnsInSQLDTAGRPtriplet(numVars); |
593 | buildTripletHeader(((3 * n) + 3), |
594 | FdocaConstants.NGDA_TRIPLET_TYPE, |
595 | FdocaConstants.SQLDTAGRP_LID); |
596 | |
597 | do { |
598 | writeLidAndLengths(lidAndLengthOverrides, n, offset, mddRequired, overrideMap); |
599 | numVars -= n; |
600 | if (numVars == 0) { |
601 | break; |
602 | } |
603 | |
604 | offset += n; |
605 | n = calculateColumnsInSQLDTAGRPtriplet(numVars); |
606 | buildTripletHeader(((3 * n) + 3), |
607 | FdocaConstants.CPT_TRIPLET_TYPE, |
608 | 0x00); |
609 | } while (true); |
610 | } |
611 | |
612 | /////////// perf end |
613 | |
614 | |
615 | protected void buildOUTOVR(ResultSet resultSet, |
616 | ColumnMetaData resultSetMetaData) throws SqlException { |
617 | createCommandData(); |
618 | markLengthBytes(CodePoint.OUTOVR); |
619 | int[][] outputOverrides = |
620 | calculateOUTOVRLidAndLengthOverrides(resultSet, resultSetMetaData); |
621 | buildSQLDTARD(resultSetMetaData.columns_, outputOverrides); |
622 | updateLengthBytes(); |
623 | } |
624 | |
625 | private int[][] calculateOUTOVRLidAndLengthOverrides(ResultSet resultSet, |
626 | ColumnMetaData resultSetMetaData) { |
627 | int numVars = resultSetMetaData.columns_; |
628 | int[][] lidAndLengths = new int[numVars][2]; //everything initialized to "default triplet" |
629 | |
630 | return lidAndLengths; |
631 | } |
632 | |
633 | protected void buildSQLDTARD(int numColumns, int[][] lidAndLengthOverrides) throws SqlException { |
634 | buildSQLCADTA(numColumns, lidAndLengthOverrides); |
635 | writeBytes(FdocaConstants.SQLDTARD_RLO_TOSEND); |
636 | } |
637 | |
638 | protected void buildSQLCADTA(int numColumns, int[][] lidAndLengthOverrides) throws SqlException { |
639 | buildSQLDTAGRP(numColumns, lidAndLengthOverrides, false, null); // false means no mdd override |
640 | writeBytes(FdocaConstants.SQLCADTA_RLO_TOSEND); |
641 | } |
642 | |
643 | private void buildFDODTA(int numVars, |
644 | int[][] protocolTypesAndLengths, |
645 | Object[] inputs) throws SqlException { |
646 | try |
647 | { |
648 | long dataLength = 0; |
649 | Object o = null; |
650 | |
651 | markLengthBytes(CodePoint.FDODTA); |
652 | write1Byte(FdocaConstants.NULL_LID); // write the 1-byte row indicator |
653 | |
654 | // write data for each input column |
655 | for (int i = 0; i < numVars; i++) { |
656 | if (inputs[i] == null) { |
657 | if ((protocolTypesAndLengths[i][0] % 2) == 1) { |
658 | write1Byte(FdocaConstants.NULL_DATA); |
659 | } else { |
660 | //bug check |
661 | } |
662 | } else { |
663 | if ((protocolTypesAndLengths[i][0] % 2) == 1) { |
664 | write1Byte(FdocaConstants.INDICATOR_NULLABLE); |
665 | } |
666 | |
667 | switch (protocolTypesAndLengths[i][0] | 0x01) { // mask out null indicator |
668 | case DRDAConstants.DRDA_TYPE_NVARMIX: |
669 | case DRDAConstants.DRDA_TYPE_NLONGMIX: |
670 | // What to do for server that don't understand 1208 (UTF-8) |
671 | // check for a promototed type, and use that instead if it exists |
672 | o = retrievePromotedParameterIfExists(i); |
673 | if (o == null) { |
674 | writeSingleorMixedCcsidLDString((String) inputs[i], netAgent_.typdef_.getCcsidMbcEncoding()); |
675 | } else { // use the promototed object instead |
676 | Clob c = (Clob) o; |
677 | dataLength = c.length(); |
678 | setFDODTALobLength(protocolTypesAndLengths, i, dataLength); |
679 | } |
680 | break; |
681 | |
682 | case DRDAConstants.DRDA_TYPE_NVARCHAR: |
683 | case DRDAConstants.DRDA_TYPE_NLONG: |
684 | o = retrievePromotedParameterIfExists(i); |
685 | if (o == null) { |
686 | |
687 | } else { // use the promototed object instead |
688 | dataLength = ((Clob) o).length(); |
689 | setFDODTALobLength(protocolTypesAndLengths, i, dataLength); |
690 | } |
691 | break; |
692 | |
693 | case DRDAConstants.DRDA_TYPE_NINTEGER: |
694 | writeIntFdocaData(((Integer) inputs[i]).intValue()); |
695 | break; |
696 | case DRDAConstants.DRDA_TYPE_NSMALL: |
697 | writeShortFdocaData(((Short) inputs[i]).shortValue()); |
698 | break; |
699 | case DRDAConstants.DRDA_TYPE_NFLOAT4: |
700 | writeFloat(((Float) inputs[i]).floatValue()); |
701 | break; |
702 | case DRDAConstants.DRDA_TYPE_NFLOAT8: |
703 | writeDouble(((Double) inputs[i]).doubleValue()); |
704 | break; |
705 | case DRDAConstants.DRDA_TYPE_NDECIMAL: |
706 | writeBigDecimal((java.math.BigDecimal) inputs[i], |
707 | (protocolTypesAndLengths[i][1] >> 8) & 0xff, // described precision not actual |
708 | protocolTypesAndLengths[i][1] & 0xff); // described scale, not actual |
709 | break; |
710 | case DRDAConstants.DRDA_TYPE_NDATE: |
711 | writeDate((java.sql.Date) inputs[i]); |
712 | break; |
713 | case DRDAConstants.DRDA_TYPE_NTIME: |
714 | writeTime((java.sql.Time) inputs[i]); |
715 | break; |
716 | case DRDAConstants.DRDA_TYPE_NTIMESTAMP: |
717 | writeTimestamp((java.sql.Timestamp) inputs[i]); |
718 | break; |
719 | case DRDAConstants.DRDA_TYPE_NINTEGER8: |
720 | writeLongFdocaData(((Long) inputs[i]).longValue()); |
721 | break; |
722 | case DRDAConstants.DRDA_TYPE_NVARBYTE: |
723 | case DRDAConstants.DRDA_TYPE_NLONGVARBYTE: |
724 | o = retrievePromotedParameterIfExists(i); |
725 | if (o == null) { |
726 | writeLDBytes((byte[]) inputs[i]); |
727 | } else { // use the promototed object instead |
728 | Blob b = (Blob) o; |
729 | dataLength = b.length(); |
730 | setFDODTALobLength(protocolTypesAndLengths, i, dataLength); |
731 | } |
732 | break; |
733 | case DRDAConstants.DRDA_TYPE_NLOBCSBCS: |
734 | case DRDAConstants.DRDA_TYPE_NLOBCDBCS: |
735 | // check for a promoted Clob |
736 | o = retrievePromotedParameterIfExists(i); |
737 | if (o == null) { |
738 | try { |
739 | dataLength = ((java.sql.Clob) inputs[i]).length(); |
740 | } catch (java.sql.SQLException e) { |
741 | throw new SqlException(netAgent_.logWriter_, |
742 | new ClientMessageId(SQLState.NET_ERROR_GETTING_BLOB_LENGTH), |
743 | e); |
744 | } |
745 | } else { |
746 | dataLength = ((Clob) o).length(); |
747 | } |
748 | setFDODTALobLength(protocolTypesAndLengths, i, dataLength); |
749 | break; |
750 | case DRDAConstants.DRDA_TYPE_NLOBBYTES: |
751 | // check for a promoted Clob |
752 | o = retrievePromotedParameterIfExists(i); |
753 | if (o == null) { |
754 | try { |
755 | dataLength = ((java.sql.Blob) inputs[i]).length(); |
756 | } catch (java.sql.SQLException e) { |
757 | throw new SqlException(netAgent_.logWriter_, |
758 | new ClientMessageId(SQLState.NET_ERROR_GETTING_BLOB_LENGTH), |
759 | e); |
760 | } |
761 | } else { // use promoted Blob |
762 | dataLength = ((Blob) o).length(); |
763 | } |
764 | setFDODTALobLength(protocolTypesAndLengths, i, dataLength); |
765 | break; |
766 | case DRDAConstants.DRDA_TYPE_NLOBCMIXED: |
767 | // check for a promoted Clob |
768 | o = retrievePromotedParameterIfExists(i); |
769 | if (o == null) { |
770 | if (((Clob) inputs[i]).isString()) { |
771 | dataLength = ((Clob) inputs[i]).getUTF8Length(); |
772 | } else // must be a Unicode stream |
773 | { |
774 | dataLength = ((Clob) inputs[i]).length(); |
775 | } |
776 | } else { // use promoted Clob |
777 | dataLength = ((Clob) o).length(); |
778 | } |
779 | setFDODTALobLength(protocolTypesAndLengths, i, dataLength); |
780 | break; |
781 | default: |
782 | throw new SqlException(netAgent_.logWriter_, |
783 | new ClientMessageId(SQLState.NET_UNRECOGNIZED_JDBC_TYPE), |
784 | new Integer(protocolTypesAndLengths[i][0]), |
785 | new Integer(numVars), new Integer(i)); |
786 | } |
787 | } |
788 | } |
789 | updateLengthBytes(); // for fdodta |
790 | } |
791 | catch ( java.sql.SQLException se ) |
792 | { |
793 | throw new SqlException(se); |
794 | } |
795 | } |
796 | |
797 | // preconditions: |
798 | private void buildEXTDTA(ColumnMetaData parameterMetaData, |
799 | Object[] inputRow, |
800 | boolean chained) throws SqlException { |
801 | try |
802 | { |
803 | // build the EXTDTA data, if necessary |
804 | if (extdtaPositions_ != null) { |
805 | boolean chainFlag, chainedWithSameCorrelator; |
806 | |
807 | for (int i = 0; i < extdtaPositions_.size(); i++) { |
808 | int index = ((Integer) extdtaPositions_.get(i)).intValue(); |
809 | |
810 | // is this the last EXTDTA to be built? |
811 | if (i != extdtaPositions_.size() - 1) { // no |
812 | chainFlag = true; |
813 | chainedWithSameCorrelator = true; |
814 | } else { // yes |
815 | chainFlag = chained; |
816 | chainedWithSameCorrelator = false; |
817 | } |
818 | |
819 | // do we have to write a null byte? |
820 | boolean writeNullByte = false; |
821 | if (parameterMetaData.nullable_[index]) { |
822 | writeNullByte = true; |
823 | } |
824 | // Use the type of the input parameter rather than the input |
825 | // column if possible. |
826 | int parameterType = parameterMetaData.clientParamtertype_[index]; |
827 | if (parameterType == 0) { |
828 | parameterType = parameterMetaData.types_[index]; |
829 | } |
830 | |
831 | // the follow types are possible due to promotion to BLOB |
832 | if (parameterType == Types.BLOB |
833 | || parameterType == Types.BINARY |
834 | || parameterType == Types.VARBINARY |
835 | || parameterType == Types.LONGVARBINARY) { |
836 | Blob o = (Blob) retrievePromotedParameterIfExists(index); |
837 | java.sql.Blob b = (o == null) ? (java.sql.Blob) inputRow[index] : o; |
838 | boolean isExternalBlob = !(b instanceof org.apache.derby.client.am.Blob); |
839 | if (isExternalBlob) { |
840 | try { |
841 | writeScalarStream(chainFlag, |
842 | chainedWithSameCorrelator, |
843 | CodePoint.EXTDTA, |
844 | (int) b.length(), |
845 | b.getBinaryStream(), |
846 | writeNullByte, |
847 | index + 1); |
848 | } catch (java.sql.SQLException e) { |
849 | throw new SqlException(netAgent_.logWriter_, |
850 | new ClientMessageId(SQLState.NET_ERROR_GETTING_BLOB_LENGTH), |
851 | e); |
852 | } |
853 | } else if (((Blob) b).isBinaryStream()) { |
854 | writeScalarStream(chainFlag, |
855 | chainedWithSameCorrelator, |
856 | CodePoint.EXTDTA, |
857 | (int) ((Blob) b).length(), |
858 | ((Blob) b).getBinaryStream(), |
859 | writeNullByte, |
860 | index + 1); |
861 | } else { // must be a binary string |
862 | // note: a possible optimization is to use writeScalarLobBytes |
863 | // when the input is small |
864 | // use this: if (b.length () < DssConstants.MAX_DSS_LEN - 6 - 4) |
865 | // writeScalarLobBytes (...) |
866 | // Yes, this would avoid having to new up a java.io.ByteArrayInputStream |
867 | writeScalarStream(chainFlag, |
868 | chainedWithSameCorrelator, |
869 | CodePoint.EXTDTA, |
870 | (int) ((Blob) b).length(), |
871 | ((Blob) b).getBinaryStream(), |
872 | writeNullByte, |
873 | index + 1); |
874 | } |
875 | } |
876 | // the follow types are possible due to promotion to CLOB |
877 | else if ( |
878 | parameterType == Types.CLOB |
879 | || parameterType == Types.CHAR |
880 | || parameterType == Types.VARCHAR |
881 | || parameterType == Types.LONGVARCHAR) { |
882 | Clob o = (Clob) retrievePromotedParameterIfExists(index); |
883 | java.sql.Clob c = (o == null) ? (java.sql.Clob) inputRow[index] : o; |
884 | boolean isExternalClob = !(c instanceof org.apache.derby.client.am.Clob); |
885 | |
886 | if (isExternalClob) { |
887 | try { |
888 | writeScalarStream(chainFlag, |
889 | chainedWithSameCorrelator, |
890 | CodePoint.EXTDTA, |
891 | (int) c.length(), |
892 | c.getCharacterStream(), |
893 | writeNullByte, |
894 | index + 1); |
895 | } catch (java.sql.SQLException e) { |
896 | throw new SqlException(netAgent_.logWriter_, |
897 | new ClientMessageId(SQLState.NET_ERROR_GETTING_BLOB_LENGTH), |
898 | e); |
899 | } |
900 | } else if (((Clob) c).isCharacterStream()) { |
901 | writeScalarStream(chainFlag, |
902 | chainedWithSameCorrelator, |
903 | CodePoint.EXTDTA, |
904 | (int) ((Clob) c).length(), |
905 | ((Clob) c).getCharacterStream(), |
906 | writeNullByte, |
907 | index + 1); |
908 | } else if (((Clob) c).isAsciiStream()) { |
909 | writeScalarStream(chainFlag, |
910 | chainedWithSameCorrelator, |
911 | CodePoint.EXTDTA, |
912 | (int) ((Clob) c).length(), |
913 | ((Clob) c).getAsciiStream(), |
914 | writeNullByte, |
915 | index + 1); |
916 | } else if (((Clob) c).isUnicodeStream()) { |
917 | writeScalarStream(chainFlag, |
918 | chainedWithSameCorrelator, |
919 | CodePoint.EXTDTA, |
920 | (int) ((Clob) c).length(), |
921 | ((Clob) c).getUnicodeStream(), |
922 | writeNullByte, |
923 | index + 1); |
924 | } else { // must be a String |
925 | // note: a possible optimization is to use writeScalarLobBytes |
926 | // when the input is small. |
927 | // use this: if (c.length () < DssConstants.MAX_DSS_LEN - 6 - 4) |
928 | // writeScalarLobBytes (...) |
929 | writeScalarStream(chainFlag, |
930 | chainedWithSameCorrelator, |
931 | CodePoint.EXTDTA, |
932 | (int) ((Clob) c).getUTF8Length(), |
933 | new java.io.ByteArrayInputStream(((Clob) c).getUtf8String()), |
934 | writeNullByte, |
935 | index + 1); |
936 | } |
937 | } |
938 | } |
939 | } |
940 | } |
941 | catch ( java.sql.SQLException se ) |
942 | { |
943 | throw new SqlException(se); |
944 | } |
945 | } |
946 | |
947 | |
948 | //-------------------------helper methods------------------------------------- |
949 | // returns the a promototedParameter object for index or null if it does not exist |
950 | private Object retrievePromotedParameterIfExists(int index) { |
951 | |
952 | // consider using a nonsynchronized container or array |
953 | if (promototedParameters_.isEmpty()) { |
954 | return null; |
955 | } |
956 | return promototedParameters_.get(new Integer(index)); |
957 | } |
958 | |
959 | private int calculateColumnsInSQLDTAGRPtriplet(int numVars) { |
960 | if (numVars > FdocaConstants.MAX_VARS_IN_NGDA) //rename to MAX_VARS_IN_SQLDTAGRP_TRIPLET |
961 | { |
962 | return FdocaConstants.MAX_VARS_IN_NGDA; |
963 | } |
964 | return numVars; |
965 | } |
966 | |
967 | |
968 | // Consider refacctor so that this does not even have to look |
969 | // at the actual object data, and only uses tags from the meta data |
970 | // only have to call this once, rather than calling this for every input row |
971 | // backburner: after refactoring this, later on, think about replacing case statements with table lookups |
972 | private java.util.Hashtable computeProtocolTypesAndLengths(Object[] inputRow, |
973 | ColumnMetaData parameterMetaData, |
974 | int[][] lidAndLengths, |
975 | java.util.Hashtable overrideMap) throws SqlException { |
976 | try |
977 | { |
978 | int numVars = parameterMetaData.columns_; |
979 | String s = null; |
980 | if (!promototedParameters_.isEmpty()) { |
981 | promototedParameters_.clear(); |
982 | } |
983 | |
984 | for (int i = 0; i < numVars; i++) { |
985 | |
986 | int jdbcType; |
987 | // Send the input type unless it is not available. |
988 | // (e.g an output parameter) |
989 | jdbcType = parameterMetaData.clientParamtertype_[i]; |
990 | if (jdbcType == 0) { |
991 | jdbcType = parameterMetaData.types_[i]; |
992 | } |
993 | |
994 | // jdbc semantics - This should happen outside of the build methods |
995 | // if describe input is not supported, we require the user to at least |
996 | // call setNull() and provide the type information. Otherwise, we won't |
997 | // be able to guess the right PROTOCOL type to send to the server, and an |
998 | // exception is thrown. |
999 | |
1000 | if (jdbcType == 0) { |
1001 | throw new SqlException(netAgent_.logWriter_, |
1002 | new ClientMessageId(SQLState.NET_INVALID_JDBC_TYPE_FOR_PARAM), |
1003 | new Integer(i)); |
1004 | } |
1005 | |
1006 | switch (jdbcType) { |
1007 | case java.sql.Types.CHAR: |
1008 | case java.sql.Types.VARCHAR: |
1009 | // lid: PROTOCOL_TYPE_NVARMIX, length override: 32767 (max) |
1010 | // dataFormat: String |
1011 | // this won't work if 1208 is not supported |
1012 | s = (String) inputRow[i]; |
1013 | // assumes UTF-8 characters at most 3 bytes long |
1014 | // Flow the String as a VARCHAR |
1015 | if (s == null || s.length() <= 32767 / 3) { |
1016 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NVARMIX; |
1017 | lidAndLengths[i][1] = 32767; |
1018 | } else { |
1019 | // Flow the data as CLOB data if the data too large to for LONGVARCHAR |
1020 | java.io.ByteArrayInputStream bais = null; |
1021 | byte[] ba = null; |
1022 | try { |
1023 | ba = s.getBytes("UTF-8"); |
1024 | bais = new java.io.ByteArrayInputStream(ba); |
1025 | Clob c = new Clob(netAgent_, bais, "UTF-8", ba.length); |
1026 | // inputRow[i] = c; |
1027 | // Place the new Lob in the promototedParameter_ collection for |
1028 | // NetStatementRequest use |
1029 | promototedParameters_.put(new Integer(i), c); |
1030 | |
1031 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED; |
1032 | lidAndLengths[i][1] = buildPlaceholderLength(c.length()); |
1033 | } catch (java.io.UnsupportedEncodingException e) { |
1034 | throw new SqlException(netAgent_.logWriter_, |
1035 | new ClientMessageId(SQLState.UNSUPPORTED_ENCODING), |
1036 | "byte array", "Clob", e); |
1037 | } |
1038 | } |
1039 | break; |
1040 | case java.sql.Types.INTEGER: |
1041 | // lid: PROTOCOL_TYPE_NINTEGER, length override: 4 |
1042 | // dataFormat: Integer |
1043 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NINTEGER; |
1044 | lidAndLengths[i][1] = 4; |
1045 | break; |
1046 | case java.sql.Types.BOOLEAN: |
1047 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NBOOLEAN; |
1048 | lidAndLengths[i][1] = 1; |
1049 | break; |
1050 | case java.sql.Types.SMALLINT: |
1051 | case java.sql.Types.TINYINT: |
1052 | case java.sql.Types.BIT: |
1053 | // lid: PROTOCOL_TYPE_NSMALL, length override: 2 |
1054 | // dataFormat: Short |
1055 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NSMALL; |
1056 | lidAndLengths[i][1] = 2; |
1057 | break; |
1058 | case java.sql.Types.REAL: |
1059 | // lid: PROTOCOL_TYPE_NFLOAT4, length override: 4 |
1060 | // dataFormat: Float |
1061 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NFLOAT4; |
1062 | lidAndLengths[i][1] = 4; |
1063 | break; |
1064 | case java.sql.Types.DOUBLE: |
1065 | case java.sql.Types.FLOAT: |
1066 | // lid: PROTOCOL_TYPE_NFLOAT8, length override: 8 |
1067 | // dataFormat: Double |
1068 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NFLOAT8; |
1069 | lidAndLengths[i][1] = 8; |
1070 | break; |
1071 | case java.sql.Types.NUMERIC: |
1072 | case java.sql.Types.DECIMAL: |
1073 | // lid: PROTOCOL_TYPE_NDECIMAL |
1074 | // dataFormat: java.math.BigDecimal |
1075 | // input only: |
1076 | // if null and describe input - use describe input precision and scale |
1077 | // if not null and describe input - calculate precision and actual scale from data |
1078 | // if null and no describe input - guess with precision 1 scale 0 |
1079 | // if not null and no describe input - calculate precision and actual scale from data |
1080 | // output only: |
1081 | // use largest precision/scale based on registered scale from registerOutParameter |
1082 | // inout: |
1083 | // if null - use largest precision/scale based on scale from registerOutParameter |
1084 | // if not null - write bigDecimal () pass registered scale so it can pad, you don't even |
1085 | // have to look at the actual scale at this level. |
1086 | /* |
1087 | if (parameterMetaData.isGuessed) { |
1088 | java.math.BigDecimal bigDecimal = (java.math.BigDecimal) inputRow[i]; |
1089 | int precision = Utils.computeBigDecimalPrecision (bigDecimal); |
1090 | lidAndLengths[i][1] = (precision << 8) + // use precision above |
1091 | (bigDecimal.scale() << 0); |
1092 | } |
1093 | */ |
1094 | // Split this entire method into two parts, the first method is called only once and the inputRow is not passed,!! |
1095 | // the second method is called for every inputRow and overrides inputDA lengths/scales based upon the acutal data! |
1096 | // for decimal and blob columns only |
1097 | int precision = parameterMetaData.sqlPrecision_[i]; |
1098 | int scale = parameterMetaData.sqlScale_[i]; |
1099 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NDECIMAL; |
1100 | lidAndLengths[i][1] = (precision << 8) + (scale << 0); |
1101 | break; |
1102 | case java.sql.Types.DATE: |
1103 | // for input, output, and inout parameters |
1104 | // lid: PROTOCOL_TYPE_NDATE, length override: 8 |
1105 | // dataFormat: java.sql.Date |
1106 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NDATE; |
1107 | lidAndLengths[i][1] = 10; |
1108 | break; |
1109 | case java.sql.Types.TIME: |
1110 | // for input, output, and inout parameters |
1111 | // lid: PROTOCOL_TYPE_NTIME, length override: 8 |
1112 | // dataFormat: java.sql.Time |
1113 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NTIME; |
1114 | lidAndLengths[i][1] = 8; |
1115 | break; |
1116 | case java.sql.Types.TIMESTAMP: |
1117 | // for input, output, and inout parameters |
1118 | // lid: PROTOCOL_TYPE_NTIME, length overrid: 26 |
1119 | // dataFormat: java.sql.Timestamp |
1120 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NTIMESTAMP; |
1121 | lidAndLengths[i][1] = 26; |
1122 | break; |
1123 | case java.sql.Types.BIGINT: |
1124 | // if SQLAM < 6 this should be mapped to decimal (19,0) in common layer |
1125 | // if SQLAM >=6, lid: PROTOCOL_TYPE_NINTEGER8, length override: 8 |
1126 | // dataFormat: Long |
1127 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NINTEGER8; |
1128 | lidAndLengths[i][1] = 8; |
1129 | break; |
1130 | case java.sql.Types.LONGVARCHAR: |
1131 | // Is this the right thing to do // should this be 32700 |
1132 | s = (String) inputRow[i]; |
1133 | if (s == null || s.length() <= 32767 / 3) { |
1134 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLONGMIX; |
1135 | lidAndLengths[i][1] = 32767; |
1136 | } else { |
1137 | // Flow the data as CLOB data if the data too large to for LONGVARCHAR |
1138 | java.io.ByteArrayInputStream bais = null; |
1139 | byte[] ba = null; |
1140 | try { |
1141 | ba = s.getBytes("UTF-8"); |
1142 | bais = new java.io.ByteArrayInputStream(ba); |
1143 | Clob c = new Clob(netAgent_, bais, "UTF-8", ba.length); |
1144 | |
1145 | // inputRow[i] = c; |
1146 | // Place the new Lob in the promototedParameter_ collection for |
1147 | // NetStatementRequest use |
1148 | promototedParameters_.put(new Integer(i), c); |
1149 | |
1150 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED; |
1151 | lidAndLengths[i][1] = buildPlaceholderLength(c.length()); |
1152 | } catch (java.io.UnsupportedEncodingException e) { |
1153 | throw new SqlException(netAgent_.logWriter_, |
1154 | new ClientMessageId(SQLState.UNSUPPORTED_ENCODING), |
1155 | "byte array", "Clob"); |
1156 | } |
1157 | } |
1158 | break; |
1159 | case java.sql.Types.BINARY: |
1160 | case java.sql.Types.VARBINARY: |
1161 | byte[] ba = (byte[]) inputRow[i]; |
1162 | if (ba == null) { |
1163 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NVARBYTE; |
1164 | lidAndLengths[i][1] = 32767; |
1165 | } else if (ba.length <= 32767) { |
1166 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NVARBYTE; |
1167 | lidAndLengths[i][1] = 32767; |
1168 | } else { |
1169 | // Promote to a BLOB. Only reach this path in the absence of describe information. |
1170 | Blob b = new Blob(ba, netAgent_, 0); |
1171 | |
1172 | // inputRow[i] = b; |
1173 | // Place the new Lob in the promototedParameter_ collection for |
1174 | // NetStatementRequest use |
1175 | promototedParameters_.put(new Integer(i), b); |
1176 | |
1177 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBBYTES; |
1178 | lidAndLengths[i][1] = buildPlaceholderLength(ba.length); |
1179 | } |
1180 | break; |
1181 | case java.sql.Types.LONGVARBINARY: |
1182 | ba = (byte[]) inputRow[i]; |
1183 | if (ba == null) { |
1184 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLONGVARBYTE; |
1185 | lidAndLengths[i][1] = 32767; |
1186 | } else if (ba.length <= 32767) { |
1187 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLONGVARBYTE; |
1188 | lidAndLengths[i][1] = 32767; |
1189 | } else { |
1190 | // Promote to a BLOB. Only reach this path in the absensce of describe information. |
1191 | Blob b = new Blob(ba, netAgent_, 0); |
1192 | |
1193 | // inputRow[i] = b; |
1194 | // Place the new Lob in the promototedParameter_ collection for |
1195 | // NetStatementRequest use |
1196 | promototedParameters_.put(new Integer(i), b); |
1197 | |
1198 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBBYTES; |
1199 | lidAndLengths[i][1] = buildPlaceholderLength(ba.length); |
1200 | } |
1201 | break; |
1202 | case java.sql.Types.BLOB: |
1203 | java.sql.Blob b = (java.sql.Blob) inputRow[i]; |
1204 | if (b == null) { |
1205 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBBYTES; |
1206 | lidAndLengths[i][1] = |
1207 | buildPlaceholderLength(parameterMetaData.sqlLength_[i]); |
1208 | } else { |
1209 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBBYTES; |
1210 | try { |
1211 | lidAndLengths[i][1] = buildPlaceholderLength(b.length()); |
1212 | } catch (java.sql.SQLException e) { |
1213 | throw new SqlException(netAgent_.logWriter_, |
1214 | new ClientMessageId(SQLState.NET_ERROR_GETTING_BLOB_LENGTH), e); |
1215 | } |
1216 | } |
1217 | break; |
1218 | case java.sql.Types.CLOB: |
1219 | { |
1220 | // use columnMeta.singleMixedByteOrDouble_ to decide protocolType |
1221 | java.sql.Clob c = (java.sql.Clob) inputRow[i]; |
1222 | boolean isExternalClob = !(c instanceof org.apache.derby.client.am.Clob); |
1223 | long lobLength = 0; |
1224 | if (c == null) { |
1225 | lobLength = parameterMetaData.sqlLength_[i]; |
1226 | } else if (isExternalClob) { |
1227 | try { |
1228 | lobLength = c.length(); |
1229 | } catch (java.sql.SQLException e) { |
1230 | throw new SqlException(netAgent_.logWriter_, |
1231 | new ClientMessageId(SQLState.NET_ERROR_GETTING_BLOB_LENGTH), |
1232 | e); |
1233 | } |
1234 | } else { |
1235 | lobLength = ((Clob) c).length(); |
1236 | } |
1237 | if (c == null) { |
1238 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED; |
1239 | lidAndLengths[i][1] = buildPlaceholderLength(lobLength); |
1240 | } else if (isExternalClob) { |
1241 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCDBCS; |
1242 | lidAndLengths[i][1] = buildPlaceholderLength(lobLength); |
1243 | } else if (((Clob) c).isCharacterStream()) { |
1244 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCDBCS; |
1245 | lidAndLengths[i][1] = buildPlaceholderLength(lobLength); |
1246 | } else if (((Clob) c).isUnicodeStream()) { |
1247 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED; |
1248 | lidAndLengths[i][1] = buildPlaceholderLength(lobLength); |
1249 | } else if (((Clob) c).isAsciiStream()) { |
1250 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCSBCS; |
1251 | lidAndLengths[i][1] = buildPlaceholderLength(lobLength); |
1252 | } else if (((Clob) c).isString()) { |
1253 | lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED; |
1254 | lidAndLengths[i][1] = buildPlaceholderLength(((Clob) c).getUTF8Length()); |
1255 | } |
1256 | } |
1257 | break; |
1258 | default : |
1259 | throw new SqlException(netAgent_.logWriter_, |
1260 | new ClientMessageId(SQLState.UNRECOGNIZED_JAVA_SQL_TYPE), |
1261 | new Integer(jdbcType)); |
1262 | } |
1263 | |
1264 | if (!parameterMetaData.nullable_[i]) { |
1265 | lidAndLengths[i][0]--; |
1266 | } |
1267 | } |
1268 | return overrideMap; |
1269 | } |
1270 | catch ( java.sql.SQLException se ) |
1271 | { |
1272 | throw new SqlException(se); |
1273 | } |
1274 | } |
1275 | |
1276 | private int buildPlaceholderLength(long totalLength) { |
1277 | if (totalLength < 0x7fff) { |
1278 | return 0x8002; // need 2 bytes |
1279 | } else if (totalLength < 0x7fffffff) { |
1280 | return 0x8004; // need 4 bytes |
1281 | } else if (totalLength < 0x7fffffffffffL) { |
1282 | return 0x8006; |
1283 | } else { |
1284 | return 0x8008; // need 8 bytes |
1285 | } |
1286 | } |
1287 | |
1288 | // Output Expected indicates wheterh the requester expects the target |
1289 | // SQLAM to return output with an SQLDTARD reply data object |
1290 | // as a result of the execution of the referenced SQL statement. |
1291 | // this is a single byte. |
1292 | // there are two possible enumerated values: |
1293 | // 0x'F1' (CodePoint.TRUE) - for true indicating the requester expects output |
1294 | // 0x'F0' (CodePoint.FALSE) - for false indicating the requeser does not expect output |
1295 | // 0x'F0' is the default. |
1296 | // |
1297 | // preconditions: |
1298 | // sqlam must support this parameter on the command, method will not check. |
1299 | private void buildOUTEXP(boolean outputExpected) throws SqlException { |
1300 | if (outputExpected) { |
1301 | writeScalar1Byte(CodePoint.OUTEXP, CodePoint.TRUE); |
1302 | } |
1303 | } |
1304 | |
1305 | // Maximum Number of Extra Blocks specifies a limit on the number of extra |
1306 | // blocks of answer set data per result set that the requester is capable of |
1307 | // receiveing. |
1308 | // this value must be able to be contained in a two byte signed number. |
1309 | // there is a minimum value of 0. |
1310 | // a zero indicates that the requester is not capable of receiving extra |
1311 | // query blocks of answer set data. |
1312 | // there is a SPCVAL of -1. |
1313 | // a value of -1 indicates that the requester is capable of receiving |
1314 | // the entire result set. |
1315 | // |
1316 | // preconditions: |
1317 | // sqlam must support this parameter on the command, method will not check. |
1318 | void buildMAXBLKEXT(int maxNumOfExtraBlocks) throws SqlException { |
1319 | if (maxNumOfExtraBlocks != 0) { |
1320 | writeScalar2Bytes(CodePoint.MAXBLKEXT, maxNumOfExtraBlocks); |
1321 | } |
1322 | } |
1323 | |
1324 | // preconditions: |
1325 | void buildQRYROWSET(int fetchSize) throws SqlException { |
1326 | writeScalar4Bytes(CodePoint.QRYROWSET, fetchSize); |
1327 | } |
1328 | |
1329 | // The Procedure Name. |
1330 | // The default value of PRCNAM is the procedure name value contained |
1331 | // within the section identified by the pkgnamcsn parameter. If that |
1332 | // value is null, then the prcnam parameter must be specified. |
1333 | // it has a max length of 255. |
1334 | // the prcnam is required on commands if the procedure name is |
1335 | // specified by a host variable. |
1336 | // the default value is the procedure name contained in the section |
1337 | // specified by the pkgnamcsn parameter on the EXCSQLSTT command. |
1338 | // |
1339 | // preconditions: |
1340 | // sqlam must support this parameter for the command, method will not check. |
1341 | // prcnam can not be null, SQLException will be thrown |
1342 | // prcnam can not be 0 length or > 255 length, SQLException will be thrown. |
1343 | private void buildPRCNAM(String prcnam) throws SqlException { |
1344 | if (prcnam == null) { |
1345 | throw new SqlException(netAgent_.logWriter_, |
1346 | new ClientMessageId(SQLState.NET_NULL_PROCEDURE_NAME)); |
1347 | } |
1348 | |
1349 | int prcnamLength = prcnam.length(); |
1350 | if ((prcnamLength == 0) || (prcnamLength > 255)) { |
1351 | throw new SqlException(netAgent_.logWriter_, |
1352 | new ClientMessageId(SQLState.NET_PROCEDURE_NAME_LENGTH_OUT_OF_RANGE), |
1353 | new Integer(prcnamLength), new Integer(255)); |
1354 | } |
1355 | |
1356 | writeScalarString(CodePoint.PRCNAM, prcnam); |
1357 | } |
1358 | |
1359 | |
1360 | // Query Block Size specifies the query block size for the reply |
1361 | // data objects and the reply messages being returned from this command. |
1362 | // this is a 4 byte unsigned binary number. |
1363 | // the sqlam 6 min value is 512 and max value is 32767. |
1364 | // this value was increased in later sqlam levels. |
1365 | // until the code is ready to support larger query block sizes, |
1366 | // it will always use DssConstants.MAX_DSS_LEN which is 32767. |
1367 | // |
1368 | // preconditions: |
1369 | // sqlam must support this parameter for the command, method will not check. |
1370 | void buildQRYBLKSZ() throws SqlException { |
1371 | writeScalar4Bytes(CodePoint.QRYBLKSZ, DssConstants.MAX_DSS_LEN); |
1372 | } |
1373 | |
1374 | // Maximum Result Set Count specifies a limit on the number of result sets |
1375 | // the requester is capable of receiving as reply data in response to an ECSQLSTT |
1376 | // command that invokes a stored procedure. If the stored procedure generates |
1377 | // more than MAXRSLCNT result sets, then the target system returns at most, the first |
1378 | // MAXRSLCNT of these result sets. The stored procedure defines the order |
1379 | // in which the target system returns result sets. |
1380 | // this is s two byte signed binary number. |
1381 | // it has a min value of 0 which indicates the requester is not capable |
1382 | // of receiving result sets as reply data in response to the command. |
1383 | // a special value, -1 (CodePoint.MAXRSLCNT_NOLIMIT = 0xffff), indicates the |
1384 | // requester is capable of receiving all result sets in response the EXCSQLSTT. |
1385 | // |
1386 | // preconditions: |
1387 | // sqlam must support this parameter for the command, method will not check. |
1388 | // the value must be in correct range (-1 to 32767), method will not check. |
1389 | private void buildMAXRSLCNT(int maxResultSetCount) throws SqlException { |
1390 | if (maxResultSetCount == 0) { |
1391 | return; |
1392 | } |
1393 | writeScalar2Bytes(CodePoint.MAXRSLCNT, maxResultSetCount); |
1394 | } |
1395 | |
1396 | // RDB Commit Allowed specifies whether an RDB should allow the processing of any |
1397 | // commit or rollback operations that occure during execution of a statement. |
1398 | // True allow the processing of commits and rollbacks |
1399 | private void buildRDBCMTOK() throws SqlException { |
1400 | writeScalar1Byte(CodePoint.RDBCMTOK, CodePoint.TRUE); |
1401 | } |
1402 | |
1403 | // Result Set Flags is a single byte where each bit it a boolean flag. |
1404 | // It specifies wheter the requester desires the server to return name, |
1405 | // label and comment information for the columns of result sets generated by the command. |
1406 | // The default is b'00000000'. |
1407 | // columnNamesRequired |
1408 | // false means the requester does not desire column names returned. |
1409 | // true means the requester desires column names returned. |
1410 | // columnLabelsRequired |
1411 | // false means the requester does not desire column labels returned. |
1412 | // true means the requester desires column labels returned. |
1413 | // columnCommentsRequired |
1414 | // false means the requester does not desire column comments returned. |
1415 | // true means the requester desired column comments returned. |
1416 | // cantProcessAnswerSetData |
1417 | // false means that for each result set, the requester expects the command |
1418 | // to return an FDOCA description of the answer set data and to possibly |
1419 | // return answer set data. the block containing the end of the description |
1420 | // may be completed if room exists with answer set data. additional blocks |
1421 | // of answer set data may also be chained to the block containing the end of the |
1422 | // FDOCA description. up to the maximum number of extra blocks of answer set data |
1423 | // per result set specified in the MAXBLKEXT parameter. |
1424 | // true means that for each result set, the requester expects the command to return |
1425 | // an FDOCA description of the answer set data but does not expect the command to |
1426 | // return any answer set data. |
1427 | // at SQLAM 7, new flags are supported which can be used to return |
1428 | // standard, extended, and light sqlda |
1429 | // |
1430 | // preconditions: |
1431 | // sqlam must support this parameter, method will not check. |
1432 | private void buildRSLSETFLG(int resultSetFlag) throws SqlException { |
1433 | writeScalar1Byte(CodePoint.RSLSETFLG, resultSetFlag); |
1434 | } |
1435 | |
1436 | void buildQRYINSID(long qryinsid) throws SqlException { |
1437 | markLengthBytes(CodePoint.QRYINSID); |
1438 | writeLong(qryinsid); |
1439 | updateLengthBytes(); |
1440 | } |
1441 | |
1442 | |
1443 | // Return SQL Descriptor Area controls whether to return |
1444 | // an SQL descriptor area that applies to the SQL statement this command |
1445 | // identifies. The target SQLAM obtains the SQL descriptor area by performing |
1446 | // an SQL DESCRIBE function on the statement after the statement has been |
1447 | // prepared. |
1448 | // The value TRUE, X'F1' (CodePoint.TRUE), indicates an SQLDA is returned |
1449 | // The value FALSE, X'F0' (CodePoint.FALSE), default, indicates an SQLDA is not returned. |
1450 | // |
1451 | // preconditions: |
1452 | // sqlam must support this parameter for the command, method will not check. |
1453 | private void buildRTNSQLDA() throws SqlException { |
1454 | writeScalar1Byte(CodePoint.RTNSQLDA, CodePoint.TRUE); |
1455 | } |
1456 | |
1457 | // Type of SQL Descriptor Area. |
1458 | // This is a single byte signed number that specifies the type of sqlda to |
1459 | // return for the command. |
1460 | // below sqlam 7 there were two possible enumerated values for this parameter. |
1461 | // 0 (CodePoint.TYPSQLDA_STD_OUTPUT)- the default, indicates return the output sqlda. |
1462 | // 1 (CodePoint.TYPSQLDA_STD_INPUT) - indicates return the input sqlda. |
1463 | // the typsqlda was enhanced at sqlam 7 to support extened describe. |
1464 | // at sqlam 7 the following enumerated values are supported. |
1465 | // 0 (CodePoint.TYPSQLDA_STD_OUTPUT) - the default, standard output sqlda. |
1466 | // 1 (CodePoint.TYPSQLDA_STD_INPUT) - standard input sqlda. |
1467 | // 2 (CodePoint.TYPSQLDA_LIGHT_OUTPUT) - light output sqlda. |
1468 | // 3 (CodePoint.TYPSQLDA_LIGHT_INPUT) - light input sqlda. |
1469 | // 4 (CodePoint.TYPSQLDA_X_OUTPUT) - extended output sqlda. |
1470 | // 5 (CodePoint.TYPSQLDA_X_INPUT) - extended input sqlda. |
1471 | // |
1472 | // preconditions: |
1473 | // sqlam or prdid must support this, method will not check. |
1474 | // valid enumerated type must be passed to method, method will not check. |
1475 | private void buildTYPSQLDA(int typeSqlda) throws SqlException { |
1476 | // possibly inspect typeSqlda value and verify against sqlam level |
1477 | if (typeSqlda != CodePoint.TYPSQLDA_STD_OUTPUT) { |
1478 | writeScalar1Byte(CodePoint.TYPSQLDA, typeSqlda); |
1479 | } |
1480 | } |
1481 | |
1482 | /** |
1483 | * Build QRYCLSIMP (Query Close Implicit). Query Close Implicit |
1484 | * controls whether the target server implicitly closes a |
1485 | * non-scrollable query upon end of data (SQLSTATE 02000). |
1486 | */ |
1487 | private void buildQRYCLSIMP() { |
1488 | writeScalar1Byte(CodePoint.QRYCLSIMP, CodePoint.QRYCLSIMP_YES); |
1489 | } |
1490 | |
1491 | // helper method to buildFDODTA to build the actual data length |
1492 | private void setFDODTALobLength(int[][] protocolTypesAndLengths, int i, long dataLength) throws SqlException { |
1493 | if (protocolTypesAndLengths[i][1] == 0x8002) { |
1494 | writeShort((short) dataLength); |
1495 | } else if (protocolTypesAndLengths[i][1] == 0x8004) { |
1496 | writeInt((int) dataLength); // 4 bytes to encode the length |
1497 | } else if (protocolTypesAndLengths[i][1] == 0x8006)// 6 bytes to encode the length |
1498 | { |
1499 | writeLong(dataLength); |
1500 | } |
1501 | //throw new SqlException (netAgent_.logWriter_, "0x8006 lob place holders not yet supported"); |
1502 | else if (protocolTypesAndLengths[i][1] == 0x8008)// 8 bytes to encode the length |
1503 | { |
1504 | writeLong(dataLength); |
1505 | } |
1506 | |
1507 | if (dataLength != 0) { |
1508 | if (extdtaPositions_ == null) { |
1509 | extdtaPositions_ = new java.util.ArrayList(); |
1510 | } |
1511 | extdtaPositions_.add(new Integer(i)); |
1512 | } |
1513 | } |
1514 | |
1515 | private boolean checkSendQryrowset(int fetchSize, |
1516 | int resultSetType) { |
1517 | // if the cursor is forward_only, ignore the fetchSize and let the server return |
1518 | // as many rows as fit in the query block. |
1519 | // if the cursor is scrollable, send qryrowset if it is supported by the server |
1520 | boolean sendQryrowset = false; |
1521 | if (resultSetType != java.sql.ResultSet.TYPE_FORWARD_ONLY) { |
1522 | sendQryrowset = true; |
1523 | } |
1524 | return sendQryrowset; |
1525 | } |
1526 | |
1527 | private int checkFetchsize(int fetchSize, int resultSetType) { |
1528 | // if fetchSize is not set for scrollable cursors, set it to the default fetchSize |
1529 | if (resultSetType != java.sql.ResultSet.TYPE_FORWARD_ONLY && fetchSize == 0) { |
1530 | fetchSize = org.apache.derby.client.am.Configuration.defaultFetchSize; |
1531 | } |
1532 | return fetchSize; |
1533 | } |
1534 | |
1535 | private int calculateResultSetFlags() { |
1536 | return CodePoint.RSLSETFLG_EXTENDED_SQLDA; |
1537 | } |
1538 | |
1539 | public void writeSetSpecialRegister(java.util.ArrayList sqlsttList) throws SqlException { |
1540 | Section section = |
1541 | netAgent_.sectionManager_.getDynamicSection(java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT); |
1542 | |
1543 | buildEXCSQLSET(section); |
1544 | |
1545 | // SQLSTT: |
1546 | for (int i = 0; i < sqlsttList.size(); i++) { |
1547 | buildSQLSTTcommandData((String) sqlsttList.get(i)); |
1548 | } |
1549 | } |
1550 | |
1551 | private int[][] allocateLidAndLengthsArray(ColumnMetaData parameterMetaData) { |
1552 | int numVars = parameterMetaData.columns_; |
1553 | int[][] lidAndLengths = parameterMetaData.protocolTypesCache_; |
1554 | if ((lidAndLengths) == null || (lidAndLengths.length != numVars)) { |
1555 | lidAndLengths = new int[numVars][2]; |
1556 | parameterMetaData.protocolTypesCache_ = lidAndLengths; |
1557 | } |
1558 | return lidAndLengths; |
1559 | } |
1560 | |
1561 | private void buildMddOverrides(java.util.ArrayList sdaOverrides) throws SqlException { |
1562 | byte[] mddBytes; |
1563 | for (int i = 0; i < sdaOverrides.size(); i++) { |
1564 | mddBytes = (byte[]) (sdaOverrides.get(i)); |
1565 | writeBytes(mddBytes); |
1566 | } |
1567 | } |
1568 | |
1569 | private int getNextOverrideLid() { |
1570 | return overrideLid_++; |
1571 | } |
1572 | } |
1573 | |
1574 | |