1 | /* |
2 | * The contents of this file are subject to the Initial |
3 | * Developer's Public License Version 1.0 (the "License"); |
4 | * you may not use this file except in compliance with the |
5 | * License. You may obtain a copy of the License at |
6 | * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. |
7 | * |
8 | * Software distributed under the License is distributed AS IS, |
9 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. |
10 | * See the License for the specific language governing rights |
11 | * and limitations under the License. |
12 | * |
13 | * The Original Code was created by Vlad Khorsun |
14 | * for the Firebird Open Source RDBMS project. |
15 | * |
16 | * Copyright (c) 2008 Vlad Khorsun <hvlad@users.sourceforge.net> |
17 | * and all contributors signed below. |
18 | * |
19 | * All Rights Reserved. |
20 | * Contributor(s): ______________________________________. |
21 | */ |
22 | |
23 | #include "firebird.h" |
24 | #include "fb_types.h" |
25 | #include "../../include/fb_blk.h" |
26 | |
27 | #include "../align.h" |
28 | #include "../exe.h" |
29 | #include "../jrd.h" |
30 | #include "../tra.h" |
31 | #include "../common/dsc.h" |
32 | #include "../../dsql/dsql.h" |
33 | #include "../../dsql/sqlda_pub.h" |
34 | #include "../common/classes/InternalMessageBuffer.h" |
35 | |
36 | #include "../blb_proto.h" |
37 | #include "../evl_proto.h" |
38 | #include "../exe_proto.h" |
39 | #include "../mov_proto.h" |
40 | #include "../mov_proto.h" |
41 | #include "../PreparedStatement.h" |
42 | #include "../Function.h" |
43 | |
44 | #include "InternalDS.h" |
45 | |
46 | using namespace Jrd; |
47 | using namespace Firebird; |
48 | |
49 | namespace EDS { |
50 | |
51 | const char* INTERNAL_PROVIDER_NAME = "Internal" ; |
52 | |
53 | class RegisterInternalProvider |
54 | { |
55 | public: |
56 | RegisterInternalProvider() |
57 | { |
58 | InternalProvider* provider = new InternalProvider(INTERNAL_PROVIDER_NAME); |
59 | Manager::addProvider(provider); |
60 | } |
61 | }; |
62 | |
63 | static RegisterInternalProvider reg; |
64 | |
65 | // InternalProvider |
66 | |
67 | void InternalProvider::jrdAttachmentEnd(thread_db* tdbb, Jrd::Attachment* att) |
68 | { |
69 | if (m_connections.getCount() == 0) |
70 | return; |
71 | |
72 | Connection** ptr = m_connections.end(); |
73 | Connection** begin = m_connections.begin(); |
74 | |
75 | for (ptr--; ptr >= begin; ptr--) |
76 | { |
77 | InternalConnection* conn = (InternalConnection*) *ptr; |
78 | if (conn->getJrdAtt() == att->att_interface) |
79 | releaseConnection(tdbb, *conn, false); |
80 | } |
81 | } |
82 | |
83 | void InternalProvider::getRemoteError(const ISC_STATUS* status, string& err) const |
84 | { |
85 | err = "" ; |
86 | |
87 | char buff[1024]; |
88 | const ISC_STATUS* p = status; |
89 | const ISC_STATUS* end = status + ISC_STATUS_LENGTH; |
90 | |
91 | while (p < end) |
92 | { |
93 | const ISC_STATUS code = *p ? p[1] : 0; |
94 | if (!fb_interpret(buff, sizeof(buff), &p)) |
95 | break; |
96 | |
97 | string rem_err; |
98 | rem_err.printf("%lu : %s\n" , code, buff); |
99 | err += rem_err; |
100 | } |
101 | } |
102 | |
103 | Connection* InternalProvider::doCreateConnection() |
104 | { |
105 | return new InternalConnection(*this); |
106 | } |
107 | |
108 | |
109 | // InternalConnection |
110 | |
111 | InternalConnection::~InternalConnection() |
112 | { |
113 | } |
114 | |
115 | // Status helper |
116 | class IntStatus : public LocalStatus |
117 | { |
118 | public: |
119 | explicit IntStatus(ISC_STATUS *p) |
120 | : LocalStatus(), v(p) |
121 | {} |
122 | |
123 | ~IntStatus() |
124 | { |
125 | if (v) |
126 | { |
127 | const ISC_STATUS *s = get(); |
128 | fb_utils::copyStatus(v, ISC_STATUS_LENGTH, s, fb_utils::statusLength(s)); |
129 | } |
130 | } |
131 | |
132 | private: |
133 | ISC_STATUS *v; |
134 | }; |
135 | |
136 | void InternalConnection::attach(thread_db* tdbb, const Firebird::string& dbName, |
137 | const Firebird::string& user, const Firebird::string& pwd, |
138 | const Firebird::string& role) |
139 | { |
140 | fb_assert(!m_attachment); |
141 | Database* dbb = tdbb->getDatabase(); |
142 | fb_assert(dbName.isEmpty() || dbName == dbb->dbb_database_name.c_str()); |
143 | |
144 | // Don't wrap raised errors. This is needed for backward compatibility. |
145 | setWrapErrors(false); |
146 | |
147 | Jrd::Attachment* attachment = tdbb->getAttachment(); |
148 | if ((user.isEmpty() || user == attachment->att_user->usr_user_name) && |
149 | pwd.isEmpty() && |
150 | (role.isEmpty() || role == attachment->att_user->usr_sql_role_name)) |
151 | { |
152 | m_isCurrent = true; |
153 | m_attachment = attachment->att_interface; |
154 | } |
155 | else |
156 | { |
157 | m_isCurrent = false; |
158 | m_dbName = dbb->dbb_database_name.c_str(); |
159 | generateDPB(tdbb, m_dpb, user, pwd, role); |
160 | |
161 | LocalStatus status; |
162 | { |
163 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
164 | Firebird::RefPtr<JProvider> jInstance(JProvider::getInstance()); |
165 | jInstance->setDbCryptCallback(&status, tdbb->getAttachment()->att_crypt_callback); |
166 | m_attachment = jInstance->attachDatabase(&status, m_dbName.c_str(), |
167 | m_dpb.getBufferLength(), m_dpb.getBuffer()); |
168 | } |
169 | |
170 | if (!status.isSuccess()) |
171 | raise(status, tdbb, "JProvider::attach" ); |
172 | } |
173 | |
174 | m_sqlDialect = (m_attachment->getHandle()->att_database->dbb_flags & DBB_DB_SQL_dialect_3) ? |
175 | SQL_DIALECT_V6 : SQL_DIALECT_V5; |
176 | } |
177 | |
178 | void InternalConnection::doDetach(thread_db* tdbb) |
179 | { |
180 | fb_assert(m_attachment); |
181 | |
182 | if (m_isCurrent) |
183 | { |
184 | m_attachment = 0; |
185 | } |
186 | else |
187 | { |
188 | LocalStatus status; |
189 | JAttachment* att = m_attachment; |
190 | m_attachment = NULL; |
191 | |
192 | { // scope |
193 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
194 | att->detach(&status); |
195 | } |
196 | |
197 | if (status.get()[1] == isc_att_shutdown) |
198 | { |
199 | status.init(); |
200 | } |
201 | |
202 | if (!status.isSuccess()) |
203 | { |
204 | m_attachment = att; |
205 | raise(status, tdbb, "JAttachment::detach" ); |
206 | } |
207 | } |
208 | |
209 | fb_assert(!m_attachment); |
210 | } |
211 | |
212 | bool InternalConnection::cancelExecution() |
213 | { |
214 | if (m_isCurrent) |
215 | return true; |
216 | |
217 | LocalStatus status; |
218 | m_attachment->cancelOperation(&status, fb_cancel_raise); |
219 | return (status.isSuccess()); |
220 | } |
221 | |
222 | // this internal connection instance is available for the current execution context if it |
223 | // a) is current conenction and current thread's attachment is equal to |
224 | // this attachment, or |
225 | // b) is not current conenction |
226 | bool InternalConnection::isAvailable(thread_db* tdbb, TraScope /*traScope*/) const |
227 | { |
228 | return !m_isCurrent || |
229 | (m_isCurrent && (tdbb->getAttachment() == m_attachment->getHandle())); |
230 | } |
231 | |
232 | bool InternalConnection::isSameDatabase(thread_db* tdbb, const Firebird::string& dbName, |
233 | const Firebird::string& user, const Firebird::string& pwd, |
234 | const Firebird::string& role) const |
235 | { |
236 | if (m_isCurrent) |
237 | { |
238 | const UserId* attUser = m_attachment->getHandle()->att_user; |
239 | return ((user.isEmpty() || user == attUser->usr_user_name) && |
240 | pwd.isEmpty() && |
241 | (role.isEmpty() || role == attUser->usr_sql_role_name)); |
242 | } |
243 | |
244 | return Connection::isSameDatabase(tdbb, dbName, user, pwd, role); |
245 | } |
246 | |
247 | Transaction* InternalConnection::doCreateTransaction() |
248 | { |
249 | return new InternalTransaction(*this); |
250 | } |
251 | |
252 | Statement* InternalConnection::doCreateStatement() |
253 | { |
254 | return new InternalStatement(*this); |
255 | } |
256 | |
257 | Blob* InternalConnection::createBlob() |
258 | { |
259 | return new InternalBlob(*this); |
260 | } |
261 | |
262 | |
263 | // InternalTransaction() |
264 | |
265 | void InternalTransaction::doStart(ISC_STATUS* status, thread_db* tdbb, ClumpletWriter& tpb) |
266 | { |
267 | fb_assert(!m_transaction); |
268 | |
269 | jrd_tra* localTran = tdbb->getTransaction(); |
270 | fb_assert(localTran); |
271 | |
272 | if (m_scope == traCommon && m_IntConnection.isCurrent()) |
273 | m_transaction = localTran->getInterface(); |
274 | else |
275 | { |
276 | JAttachment* att = m_IntConnection.getJrdAtt(); |
277 | |
278 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
279 | IntStatus s(status); |
280 | m_transaction = att->startTransaction(&s, tpb.getBufferLength(), tpb.getBuffer()); |
281 | |
282 | m_transaction->getHandle()->tra_callback_count = localTran->tra_callback_count; |
283 | } |
284 | } |
285 | |
286 | void InternalTransaction::doPrepare(ISC_STATUS* /*status*/, thread_db* /*tdbb*/, |
287 | int /*info_len*/, const char* /*info*/) |
288 | { |
289 | fb_assert(m_transaction); |
290 | fb_assert(false); |
291 | } |
292 | |
293 | void InternalTransaction::doCommit(ISC_STATUS* status, thread_db* tdbb, bool retain) |
294 | { |
295 | fb_assert(m_transaction); |
296 | |
297 | if (m_scope == traCommon && m_IntConnection.isCurrent()) |
298 | { |
299 | if (!retain) { |
300 | m_transaction = NULL; |
301 | } |
302 | } |
303 | else |
304 | { |
305 | IntStatus s(status); |
306 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
307 | if (retain) |
308 | m_transaction->commitRetaining(&s); |
309 | else |
310 | m_transaction->commit(&s); |
311 | } |
312 | } |
313 | |
314 | void InternalTransaction::doRollback(ISC_STATUS* status, thread_db* tdbb, bool retain) |
315 | { |
316 | fb_assert(m_transaction); |
317 | |
318 | if (m_scope == traCommon && m_IntConnection.isCurrent()) |
319 | { |
320 | if (!retain) { |
321 | m_transaction = NULL; |
322 | } |
323 | } |
324 | else |
325 | { |
326 | IntStatus s(status); |
327 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
328 | if (retain) |
329 | m_transaction->rollbackRetaining(&s); |
330 | else |
331 | m_transaction->rollback(&s); |
332 | } |
333 | |
334 | if (status[1] == isc_att_shutdown && !retain) |
335 | { |
336 | m_transaction = NULL; |
337 | fb_utils::init_status(status); |
338 | } |
339 | } |
340 | |
341 | |
342 | // InternalStatement |
343 | |
344 | InternalStatement::InternalStatement(InternalConnection& conn) : |
345 | Statement(conn), |
346 | m_intConnection(conn), |
347 | m_intTransaction(0), |
348 | m_request(0), |
349 | m_cursor(0), |
350 | m_inMetadata(new MsgMetadata), |
351 | m_outMetadata(new MsgMetadata) |
352 | { |
353 | } |
354 | |
355 | InternalStatement::~InternalStatement() |
356 | { |
357 | } |
358 | |
359 | void InternalStatement::doPrepare(thread_db* tdbb, const string& sql) |
360 | { |
361 | m_inMetadata->items.clear(); |
362 | m_outMetadata->items.clear(); |
363 | |
364 | JAttachment* att = m_intConnection.getJrdAtt(); |
365 | JTransaction* tran = getIntTransaction()->getJrdTran(); |
366 | |
367 | LocalStatus status; |
368 | |
369 | if (m_request) |
370 | { |
371 | doClose(tdbb, true); |
372 | fb_assert(!m_allocated); |
373 | } |
374 | |
375 | { |
376 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
377 | |
378 | CallerName save_caller_name(tran->getHandle()->tra_caller_name); |
379 | |
380 | if (m_callerPrivileges) |
381 | { |
382 | jrd_req* request = tdbb->getRequest(); |
383 | JrdStatement* statement = request ? request->getStatement() : NULL; |
384 | CallerName callerName; |
385 | const Routine* routine; |
386 | |
387 | if (statement && statement->parentStatement) |
388 | statement = statement->parentStatement; |
389 | |
390 | if (statement && statement->triggerName.hasData()) |
391 | tran->getHandle()->tra_caller_name = CallerName(obj_trigger, statement->triggerName); |
392 | else if (statement && (routine = statement->getRoutine()) && |
393 | routine->getName().identifier.hasData()) |
394 | { |
395 | if (routine->getName().package.isEmpty()) |
396 | { |
397 | tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(), |
398 | routine->getName().identifier); |
399 | } |
400 | else |
401 | { |
402 | tran->getHandle()->tra_caller_name = CallerName(obj_package_header, |
403 | routine->getName().package); |
404 | } |
405 | } |
406 | else |
407 | tran->getHandle()->tra_caller_name = CallerName(); |
408 | } |
409 | |
410 | m_request = att->prepare(&status, tran, sql.length(), sql.c_str(), m_connection.getSqlDialect(), 0); |
411 | m_allocated = (m_request != NULL); |
412 | |
413 | tran->getHandle()->tra_caller_name = save_caller_name; |
414 | } |
415 | |
416 | if (!status.isSuccess()) |
417 | raise(status, tdbb, "JAttachment::prepare" , &sql); |
418 | |
419 | const DsqlCompiledStatement* statement = m_request->getHandle()->getStatement(); |
420 | |
421 | if (statement->getSendMsg()) |
422 | { |
423 | try |
424 | { |
425 | PreparedStatement::parseDsqlMessage(statement->getSendMsg(), m_inDescs, |
426 | m_inMetadata, m_in_buffer); |
427 | m_inputs = m_inMetadata->items.getCount(); |
428 | } |
429 | catch (const Exception&) |
430 | { |
431 | raise(tdbb->tdbb_status_vector, tdbb, "parse input message" , &sql); |
432 | } |
433 | } |
434 | else |
435 | m_inputs = 0; |
436 | |
437 | if (statement->getReceiveMsg()) |
438 | { |
439 | try |
440 | { |
441 | PreparedStatement::parseDsqlMessage(statement->getReceiveMsg(), m_outDescs, |
442 | m_outMetadata, m_out_buffer); |
443 | m_outputs = m_outMetadata->items.getCount(); |
444 | } |
445 | catch (const Exception&) |
446 | { |
447 | raise(tdbb->tdbb_status_vector, tdbb, "parse output message" , &sql); |
448 | } |
449 | } |
450 | else |
451 | m_outputs = 0; |
452 | |
453 | m_stmt_selectable = false; |
454 | |
455 | switch (statement->getType()) |
456 | { |
457 | case DsqlCompiledStatement::TYPE_SELECT: |
458 | case DsqlCompiledStatement::TYPE_SELECT_UPD: |
459 | case DsqlCompiledStatement::TYPE_SELECT_BLOCK: |
460 | m_stmt_selectable = true; |
461 | break; |
462 | |
463 | case DsqlCompiledStatement::TYPE_START_TRANS: |
464 | case DsqlCompiledStatement::TYPE_COMMIT: |
465 | case DsqlCompiledStatement::TYPE_ROLLBACK: |
466 | case DsqlCompiledStatement::TYPE_COMMIT_RETAIN: |
467 | case DsqlCompiledStatement::TYPE_ROLLBACK_RETAIN: |
468 | case DsqlCompiledStatement::TYPE_CREATE_DB: |
469 | status.set(Arg::Gds(isc_eds_expl_tran_ctrl).value()); |
470 | raise(status, tdbb, "JAttachment::prepare" , &sql); |
471 | break; |
472 | |
473 | case DsqlCompiledStatement::TYPE_INSERT: |
474 | case DsqlCompiledStatement::TYPE_DELETE: |
475 | case DsqlCompiledStatement::TYPE_UPDATE: |
476 | case DsqlCompiledStatement::TYPE_UPDATE_CURSOR: |
477 | case DsqlCompiledStatement::TYPE_DELETE_CURSOR: |
478 | case DsqlCompiledStatement::TYPE_DDL: |
479 | case DsqlCompiledStatement::TYPE_EXEC_PROCEDURE: |
480 | case DsqlCompiledStatement::TYPE_SET_GENERATOR: |
481 | case DsqlCompiledStatement::TYPE_SAVEPOINT: |
482 | case DsqlCompiledStatement::TYPE_EXEC_BLOCK: |
483 | break; |
484 | } |
485 | } |
486 | |
487 | |
488 | void InternalStatement::doExecute(thread_db* tdbb) |
489 | { |
490 | JTransaction* transaction = getIntTransaction()->getJrdTran(); |
491 | |
492 | LocalStatus status; |
493 | { |
494 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
495 | |
496 | fb_assert(m_inMetadata->length == m_in_buffer.getCount()); |
497 | InternalMessageBuffer inMsg(m_inMetadata, m_in_buffer.begin()); |
498 | fb_assert(m_outMetadata->length == m_out_buffer.getCount()); |
499 | InternalMessageBuffer outMsg(m_outMetadata, m_out_buffer.begin()); |
500 | |
501 | m_request->execute(&status, transaction, |
502 | inMsg.metadata, inMsg.buffer, outMsg.metadata, outMsg.buffer); |
503 | } |
504 | |
505 | if (!status.isSuccess()) |
506 | raise(status, tdbb, "JStatement::execute" ); |
507 | } |
508 | |
509 | |
510 | void InternalStatement::doOpen(thread_db* tdbb) |
511 | { |
512 | JTransaction* transaction = getIntTransaction()->getJrdTran(); |
513 | |
514 | LocalStatus status; |
515 | { |
516 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
517 | |
518 | if (m_cursor) |
519 | { |
520 | m_cursor->close(&status); |
521 | m_cursor = NULL; |
522 | } |
523 | |
524 | fb_assert(m_inMetadata->length == m_in_buffer.getCount()); |
525 | InternalMessageBuffer inMsg(m_inMetadata, m_in_buffer.begin()); |
526 | |
527 | m_cursor = m_request->openCursor(&status, transaction, |
528 | inMsg.metadata, inMsg.buffer, m_outMetadata); |
529 | } |
530 | |
531 | if (!status.isSuccess()) |
532 | raise(status, tdbb, "JStatement::open" ); |
533 | } |
534 | |
535 | |
536 | bool InternalStatement::doFetch(thread_db* tdbb) |
537 | { |
538 | LocalStatus status; |
539 | bool res = true; |
540 | |
541 | { |
542 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
543 | |
544 | fb_assert(m_outMetadata->length == m_out_buffer.getCount()); |
545 | fb_assert(m_cursor); |
546 | res = m_cursor->fetchNext(&status, m_out_buffer.begin()); |
547 | } |
548 | |
549 | if (!status.isSuccess()) |
550 | raise(status, tdbb, "JResultSet::fetch" ); |
551 | |
552 | return res; |
553 | } |
554 | |
555 | |
556 | void InternalStatement::doClose(thread_db* tdbb, bool drop) |
557 | { |
558 | LocalStatus status; |
559 | { |
560 | EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); |
561 | |
562 | if (m_cursor) |
563 | m_cursor->close(&status); |
564 | |
565 | m_cursor = NULL; |
566 | if (!status.isSuccess()) |
567 | { |
568 | raise(status, tdbb, "JResultSet::close" ); |
569 | } |
570 | |
571 | if (drop) |
572 | { |
573 | if (m_request) |
574 | m_request->free(&status); |
575 | |
576 | m_allocated = false; |
577 | m_request = NULL; |
578 | |
579 | if (!status.isSuccess()) |
580 | { |
581 | raise(status, tdbb, "JStatement::free" ); |
582 | } |
583 | } |
584 | } |
585 | } |
586 | |
587 | void InternalStatement::putExtBlob(thread_db* tdbb, dsc& src, dsc& dst) |
588 | { |
589 | if (m_transaction->getScope() == traCommon) |
590 | MOV_move(tdbb, &src, &dst); |
591 | else |
592 | Statement::putExtBlob(tdbb, src, dst); |
593 | } |
594 | |
595 | void InternalStatement::getExtBlob(thread_db* tdbb, const dsc& src, dsc& dst) |
596 | { |
597 | fb_assert(dst.dsc_length == src.dsc_length); |
598 | fb_assert(dst.dsc_length == sizeof(bid)); |
599 | |
600 | if (m_transaction->getScope() == traCommon) |
601 | memcpy(dst.dsc_address, src.dsc_address, sizeof(bid)); |
602 | else |
603 | Statement::getExtBlob(tdbb, src, dst); |
604 | } |
605 | |
606 | |
607 | |
608 | // InternalBlob |
609 | |
610 | InternalBlob::InternalBlob(InternalConnection& conn) : |
611 | Blob(conn), |
612 | m_connection(conn), |
613 | m_blob(NULL) |
614 | { |
615 | memset(&m_blob_id, 0, sizeof(m_blob_id)); |
616 | } |
617 | |
618 | InternalBlob::~InternalBlob() |
619 | { |
620 | fb_assert(!m_blob); |
621 | } |
622 | |
623 | void InternalBlob::open(thread_db* tdbb, Transaction& tran, const dsc& desc, const UCharBuffer* bpb) |
624 | { |
625 | fb_assert(!m_blob); |
626 | fb_assert(sizeof(m_blob_id) == desc.dsc_length); |
627 | |
628 | JAttachment* att = m_connection.getJrdAtt(); |
629 | JTransaction* transaction = static_cast<InternalTransaction&>(tran).getJrdTran(); |
630 | memcpy(&m_blob_id, desc.dsc_address, sizeof(m_blob_id)); |
631 | |
632 | LocalStatus status; |
633 | { |
634 | EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION); |
635 | |
636 | USHORT bpb_len = bpb ? bpb->getCount() : 0; |
637 | const UCHAR* bpb_buff = bpb ? bpb->begin() : NULL; |
638 | |
639 | m_blob = att->openBlob(&status, transaction, &m_blob_id, bpb_len, bpb_buff); |
640 | } |
641 | |
642 | if (!status.isSuccess()) |
643 | m_connection.raise(status, tdbb, "JAttachment::openBlob" ); |
644 | |
645 | fb_assert(m_blob); |
646 | } |
647 | |
648 | void InternalBlob::create(thread_db* tdbb, Transaction& tran, dsc& desc, const UCharBuffer* bpb) |
649 | { |
650 | fb_assert(!m_blob); |
651 | fb_assert(sizeof(m_blob_id) == desc.dsc_length); |
652 | |
653 | JAttachment* att = m_connection.getJrdAtt(); |
654 | JTransaction* transaction = ((InternalTransaction&) tran).getJrdTran(); |
655 | memset(&m_blob_id, 0, sizeof(m_blob_id)); |
656 | |
657 | LocalStatus status; |
658 | { |
659 | EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION); |
660 | |
661 | const USHORT bpb_len = bpb ? bpb->getCount() : 0; |
662 | const UCHAR* bpb_buff = bpb ? bpb->begin() : NULL; |
663 | |
664 | m_blob = att->createBlob(&status, transaction, &m_blob_id, bpb_len, bpb_buff); |
665 | memcpy(desc.dsc_address, &m_blob_id, sizeof(m_blob_id)); |
666 | } |
667 | |
668 | if (!status.isSuccess()) |
669 | m_connection.raise(status, tdbb, "JAttachment::createBlob" ); |
670 | |
671 | fb_assert(m_blob); |
672 | } |
673 | |
674 | USHORT InternalBlob::read(thread_db* tdbb, UCHAR* buff, USHORT len) |
675 | { |
676 | fb_assert(m_blob); |
677 | |
678 | USHORT result = 0; |
679 | LocalStatus status; |
680 | { |
681 | EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION); |
682 | result = m_blob->getSegment(&status, len, buff); |
683 | } |
684 | |
685 | switch (status.get()[1]) |
686 | { |
687 | case isc_segstr_eof: |
688 | fb_assert(result == 0); |
689 | break; |
690 | case isc_segment: |
691 | case 0: |
692 | break; |
693 | default: |
694 | m_connection.raise(status, tdbb, "JBlob::getSegment" ); |
695 | } |
696 | |
697 | return result; |
698 | } |
699 | |
700 | void InternalBlob::write(thread_db* tdbb, const UCHAR* buff, USHORT len) |
701 | { |
702 | fb_assert(m_blob); |
703 | |
704 | LocalStatus status; |
705 | { |
706 | EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION); |
707 | m_blob->putSegment(&status, len, buff); |
708 | } |
709 | |
710 | if (!status.isSuccess()) |
711 | m_connection.raise(status, tdbb, "JBlob::putSegment" ); |
712 | } |
713 | |
714 | void InternalBlob::close(thread_db* tdbb) |
715 | { |
716 | fb_assert(m_blob); |
717 | LocalStatus status; |
718 | { |
719 | EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION); |
720 | m_blob->close(&status); |
721 | } |
722 | |
723 | if (!status.isSuccess()) |
724 | m_connection.raise(status, tdbb, "JBlob::close" ); |
725 | |
726 | fb_assert(!m_blob); |
727 | } |
728 | |
729 | void InternalBlob::cancel(thread_db* tdbb) |
730 | { |
731 | if (!m_blob) { |
732 | return; |
733 | } |
734 | |
735 | LocalStatus status; |
736 | { |
737 | EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION); |
738 | m_blob->cancel(&status); |
739 | } |
740 | |
741 | if (!status.isSuccess()) |
742 | m_connection.raise(status, tdbb, "JBlob::cancel" ); |
743 | |
744 | fb_assert(!m_blob); |
745 | } |
746 | |
747 | |
748 | } // namespace EDS |
749 | |