1
00:00:04,069 --> 00:00:07,230
So a few videos ago we changed our

2
00:00:07,230 --> 00:00:09,929
content providers query function to use

3
00:00:09,929 --> 00:00:12,509
appendWhereEscapeString rather than

4
00:00:12,509 --> 00:00:14,940
appendWhere. Now I didn't go into a lot

5
00:00:14,940 --> 00:00:17,100
of detail about this function because we

6
00:00:17,100 --> 00:00:19,109
couldn't test the code at that stage, but

7
00:00:19,109 --> 00:00:21,689
we finished the previous video by seeing

8
00:00:21,689 --> 00:00:24,029
that appendWhere worked, but there was a

9
00:00:24,029 --> 00:00:26,189
problem using appendWhereEscapeString.

10
00:00:26,189 --> 00:00:27,630
Obviously it's not quite as

11
00:00:27,630 --> 00:00:29,130
straightforward as just swapping one

12
00:00:29,130 --> 00:00:30,990
function out for the other. So there's

13
00:00:30,990 --> 00:00:32,579
something going on with the escape

14
00:00:32,579 --> 00:00:34,739
String version of appendWhere, and it

15
00:00:34,739 --> 00:00:36,780
would be really useful to log the SQL

16
00:00:36,780 --> 00:00:38,850
that it produces to see what's going on.

17
00:00:38,850 --> 00:00:41,760
Unfortunately though, we're using a query

18
00:00:41,760 --> 00:00:44,100
Builder, and the query builder class does

19
00:00:44,100 --> 00:00:46,320
not provide a function for accessing the

20
00:00:46,320 --> 00:00:49,170
SQL that it creates. Now when you find

21
00:00:49,170 --> 00:00:51,390
yourself in a situation like this, it's

22
00:00:51,390 --> 00:00:53,309
worth having a look at the source code

23
00:00:53,309 --> 00:00:55,800
for the classes that you're using. So in

24
00:00:55,800 --> 00:00:57,360
this case we're interested in the query

25
00:00:57,360 --> 00:01:00,480
Builder source code, which we can get by

26
00:01:00,480 --> 00:01:02,699
control clicking on the query function

27
00:01:02,699 --> 00:01:04,530
called in our code - so right down at the

28
00:01:04,530 --> 00:01:06,900
end of the query function that we've

29
00:01:06,900 --> 00:01:10,110
added to this AppProvider. So I'm going to

30
00:01:10,110 --> 00:01:11,580
ctrl click that, or command if you're on

31
00:01:11,580 --> 00:01:14,520
a Mac. You can see here now that we've

32
00:01:14,520 --> 00:01:16,259
got to the source of the query function

33
00:01:16,259 --> 00:01:17,939
that we're calling, and it doesn't really

34
00:01:17,939 --> 00:01:20,310
do much. Now as this is a Kotlin course,

35
00:01:20,310 --> 00:01:23,009
I'll very briefly talk about overloading

36
00:01:23,009 --> 00:01:24,869
functions in Java. Now that's not

37
00:01:24,869 --> 00:01:27,150
something we do in Kotlin, because Kotlin

38
00:01:27,150 --> 00:01:29,100
provides default values for function

39
00:01:29,100 --> 00:01:31,680
arguments. Java, on the other hand, doesn't

40
00:01:31,680 --> 00:01:34,049
let you do that. Instead Java lets you

41
00:01:34,049 --> 00:01:35,939
create different versions of the same

42
00:01:35,939 --> 00:01:38,490
function or method, as it's Java with

43
00:01:38,490 --> 00:01:40,380
different arguments. That's called

44
00:01:40,380 --> 00:01:42,720
overloading the method. Now the query

45
00:01:42,720 --> 00:01:44,850
method we're using is an overloaded

46
00:01:44,850 --> 00:01:47,520
version of another query method. Now this

47
00:01:47,520 --> 00:01:49,770
one doesn't do much - it just calls the

