1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _ANDROID__DATABASE_WINDOW_H
18#define _ANDROID__DATABASE_WINDOW_H
19
20#include <cutils/log.h>
21#include <stddef.h>
22#include <stdint.h>
23
24#include <binder/IMemory.h>
25#include <utils/RefBase.h>
26
27#include <jni.h>
28
29#define DEFAULT_WINDOW_SIZE 4096
30#define MAX_WINDOW_SIZE (1024 * 1024)
31#define WINDOW_ALLOCATION_SIZE 4096
32
33#define ROW_SLOT_CHUNK_NUM_ROWS 16
34
35// Row slots are allocated in chunks of ROW_SLOT_CHUNK_NUM_ROWS,
36// with an offset after the rows that points to the next chunk
37#define ROW_SLOT_CHUNK_SIZE ((ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)) + sizeof(uint32_t))
38
39
40#if LOG_NDEBUG
41
42#define IF_LOG_WINDOW() if (false)
43#define LOG_WINDOW(...)
44
45#else
46
47#define IF_LOG_WINDOW() IF_LOG(LOG_DEBUG, "CursorWindow")
48#define LOG_WINDOW(...) LOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__)
49
50#endif
51
52
53// When defined to true strings are stored as UTF8, otherwise they're UTF16
54#define WINDOW_STORAGE_UTF8 1
55
56// When defined to true numberic values are stored inline in the field_slot_t, otherwise they're allocated in the window
57#define WINDOW_STORAGE_INLINE_NUMERICS 1
58
59namespace android {
60
61typedef struct
62{
63    uint32_t numRows;
64    uint32_t numColumns;
65} window_header_t;
66
67typedef struct
68{
69    uint32_t offset;
70} row_slot_t;
71
72typedef struct
73{
74    uint8_t type;
75    union {
76        double d;
77        int64_t l;
78        struct {
79            uint32_t offset;
80            uint32_t size;
81        } buffer;
82    } data;
83} __attribute__((packed)) field_slot_t;
84
85#define FIELD_TYPE_INTEGER 1
86#define FIELD_TYPE_FLOAT 2
87#define FIELD_TYPE_STRING 3
88#define FIELD_TYPE_BLOB 4
89#define FIELD_TYPE_NULL 5
90
91/**
92 * This class stores a set of rows from a database in a buffer. The begining of the
93 * window has first chunk of row_slot_ts, which are offsets to the row directory, followed by
94 * an offset to the next chunk in a linked-list of additional chunk of row_slot_ts in case
95 * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a
96 * field_slot_t per column, which has the size, offset, and type of the data for that field.
97 * Note that the data types come from sqlite3.h.
98 */
99class CursorWindow
100{
101public:
102                        CursorWindow(size_t maxSize);
103                        CursorWindow(){}
104    bool                setMemory(const sp<IMemory>&);
105                        ~CursorWindow();
106
107    bool                initBuffer(bool localOnly);
108    sp<IMemory>         getMemory() {return mMemory;}
109
110    size_t              size() {return mSize;}
111    uint8_t *           data() {return mData;}
112    uint32_t            getNumRows() {return mHeader->numRows;}
113    uint32_t            getNumColumns() {return mHeader->numColumns;}
114    void                freeLastRow() {
115                            if (mHeader->numRows > 0) {
116                                mHeader->numRows--;
117                            }
118                        }
119    bool                setNumColumns(uint32_t numColumns)
120                            {
121                                uint32_t cur = mHeader->numColumns;
122                                if (cur > 0 && cur != numColumns) {
123                                    LOGE("Trying to go from %d columns to %d", cur, numColumns);
124                                    return false;
125                                }
126                                mHeader->numColumns = numColumns;
127                                return true;
128                            }
129
130    int32_t             freeSpace();
131
132    void                clear();
133
134                        /**
135                         * Allocate a row slot and its directory. The returned
136                         * pointer points to the begining of the row's directory
137                         * or NULL if there wasn't room. The directory is
138                         * initialied with NULL entries for each field.
139                         */
140    field_slot_t *      allocRow();
141
142                        /**
143                         * Allocate a portion of the window. Returns the offset
144                         * of the allocation, or 0 if there isn't enough space.
145                         * If aligned is true, the allocation gets 4 byte alignment.
146                         */
147    uint32_t            alloc(size_t size, bool aligned = false);
148
149    uint32_t            read_field_slot(int row, int column, field_slot_t * slot);
150
151                        /**
152                         * Copy data into the window at the given offset.
153                         */
154    void                copyIn(uint32_t offset, uint8_t const * data, size_t size);
155    void                copyIn(uint32_t offset, int64_t data);
156    void                copyIn(uint32_t offset, double data);
157
158    void                copyOut(uint32_t offset, uint8_t * data, size_t size);
159    int64_t             copyOutLong(uint32_t offset);
160    double              copyOutDouble(uint32_t offset);
161
162    bool                putLong(unsigned int row, unsigned int col, int64_t value);
163    bool                putDouble(unsigned int row, unsigned int col, double value);
164    bool                putNull(unsigned int row, unsigned int col);
165
166    bool                getLong(unsigned int row, unsigned int col, int64_t * valueOut);
167    bool                getDouble(unsigned int row, unsigned int col, double * valueOut);
168    bool                getNull(unsigned int row, unsigned int col, bool * valueOut);
169
170    uint8_t *           offsetToPtr(uint32_t offset) {return mData + offset;}
171
172    row_slot_t *        allocRowSlot();
173
174    row_slot_t *        getRowSlot(int row);
175
176                        /**
177                         * return NULL if Failed to find rowSlot or
178                         * Invalid rowSlot
179                         */
180    field_slot_t *      getFieldSlotWithCheck(int row, int column);
181    field_slot_t *      getFieldSlot(int row, int column)
182                            {
183                                int fieldDirOffset = getRowSlot(row)->offset;
184                                return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
185                            }
186
187private:
188    uint8_t * mData;
189    size_t mSize;
190    size_t mMaxSize;
191    window_header_t * mHeader;
192    sp<IMemory> mMemory;
193
194    /**
195     * Offset of the lowest unused data byte in the array.
196     */
197    uint32_t mFreeOffset;
198};
199
200}; // namespace android
201
202#endif
203