SQLite

Check-in [e3943fa7bb]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add an API to query an ota handle for the total number of key/value operations performed so far.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | ota-update
Files: files | file ages | folders
SHA1: e3943fa7bbbfc5e16f73a494d8fa54d19e9cfcf9
User & Date: dan 2014-09-18 14:48:38.579
Context
2014-09-18
15:22
Add new file ext/ota/README.txt, containing notes regarding the implementation of the ota extension. (check-in: 3c6e1cbb4b user: dan tags: ota-update)
14:48
Add an API to query an ota handle for the total number of key/value operations performed so far. (check-in: e3943fa7bb user: dan tags: ota-update)
11:31
Merge latest trunk changes with this branch. (check-in: 67ea2979d5 user: dan tags: ota-update)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/ota/ota.c.
51
52
53
54
55
56
57

58
59
60
61
62
63
64
  int i;
  const char *zTarget;            /* Target database to apply OTA to */
  const char *zOta;               /* Database containing OTA */
  char *zErrmsg;                  /* Error message, if any */
  sqlite3ota *pOta;               /* OTA handle */
  int nStep = 0;                  /* Maximum number of step() calls */
  int rc;


  /* Process command line arguments. Following this block local variables 
  ** zTarget, zOta and nStep are all set. */
  if( argc==5 ){
    int nArg1 = strlen(argv[1]);
    if( nArg1>5 || nArg1<2 || memcmp("-step", argv[1], nArg1) ) usage(argv[0]);
    nStep = atoi(argv[2]);







>







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  int i;
  const char *zTarget;            /* Target database to apply OTA to */
  const char *zOta;               /* Database containing OTA */
  char *zErrmsg;                  /* Error message, if any */
  sqlite3ota *pOta;               /* OTA handle */
  int nStep = 0;                  /* Maximum number of step() calls */
  int rc;
  sqlite3_int64 nProgress = 0;

  /* Process command line arguments. Following this block local variables 
  ** zTarget, zOta and nStep are all set. */
  if( argc==5 ){
    int nArg1 = strlen(argv[1]);
    if( nArg1>5 || nArg1<2 || memcmp("-step", argv[1], nArg1) ) usage(argv[0]);
    nStep = atoi(argv[2]);
72
73
74
75
76
77
78

79
80
81
82
83
84



85
86
87
88



89
90
91
92
93
94
95
96
97
98
99

  /* Open an OTA handle. If nStep is less than or equal to zero, call
  ** sqlite3ota_step() until either the OTA has been completely applied
  ** or an error occurs. Or, if nStep is greater than zero, call
  ** sqlite3ota_step() a maximum of nStep times.  */
  pOta = sqlite3ota_open(zTarget, zOta);
  for(i=0; (nStep<=0 || i<nStep) && sqlite3ota_step(pOta)==SQLITE_OK; i++);

  rc = sqlite3ota_close(pOta, &zErrmsg);

  /* Let the user know what happened. */
  switch( rc ){
    case SQLITE_OK:
      fprintf(stdout, "SQLITE_OK: ota update incomplete\n");



      break;

    case SQLITE_DONE:
      fprintf(stdout, "SQLITE_DONE: ota update completed\n");



      break;

    default:
      fprintf(stderr, "error=%d: %s\n", rc, zErrmsg);
      break;
  }

  sqlite3_free(zErrmsg);
  return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1;
}








>





|
>
>
>



|
>
>
>











73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

  /* Open an OTA handle. If nStep is less than or equal to zero, call
  ** sqlite3ota_step() until either the OTA has been completely applied
  ** or an error occurs. Or, if nStep is greater than zero, call
  ** sqlite3ota_step() a maximum of nStep times.  */
  pOta = sqlite3ota_open(zTarget, zOta);
  for(i=0; (nStep<=0 || i<nStep) && sqlite3ota_step(pOta)==SQLITE_OK; i++);
  nProgress = sqlite3ota_progress(pOta);
  rc = sqlite3ota_close(pOta, &zErrmsg);

  /* Let the user know what happened. */
  switch( rc ){
    case SQLITE_OK:
      fprintf(stdout, 
          "SQLITE_OK: ota update incomplete (%lld operations so far)\n",
          nProgress
      );
      break;

    case SQLITE_DONE:
      fprintf(stdout, 
          "SQLITE_DONE: ota update completed (%lld operations)\n",
          nProgress
      );
      break;

    default:
      fprintf(stderr, "error=%d: %s\n", rc, zErrmsg);
      break;
  }

  sqlite3_free(zErrmsg);
  return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1;
}