48
00:01:49,770 --> 00:01:52,020
one it's overloading and returns the

49
00:01:52,020 --> 00:01:54,210
result of calling that. Now if we

50
00:01:54,210 --> 00:01:55,950
actually can click on the query function

51
00:01:55,950 --> 00:01:59,670
that it's calling - this one here - we can

52
00:01:59,670 --> 00:02:00,990
see the source for that one on-screen

53
00:02:00,990 --> 00:02:03,030
now. Now this version of the query is

54
00:02:03,030 --> 00:02:04,890
slightly different. It's got an extra

55
00:02:04,890 --> 00:02:07,290
cancellation signal argument right at

56
00:02:07,290 --> 00:02:09,060
the end of the parameter list. Now the

57
00:02:09,060 --> 00:02:11,068
function we call just sets that argument

58
00:02:11,068 --> 00:02:13,980
to null. In Kotlin we'd use a default

59
00:02:13,980 --> 00:02:16,200
value of null, rather than overloading

60
00:02:16,200 --> 00:02:18,840
the function. In Java however, you declare

61
00:02:18,840 --> 00:02:20,909
the method again with the additional

62
00:02:20,909 --> 00:02:22,590
parameter. Now that's a bit more 

63
00:02:22,590 --> 00:02:24,480
verbose, but that's all that's meant by

64
00:02:24,480 --> 00:02:27,480
method overloading in Java. so watch out

65
00:02:27,480 --> 00:02:28,860
for this when you're reading the Java

66
00:02:28,860 --> 00:02:30,930
source code. There'll often be different

67
00:02:30,930 --> 00:02:33,180
versions of the same method, and often

68
00:02:33,180 --> 00:02:34,620
the one you will be using will call

69
00:02:34,620 --> 00:02:36,239
another version with different

70
00:02:36,239 --> 00:02:38,400
parameters. Alright so let's dig

71
00:02:38,400 --> 00:02:39,959
in and see what this particular method's

72
00:02:39,959 --> 00:02:42,390
doing. Now when I'm reading the Android

73
00:02:42,390 --> 00:02:44,340
sources, I don't try to understand

74
00:02:44,340 --> 00:02:47,190
everything in fine detail, at least not

75
00:02:47,190 --> 00:02:47,910
at first.

76
00:02:47,910 --> 00:02:49,620
Now and then you'll hit a problem that's

77
00:02:49,620 --> 00:02:51,480
complex enough that you have to check

78
00:02:51,480 --> 00:02:54,030
the source very carefully. Often though, a

79
00:02:54,030 --> 00:02:55,950
quick scan of the methods and comments

80
00:02:55,950 --> 00:02:58,319
is enough. Now this particular method's

81
00:02:58,319 --> 00:03:00,450
quite straightforward. Firstly, if no

82
00:03:00,450 --> 00:03:02,910
tables were specified it returns null,

83
00:03:02,910 --> 00:03:04,500
right at the start of the method there -

84
00:03:04,500 --> 00:03:07,620
you can see line 376. That makes sense.

85
00:03:07,620 --> 00:03:08,940
We're not going to get anything back if

86
00:03:08,940 --> 00:03:10,650
we haven't specified any tables to query.

87
00:03:10,650 --> 00:03:13,709
The next bit of code down here, starting

88
00:03:13,709 --> 00:03:16,859
on line 379, deals with the escaping to

89
00:03:16,859 --> 00:03:19,290
prevent injection attacks. So you can see

90
00:03:19,290 --> 00:03:21,299
that it's calling a validateSql

91
00:03:21,299 --> 00:03:24,870
method there on line 389, and it's

92
00:03:24,870 --> 00:03:26,430
calling that method of the SQLite

93
00:03:26,430 --> 00:03:28,500
Database class. And that method will

94
00:03:28,500 --> 00:03:30,239
throw an exception if anything dodgy is

