1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent tw=79 ft=cpp: */
4 * Copyright (C) 2007 Sergey Yanovich <ynvich@gmail.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include <abstract/aacore.h>
25 #include "nsStringAPI.h"
26 #include "nsEmbedString.h"
28 #include "nsArrayUtils.h"
31 #include "unstable/mozIStorageConnection.h"
32 #include "unstable/mozIStorageStatement.h"
34 /* Project includes */
35 #include <abstract/base/aaIEntity.h>
36 #include <abstract/base/aaIFlow.h>
37 #include <abstract/base/aaIFact.h>
38 #include <abstract/base/aaIEvent.h>
39 #include <abstract/storage/aaISaveQuery.h>
40 #include "aaSaveEvent.h"
43 #define AA_READ_ID_BEGIN "SELECT id FROM "
44 #define AA_READ_ID_END " WHERE _ROWID_ == last_insert_rowid()"
46 #define AA_EVENT_SAVE "INSERT INTO event (day, id) SELECT\
47 (replace(round(julianday(?,'unixepoch')),'.0','')) AS _day,\
48 IFNULL(max(event.id),0) + 1 FROM event WHERE event.day == _day"
49 #define AA_TRANSFER_SAVE "INSERT INTO transfer (day, event_id, id, amount)\
50 SELECT (replace(round(julianday(?,'unixepoch')),'.0','')) AS _day,\
51 ? AS _event_id, IFNULL(MAX(transfer.id),0) + 1, ? FROM transfer\
52 WHERE transfer.day == _day AND transfer.event_id == _event_id"
53 #define AA_FACT_SAVE "INSERT INTO fact (day, event_id, transfer_id, side, flow_id)\
54 VALUES ((replace(round(julianday(?,'unixepoch')),'.0','')),?,?,?,?)"
55 #define AA_TRANSFER_VALIDATE "SELECT 1 FROM term AS termF, term AS termT\
56 WHERE termF.flow_id=? AND termF.side=1 AND termT.flow_id=? AND termT.side=0\
57 AND termF.resource_id=termT.resource_id;"
58 #define AA_STATE_LOAD "SELECT fact.flow_id, fact.side, fact.day,\
59 transfer.amount, flow.rate, state.id, state.start, state.side, state.amount\
61 LEFT JOIN transfer ON fact.day == (replace(round(julianday(?,'unixepoch')),\
62 '.0', '')) AND fact.event_id == ? AND fact.day == transfer.day AND\
63 fact.event_id == transfer.event_id AND fact.transfer_id == transfer.id\
64 LEFT JOIN flow ON fact.flow_id == flow.id\
65 LEFT JOIN state ON fact.flow_id == state.flow_id AND state.paid IS NULL\
66 ORDER BY fact.flow_id, fact.side"
68 #define AA_STATE_INSERT "INSERT INTO state (flow_id, side,\
69 amount,start) VALUES (?,?,?,?)"
70 #define AA_STATE_DELETE "DELETE FROM state WHERE id == ?"
71 #define AA_STATE_UPDATE "UPDATE state SET side = ?, amount = ? WHERE id == ?"
72 #define AA_STATE_TERMINATE "UPDATE state SET paid = ? WHERE id == ?"
77 State() :mReady(0) {;}
78 State(mozIStorageStatement
*aStatement
);
80 PRBool
Adjust(mozIStorageConnection
*aConnection
);
94 PRBool
isSignificant() const {return (mSum
> 0.00009) || (mSum
< -0.00009);}
95 PRBool
insert(mozIStorageConnection
*aConnection
);
96 PRBool
update(mozIStorageConnection
*aConnection
);
97 PRBool
replace(mozIStorageConnection
*aConnection
);
100 State::State(mozIStorageStatement
*aStatement
)
101 :mReady(PR_FALSE
), mNew(PR_FALSE
), mUpdate(PR_FALSE
)
107 rv
= aStatement
->GetInt64(0, &mFlow
);
108 if (NS_FAILED(rv
)) return;
110 rv
= aStatement
->GetInt32(1, &mFactSide
);
111 if (NS_FAILED(rv
)) return;
113 rv
= aStatement
->GetInt64(2, &mDay
);
114 if (NS_FAILED(rv
)) return;
116 rv
= aStatement
->GetDouble(3, &mFactSum
);
117 if (NS_FAILED(rv
)) return;
119 rv
= aStatement
->GetDouble(4, &mRate
);
120 if (NS_FAILED(rv
)) return;
122 rv
= aStatement
->GetTypeOfIndex(5, &type
);
123 if (NS_FAILED(rv
)) return;
125 if (type
== mozIStorageValueArray::VALUE_TYPE_NULL
) {
127 mSum
= mFactSum
* (mSide
? mRate
: (1 / mRate
));
134 rv
= aStatement
->GetInt64(5, &mId
);
135 if (NS_FAILED(rv
)) return;
137 rv
= aStatement
->GetInt64(6, &stateStart
);
138 if (NS_FAILED(rv
)) return;
140 if (stateStart
== mDay
)
143 if (stateStart
> mDay
)
146 rv
= aStatement
->GetInt32(7, &mSide
);
147 if (NS_FAILED(rv
)) return;
149 rv
= aStatement
->GetDouble(8, &mSum
);
150 if (NS_FAILED(rv
)) return;
152 if (mSide
== mFactSide
) {
153 double delta
= mSum
- mFactSum
;
158 mSum
= -delta
* (mSide
? mRate
: (1 / mRate
));
168 State::Adjust(mozIStorageConnection
*aConnection
)
170 if (NS_UNLIKELY( !mReady
))
173 return insert(aConnection
);
175 return update(aConnection
);
176 return replace(aConnection
);
180 State::insert(mozIStorageConnection
*aConnection
)
184 if (! isSignificant() )
187 nsCOMPtr
<mozIStorageStatement
> statement
;
188 rv
= aConnection
->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_INSERT
),
189 getter_AddRefs(statement
));
190 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
192 rv
= statement
->BindInt64Parameter(0, mFlow
);
193 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
195 rv
= statement
->BindInt64Parameter(1, mSide
);
196 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
198 rv
= statement
->BindDoubleParameter(2, mSum
);
199 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
201 rv
= statement
->BindInt64Parameter(3, mDay
);
202 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
204 rv
= statement
->Execute();
205 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
211 State::update(mozIStorageConnection
*aConnection
)
214 nsCOMPtr
<mozIStorageStatement
> statement
;
216 if (! isSignificant() ) {
217 rv
= aConnection
->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_DELETE
),
218 getter_AddRefs(statement
));
219 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
221 rv
= statement
->BindInt64Parameter(0, mId
);
222 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
224 rv
= aConnection
->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_UPDATE
),
225 getter_AddRefs(statement
));
226 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
228 rv
= statement
->BindInt64Parameter(0, mSide
);
229 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
231 rv
= statement
->BindDoubleParameter(1, mSum
);
232 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
234 rv
= statement
->BindInt64Parameter(2, mId
);
235 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
238 rv
= statement
->Execute();
239 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
245 State::replace(mozIStorageConnection
*aConnection
)
248 nsCOMPtr
<mozIStorageStatement
> statement
;
250 rv
= aConnection
->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_TERMINATE
),
251 getter_AddRefs(statement
));
252 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
254 rv
= statement
->BindInt64Parameter(0, mDay
);
255 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
257 rv
= statement
->BindInt64Parameter(1, mId
);
258 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
260 rv
= statement
->Execute();
261 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
263 if ( isSignificant() )
264 return insert(aConnection
);
269 /*************** aaSaveEvent **********************/
270 aaSaveEvent::aaSaveEvent(nsISupports
*aOuter
)
273 mConnection
= do_QueryInterface(aOuter
);
277 rv
= mConnection
->GetConnectionReady(&isReady
);
279 mConnection
= nsnull
;
282 aaSaveEvent::~aaSaveEvent()
286 NS_IMPL_ISUPPORTS1(aaSaveEvent
,
290 aaSaveEvent::Save(aaIDataNode
*aNode
, aaIDataNode
*aOldNode
)
292 NS_ENSURE_TRUE(! aOldNode
, NS_ERROR_INVALID_ARG
);
294 nsCOMPtr
<aaIEvent
> event(do_QueryInterface(aNode
));
295 NS_ENSURE_ARG_POINTER(event
);
297 nsCOMPtr
<nsIArray
> block(do_QueryInterface(aNode
));
298 NS_ENSURE_ARG_POINTER(block
);
301 PRUint32 i
= 0, count
;
302 rv
= block
->GetLength( &count
);
303 NS_ENSURE_SUCCESS(rv
, rv
);
304 NS_ENSURE_TRUE(count
, NS_ERROR_INVALID_ARG
);
306 rv
= mConnection
->BeginTransaction();
307 NS_ENSURE_SUCCESS(rv
, rv
);
310 aaGuard
guard(mConnection
);
311 rv
= saveEvent(event
);
312 NS_ENSURE_SUCCESS(rv
, rv
);
314 nsCOMPtr
<aaIFact
> fact
;
315 for (; i
< count
; i
++) {
316 fact
= do_QueryElementAt(block
, i
);
317 NS_ENSURE_TRUE(fact
, NS_ERROR_INVALID_ARG
);
318 fact
->SetEvent( event
);
320 if (NS_FAILED(rv
)) return rv
;
322 rv
= adjustStates(event
);
323 NS_ENSURE_SUCCESS(rv
, rv
);
324 return guard
.Dismiss();
328 /* Private methods */
330 aaSaveEvent::readID(const char *table
)
334 nsEmbedCString
query(AA_READ_ID_BEGIN
);
336 query
+= AA_READ_ID_END
;
338 nsCOMPtr
<mozIStorageStatement
> statement
;
339 rv
= mConnection
->CreateStatement(query
, getter_AddRefs(statement
));
340 NS_ENSURE_SUCCESS(rv
, -1);
343 rv
= statement
->ExecuteStep(&ignore
);
344 NS_ENSURE_SUCCESS(rv
, -1);
347 rv
= statement
->GetInt64(0, &id
);
354 aaSaveEvent::saveEvent(aaIEvent
*aEvent
)
359 rv
= aEvent
->GetTime(&time
);
360 NS_ENSURE_SUCCESS(rv
, rv
);
363 nsCOMPtr
<mozIStorageStatement
> statement
;
364 rv
= mConnection
->CreateStatement(NS_LITERAL_CSTRING(AA_EVENT_SAVE
),
365 getter_AddRefs(statement
));
366 NS_ENSURE_SUCCESS(rv
, rv
);
368 rv
= statement
->BindInt64Parameter(0, time
);
369 NS_ENSURE_SUCCESS(rv
, rv
);
371 rv
= statement
->Execute();
372 NS_ENSURE_SUCCESS(rv
, rv
);
374 PRInt64 id
= readID("event");
375 NS_ENSURE_SUCCESS(id
!= -1, NS_ERROR_FAILURE
);
377 return aEvent
->SetId(id
);
381 aaSaveEvent::validateTransfer(PRInt64 fromFlowId
, PRInt64 toFlowId
)
383 NS_ENSURE_TRUE(fromFlowId
|| toFlowId
, NS_ERROR_INVALID_ARG
);
384 if (!fromFlowId
|| ! toFlowId
)
388 nsCOMPtr
<mozIStorageStatement
> statement
;
389 rv
= mConnection
->CreateStatement(NS_LITERAL_CSTRING(AA_TRANSFER_VALIDATE
),
390 getter_AddRefs(statement
));
391 NS_ENSURE_SUCCESS(rv
, rv
);
393 rv
= statement
->BindInt64Parameter(0, fromFlowId
);
394 NS_ENSURE_SUCCESS(rv
, rv
);
396 rv
= statement
->BindInt64Parameter(1, toFlowId
);
397 NS_ENSURE_SUCCESS(rv
, rv
);
399 PRBool isFirst
= PR_TRUE
;
403 rv
= statement
->ExecuteStep(&hasMore
);
406 rv
= statement
->GetState(&state
);
409 if (state
!= mozIStorageStatement::MOZ_STORAGE_STATEMENT_EXECUTING
) {
412 return NS_ERROR_FAILURE
;
416 rv
= NS_ERROR_FAILURE
;
423 NS_ENSURE_SUCCESS(rv
, rv
);
429 aaSaveEvent::saveAct(aaIFact
*fact
)
431 NS_ENSURE_ARG_POINTER(fact
);
435 rv
= fact
->GetAmount( &amount
);
436 NS_ENSURE_SUCCESS(rv
, rv
);
437 NS_ENSURE_TRUE(amount
> 0.00009 || amount
< -0.00009, NS_ERROR_INVALID_ARG
);
440 rv
= fact
->GetTime(&time
);
441 NS_ENSURE_SUCCESS(rv
, rv
);
445 rv
= fact
->GetEventId(&eventId
);
446 NS_ENSURE_SUCCESS(rv
, rv
);
448 nsCOMPtr
<mozIStorageStatement
> statement
;
449 rv
= mConnection
->CreateStatement(NS_LITERAL_CSTRING(AA_TRANSFER_SAVE
),
450 getter_AddRefs(statement
));
451 NS_ENSURE_SUCCESS(rv
, rv
);
453 rv
= statement
->BindInt64Parameter(0, time
);
454 NS_ENSURE_SUCCESS(rv
, rv
);
455 rv
= statement
->BindInt64Parameter(1, eventId
);
456 NS_ENSURE_SUCCESS(rv
, rv
);
457 rv
= statement
->BindDoubleParameter(2, amount
);
458 NS_ENSURE_SUCCESS(rv
, rv
);
460 rv
= statement
->Execute();
461 NS_ENSURE_SUCCESS(rv
, rv
);
463 PRInt64 id
= readID("transfer");
464 NS_ENSURE_SUCCESS(id
!= -1, NS_ERROR_FAILURE
);
466 rv
= fact
->SetId(id
);
467 NS_ENSURE_SUCCESS(rv
, rv
);
473 aaSaveEvent::saveFact(aaIFact
*fact
)
475 NS_ENSURE_ARG_POINTER(fact
);
478 PRInt64 giveFlowId
= 0, takeFlowId
= 0, eventId
, factId
;
479 nsCOMPtr
<aaIFlow
> flow
;
480 rv
= fact
->GetTakeFrom(getter_AddRefs( flow
));
481 NS_ENSURE_SUCCESS(rv
, rv
);
483 rv
= flow
->GetId( &takeFlowId
);
484 NS_ENSURE_SUCCESS(rv
, rv
);
487 rv
= fact
->GetGiveTo(getter_AddRefs( flow
));
488 NS_ENSURE_SUCCESS(rv
, rv
);
490 rv
= flow
->GetId( &giveFlowId
);
491 NS_ENSURE_SUCCESS(rv
, rv
);
494 rv
= validateTransfer(takeFlowId
, giveFlowId
);
495 if (NS_FAILED(rv
)) return rv
;
498 NS_ENSURE_SUCCESS(rv
, rv
);
501 rv
= fact
->GetTime(&time
);
502 NS_ENSURE_SUCCESS(rv
, rv
);
505 rv
= fact
->GetEventId(&eventId
);
506 NS_ENSURE_SUCCESS(rv
, rv
);
508 rv
= fact
->GetId(&factId
);
509 NS_ENSURE_SUCCESS(rv
, rv
);
511 nsCOMPtr
<mozIStorageStatement
> statement
;
512 rv
= mConnection
->CreateStatement(NS_LITERAL_CSTRING(AA_FACT_SAVE
),
513 getter_AddRefs(statement
));
514 NS_ENSURE_SUCCESS(rv
, rv
);
517 rv
= statement
->BindInt64Parameter(0, time
);
518 NS_ENSURE_SUCCESS(rv
, rv
);
519 rv
= statement
->BindInt64Parameter(1, eventId
);
520 NS_ENSURE_SUCCESS(rv
, rv
);
521 rv
= statement
->BindInt64Parameter(2, factId
);
522 NS_ENSURE_SUCCESS(rv
, rv
);
523 rv
= statement
->BindInt32Parameter(3, 0);
524 NS_ENSURE_SUCCESS(rv
, rv
);
525 rv
= statement
->BindInt64Parameter(4, giveFlowId
);
526 NS_ENSURE_SUCCESS(rv
, rv
);
528 rv
= statement
->Execute();
529 NS_ENSURE_SUCCESS(rv
, rv
);
532 rv
= statement
->BindInt64Parameter(0, time
);
533 NS_ENSURE_SUCCESS(rv
, rv
);
534 rv
= statement
->BindInt64Parameter(1, eventId
);
535 NS_ENSURE_SUCCESS(rv
, rv
);
536 rv
= statement
->BindInt64Parameter(2, factId
);
537 NS_ENSURE_SUCCESS(rv
, rv
);
538 rv
= statement
->BindInt32Parameter(3, 1);
539 NS_ENSURE_SUCCESS(rv
, rv
);
540 rv
= statement
->BindInt64Parameter(4, takeFlowId
);
541 NS_ENSURE_SUCCESS(rv
, rv
);
543 rv
= statement
->Execute();
544 NS_ENSURE_SUCCESS(rv
, rv
);
550 aaSaveEvent::adjustStates(aaIEvent
*aEvent
)
553 nsCOMPtr
<mozIStorageStatement
> statement
;
556 rv
= aEvent
->GetId(&eventId
);
557 NS_ENSURE_SUCCESS(rv
, rv
);
560 rv
= aEvent
->GetTime(&time
);
561 NS_ENSURE_SUCCESS(rv
, rv
);
564 rv
= mConnection
->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_LOAD
),
565 getter_AddRefs(statement
));
566 NS_ENSURE_SUCCESS(rv
, rv
);
568 rv
= statement
->BindInt64Parameter(0, time
);
569 NS_ENSURE_SUCCESS(rv
, rv
);
571 rv
= statement
->BindInt64Parameter(1, eventId
);
572 NS_ENSURE_SUCCESS(rv
, rv
);
577 rv
= statement
->ExecuteStep(&hasMore
);
580 rv
= statement
->GetState(&state
);
583 if (state
== mozIStorageStatement::MOZ_STORAGE_STATEMENT_EXECUTING
) {
584 State
state(statement
);
585 if (! state
.Adjust(mConnection
) ) {
586 rv
= NS_ERROR_FAILURE
;
592 NS_ENSURE_SUCCESS(rv
, rv
);