Changes to ext/ota/sqlite3ota.c.
45
46
47
48
49
50
51

52
53
54
55
56
57
58
/*
** A structure to store values read from the ota_state table in memory.
*/
struct OtaState {
  char *zTbl;
  char *zIdx;
  int nRow;

};

/*
** An iterator of this type is used to iterate through all objects in
** the target database that require updating. For each such table, the
** iterator visits, in order:
**







>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*
** A structure to store values read from the ota_state table in memory.
*/
struct OtaState {
  char *zTbl;
  char *zIdx;
  int nRow;
  sqlite3_int64 nProgress;
};

/*
** An iterator of this type is used to iterate through all objects in
** the target database that require updating. For each such table, the
** iterator visits, in order:
**
89
90
91
92
93
94
95

96
97
98
99
100
101
102
*/
struct sqlite3ota {
  sqlite3 *db;                    /* "main" -> target db, "ota" -> ota db */
  char *zTarget;                  /* Path to target db */
  int rc;                         /* Value returned by last ota_step() call */
  char *zErrmsg;                  /* Error message if rc!=SQLITE_OK */
  int nStep;                      /* Rows processed for current object */

  OtaObjIter objiter;
};

/*
** Prepare the SQL statement in buffer zSql against database handle db.
** If successful, set *ppStmt to point to the new statement and return
** SQLITE_OK. 







>







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
*/
struct sqlite3ota {
  sqlite3 *db;                    /* "main" -> target db, "ota" -> ota db */
  char *zTarget;                  /* Path to target db */
  int rc;                         /* Value returned by last ota_step() call */
  char *zErrmsg;                  /* Error message if rc!=SQLITE_OK */
  int nStep;                      /* Rows processed for current object */
  int nProgress;                  /* Rows processed for all objects */
  OtaObjIter objiter;
};

/*
** Prepare the SQL statement in buffer zSql against database handle db.
** If successful, set *ppStmt to point to the new statement and return
** SQLITE_OK. 
877
878
879
880
881
882
883

884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
        otaObjIterPrepareAll(p, pIter, 0);
        
        /* Advance to the next row to process. */
        if( p->rc==SQLITE_OK ){
          int rc = sqlite3_step(pIter->pSelect);
          if( rc==SQLITE_ROW ){
            p->nStep++;

            return otaStep(p);
          }
          p->rc = sqlite3_reset(pIter->pSelect);
          p->nStep = 0;
        }
      }

      otaObjIterNext(p, pIter);
    }

    if( p->rc==SQLITE_OK && pIter->zTbl==0 ){
      p->rc = SQLITE_DONE;
    }
  }
  return p->rc;
}

static void otaSaveTransactionState(sqlite3ota *p){
  otaMPrintfExec(p, 
    "INSERT OR REPLACE INTO ota.ota_state(rowid, tbl, idx, row, progress)"
    "VALUES(1, %Q, %Q, %d, NULL)",
    p->objiter.zTbl, p->objiter.zIdx, p->nStep
  );
}

/*
** Allocate an OtaState object and load the contents of the ota_state 
** table into it. Return a pointer to the new object. It is the 
** responsibility of the caller to eventually free the object using







>




















|
|







879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
        otaObjIterPrepareAll(p, pIter, 0);
        
        /* Advance to the next row to process. */
        if( p->rc==SQLITE_OK ){
          int rc = sqlite3_step(pIter->pSelect);
          if( rc==SQLITE_ROW ){
            p->nStep++;
            p->nProgress++;
            return otaStep(p);
          }
          p->rc = sqlite3_reset(pIter->pSelect);
          p->nStep = 0;
        }
      }

      otaObjIterNext(p, pIter);
    }

    if( p->rc==SQLITE_OK && pIter->zTbl==0 ){
      p->rc = SQLITE_DONE;
    }
  }
  return p->rc;
}