95
00:03:30,239 --> 00:03:33,060
detected. The comment gives that away - the

96
00:03:33,060 --> 00:03:35,069
end of the line there, "will throw if query is

97
00:03:35,069 --> 00:03:37,769
invalid". So far so good, but what happens

98
00:03:37,769 --> 00:03:39,829
next? Well it builds up a query string.

99
00:03:39,829 --> 00:03:41,940
You can see it's starting to do that on

100
00:03:41,940 --> 00:03:44,549
line 392, and it's building up that query

101
00:03:44,549 --> 00:03:45,870
string from the arguments that were

102
00:03:45,870 --> 00:03:48,090
passed in. Now that string's very similar

103
00:03:48,090 --> 00:03:50,819
to the sequel that it validated. So read

104
00:03:50,819 --> 00:03:52,440
the comment to understand why it builds

105
00:03:52,440 --> 00:03:54,810
the query string twice. So as it says up

106
00:03:54,810 --> 00:03:55,500
here,

107
00:03:55,500 --> 00:03:59,519
"An attacker can't create an expression

108
00:03:59,519 --> 00:04:01,470
that would escape the SQL expression

109
00:04:01,470 --> 00:04:04,349
while maintaining balance parentheses in

110
00:04:04,349 --> 00:04:07,590
both the wrapped and original forms." So

111
00:04:07,590 --> 00:04:09,389
basically, if an injection attack is

112
00:04:09,389 --> 00:04:12,389
tried, this code will either throw an

113
00:04:12,389 --> 00:04:14,459
exception when validating the SQL

114
00:04:14,459 --> 00:04:17,760
string, or it'll attempt to execute an invalid

115
00:04:17,760 --> 00:04:20,639
string that the database will reject. So

116
00:04:20,639 --> 00:04:22,140
it's not possible for both the escaped

117
00:04:22,140 --> 00:04:24,419
and original sequel to be valid in the

118
00:04:24,419 --> 00:04:26,610
case of an attempted attack. So the

119
00:04:26,610 --> 00:04:27,880
result is that an 

120
00:04:27,880 --> 00:04:30,160
attack string will either cause an exception

121
00:04:30,160 --> 00:04:31,930
to be thrown by the validate single

122
00:04:31,930 --> 00:04:34,390
method, or it'll cause an error when the

123
00:04:34,390 --> 00:04:36,520
database tried to execute the SQL.

124
00:04:36,520 --> 00:04:38,560
Whichever happens though, the attack

125
00:04:38,560 --> 00:04:40,810
won't work. But with that said, we're

126
00:04:40,810 --> 00:04:42,550
not here to understand the fine details

127
00:04:42,550 --> 00:04:45,220
of how escaping works. We're trying to

128
00:04:45,220 --> 00:04:46,600
see if there's anything that can help us

129
00:04:46,600 --> 00:04:49,930
to work out why our query failed. So

130
00:04:49,930 --> 00:04:51,100
scrolling down a little bit,

131
00:04:51,100 --> 00:04:53,920
notice the code on line 396. That's

132
00:04:53,920 --> 00:04:56,350
pretty interesting. After building the

133
00:04:56,350 --> 00:04:58,360
original SQL string in the variable

134
00:04:58,360 --> 00:05:01,540
SQL, that method's actually logging it. Now

135
00:05:01,540 --> 00:05:03,190
it does things slightly different to how

136
00:05:03,190 --> 00:05:05,260
we've been logging. Now we use debug

137
00:05:05,260 --> 00:05:07,300
level logging, and rely on those log

138
00:05:07,300 --> 00:05:09,490
calls being stripped out when we build

139
00:05:09,490 --> 00:05:12,040
the release version of the app. But in a

140
00:05:12,040 --> 00:05:14,350
library class like this one, stripping

141
00:05:14,350 --> 00:05:15,970
out the debug logging calls would make

142
00:05:15,970 --> 00:05:18,280
life very hard for people using the

143
00:05:18,280 --> 00:05:20,890
class - us in other words. So to prevent

144
00:05:20,890 --> 00:05:22,840
all those debug log entries from filling

145
00:05:22,840 --> 00:05:24,910
up the logcat and slowing the app down,

146
00:05:24,910 --> 00:05:27,370
this code checks if debug logging is

147
00:05:27,370 --> 00:05:31,180
enabled and only calls Log.d if it is. So

148
00:05:31,180 --> 00:05:33,640
at this point, yay we've struck gold. We

149
00:05:33,640 --> 00:05:35,680
want to log the SQL and this method

150
00:05:35,680 --> 00:05:37,900
is already doing it for us. So all we

151
00:05:37,900 --> 00:05:39,400
have to do is work out how to tell

152
00:05:39,400 --> 00:05:42,250
Android to enable debug logging for this

153
00:05:42,250 --> 00:05:44,500
particular class. As it turns out it's

154
00:05:44,500 --> 00:05:47,350
very easy to do, so let's do that. Now

155
00:05:47,350 --> 00:05:49,000
what we'll need first is the tag that

156
00:05:49,000 --> 00:05:51,040
the class is using, so I'm going to come

157
00:05:51,040 --> 00:05:54,160
over here and click on the tag, and I'm

158
00:05:54,160 --> 00:05:56,020
going to double click on the contents of

159
00:05:56,020 --> 00:05:58,150
that tag. In this case it's set to SQL

160
00:05:58,150 --> 00:05:59,710
iteQueryBuilder. I'm going to take a copy

161
00:05:59,710 --> 00:06:01,240
of that, making sure that I didn't

162
00:06:01,240 --> 00:06:02,500
include the double quotes when I've

163
00:06:02,500 --> 00:06:04,230
copied it. We just want the tags value,

164
00:06:04,230 --> 00:06:07,360
not a delimited Java string. Alright so

165
00:06:07,360 --> 00:06:09,790
to enable logging at the debug level for

166
00:06:09,790 --> 00:06:12,220
this tag, we can use adb to set a

167
00:06:12,220 --> 00:06:14,590
property on the device or emulator. So

168
00:06:14,590 --> 00:06:17,170
I'm going to open the terminal window, and I'm

169
00:06:17,170 --> 00:06:24,220
going to type adb shell setprop log dot

170
00:06:24,220 --> 00:06:27,250
tag dot. Then I'm going to paste in what I

171
00:06:27,250 --> 00:06:28,780
copied from the Java source code,

172
00:06:28,780 --> 00:06:31,090
in this case eSQLiteQueryBuilder space

173
00:06:31,090 --> 00:06:36,040
then DEBUG in uppercase, press enter. Now

174
00:06:36,040 --> 00:06:38,470
the properties name is log dot tag dot, and

175
00:06:38,470 --> 00:06:39,760
then the tag that we're interested in as

176
00:06:39,760 --> 00:06:41,380
you saw there, which I've pasted into the

177
00:06:41,380 --> 00:06:41,650
terminal.

178
00:06:41,650 --> 00:06:44,530
Now the class is logging the SQL at

179
00:06:44,530 --> 00:06:46,419
the debug level, so that's why I've used

180
00:06:46,419 --> 00:06:49,300
debug as the property value. And it's

181
00:06:49,300 --> 00:06:51,669
actually as easy as that. If a class in the

182
00:06:51,669 --> 00:06:53,919
Android framework does some logging, you

183
00:06:53,919 --> 00:06:55,840
can enable it by setting the property

184
00:06:55,840 --> 00:06:57,940
using adb shell. Now there was another

185
00:06:57,940 --> 00:07:00,460
way to do that by creating a prop file

186
00:07:00,460 --> 00:07:02,889
on the emulator, but as many students

187
00:07:02,889 --> 00:07:04,479
are using their phones to run these apps,

188
00:07:04,479 --> 00:07:06,729
I prefer not making a change to the