static void otaSaveTransactionState(sqlite3ota *p){
  otaMPrintfExec(p, 
    "INSERT OR REPLACE INTO ota.ota_state(rowid, tbl, idx, row, progress)"
    "VALUES(1, %Q, %Q, %d, %lld)",
    p->objiter.zTbl, p->objiter.zIdx, p->nStep, p->nProgress
  );
}

/*
** Allocate an OtaState object and load the contents of the ota_state 
** table into it. Return a pointer to the new object. It is the 
** responsibility of the caller to eventually free the object using
938
939
940
941
942
943
944

945
946
947
948
949
950
951
        if( zIdx ){
          pRet->zIdx = &pRet->zTbl[nTbl];
          memcpy(pRet->zIdx, zIdx, nIdx);
        }else{
          pRet->zIdx = 0;
        }
        pRet->nRow = sqlite3_column_int(pStmt, 2);

      }
    }else{
      pRet = (OtaState*)sqlite3_malloc(sizeof(OtaState));
      if( pRet ){
        memset(pRet, 0, sizeof(*pRet));
      }
    }







>







941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
        if( zIdx ){
          pRet->zIdx = &pRet->zTbl[nTbl];
          memcpy(pRet->zIdx, zIdx, nIdx);
        }else{
          pRet->zIdx = 0;
        }
        pRet->nRow = sqlite3_column_int(pStmt, 2);
        pRet->nProgress = sqlite3_column_int64(pStmt, 3);
      }
    }else{
      pRet = (OtaState*)sqlite3_malloc(sizeof(OtaState));
      if( pRet ){
        memset(pRet, 0, sizeof(*pRet));
      }
    }
1071
1072
1073
1074
1075
1076
1077

1078
1079
1080
1081
1082
1083
1084

    /* Point the object iterator at the first object */
    if( p->rc==SQLITE_OK ){
      p->rc = otaObjIterFirst(p, &p->objiter);
    }

    if( p->rc==SQLITE_OK ){

      otaLoadTransactionState(p, pState);
    }

    sqlite3_free(pState);
  }

  return p;







>







1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089

    /* Point the object iterator at the first object */
    if( p->rc==SQLITE_OK ){
      p->rc = otaObjIterFirst(p, &p->objiter);
    }

    if( p->rc==SQLITE_OK ){
      p->nProgress = pState->nProgress;
      otaLoadTransactionState(p, pState);
    }

    sqlite3_free(pState);
  }

  return p;
1123
1124
1125
1126
1127
1128
1129









1130
1131
1132
1133
1134
1135
1136
    sqlite3_free(p);
  }else{
    rc = SQLITE_NOMEM;
    *pzErrmsg = 0;
  }
  return rc;
}











/**************************************************************************/

#ifdef SQLITE_TEST 

#include <tcl.h>







>
>
>
>
>
>
>
>
>







1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
    sqlite3_free(p);
  }else{
    rc = SQLITE_NOMEM;
    *pzErrmsg = 0;
  }
  return rc;
}

/*
** Return the total number of key-value operations (inserts, deletes or 
** updates) that have been performed on the target database since the
** current OTA update was started.
*/
sqlite3_int64 sqlite3ota_progress(sqlite3ota *pOta){
  return pOta->nProgress;
}


/**************************************************************************/

#ifdef SQLITE_TEST 

#include <tcl.h>
Changes to ext/ota/sqlite3ota.h.
211
212
213
214
215
216
217







218
219
**
** Otherwise, if no error occurs, this function returns SQLITE_OK if the
** update has been partially applied, or SQLITE_DONE if it has been 
** completely applied.
*/
int sqlite3ota_close(sqlite3ota *pOta, char **pzErrmsg);








#endif /* _SQLITE3OTA_H */








>
>
>
>
>
>
>


211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
**
** Otherwise, if no error occurs, this function returns SQLITE_OK if the
** update has been partially applied, or SQLITE_DONE if it has been 
** completely applied.
*/
int sqlite3ota_close(sqlite3ota *pOta, char **pzErrmsg);

/*
** Return the total number of key-value operations (inserts, deletes or 
** updates) that have been performed on the target database since the
** current OTA update was started.
*/
sqlite3_int64 sqlite3ota_progress(sqlite3ota *pOta);

#endif /* _SQLITE3OTA_H */