189
00:07:06,729 --> 00:07:08,949
phone itself. So this method that we've

190
00:07:08,949 --> 00:07:11,050
done here doesn't make any permanent

191
00:07:11,050 --> 00:07:13,270
change, but what it does mean is that you

192
00:07:13,270 --> 00:07:15,490
have to enter the command again every

193
00:07:15,490 --> 00:07:17,169
time the device - the emulator - is

194
00:07:17,169 --> 00:07:19,360
restarted. Now if you are using a

195
00:07:19,360 --> 00:07:21,669
physical device for this course, reboot

196
00:07:21,669 --> 00:07:23,740
it after this video to put the logging

197
00:07:23,740 --> 00:07:25,750
back to how it was. Alright, so with all

198
00:07:25,750 --> 00:07:27,699
that said, does it work? Well at the end

199
00:07:27,699 --> 00:07:29,229
of the previous video we changed the

200
00:07:29,229 --> 00:07:31,449
code so that it worked. So I'm going to

201
00:07:31,449 --> 00:07:33,849
exit out of terminal now, and we'll

202
00:07:33,849 --> 00:07:34,870
go back. We'll close down some of

203
00:07:34,870 --> 00:07:35,979
these files now, we don't need

204
00:07:35,979 --> 00:07:38,130
them anymore, or just that one file. So

205
00:07:38,130 --> 00:07:40,270
looking at the code, we changed it back

206
00:07:40,270 --> 00:07:42,940
to appendWhere on line 80, as you can see

207
00:07:42,940 --> 00:07:44,860
there. So it's using that rather than 

208
00:07:44,860 --> 00:07:46,990
appendWhereEscapeString. So let's run the

209
00:07:46,990 --> 00:07:49,120
app first and see what the valid SQL

210
00:07:49,120 --> 00:07:50,199
looks like, because we know that that

211
00:07:50,199 --> 00:07:57,630
that's working.

212
00:07:57,630 --> 00:07:59,940
Alright so there's the debug coming from

213
00:07:59,940 --> 00:08:01,770
SQLiteQueryBuilder, as you can see

214
00:08:01,770 --> 00:08:03,960
there. So that obviously worked - the

215
00:08:03,960 --> 00:08:05,940
command, the adb shell setprop command

216
00:08:05,940 --> 00:08:07,920
that we used - and you can see it's using

217
00:08:07,920 --> 00:08:09,690
a SELECT Name comma SortOrder FROM

218
00:08:09,690 --> 00:08:12,270
Tasks WHERE, then parentheses underscore ID

219
00:08:12,270 --> 00:08:14,970
equals 2 ORDER BY SortOrder. No surprises

220
00:08:14,970 --> 00:08:16,530
there, and what I could have done to

221
00:08:16,530 --> 00:08:18,060
get, to find that quickly, I could have

222
00:08:18,060 --> 00:08:20,490
just done a filter on 

223
00:08:20,490 --> 00:08:23,970
logcat, sqlite query builder or just do an

224
00:08:23,970 --> 00:08:25,470
sqlite to find that really

225
00:08:25,470 --> 00:08:27,090
quickly. If you're having trouble that's one

226
00:08:27,090 --> 00:08:29,040
way to quickly find it, but again, no

227
00:08:29,040 --> 00:08:31,260
surprise there. That's valid SQL and

228
00:08:31,260 --> 00:08:33,049
of course the app was actually working.

229
00:08:33,049 --> 00:08:35,370
Alright, so let's now change the code

230
00:08:35,370 --> 00:08:38,669
back to use the appendWhereEscape

231
00:08:38,669 --> 00:08:41,070
String and see what went wrong. So what

232
00:08:41,070 --> 00:08:42,270
I'm going to do is duplicate that line

233
00:08:42,270 --> 00:08:45,120
initially, then I'm going to comment that

234
00:08:45,120 --> 00:08:47,940
out. Then I'm going to set the second line to

235
00:08:47,940 --> 00:08:51,240
EscapeString. So let's stop the app and

236
00:08:51,240 --> 00:08:51,930
start it again.

237
00:08:51,930 --> 00:08:54,510
Run it, then we'll swing over to the

238
00:08:54,510 --> 00:08:57,810
logcat and see what it's done. Actually I'll open

239
00:08:57,810 --> 00:09:00,030
the logcat again. You can see now that's

240
00:09:00,030 --> 00:09:02,040
the cause of our problem. Looking at the

241
00:09:02,040 --> 00:09:04,620
WHERE clause we've got parenthesis id,

242
00:09:04,620 --> 00:09:07,250
underscore id equals two in single quotes.

243
00:09:07,250 --> 00:09:09,750
We only want the value 2 here to be

244
00:09:09,750 --> 00:09:11,220
escaped. We don't want the entire

245
00:09:11,220 --> 00:09:13,620
conditioning quotes as showing at the

246
00:09:13,620 --> 00:09:15,660
moment, so that's the reason why we're

247
00:09:15,660 --> 00:09:18,060
not getting any data back. So to fix this

248
00:09:18,060 --> 00:09:20,820
we can use appendWhere for the column

249
00:09:20,820 --> 00:09:23,400
name, then appendWhereEscapeString for

250
00:09:23,400 --> 00:09:26,010
the value - in this case our taskId. So let's

251
00:09:26,010 --> 00:09:27,810
have a go at doing that. So I'm going to

252
00:09:27,810 --> 00:09:30,450
uncomment this again, the appendWhere. I'm

253
00:09:30,450 --> 00:09:31,860
going to change that now so it's just

254
00:09:31,860 --> 00:09:34,800
got, in double quotes, dollar left and

255
00:09:34,800 --> 00:09:37,020
right curly braces TaskContract dot

256
00:09:37,020 --> 00:09:39,510
Columns.ID, then right

257
00:09:39,510 --> 00:09:41,580
curly brace equals. I'm going to delete

258
00:09:41,580 --> 00:09:44,520
that last part there. So we've just got

259
00:09:44,520 --> 00:09:47,130
the equals and a space, and then let's

260
00:09:47,130 --> 00:09:48,990
fix the next line that's already

261
00:09:48,990 --> 00:09:51,120
got the appendWhereEscapeString, and I'm

262
00:09:51,120 --> 00:09:53,910
going to delete everything other than

263
00:09:53,910 --> 00:09:56,850
the dollar taskId. So you can see that

264
00:09:56,850 --> 00:09:59,160
we're just escaping now, effectively, the

265
00:09:59,160 --> 00:10:01,290
taskId. Everything else is just a

266
00:10:01,290 --> 00:10:03,660
general appendWhere on the previous

267
00:10:03,660 --> 00:10:05,190
line. So now that we've done that,

268
00:10:05,190 --> 00:10:10,620
let's stop this and start it again, swing

269
00:10:10,620 --> 00:10:12,110
over to our logcat.

270
00:10:12,110 --> 00:10:14,370
And you can see now we've got some valid

271
00:10:14,370 --> 00:10:16,920
SQL: SELECT Name comma SortOrder FROM

272
00:10:16,920 --> 00:10:18,870
Tasks WHERE, and in parentheses underscore

273
00:10:18,870 --> 00:10:21,000
id equals, then the value here in single

274
00:10:21,000 --> 00:10:23,610
quotes 2. So that's now correct, and if I

275
00:10:23,610 --> 00:10:26,250
actually delete this filter now, we've

276
00:10:26,250 --> 00:10:29,490
got rows in returned cursor equals 1 and

277
00:10:29,490 --> 00:10:30,930
we've actually got our records showing

278
00:10:30,930 --> 00:10:32,640
on the screen there. Now we added the

279
00:10:32,640 --> 00:10:34,350
appendWhereEscapeString to the code a

280
00:10:34,350 --> 00:10:36,840
few videos ago, but trying to explain all

281
00:10:36,840 --> 00:10:37,920
this when we couldn't run the app would

282
00:10:37,920 --> 00:10:39,990
have been confusing. Seeing the different

283
00:10:39,990 --> 00:10:41,520
SQL that it produces makes it much

284
00:10:41,520 --> 00:10:44,730
easier to see how to use it correctly. So

285
00:10:44,730 --> 00:10:46,980
you use appendWhereEscapeString to

286
00:10:46,980 --> 00:10:49,170
append the values, not to append an

287
00:10:49,170 --> 00:10:50,640
entire WHERE clause.

288
00:10:50,640 --> 00:10:52,290
Alright, so now that we've got that fixed

289
00:10:52,290 --> 00:10:55,440
I'll just close down logcat, and let's

290
00:10:55,440 --> 00:10:57,210
make the same changes to the commented

291
00:10:57,210 --> 00:10:59,310
out code for the TIMINGS and TASK

292
00:10:59,310 --> 00:11:01,470
DURATIONS, because if we don't do it now

293
00:11:01,470 --> 00:11:02,910
it'll be too easy to forget to do it

294
00:11:02,910 --> 00:11:04,530
later. So what I'm going to do is take a

295
00:11:04,530 --> 00:11:07,140
copy of that first line, change that to

296
00:11:07,140 --> 00:11:10,110
just the appendWhere. I'm going to

297
00:11:10,110 --> 00:11:12,240
delete after the equal signs, equal sign,

298
00:11:12,240 --> 00:11:14,730
up and to the double quote. I'll put a

299
00:11:14,730 --> 00:11:17,160
space after there. Then the second line,

300
00:11:17,160 --> 00:11:19,710
I'm going to delete everything but, in

301
00:11:19,710 --> 00:11:21,660
the double quotes rather, everything but

302
00:11:21,660 --> 00:11:23,730
the $timingId, and we'll do the

303
00:11:23,730 --> 00:11:27,120
same for the durations, TASK_DURATIONS_

304
00:11:27,120 --> 00:11:31,100
ID. Change the first call to appendWhere,

305
00:11:31,100 --> 00:11:32,760
in double quotes,

306
00:11:32,760 --> 00:11:36,420
delete after the equals sign. Then leave

307
00:11:36,420 --> 00:11:38,100
the appendWhereEscapeString as the

308
00:11:38,100 --> 00:11:40,170
second call, deleting everything but in

309
00:11:40,170 --> 00:11:43,260
this case, the $durationId. So that

310
00:11:43,260 --> 00:11:45,150
should hopefully work when it comes time

311
00:11:45,150 --> 00:11:47,310
to use that code. Now with that said, it's

312
00:11:47,310 --> 00:11:49,500
quite easy to make a mistake when typing

313
00:11:49,500 --> 00:11:51,660
code into a comment, obviously because

314
00:11:51,660 --> 00:11:53,820
there's no syntax checking. But I'd much

315
00:11:53,820 --> 00:11:55,590
rather have a minor mistake in there and

316
00:11:55,590 --> 00:11:57,570
have to correct it when we uncomment the

317
00:11:57,570 --> 00:11:59,280
code, rather than forgetting to use

318
00:11:59,280 --> 00:12:02,130
EscapeString correctly. Alright, so at

319
00:12:02,130 --> 00:12:03,930
this point queries against our database

320
00:12:03,930 --> 00:12:06,780
using the AppProvider class are working

321
00:12:06,780 --> 00:12:08,730
now. In the next video we'll finish off

322
00:12:08,730 --> 00:12:10,950
the Content Provider, writing the code to

323
00:12:10,950 --> 00:12:13,320
insert new rows, as well as updating rows

324
00:12:13,320 --> 00:12:16,140
and deleting existing ones. So I'll see

325
00:12:16,140 --> 00:12:19,010
you in the next video.

